@amerged/ohmyhost-mcp 0.1.36 → 0.1.38

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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.md +3 -3
  3. package/dist/{chunk-LV7JW4C4.js → chunk-Z7AT2PTU.js} +7960 -2431
  4. package/dist/index.js +1 -1
  5. package/dist/stdio-main.js +1279 -320
  6. package/package.json +1 -1
  7. package/src/apps/mcp/package.json +5 -5
  8. package/src/apps/mcp/src/local-client.ts +10 -1
  9. package/src/apps/mcp/src/local-server.ts +367 -1
  10. package/src/apps/product-cli/package.json +2 -2
  11. package/src/apps/product-cli/src/cli.ts +37 -1
  12. package/src/apps/product-cli/src/command.ts +228 -2
  13. package/src/apps/product-cli/src/composition.ts +4 -0
  14. package/src/apps/product-cli/src/product-api.ts +11 -1
  15. package/src/apps/product-cli/src/repository-init.ts +181 -9
  16. package/src/packages/agent-skills/package.json +1 -1
  17. package/src/packages/agent-skills/src/generated-skill-resources.ts +9 -9
  18. package/src/packages/contracts/package.json +6 -1
  19. package/src/packages/contracts/src/framework-admission-corpus.ts +15 -18
  20. package/src/packages/contracts/src/framework-build-script.mjs +10 -3
  21. package/src/packages/contracts/src/index.ts +3 -0
  22. package/src/packages/contracts/src/problem-policy.ts +2 -2
  23. package/src/packages/contracts/src/shared-mail.ts +236 -0
  24. package/src/packages/sdk-ts/package.json +2 -2
  25. package/src/packages/sdk-ts/src/generated/index.ts +112 -0
  26. package/src/packages/sdk-ts/src/generated/sdk.gen.ts +870 -0
  27. package/src/packages/sdk-ts/src/generated/shared-mail-response.ts +238 -0
  28. package/src/packages/sdk-ts/src/generated/types.gen.ts +1207 -0
  29. package/src/packages/sdk-ts/src/index.ts +2 -0
  30. package/src/packages/sdk-ts/src/shared-mail-response.ts +1 -0
  31. package/src/packages/sdk-ts/src/shared-mail.ts +225 -0
  32. package/src/packages/workos-auth-contracts/package.json +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amerged/ohmyhost-mcp",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
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.36",
3
+ "version": "0.1.38",
4
4
  "private": true,
5
5
  "ohmyhost": {
6
6
  "deployment": "production",
@@ -30,15 +30,15 @@
30
30
  "build": "tsc --project tsconfig.build.json",
31
31
  "deploy:dry-run": "wrangler deploy --dry-run --outdir .wrangler/dry-run",
32
32
  "test": "vitest run --root ../.. apps/mcp/test",
33
- "typecheck": "tsc --project tsconfig.json --noEmit"
33
+ "typecheck": "tsc --project tsconfig.json --noEmit --incremental --tsBuildInfoFile typecheck.tsbuildinfo"
34
34
  },
35
35
  "dependencies": {
36
- "@ohmyhost/contracts": "workspace:*",
37
- "@modelcontextprotocol/server": "2.0.0",
36
+ "@modelcontextprotocol/server": "2.3.0",
38
37
  "@ohmyhost/agent-skills": "workspace:*",
38
+ "@ohmyhost/contracts": "workspace:*",
39
39
  "@ohmyhost/product-cli": "workspace:*",
40
40
  "@ohmyhost/sdk-ts": "workspace:*",
41
- "zod": "4.4.3"
41
+ "zod": "4.6.6"
42
42
  },
43
43
  "devDependencies": {
44
44
  "wrangler": "4.125.0"
@@ -1,4 +1,9 @@
1
- import { executeManagedMail, type ManagedMailCommand } from "@ohmyhost/sdk-ts";
1
+ import {
2
+ executeManagedMail,
3
+ executeSharedMail,
4
+ type ManagedMailCommand,
5
+ type SharedMailCommand,
6
+ } from "@ohmyhost/sdk-ts";
2
7
  import {
3
8
  assertProjectDatabaseAccess,
4
9
  assertProjectDatabaseAccessCredential,
@@ -838,6 +843,10 @@ export class GeneratedSdkLocalMcpClient implements LocalMcpProductClient {
838
843
  { client: this.#client },
839
844
  );
840
845
  }
846
+ public sharedMail(input: SharedMailCommand) {
847
+ return executeSharedMail(this.#client, input);
848
+ }
849
+
841
850
  public managedMail(input: ManagedMailCommand) {
842
851
  return executeManagedMail(this.#client, input);
843
852
  }
@@ -4,7 +4,7 @@ import {
4
4
  formatMcpSourceFileResponse,
5
5
  McpSourceChangesInputError,
6
6
  } from "@ohmyhost/contracts/mcp-source-codec";
7
- import type { ManagedMailCommand } from "@ohmyhost/sdk-ts";
7
+ import type { ManagedMailCommand, SharedMailCommand } from "@ohmyhost/sdk-ts";
8
8
  import {
9
9
  parseManagedSourceRequest,
10
10
  isManagedSourcePath,
@@ -289,6 +289,7 @@ export interface LocalMcpProductClient {
289
289
  getDeployment(input: DeploymentGetInput): Promise<Deployment>;
290
290
  getOperation(operationId: string): Promise<Operation>;
291
291
  reconcileOperation(input: OperationReconcileInput): Promise<ProviderReconciliationAttempt>;
292
+ sharedMail?(input: SharedMailCommand): Promise<unknown>;
292
293
  managedMail?(input: ManagedMailCommand): Promise<unknown>;
293
294
  listOperationEvents(
294
295
  operationId: string,
@@ -1548,6 +1549,371 @@ export function createLocalOhmyhostMcpServer(dependencies: LocalOhmyhostMcpDepen
1548
1549
  ),
1549
1550
  mutationAnnotations(),
1550
1551
  );
1552
+ registerProductTool(
1553
+ server,
1554
+ dependencies,
1555
+ "workspace_mail_domain_dns_revoke",
1556
+ "Revoke the selected workspace sender DNS grant at its current revision with explicit confirmation. This does not retire the sender or remove existing DNS records.",
1557
+ z
1558
+ .object({
1559
+ organization_id: identifier,
1560
+ mail_domain_id: identifier,
1561
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1562
+ idempotency_key: idempotencyKey,
1563
+ confirmed: z.literal(true),
1564
+ })
1565
+ .strict(),
1566
+ async (client, input) => {
1567
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1568
+ return client.sharedMail({
1569
+ action: "domain_dns_revoke",
1570
+ organizationId: input.organization_id,
1571
+ mailDomainId: input.mail_domain_id,
1572
+ expectedRevision: input.expected_revision,
1573
+ idempotencyKey: input.idempotency_key,
1574
+ });
1575
+ },
1576
+ mutationAnnotations(),
1577
+ );
1578
+ registerProductTool(
1579
+ server,
1580
+ dependencies,
1581
+ "application_domain_identity_authorization_revoke",
1582
+ "Revoke the current application identity DNS grant with explicit confirmation. The application hostname and its verified proof remain unchanged; no website routing or DNS records are removed.",
1583
+ z
1584
+ .object({
1585
+ project_id: identifier,
1586
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1587
+ idempotency_key: idempotencyKey,
1588
+ confirmed: z.literal(true),
1589
+ })
1590
+ .strict(),
1591
+ async (client, input) => {
1592
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1593
+ return client.sharedMail({
1594
+ action: "identity_authorization_revoke",
1595
+ projectId: input.project_id,
1596
+ expectedRevision: input.expected_revision,
1597
+ idempotencyKey: input.idempotency_key,
1598
+ });
1599
+ },
1600
+ mutationAnnotations(),
1601
+ );
1602
+ registerProductTool(
1603
+ server,
1604
+ dependencies,
1605
+ "workspace_mail_domains_list",
1606
+ "List only workspace sender domains this account and connected client may read. Project edit consent alone grants no sender-domain access.",
1607
+ z.object({ organization_id: identifier }).strict(),
1608
+ async (client, input) => {
1609
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1610
+ return client.sharedMail({ action: "domains_list", organizationId: input.organization_id });
1611
+ },
1612
+ );
1613
+ registerProductTool(
1614
+ server,
1615
+ dependencies,
1616
+ "workspace_mail_domain_create",
1617
+ "Create one workspace-owned transactional sender domain. Requires explicit workspace mail administration. This creates no mailbox and preserves existing MX records.",
1618
+ z
1619
+ .object({
1620
+ organization_id: identifier,
1621
+ domain: z.string().min(1).max(253),
1622
+ sending: z.literal(true),
1623
+ idempotency_key: idempotencyKey,
1624
+ })
1625
+ .strict(),
1626
+ async (client, input) => {
1627
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1628
+ return client.sharedMail({
1629
+ action: "domain_create",
1630
+ organizationId: input.organization_id,
1631
+ domain: input.domain,
1632
+ sending: input.sending,
1633
+ idempotencyKey: input.idempotency_key,
1634
+ });
1635
+ },
1636
+ mutationAnnotations(),
1637
+ );
1638
+ registerProductTool(
1639
+ server,
1640
+ dependencies,
1641
+ "workspace_mail_domain_get",
1642
+ "Read sender verification, lifecycle, revision and DNS records for one authorized workspace resource.",
1643
+ z.object({ organization_id: identifier, mail_domain_id: identifier }).strict(),
1644
+ async (client, input) => {
1645
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1646
+ return client.sharedMail({
1647
+ action: "domain_get",
1648
+ organizationId: input.organization_id,
1649
+ mailDomainId: input.mail_domain_id,
1650
+ });
1651
+ },
1652
+ );
1653
+ registerProductTool(
1654
+ server,
1655
+ dependencies,
1656
+ "workspace_mail_domain_retire",
1657
+ "Retire an explicitly selected workspace sender only after every send and inbound reference is detached and provider effects settle. Requires current revision and explicit confirmation. Retain the same request key after uncertainty.",
1658
+ z
1659
+ .object({
1660
+ organization_id: identifier,
1661
+ mail_domain_id: identifier,
1662
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1663
+ idempotency_key: idempotencyKey,
1664
+ confirmed: z.literal(true),
1665
+ })
1666
+ .strict(),
1667
+ async (client, input) => {
1668
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1669
+ return client.sharedMail({
1670
+ action: "domain_retire",
1671
+ organizationId: input.organization_id,
1672
+ mailDomainId: input.mail_domain_id,
1673
+ expectedRevision: input.expected_revision,
1674
+ idempotencyKey: input.idempotency_key,
1675
+ });
1676
+ },
1677
+ mutationAnnotations(),
1678
+ );
1679
+ registerProductTool(
1680
+ server,
1681
+ dependencies,
1682
+ "workspace_mail_domain_dns_authorize",
1683
+ "Request human Cloudflare consent for this selected workspace sender, zone and revision. No provider credentials are accepted. Open the returned link for the human; never approve it automatically.",
1684
+ z
1685
+ .object({
1686
+ organization_id: identifier,
1687
+ mail_domain_id: identifier,
1688
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1689
+ zone: z.string().min(1).max(253),
1690
+ idempotency_key: idempotencyKey,
1691
+ })
1692
+ .strict(),
1693
+ async (client, input) => {
1694
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1695
+ return client.sharedMail({
1696
+ action: "domain_dns_authorize",
1697
+ organizationId: input.organization_id,
1698
+ mailDomainId: input.mail_domain_id,
1699
+ expectedRevision: input.expected_revision,
1700
+ zone: input.zone,
1701
+ idempotencyKey: input.idempotency_key,
1702
+ });
1703
+ },
1704
+ mutationAnnotations(),
1705
+ );
1706
+ registerProductTool(
1707
+ server,
1708
+ dependencies,
1709
+ "workspace_mail_domain_dns_status",
1710
+ "Read exact workspace sender DNS authorization status. An existing verified resource needs no new DNS grant merely to attach a same-domain project.",
1711
+ z.object({ organization_id: identifier, mail_domain_id: identifier }).strict(),
1712
+ async (client, input) => {
1713
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1714
+ return client.sharedMail({
1715
+ action: "domain_dns_status",
1716
+ organizationId: input.organization_id,
1717
+ mailDomainId: input.mail_domain_id,
1718
+ });
1719
+ },
1720
+ );
1721
+ registerProductTool(
1722
+ server,
1723
+ dependencies,
1724
+ "mail_binding_get",
1725
+ "Read the Prod sender binding and per-project From addresses, default From and default Reply-To. Dev uses this logical project sender identity.",
1726
+ z.object({ project_id: identifier, environment_id: identifier }).strict(),
1727
+ async (client, input) => {
1728
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1729
+ return client.sharedMail({
1730
+ action: "binding_get",
1731
+ projectId: input.project_id,
1732
+ environmentId: input.environment_id,
1733
+ });
1734
+ },
1735
+ );
1736
+ registerProductTool(
1737
+ server,
1738
+ dependencies,
1739
+ "mail_binding_set",
1740
+ "Attach a verified workspace sender or update its project settings. Requires target project edit and explicit sender use permission. The verified application and sender must share the registrable main domain. Set exact From addresses; no per-prefix DNS is needed. Reply-To may name an external existing mailbox and a per-message value overrides the default. Attaching changes no sender DNS and grants no receiving access.",
1741
+ z
1742
+ .object({
1743
+ project_id: identifier,
1744
+ environment_id: identifier,
1745
+ mail_domain_id: identifier,
1746
+ sending: z.boolean(),
1747
+ sender_addresses: z.array(z.email().max(320)).min(1).max(32),
1748
+ default_from: z.email().max(320),
1749
+ default_reply_to: z.email().max(320).nullable(),
1750
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1751
+ idempotency_key: idempotencyKey,
1752
+ })
1753
+ .strict(),
1754
+ async (client, input) => {
1755
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1756
+ return client.sharedMail({
1757
+ action: "binding_set",
1758
+ projectId: input.project_id,
1759
+ environmentId: input.environment_id,
1760
+ mailDomainId: input.mail_domain_id,
1761
+ sending: input.sending,
1762
+ senderAddresses: input.sender_addresses,
1763
+ defaultFrom: input.default_from,
1764
+ defaultReplyTo: input.default_reply_to,
1765
+ expectedRevision: input.expected_revision,
1766
+ idempotencyKey: input.idempotency_key,
1767
+ });
1768
+ },
1769
+ mutationAnnotations(),
1770
+ );
1771
+ registerProductTool(
1772
+ server,
1773
+ dependencies,
1774
+ "mail_binding_detach",
1775
+ "Detach only this project send binding with current revision and explicit confirmation. Sibling senders, provider verification and the exclusive inbound owner remain intact.",
1776
+ z
1777
+ .object({
1778
+ project_id: identifier,
1779
+ environment_id: identifier,
1780
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1781
+ idempotency_key: idempotencyKey,
1782
+ confirmed: z.literal(true),
1783
+ })
1784
+ .strict(),
1785
+ async (client, input) => {
1786
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1787
+ return client.sharedMail({
1788
+ action: "binding_detach",
1789
+ projectId: input.project_id,
1790
+ environmentId: input.environment_id,
1791
+ expectedRevision: input.expected_revision,
1792
+ idempotencyKey: input.idempotency_key,
1793
+ });
1794
+ },
1795
+ mutationAnnotations(),
1796
+ );
1797
+ registerProductTool(
1798
+ server,
1799
+ dependencies,
1800
+ "application_domain_identity_get",
1801
+ "Read the project intended application hostname, current revision and ownership proof. An awaiting deployment declaration or technical OMH hostname alone is not verified customer-domain identity.",
1802
+ z.object({ project_id: identifier }).strict(),
1803
+ async (client, input) => {
1804
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1805
+ return client.sharedMail({ action: "identity_get", projectId: input.project_id });
1806
+ },
1807
+ );
1808
+ registerProductTool(
1809
+ server,
1810
+ dependencies,
1811
+ "application_domain_identity_declare",
1812
+ "Declare the intended customer application hostname before deployment. Returns a project-bound TXT ownership challenge. This does not route website traffic or prove ownership; verify the challenge before attaching a shared sender.",
1813
+ z
1814
+ .object({
1815
+ project_id: identifier,
1816
+ hostname: z.string().min(1).max(253),
1817
+ idempotency_key: idempotencyKey,
1818
+ })
1819
+ .strict(),
1820
+ async (client, input) => {
1821
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1822
+ return client.sharedMail({
1823
+ action: "identity_declare",
1824
+ projectId: input.project_id,
1825
+ hostname: input.hostname,
1826
+ idempotencyKey: input.idempotency_key,
1827
+ });
1828
+ },
1829
+ mutationAnnotations(),
1830
+ );
1831
+ registerProductTool(
1832
+ server,
1833
+ dependencies,
1834
+ "application_domain_identity_verify",
1835
+ "Verify the exact current project and hostname TXT challenge independently of deployment. Read the resulting proof before attaching a same-main-domain workspace sender.",
1836
+ z
1837
+ .object({
1838
+ project_id: identifier,
1839
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1840
+ idempotency_key: idempotencyKey,
1841
+ })
1842
+ .strict(),
1843
+ async (client, input) => {
1844
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1845
+ return client.sharedMail({
1846
+ action: "identity_verify",
1847
+ projectId: input.project_id,
1848
+ expectedRevision: input.expected_revision,
1849
+ idempotencyKey: input.idempotency_key,
1850
+ });
1851
+ },
1852
+ mutationAnnotations(),
1853
+ );
1854
+ registerProductTool(
1855
+ server,
1856
+ dependencies,
1857
+ "application_domain_identity_revoke",
1858
+ "Revoke only the selected current application-domain proof with explicit confirmation. This does not delete or retarget the website. Sender reuse requires a current eligible identity.",
1859
+ z
1860
+ .object({
1861
+ project_id: identifier,
1862
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1863
+ idempotency_key: idempotencyKey,
1864
+ confirmed: z.literal(true),
1865
+ })
1866
+ .strict(),
1867
+ async (client, input) => {
1868
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1869
+ return client.sharedMail({
1870
+ action: "identity_revoke",
1871
+ projectId: input.project_id,
1872
+ expectedRevision: input.expected_revision,
1873
+ idempotencyKey: input.idempotency_key,
1874
+ });
1875
+ },
1876
+ mutationAnnotations(),
1877
+ );
1878
+ registerProductTool(
1879
+ server,
1880
+ dependencies,
1881
+ "application_domain_identity_authorize",
1882
+ "Request exact-purpose Cloudflare consent to write this project hostname ownership challenge at the current revision. Open the private authorization URL for the human; never approve it automatically. Manual DNS remains available.",
1883
+ z
1884
+ .object({
1885
+ project_id: identifier,
1886
+ expected_revision: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
1887
+ zone: z.string().min(1).max(253),
1888
+ idempotency_key: idempotencyKey,
1889
+ })
1890
+ .strict(),
1891
+ async (client, input) => {
1892
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1893
+ return client.sharedMail({
1894
+ action: "identity_authorize",
1895
+ projectId: input.project_id,
1896
+ expectedRevision: input.expected_revision,
1897
+ zone: input.zone,
1898
+ idempotencyKey: input.idempotency_key,
1899
+ });
1900
+ },
1901
+ mutationAnnotations(),
1902
+ );
1903
+ registerProductTool(
1904
+ server,
1905
+ dependencies,
1906
+ "application_domain_identity_authorization_status",
1907
+ "Read the selected project application-domain identity DNS authorization status. Zone visibility or consent alone is not ownership proof; run verification.",
1908
+ z.object({ project_id: identifier }).strict(),
1909
+ async (client, input) => {
1910
+ if (!client.sharedMail) throw new Error("Shared mail unavailable");
1911
+ return client.sharedMail({
1912
+ action: "identity_authorization_status",
1913
+ projectId: input.project_id,
1914
+ });
1915
+ },
1916
+ );
1551
1917
  registerProductTool(
1552
1918
  server,
1553
1919
  dependencies,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohmyhost/product-cli",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "private": true,
5
5
  "ohmyhost": {
6
6
  "deployment": "production",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "scripts": {
34
34
  "build": "tsc --project tsconfig.build.json",
35
- "typecheck": "tsc --project tsconfig.json --noEmit",
35
+ "typecheck": "tsc --project tsconfig.json --noEmit --incremental --tsBuildInfoFile typecheck.tsbuildinfo",
36
36
  "test": "vitest run --root ../.. apps/product-cli/test"
37
37
  },
38
38
  "dependencies": {
@@ -470,6 +470,37 @@ const HELP_USAGE = Object.freeze({
470
470
  "printf '%s' \"$SECRET_VALUE\" | ohmyhost secret set NAME --project ULID --environment ENVIRONMENT_ULID --idempotency-key KEY [--profile-user USER_ID --profile-organization ULID | --token-user USER_ID --token-organization ULID] --stdin [--wait] --json (with --profile-user and --profile-organization the saved login that runs it must belong to that user and organization; with --token-user and --token-organization it runs only with an OHMYHOST_TOKEN of that user and organization, never with a saved login)",
471
471
  "secret delete":
472
472
  "ohmyhost secret delete NAME --project ULID --environment ENVIRONMENT_ULID --idempotency-key KEY [--wait] --json",
473
+ "mail workspace list": "ohmyhost mail workspace list --organization ULID --json",
474
+ "mail workspace create":
475
+ "ohmyhost mail workspace create --organization ULID --domain DOMAIN --sending true --idempotency-key KEY --json",
476
+ "mail workspace status":
477
+ "ohmyhost mail workspace status --organization ULID --mail-domain ULID --json",
478
+ "mail workspace retire":
479
+ "ohmyhost mail workspace retire --organization ULID --mail-domain ULID --expected-revision N --idempotency-key KEY --yes --json",
480
+ "mail workspace dns-authorize":
481
+ "ohmyhost mail workspace dns-authorize --organization ULID --mail-domain ULID --expected-revision N --zone DOMAIN --idempotency-key KEY --json",
482
+ "mail workspace dns-revoke":
483
+ "ohmyhost mail workspace dns-revoke --organization ULID --mail-domain ULID --expected-revision N --idempotency-key KEY --yes --json",
484
+ "mail workspace dns-status":
485
+ "ohmyhost mail workspace dns-status --organization ULID --mail-domain ULID --json",
486
+ "mail binding get": "ohmyhost mail binding get --project ULID --environment PROD_ULID --json",
487
+ "mail binding set":
488
+ "ohmyhost mail binding set --project ULID --environment PROD_ULID --mail-domain ULID --sending true --sender-addresses contact@mail.example.com,contracts@mail.example.com --default-from contracts@mail.example.com [--reply-to owner@example.com] --expected-revision N --idempotency-key KEY --json",
489
+ "mail binding detach":
490
+ "ohmyhost mail binding detach --project ULID --environment PROD_ULID --expected-revision N --idempotency-key KEY --yes --json",
491
+ "mail identity get": "ohmyhost mail identity get --project ULID --json",
492
+ "mail identity declare":
493
+ "ohmyhost mail identity declare --project ULID --hostname sign.example.com --idempotency-key KEY --json",
494
+ "mail identity verify":
495
+ "ohmyhost mail identity verify --project ULID --expected-revision N --idempotency-key KEY --json",
496
+ "mail identity revoke":
497
+ "ohmyhost mail identity revoke --project ULID --expected-revision N --idempotency-key KEY --yes --json",
498
+ "mail identity authorize":
499
+ "ohmyhost mail identity authorize --project ULID --expected-revision N --zone example.com --idempotency-key KEY --json",
500
+ "mail identity authorization-revoke":
501
+ "ohmyhost mail identity authorization-revoke --project ULID --expected-revision N --idempotency-key KEY --yes --json",
502
+ "mail identity authorization-status":
503
+ "ohmyhost mail identity authorization-status --project ULID --json",
473
504
  "mail setup":
474
505
  "ohmyhost mail setup --project ULID --environment ULID --domain DOMAIN --sending true --receiving false --idempotency-key KEY --json",
475
506
  "mail status": "ohmyhost mail status --project ULID --environment ULID --json",
@@ -1114,6 +1145,11 @@ export class ProductCli {
1114
1145
  if (command.kind === "secret-list") return await this.listEnvironmentSecrets(command, signal);
1115
1146
  if (command.kind === "function-runs") return await this.listFunctionRuns(command, signal);
1116
1147
  if (command.kind === "secret-set") return await this.putEnvironmentSecret(command, signal);
1148
+ if (command.kind === "shared-mail") {
1149
+ const api = await this.authenticatedApi(command.credentialStore, signal);
1150
+ if (!api.sharedMail) throw new Error("Shared mail unavailable");
1151
+ return success(command.label, { mail: await api.sharedMail(command.request) });
1152
+ }
1117
1153
  if (command.kind === "managed-mail") {
1118
1154
  const api = await this.authenticatedApi(command.credentialStore, signal);
1119
1155
  if (!api.managedMail) throw new Error("Mail unavailable");
@@ -3120,7 +3156,7 @@ const parsedCommandName = (command: ProductCliCommand): CommandLabel => {
3120
3156
  if (command.kind === "function-runs") return "function runs";
3121
3157
  if (command.kind === "secret-set") return "secret set";
3122
3158
  if (command.kind === "secret-delete") return "secret delete";
3123
- if (command.kind === "managed-mail") return command.label;
3159
+ if (command.kind === "shared-mail" || command.kind === "managed-mail") return command.label;
3124
3160
  if (command.kind === "profile-list") return "profile list";
3125
3161
  return command.kind;
3126
3162
  };