@amerged/ohmyhost-mcp 0.1.39 → 0.1.41

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/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { createRequire as __ohmyhostCreateRequire } from "node:module"; const re
2
2
  import {
3
3
  createOhmyhostMcpServer,
4
4
  ohmyhostMcpHandler
5
- } from "./chunk-KQS5IMSO.js";
5
+ } from "./chunk-6HQPHICK.js";
6
6
  export {
7
7
  createOhmyhostMcpServer,
8
8
  ohmyhostMcpHandler
@@ -1 +1 @@
1
- PostgreSQL WebSocket bridge and authentication prelude handling adapted from cloudflare-postgres packages/cli, commit e05d9102c840e283602272ed0e16a95be3e3b8ea. Upstream license: Apache-2.0.
1
+ PostgreSQL WebSocket bridge and authentication prelude handling adapted from cloudflare-postgres (https://github.com/amerged-org/cloudflare-postgres) packages/cli, commit e05d9102c840e283602272ed0e16a95be3e3b8ea. Upstream license: Apache-2.0.
@@ -30,7 +30,7 @@ import {
30
30
  serverIdentityOf,
31
31
  setNegotiatedProtocolVersion,
32
32
  validateEnvelopeMeta
33
- } from "./chunk-KQS5IMSO.js";
33
+ } from "./chunk-6HQPHICK.js";
34
34
 
35
35
  // node_modules/.pnpm/ignore@7.0.12/node_modules/ignore/index.js
36
36
  var require_ignore = __commonJS({
@@ -24110,7 +24110,7 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
24110
24110
  },
24111
24111
  better_auth_version_required: {
24112
24112
  paths: ["manifest"],
24113
- template: '"{{path}}" must declare better-auth at exactly 1.7.1 in dependencies because ohmyhost.yaml sets auth.provider: better-auth. Pin that version or set auth.provider: none, commit and push the change, then plan the new commit.'
24113
+ template: '"{{path}}" must declare better-auth at exactly 1.7.7 in dependencies because ohmyhost.yaml sets auth.provider: better-auth. Pin that version or set auth.provider: none, commit and push the change, then plan the new commit.'
24114
24114
  },
24115
24115
  package_manifest_invalid: {
24116
24116
  paths: ["manifest"],
@@ -25417,31 +25417,41 @@ function assertOrganizationCreditUsage(value) {
25417
25417
  };
25418
25418
  const identifier3 = (input) => typeof input === "string" && /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u.test(input);
25419
25419
  const amount = (input) => typeof input === "string" && /^(0|[1-9][0-9]{0,37})$/u.test(input);
25420
- const report = record7(value, "organization_id,month,as_of,unit,data,next_cursor");
25421
- if (!identifier3(report["organization_id"]) || typeof report["month"] !== "string" || !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(report["month"]) || typeof report["as_of"] !== "string" || !Number.isFinite(Date.parse(report["as_of"])) || new Date(report["as_of"]).toISOString() !== report["as_of"] || report["unit"] !== "microcredits" || !Array.isArray(report["data"]) || report["data"].length > 20 || report["next_cursor"] !== null && !identifier3(report["next_cursor"]))
25420
+ const instant2 = (input) => typeof input === "string" && Number.isFinite(Date.parse(input)) && new Date(input).toISOString() === input;
25421
+ const report = record7(value, "organization_id,as_of,unit,period,from,projects,days");
25422
+ if (!identifier3(report["organization_id"]) || !instant2(report["as_of"]) || !instant2(report["from"]) || report["unit"] !== "microcredits" || typeof report["period"] !== "string" || !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(report["period"]) || !Array.isArray(report["projects"]) || report["projects"].length > 1e3 || !Array.isArray(report["days"]) || report["days"].length > 15)
25422
25423
  throw new TypeError("Invalid usage report");
25423
25424
  let previous = "";
25424
- for (const input of report["data"]) {
25425
- const project = record7(input, "project_id,reserved_micros,meters");
25426
- if (!identifier3(project["project_id"]) || String(project["project_id"]) <= previous || !amount(project["reserved_micros"]) || !Array.isArray(project["meters"]) || project["meters"].length > 1e3)
25425
+ for (const input of report["projects"]) {
25426
+ const project = record7(input, "project_id,used_micros");
25427
+ if (!identifier3(project["project_id"]) || String(project["project_id"]) <= previous || !amount(project["used_micros"]))
25427
25428
  throw new TypeError("Invalid usage project");
25428
25429
  previous = String(project["project_id"]);
25429
- for (const input2 of project["meters"]) {
25430
- const meter = record7(input2, "environment_id,meter,unit,rate_card_id,quantity,charged_micros,funded_micros,platform_overrun_micros");
25431
- if (meter["environment_id"] !== null && !identifier3(meter["environment_id"]))
25432
- throw new TypeError("Invalid usage environment");
25433
- for (const key of ["meter", "unit", "rate_card_id"])
25434
- if (typeof meter[key] !== "string" || !/^[A-Za-z0-9_.:/-]{1,128}$/u.test(meter[key]))
25435
- throw new TypeError("Invalid usage meter");
25436
- for (const key of ["quantity", "charged_micros", "funded_micros", "platform_overrun_micros"])
25437
- if (!amount(meter[key]))
25430
+ }
25431
+ let previousDay = "";
25432
+ for (const input of report["days"]) {
25433
+ const day = record7(input, "day,projects");
25434
+ if (typeof day["day"] !== "string" || !/^20[0-9]{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/u.test(day["day"]) || day["day"] <= previousDay || !Array.isArray(day["projects"]) || day["projects"].length > 1e3)
25435
+ throw new TypeError("Invalid usage day");
25436
+ previousDay = day["day"];
25437
+ previous = "";
25438
+ for (const projectInput of day["projects"]) {
25439
+ const project = record7(projectInput, "project_id,meters");
25440
+ if (!identifier3(project["project_id"]) || String(project["project_id"]) <= previous || !Array.isArray(project["meters"]) || project["meters"].length > 1e3)
25441
+ throw new TypeError("Invalid usage project");
25442
+ previous = String(project["project_id"]);
25443
+ for (const meterInput of project["meters"]) {
25444
+ const meter = record7(meterInput, "environment_id,meter,unit,rate_card_id,quantity,charged_micros");
25445
+ if (meter["environment_id"] !== null && !identifier3(meter["environment_id"]))
25446
+ throw new TypeError("Invalid usage environment");
25447
+ for (const key of ["meter", "unit", "rate_card_id"])
25448
+ if (typeof meter[key] !== "string" || !/^[A-Za-z0-9_.:/-]{1,128}$/u.test(meter[key]))
25449
+ throw new TypeError("Invalid usage meter");
25450
+ if (typeof meter["quantity"] !== "string" || !/^(0|[1-9][0-9]{0,29})(\.[0-9]{1,12})?$/u.test(meter["quantity"]) || !amount(meter["charged_micros"]))
25438
25451
  throw new TypeError("Invalid usage amount");
25439
- if (BigInt(String(meter["charged_micros"])) !== BigInt(String(meter["funded_micros"])) + BigInt(String(meter["platform_overrun_micros"])))
25440
- throw new TypeError("Inconsistent usage charge");
25452
+ }
25441
25453
  }
25442
25454
  }
25443
- if (report["next_cursor"] !== null && report["next_cursor"] !== previous)
25444
- throw new TypeError("Invalid usage cursor");
25445
25455
  }
25446
25456
  function assertOrganizationAccount(value) {
25447
25457
  if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).sort().join(",") !== "as_of,available_micros,monthly_micros,name,next_expiry,one_time_micros,organization_id,paid_until,plan,plan_source,reserved_micros,workos_organization_id")
@@ -25452,7 +25462,9 @@ function assertOrganizationAccount(value) {
25452
25462
  for (const field of ["available_micros", "monthly_micros", "one_time_micros", "reserved_micros"])
25453
25463
  if (typeof v[field] !== "string" || !/^(0|[1-9][0-9]{0,18})$/u.test(v[field]))
25454
25464
  throw new TypeError("Invalid account credits");
25455
- if (BigInt(String(v["monthly_micros"])) + BigInt(String(v["one_time_micros"])) !== BigInt(String(v["available_micros"])))
25465
+ const held = BigInt(String(v["reserved_micros"]));
25466
+ const balance = BigInt(String(v["monthly_micros"])) + BigInt(String(v["one_time_micros"]));
25467
+ if (BigInt(String(v["available_micros"])) !== (balance > held ? balance - held : 0n))
25456
25468
  throw new TypeError("Account credit buckets do not balance");
25457
25469
  for (const field of ["as_of", "paid_until", "next_expiry"]) {
25458
25470
  if (field !== "as_of" && v[field] === null)
@@ -27050,7 +27062,7 @@ function exact3(v, keys) {
27050
27062
  // apps/product-cli/package.json
27051
27063
  var package_default2 = {
27052
27064
  name: "@ohmyhost/product-cli",
27053
- version: "0.1.39",
27065
+ version: "0.1.41",
27054
27066
  private: true,
27055
27067
  ohmyhost: {
27056
27068
  deployment: "production",
@@ -28128,7 +28140,7 @@ var HELP_USAGE = Object.freeze({
28128
28140
  "billing checkout": "ohmyhost billing checkout --organization ULID --offer topup|paid [--packs 1] --idempotency-key KEY --json (returns a human payment URL; never auto-pays)",
28129
28141
  "billing status": "ohmyhost billing status --organization ULID --checkout ULID --json",
28130
28142
  "billing portal": "ohmyhost billing portal --organization ULID --json (short-lived human URL; request fresh after expiry)",
28131
- "credits usage": "ohmyhost credits usage --organization ULID --month YYYY-MM [--cursor ULID] --json",
28143
+ "credits usage": "ohmyhost credits usage --organization ULID --json (billed usage of the last up to 14 UTC days by day, project and meter, and each project's use this UTC month)",
28132
28144
  "budget get": "ohmyhost budget get --project ULID --json",
28133
28145
  "budget set": "ohmyhost budget set --project ULID --credits NUMBER|none [--mode continue|stop] --idempotency-key KEY --json",
28134
28146
  "organization create": "ohmyhost organization create --name NAME --idempotency-key KEY [--source SOURCE] --json (SOURCE is optional attribution from a link's r value; a login without organization is bound to the new workspace, another login keeps its own)",
@@ -29791,9 +29803,7 @@ var getOrganizationCreditUsage = (parameters, options) => {
29791
29803
  {
29792
29804
  args: [
29793
29805
  { in: "headers", key: "X-Request-Id" },
29794
- { in: "path", key: "organization_id" },
29795
- { in: "query", key: "month" },
29796
- { in: "query", key: "cursor" }
29806
+ { in: "path", key: "organization_id" }
29797
29807
  ]
29798
29808
  }
29799
29809
  ]);
@@ -32175,12 +32185,8 @@ var GeneratedSdkProductApi = class {
32175
32185
  createBillingPortal(organizationId) {
32176
32186
  return createBillingPortal({ organization_id: organizationId, body: {} }, { client: this.#client });
32177
32187
  }
32178
- getOrganizationCreditUsage(input) {
32179
- return getOrganizationCreditUsage({
32180
- organization_id: input.organizationId,
32181
- month: input.month,
32182
- ...input.cursor ? { cursor: input.cursor } : {}
32183
- }, { client: this.#client });
32188
+ getOrganizationCreditUsage(organizationId) {
32189
+ return getOrganizationCreditUsage({ organization_id: organizationId }, { client: this.#client });
32184
32190
  }
32185
32191
  getProjectCreditBudget(projectId) {
32186
32192
  return getProjectCreditBudget({ project_id: projectId }, { client: this.#client });
@@ -33209,12 +33215,8 @@ var GeneratedSdkLocalMcpClient = class {
33209
33215
  assertBillingPortal(value);
33210
33216
  return value;
33211
33217
  }
33212
- async getOrganizationCreditUsage(input) {
33213
- const value = await getOrganizationCreditUsage({
33214
- organization_id: input.organizationId,
33215
- month: input.month,
33216
- ...input.cursor ? { cursor: input.cursor } : {}
33217
- }, { client: this.#client });
33218
+ async getOrganizationCreditUsage(organizationId) {
33219
+ const value = await getOrganizationCreditUsage({ organization_id: organizationId }, { client: this.#client });
33218
33220
  assertOrganizationCreditUsage(value);
33219
33221
  return value;
33220
33222
  }
@@ -33804,7 +33806,7 @@ function createLocalOhmyhostMcpServer(dependencies) {
33804
33806
  hostname: input.hostname,
33805
33807
  idempotencyKey: input.idempotency_key
33806
33808
  }), destructiveAnnotations());
33807
- registerProductTool(server, dependencies, "billing_checkout_create", "Owner-only: create or resume a hosted Checkout. Paid is USD 10/month; each top-up pack is USD 10 before tax; a purchase grants 100 credits per dollar up to USD 100 and 125 credits per dollar for the part above, so 10 packs grant 10000 and 20 packs grant 22500 top-up credits. Monthly Paid credits expire at billing-period end; top-ups carry over while Paid and expire on downgrade to Free. Return the URL to the human to review/pay; never auto-pay or treat browser return as confirmation. Preserve the same offer/packs/idempotency key after uncertainty. An existing active, overdue, unpaid or paused subscription must be managed through billing_portal_create, not replaced with another Paid purchase. Then read checkout status and organization credits. Works at zero credit. Top-ups and enabling auto-recharge require active Paid access.", external_exports.object({
33809
+ registerProductTool(server, dependencies, "billing_checkout_create", "Owner-only: create or resume a hosted Checkout. Paid is USD 10/month; each top-up pack is USD 10 before tax; a purchase grants 100 credits per dollar up to USD 100 and 125 credits per dollar for the part above, so 10 packs grant 10000 and 20 packs grant 22500 top-up credits. Monthly Paid credits expire at billing-period end; top-ups never expire, also after a downgrade to Free. Return the URL to the human to review/pay; never auto-pay or treat browser return as confirmation. Preserve the same offer/packs/idempotency key after uncertainty. An existing active, overdue, unpaid or paused subscription must be managed through billing_portal_create, not replaced with another Paid purchase. Then read checkout status and organization credits. Works at zero credit. Top-ups and enabling auto-recharge require active Paid access.", external_exports.object({
33808
33810
  organization_id: identifier2,
33809
33811
  offer: external_exports.enum(["topup", "paid"]),
33810
33812
  packs: external_exports.number().int().min(1).max(100).default(1),
@@ -33815,12 +33817,12 @@ function createLocalOhmyhostMcpServer(dependencies) {
33815
33817
  packs: input.packs,
33816
33818
  idempotencyKey: input.idempotency_key
33817
33819
  }), mutationAnnotations());
33818
- registerProductTool(server, dependencies, "billing_checkout_get", "Owner-only: observe the original checkout and reconcile confirmed credits/refunds, without another purchase. payment_confirmed is historical; read organization_credits_get for spendable funds and organization_account_get's effective plan for Paid coverage; paid_until remains the paid Stripe period end during renewal grace. Follow required_action: complete_checkout means give its URL to the human; open_billing_portal means call billing_portal_create and give that fresh URL to the human to resolve payment. contact_support means contact https://ohmyho.st/contact about the original invoice; none means no human payment step now, not proof of current Paid coverage. Never start a second subscription to repair a failed renewal. Follow billing_issue when tax needs attention: use billing_portal_create for open_billing_portal, or https://ohmyho.st/contact for contact_support; retain the original invoice and never disable tax. Retry the same checkout after an outage. state=expired ends this attempt; use a new key only for an explicitly requested new purchase, never automatically after an error or timeout.", external_exports.object({ organization_id: identifier2, checkout_id: identifier2 }), (client2, input) => client2.getBillingCheckout({
33820
+ registerProductTool(server, dependencies, "billing_checkout_get", "Owner-only: observe the original checkout and reconcile confirmed credits/refunds, without another purchase. payment_confirmed is historical; read organization_credits_get for spendable funds and organization_account_get's effective plan for Paid coverage; paid_until is the end of paid coverage: the paid Stripe period end plus its 14-day renewal grace. Follow required_action: complete_checkout means give its URL to the human; open_billing_portal means call billing_portal_create and give that fresh URL to the human to resolve payment. contact_support means contact https://ohmyho.st/contact about the original invoice; none means no human payment step now, not proof of current Paid coverage. Never start a second subscription to repair a failed renewal. Follow billing_issue when tax needs attention: use billing_portal_create for open_billing_portal, or https://ohmyho.st/contact for contact_support; retain the original invoice and never disable tax. Retry the same checkout after an outage. state=expired ends this attempt; use a new key only for an explicitly requested new purchase, never automatically after an error or timeout.", external_exports.object({ organization_id: identifier2, checkout_id: identifier2 }), (client2, input) => client2.getBillingCheckout({
33819
33821
  organizationId: input.organization_id,
33820
33822
  checkoutId: input.checkout_id
33821
33823
  }));
33822
33824
  registerProductTool(server, dependencies, "billing_recharge_get", "Owner-only: read auto-recharge consent, spending limit and payment handoff. Reading never initiates a charge. Return private setup_url/invoice_url only to the human; never log them. Read again after Stripe card setup or payment. billing_issue identifies the original invoice: open_billing_portal means collect corrected billing details through billing_portal_create; contact_support means use https://ohmyho.st/contact. Never disable tax, discard the invoice or start another purchase to repair it.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getBillingRecharge(input.organization_id));
33823
- registerProductTool(server, dependencies, "billing_recharge_configure", "Owner-only: enable or disable automatic off-session payments. Enabling requires active Paid access. NEVER enable without explicit human approval for USD 9 plus tax per 1000 top-up credits, which carry over while Paid and expire on downgrade to Free, refill below 100 credits, and the chosen gross USD monthly limit. Set consent off_session_v1 only after that approval; null when disabling. Read current revision first. Preserve the original idempotency key and payload after uncertainty. A saved Stripe card may require setup_url. Disabling prevents new payment initiation; in-progress payments may finish. This does not create a subscription or Paid access.", external_exports.object({
33825
+ registerProductTool(server, dependencies, "billing_recharge_configure", "Owner-only: enable or disable automatic off-session payments. Enabling requires active Paid access. NEVER enable without explicit human approval for USD 9 plus tax per 1000 top-up credits, which never expire, refill below 100 credits, and the chosen gross USD monthly limit. Set consent off_session_v1 only after that approval; null when disabling. Read current revision first. Preserve the original idempotency key and payload after uncertainty. A saved Stripe card may require setup_url. Disabling prevents new payment initiation; in-progress payments may finish. This does not create a subscription or Paid access.", external_exports.object({
33824
33826
  organization_id: identifier2,
33825
33827
  enabled: external_exports.boolean(),
33826
33828
  monthly_limit_minor: external_exports.number().int().min(1e3).max(1e5),
@@ -33846,19 +33848,11 @@ function createLocalOhmyhostMcpServer(dependencies) {
33846
33848
  idempotencyKey: input.idempotency_key
33847
33849
  }), mutationAnnotations());
33848
33850
  registerProductTool(server, dependencies, "project_export_get", "Owner-only: read the original SQL ZIP export's progress/error and verified download URL. Follow next_poll_after_seconds while queued/running; never create another export to poll. The signed URL lasts 24 hours and is only issued with sufficient remaining seven-day archive retention. Keep the URL out of source, logs and persisted project notes. The password cannot be retrieved. Available at zero credits.", external_exports.object({ project_id: identifier2, export_id: identifier2 }), (client2, input) => client2.getProjectExport({ projectId: input.project_id, exportId: input.export_id }));
33849
- registerProductTool(server, dependencies, "organization_usage_get", "Read posted UTC-month usage by project, environment and published meter/rate. One credit is 1000000 microcredits. Includes corrections; null environment means shared project cost. Current reservations are separate. Follow next_cursor with the same month (20 projects/page). Late or unmetered usage is not zero consumption. platform_overrun_micros is platform expense, not customer debt. Owner-only; works at zero credit without new charges.", external_exports.object({
33850
- organization_id: identifier2,
33851
- month: external_exports.string().regex(/^20[0-9]{2}-(0[1-9]|1[0-2])$/u),
33852
- cursor: identifier2.optional()
33853
- }), (client2, input) => client2.getOrganizationCreditUsage({
33854
- organizationId: input.organization_id,
33855
- month: input.month,
33856
- ...input.cursor ? { cursor: input.cursor } : {}
33857
- }));
33858
- registerProductTool(server, dependencies, "organization_account_get", "Owner-only: read the effective Free/Paid plan, its Stripe or granted source, available monthly credits that expire at period end and top-up credits that carry over while Paid but expire on downgrade to Free, reservations and next expiry. Granted Paid features do not imply a Stripe subscription or extra monthly Paid allowance. paid_until is the paid Stripe period end or grant end; null on Free or for an unbounded grant. An unpaid renewal may retain Paid features for up to 14 days after that Stripe period end, without new monthly credits. This read grants no access or credits.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationAccount(input.organization_id));
33851
+ registerProductTool(server, dependencies, "organization_usage_get", "Read the billed usage of the last up to 14 UTC days (today included) grouped by day, project and meter, and what each project has used so far this UTC month. One credit is 1000000 microcredits. Null environment means shared project cost. Charges can arrive late and unmetered usage is not zero consumption. Owner-only; works at zero credit without new charges.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationCreditUsage(input.organization_id));
33852
+ registerProductTool(server, dependencies, "organization_account_get", "Owner-only: read the effective Free/Paid plan, its Stripe or granted source, the monthly credits that expire at next_expiry, the top-up and bonus credits that never expire, the reservations that hold part of them, and available_micros (monthly plus one-time minus reservations). Granted Paid features do not imply a Stripe subscription or extra monthly Paid allowance. paid_until is the end of the paid coverage, which includes the 14-day renewal grace of a Stripe subscription; null on Free. This read grants no access or credits.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationAccount(input.organization_id));
33859
33853
  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 30 days of Paid and 1,000 credits; that workspace's first payment gives this workspace 1,000 credits, plus 30 days of Paid unless a Stripe subscription or an unbounded grant already covers it. Any member may read it.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationReferral(input.organization_id));
33860
- 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. Top-ups and enabling auto-recharge require active Paid access.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationCredits(input.organization_id));
33861
- 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));
33854
+ registerProductTool(server, dependencies, "organization_credits_get", "Read the owner's shared organization credit pool (available_micros is monthly plus one-time credit minus reservations), the seven-day grace_started_at/grace_expires_at that begins when the credit is used up, 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 are not customer debt. Works at zero credit. Top-ups and enabling auto-recharge require active Paid access.", external_exports.object({ organization_id: identifier2 }), (client2, input) => client2.getOrganizationCredits(input.organization_id));
33855
+ registerProductTool(server, dependencies, "project_budget_get", "Read the owner's project UTC-month budget, this month's use and open reservations. A budget never allocates a second wallet.", external_exports.object({ project_id: identifier2 }), (client2, input) => client2.getProjectCreditBudget(input.project_id));
33862
33856
  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({
33863
33857
  project_id: identifier2,
33864
33858
  amount_micros: external_exports.string().regex(/^(0|[1-9][0-9]{0,18})$/u).nullable(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amerged/ohmyhost-mcp",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohmyhost/mcp",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "private": true,
5
5
  "ohmyhost": {
6
6
  "deployment": "production",
@@ -536,15 +536,9 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
536
536
  assertBillingPortal(value);
537
537
  return value;
538
538
  }
539
- public async getOrganizationCreditUsage(
540
- input: Parameters<LocalMcpProductClient["getOrganizationCreditUsage"]>[0],
541
- ) {
539
+ public async getOrganizationCreditUsage(organizationId: string) {
542
540
  const value = await getOrganizationCreditUsage(
543
- {
544
- organization_id: input.organizationId,
545
- month: input.month,
546
- ...(input.cursor ? { cursor: input.cursor } : {}),
547
- },
541
+ { organization_id: organizationId },
548
542
  { client: this.#client },
549
543
  );
550
544
  assertOrganizationCreditUsage(value);
@@ -189,11 +189,9 @@ export interface LocalMcpProductClient {
189
189
  idempotencyKey: string;
190
190
  }): Promise<import("@ohmyhost/sdk-ts").BillingRecharge>;
191
191
  createBillingPortal(organizationId: string): Promise<import("@ohmyhost/sdk-ts").BillingPortal>;
192
- getOrganizationCreditUsage(input: {
193
- organizationId: string;
194
- month: string;
195
- cursor?: string;
196
- }): Promise<import("@ohmyhost/sdk-ts").OrganizationCreditUsage>;
192
+ getOrganizationCreditUsage(
193
+ organizationId: string,
194
+ ): Promise<import("@ohmyhost/sdk-ts").OrganizationCreditUsage>;
197
195
  getOrganizationAccount(
198
196
  organizationId: string,
199
197
  ): Promise<import("@ohmyhost/sdk-ts").OrganizationAccount>;
@@ -702,7 +700,7 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
702
700
  server,
703
701
  dependencies,
704
702
  "billing_checkout_create",
705
- "Owner-only: create or resume a hosted Checkout. Paid is USD 10/month; each top-up pack is USD 10 before tax; a purchase grants 100 credits per dollar up to USD 100 and 125 credits per dollar for the part above, so 10 packs grant 10000 and 20 packs grant 22500 top-up credits. Monthly Paid credits expire at billing-period end; top-ups carry over while Paid and expire on downgrade to Free. Return the URL to the human to review/pay; never auto-pay or treat browser return as confirmation. Preserve the same offer/packs/idempotency key after uncertainty. An existing active, overdue, unpaid or paused subscription must be managed through billing_portal_create, not replaced with another Paid purchase. Then read checkout status and organization credits. Works at zero credit. Top-ups and enabling auto-recharge require active Paid access.",
703
+ "Owner-only: create or resume a hosted Checkout. Paid is USD 10/month; each top-up pack is USD 10 before tax; a purchase grants 100 credits per dollar up to USD 100 and 125 credits per dollar for the part above, so 10 packs grant 10000 and 20 packs grant 22500 top-up credits. Monthly Paid credits expire at billing-period end; top-ups never expire, also after a downgrade to Free. Return the URL to the human to review/pay; never auto-pay or treat browser return as confirmation. Preserve the same offer/packs/idempotency key after uncertainty. An existing active, overdue, unpaid or paused subscription must be managed through billing_portal_create, not replaced with another Paid purchase. Then read checkout status and organization credits. Works at zero credit. Top-ups and enabling auto-recharge require active Paid access.",
706
704
  z.object({
707
705
  organization_id: identifier,
708
706
  offer: z.enum(["topup", "paid"]),
@@ -722,7 +720,7 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
722
720
  server,
723
721
  dependencies,
724
722
  "billing_checkout_get",
725
- "Owner-only: observe the original checkout and reconcile confirmed credits/refunds, without another purchase. payment_confirmed is historical; read organization_credits_get for spendable funds and organization_account_get's effective plan for Paid coverage; paid_until remains the paid Stripe period end during renewal grace. Follow required_action: complete_checkout means give its URL to the human; open_billing_portal means call billing_portal_create and give that fresh URL to the human to resolve payment. contact_support means contact https://ohmyho.st/contact about the original invoice; none means no human payment step now, not proof of current Paid coverage. Never start a second subscription to repair a failed renewal. Follow billing_issue when tax needs attention: use billing_portal_create for open_billing_portal, or https://ohmyho.st/contact for contact_support; retain the original invoice and never disable tax. Retry the same checkout after an outage. state=expired ends this attempt; use a new key only for an explicitly requested new purchase, never automatically after an error or timeout.",
723
+ "Owner-only: observe the original checkout and reconcile confirmed credits/refunds, without another purchase. payment_confirmed is historical; read organization_credits_get for spendable funds and organization_account_get's effective plan for Paid coverage; paid_until is the end of paid coverage: the paid Stripe period end plus its 14-day renewal grace. Follow required_action: complete_checkout means give its URL to the human; open_billing_portal means call billing_portal_create and give that fresh URL to the human to resolve payment. contact_support means contact https://ohmyho.st/contact about the original invoice; none means no human payment step now, not proof of current Paid coverage. Never start a second subscription to repair a failed renewal. Follow billing_issue when tax needs attention: use billing_portal_create for open_billing_portal, or https://ohmyho.st/contact for contact_support; retain the original invoice and never disable tax. Retry the same checkout after an outage. state=expired ends this attempt; use a new key only for an explicitly requested new purchase, never automatically after an error or timeout.",
726
724
  z.object({ organization_id: identifier, checkout_id: identifier }),
727
725
  (client, input) =>
728
726
  client.getBillingCheckout({
@@ -742,7 +740,7 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
742
740
  server,
743
741
  dependencies,
744
742
  "billing_recharge_configure",
745
- "Owner-only: enable or disable automatic off-session payments. Enabling requires active Paid access. NEVER enable without explicit human approval for USD 9 plus tax per 1000 top-up credits, which carry over while Paid and expire on downgrade to Free, refill below 100 credits, and the chosen gross USD monthly limit. Set consent off_session_v1 only after that approval; null when disabling. Read current revision first. Preserve the original idempotency key and payload after uncertainty. A saved Stripe card may require setup_url. Disabling prevents new payment initiation; in-progress payments may finish. This does not create a subscription or Paid access.",
743
+ "Owner-only: enable or disable automatic off-session payments. Enabling requires active Paid access. NEVER enable without explicit human approval for USD 9 plus tax per 1000 top-up credits, which never expire, refill below 100 credits, and the chosen gross USD monthly limit. Set consent off_session_v1 only after that approval; null when disabling. Read current revision first. Preserve the original idempotency key and payload after uncertainty. A saved Stripe card may require setup_url. Disabling prevents new payment initiation; in-progress payments may finish. This does not create a subscription or Paid access.",
746
744
  z.object({
747
745
  organization_id: identifier,
748
746
  enabled: z.boolean(),
@@ -804,24 +802,15 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
804
802
  server,
805
803
  dependencies,
806
804
  "organization_usage_get",
807
- "Read posted UTC-month usage by project, environment and published meter/rate. One credit is 1000000 microcredits. Includes corrections; null environment means shared project cost. Current reservations are separate. Follow next_cursor with the same month (20 projects/page). Late or unmetered usage is not zero consumption. platform_overrun_micros is platform expense, not customer debt. Owner-only; works at zero credit without new charges.",
808
- z.object({
809
- organization_id: identifier,
810
- month: z.string().regex(/^20[0-9]{2}-(0[1-9]|1[0-2])$/u),
811
- cursor: identifier.optional(),
812
- }),
813
- (client, input) =>
814
- client.getOrganizationCreditUsage({
815
- organizationId: input.organization_id,
816
- month: input.month,
817
- ...(input.cursor ? { cursor: input.cursor } : {}),
818
- }),
805
+ "Read the billed usage of the last up to 14 UTC days (today included) grouped by day, project and meter, and what each project has used so far this UTC month. One credit is 1000000 microcredits. Null environment means shared project cost. Charges can arrive late and unmetered usage is not zero consumption. Owner-only; works at zero credit without new charges.",
806
+ z.object({ organization_id: identifier }),
807
+ (client, input) => client.getOrganizationCreditUsage(input.organization_id),
819
808
  );
820
809
  registerProductTool(
821
810
  server,
822
811
  dependencies,
823
812
  "organization_account_get",
824
- "Owner-only: read the effective Free/Paid plan, its Stripe or granted source, available monthly credits that expire at period end and top-up credits that carry over while Paid but expire on downgrade to Free, reservations and next expiry. Granted Paid features do not imply a Stripe subscription or extra monthly Paid allowance. paid_until is the paid Stripe period end or grant end; null on Free or for an unbounded grant. An unpaid renewal may retain Paid features for up to 14 days after that Stripe period end, without new monthly credits. This read grants no access or credits.",
813
+ "Owner-only: read the effective Free/Paid plan, its Stripe or granted source, the monthly credits that expire at next_expiry, the top-up and bonus credits that never expire, the reservations that hold part of them, and available_micros (monthly plus one-time minus reservations). Granted Paid features do not imply a Stripe subscription or extra monthly Paid allowance. paid_until is the end of the paid coverage, which includes the 14-day renewal grace of a Stripe subscription; null on Free. This read grants no access or credits.",
825
814
  z.object({ organization_id: identifier }),
826
815
  (client, input) => client.getOrganizationAccount(input.organization_id),
827
816
  );
@@ -837,7 +826,7 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
837
826
  server,
838
827
  dependencies,
839
828
  "organization_credits_get",
840
- "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. Top-ups and enabling auto-recharge require active Paid access.",
829
+ "Read the owner's shared organization credit pool (available_micros is monthly plus one-time credit minus reservations), the seven-day grace_started_at/grace_expires_at that begins when the credit is used up, 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 are not customer debt. Works at zero credit. Top-ups and enabling auto-recharge require active Paid access.",
841
830
  z.object({ organization_id: identifier }),
842
831
  (client, input) => client.getOrganizationCredits(input.organization_id),
843
832
  );
@@ -845,7 +834,7 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
845
834
  server,
846
835
  dependencies,
847
836
  "project_budget_get",
848
- "Read the owner's project UTC-month budget, measured usage and open reservations. A budget never allocates a second wallet.",
837
+ "Read the owner's project UTC-month budget, this month's use and open reservations. A budget never allocates a second wallet.",
849
838
  z.object({ project_id: identifier }),
850
839
  (client, input) => client.getProjectCreditBudget(input.project_id),
851
840
  );
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohmyhost/product-cli",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "private": true,
5
5
  "ohmyhost": {
6
6
  "deployment": "production",
@@ -351,7 +351,7 @@ const HELP_USAGE = Object.freeze({
351
351
  "billing portal":
352
352
  "ohmyhost billing portal --organization ULID --json (short-lived human URL; request fresh after expiry)",
353
353
  "credits usage":
354
- "ohmyhost credits usage --organization ULID --month YYYY-MM [--cursor ULID] --json",
354
+ "ohmyhost credits usage --organization ULID --json (billed usage of the last up to 14 UTC days by day, project and meter, and each project's use this UTC month)",
355
355
  "budget get": "ohmyhost budget get --project ULID --json",
356
356
  "budget set":
357
357
  "ohmyhost budget set --project ULID --credits NUMBER|none [--mode continue|stop] --idempotency-key KEY --json",
@@ -844,7 +844,7 @@ export class ProductCli {
844
844
  }
845
845
  if (command.kind === "credits-usage") {
846
846
  const api = await this.authenticatedApi(command.credentialStore, signal);
847
- const usage = await api.getOrganizationCreditUsage(command);
847
+ const usage = await api.getOrganizationCreditUsage(command.organizationId);
848
848
  try {
849
849
  assertOrganizationCreditUsage(usage);
850
850
  } catch {
@@ -199,8 +199,6 @@ export type ProductCliCommand =
199
199
  | {
200
200
  readonly kind: "credits-usage";
201
201
  readonly organizationId: string;
202
- readonly month: string;
203
- readonly cursor?: string;
204
202
  readonly credentialStore: "native";
205
203
  }
206
204
  | {
@@ -1407,20 +1405,8 @@ export const parseProductCliCommand = (argv: readonly string[]): ProductCliComma
1407
1405
  if (first === "credits" && values[0] === "usage") {
1408
1406
  values.shift();
1409
1407
  if (yes || wait || follow || stdin) throw new InvalidCommandError();
1410
- const options = parseOptionalOptions(values, ["--organization", "--month", "--cursor"]);
1411
- if (
1412
- !options["--organization"] ||
1413
- !options["--month"] ||
1414
- !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(options["--month"])
1415
- )
1416
- throw new InvalidCommandError();
1417
- return {
1418
- kind: "credits-usage",
1419
- organizationId: options["--organization"],
1420
- month: options["--month"],
1421
- ...(options["--cursor"] ? { cursor: options["--cursor"] } : {}),
1422
- credentialStore,
1423
- };
1408
+ const options = parseOptions(values, ["--organization"]);
1409
+ return { kind: "credits-usage", organizationId: options["--organization"], credentialStore };
1424
1410
  }
1425
1411
  if (first === "credits" && values[0] === "account") {
1426
1412
  values.shift();
@@ -230,11 +230,7 @@ export interface ProductApi {
230
230
  organizationId: string,
231
231
  ): Promise<import("@ohmyhost/sdk-ts").OrganizationReferral>;
232
232
  getOrganizationCredits(organizationId: string): Promise<OrganizationCredits>;
233
- getOrganizationCreditUsage(input: {
234
- organizationId: string;
235
- month: string;
236
- cursor?: string;
237
- }): Promise<OrganizationCreditUsage>;
233
+ getOrganizationCreditUsage(organizationId: string): Promise<OrganizationCreditUsage>;
238
234
  getProjectCreditBudget(projectId: string): Promise<ProjectCreditBudget>;
239
235
  setProjectCreditBudget(input: {
240
236
  projectId: string;
@@ -614,15 +610,9 @@ export class GeneratedSdkProductApi implements ProductApi {
614
610
  { client: this.#client },
615
611
  );
616
612
  }
617
- public getOrganizationCreditUsage(
618
- input: Parameters<ProductApi["getOrganizationCreditUsage"]>[0],
619
- ) {
613
+ public getOrganizationCreditUsage(organizationId: string) {
620
614
  return getOrganizationCreditUsage(
621
- {
622
- organization_id: input.organizationId,
623
- month: input.month,
624
- ...(input.cursor ? { cursor: input.cursor } : {}),
625
- },
615
+ { organization_id: organizationId },
626
616
  { client: this.#client },
627
617
  );
628
618
  }
@@ -552,9 +552,6 @@ export function parseOrganizationCredits(value: unknown): OrganizationCredits {
552
552
  "as_of",
553
553
  "available_micros",
554
554
  "reserved_micros",
555
- "spent_micros",
556
- "expired_micros",
557
- "platform_overrun_micros",
558
555
  "grace_started_at",
559
556
  "grace_expires_at",
560
557
  "active_meters",
@@ -586,13 +583,7 @@ export function parseOrganizationCredits(value: unknown): OrganizationCredits {
586
583
  )
587
584
  )
588
585
  throw new ResponseContractError();
589
- for (const field of [
590
- "available_micros",
591
- "reserved_micros",
592
- "spent_micros",
593
- "expired_micros",
594
- "platform_overrun_micros",
595
- ]) {
586
+ for (const field of ["available_micros", "reserved_micros"]) {
596
587
  const amount = input[field];
597
588
  if (
598
589
  typeof amount !== "string" ||