@mcpcloud/cli 0.8.0-next-20260701231709 → 0.9.1

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 (2) hide show
  1. package/dist/index.js +205 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8816,6 +8816,210 @@ function registerApiKeyCommands(program2) {
8816
8816
  }));
8817
8817
  }
8818
8818
 
8819
+ // src/commands/domains-namespaces.ts
8820
+ var NAMESPACE_STATUS_LABELS = {
8821
+ pending_verification: "verifying",
8822
+ verified: "verified",
8823
+ removed: "removed"
8824
+ };
8825
+ function printNamespaceRecords(namespace) {
8826
+ printInfo(`Create these DNS records once for ${namespace.parentDomain} — every future subdomain is then covered:`);
8827
+ const rows = [
8828
+ {
8829
+ type: "TXT",
8830
+ name: namespace.verificationTxt.name,
8831
+ value: namespace.verificationTxt.value
8832
+ }
8833
+ ];
8834
+ if (namespace.wildcardCname) {
8835
+ rows.push({
8836
+ type: "CNAME",
8837
+ name: namespace.wildcardCname.name,
8838
+ value: namespace.wildcardCname.value
8839
+ });
8840
+ }
8841
+ printList(rows, [
8842
+ { key: "type", label: "Type", width: 6 },
8843
+ { key: "name", label: "Name", width: 44 },
8844
+ { key: "value", label: "Value", width: 44 }
8845
+ ], rows);
8846
+ }
8847
+ function registerDomainNamespaceCommands(domains) {
8848
+ const namespaces = domains.command("namespaces").description("Verify a parent domain once, then attach subdomains to any server with no further DNS work");
8849
+ namespaces.command("list").description("List the domain namespaces in an organization").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (opts) => {
8850
+ const organizationId = await resolveOrgId(opts.org);
8851
+ const data = await api.get("/api/v1/domains/namespaces", { organization_id: organizationId });
8852
+ printList(data.namespaces.map((namespace) => ({
8853
+ parent: namespace.parentDomain,
8854
+ status: NAMESPACE_STATUS_LABELS[namespace.status],
8855
+ wildcard: namespace.wildcardConfigured ? "configured" : "—",
8856
+ verified: namespace.verifiedAt ? formatDate(namespace.verifiedAt) : "—"
8857
+ })), [
8858
+ { key: "parent", label: "Parent domain", width: 32 },
8859
+ { key: "status", label: "Status", width: 12 },
8860
+ { key: "wildcard", label: "Wildcard", width: 12 },
8861
+ { key: "verified", label: "Verified", width: 22 }
8862
+ ], data);
8863
+ }));
8864
+ namespaces.command("add <parentDomain>").description("Register a domain namespace and print its one-time DNS records (admin role required)").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (parentDomain, opts) => {
8865
+ const organizationId = await resolveOrgId(opts.org);
8866
+ const namespace = await api.post("/api/v1/domains/namespaces", { organizationId, parentDomain });
8867
+ if (isJsonMode()) {
8868
+ printJson(namespace);
8869
+ return;
8870
+ }
8871
+ printSuccess(`${namespace.parentDomain} namespace added.`);
8872
+ printNamespaceRecords(namespace);
8873
+ printInfo("Verification runs automatically — or run `mcp domains namespaces verify <parentDomain>` to check now.");
8874
+ }));
8875
+ namespaces.command("verify <parentDomain>").description("Check the namespace verification records now").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (parentDomain, opts) => {
8876
+ const organizationId = await resolveOrgId(opts.org);
8877
+ const data = await api.post("/api/v1/domains/namespaces/verify", {
8878
+ organizationId,
8879
+ parentDomain
8880
+ });
8881
+ if (isJsonMode()) {
8882
+ printJson(data);
8883
+ return;
8884
+ }
8885
+ if (data.verified) {
8886
+ printSuccess(`${data.namespace.parentDomain} is verified. Attach subdomains with \`mcp domains add <label>.${data.namespace.parentDomain} --server <id>\`.`);
8887
+ } else {
8888
+ printInfo(data.error ?? "Not verified yet — DNS may still be propagating.");
8889
+ printNamespaceRecords(data.namespace);
8890
+ }
8891
+ }));
8892
+ namespaces.command("remove <parentDomain>").description("Remove a domain namespace — existing attached hostnames keep working (admin role required)").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (parentDomain, opts) => {
8893
+ const organizationId = await resolveOrgId(opts.org);
8894
+ const data = await api.delete("/api/v1/domains/namespaces", { organizationId, parentDomain });
8895
+ if (isJsonMode()) {
8896
+ printJson(data);
8897
+ return;
8898
+ }
8899
+ printSuccess(`${parentDomain} namespace removed. Hostnames already attached under it keep serving.`);
8900
+ }));
8901
+ }
8902
+
8903
+ // src/commands/domains.ts
8904
+ var STATUS_LABELS = {
8905
+ pending_verification: "verifying dns",
8906
+ pending_cert: "issuing certificate",
8907
+ active: "active",
8908
+ failed: "attention needed",
8909
+ removed: "removed"
8910
+ };
8911
+ function printDnsRecords(domain, cnameTarget) {
8912
+ printInfo(`Create these DNS records for ${domain.hostname}:`);
8913
+ const rows = [
8914
+ { type: "CNAME", name: domain.hostname, value: cnameTarget }
8915
+ ];
8916
+ if (domain.ownershipVerification) {
8917
+ rows.push({
8918
+ type: "TXT",
8919
+ name: domain.ownershipVerification.name,
8920
+ value: domain.ownershipVerification.value
8921
+ });
8922
+ }
8923
+ for (const record of domain.certificateValidationRecords) {
8924
+ rows.push({ type: "TXT", name: record.name, value: record.value });
8925
+ }
8926
+ printList(rows, [
8927
+ { key: "type", label: "Type", width: 6 },
8928
+ { key: "name", label: "Name", width: 44 },
8929
+ { key: "value", label: "Value", width: 44 }
8930
+ ], rows);
8931
+ }
8932
+ function printDomainStatus(domain) {
8933
+ printKeyValue({
8934
+ hostname: domain.hostname,
8935
+ status: STATUS_LABELS[domain.status],
8936
+ url: domain.status === "active" ? `https://${domain.hostname}/mcp` : "—",
8937
+ "last checked": domain.lastSyncedAt ? formatDate(domain.lastSyncedAt) : "—",
8938
+ ...domain.lastError ? { error: domain.lastError } : {}
8939
+ });
8940
+ }
8941
+ function registerDomainCommands(program2) {
8942
+ const domains = program2.command("domains").description("Serve servers from custom domains you own (Pro+)");
8943
+ registerDomainNamespaceCommands(domains);
8944
+ domains.command("list").description("List the custom domains in an organization").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (opts) => {
8945
+ const organizationId = await resolveOrgId(opts.org);
8946
+ const data = await api.get("/api/v1/domains", {
8947
+ organization_id: organizationId
8948
+ });
8949
+ if (!data.allowed) {
8950
+ printInfo("Bring your own domain requires the Pro plan or higher for this organization.");
8951
+ if (isJsonMode())
8952
+ printJson(data);
8953
+ return;
8954
+ }
8955
+ printList(data.domains.map((domain) => ({
8956
+ hostname: domain.hostname,
8957
+ status: STATUS_LABELS[domain.status],
8958
+ server: domain.serverId,
8959
+ added: formatDate(domain.createdAt)
8960
+ })), [
8961
+ { key: "hostname", label: "Hostname", width: 36 },
8962
+ { key: "status", label: "Status", width: 20 },
8963
+ { key: "server", label: "Server", width: 34 },
8964
+ { key: "added", label: "Added", width: 22 }
8965
+ ], data);
8966
+ if (!isJsonMode()) {
8967
+ printInfo(`${data.used} of ${data.limit === null ? "unlimited" : data.limit} domains used.`);
8968
+ }
8969
+ }));
8970
+ domains.command("add <hostname>").description("Attach a custom domain to a server (admin role required)").requiredOption("--server <serverId>", "Server id to attach the domain to").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (hostname2, opts) => {
8971
+ const organizationId = await resolveOrgId(opts.org);
8972
+ const data = await api.post("/api/v1/domains", {
8973
+ organizationId,
8974
+ serverId: opts.server,
8975
+ hostname: hostname2
8976
+ });
8977
+ if (isJsonMode()) {
8978
+ printJson(data);
8979
+ return;
8980
+ }
8981
+ printSuccess(`${data.domain.hostname} added.`);
8982
+ printDnsRecords(data.domain, data.cnameTarget);
8983
+ printInfo("Verification runs automatically once the records propagate — or run `mcp domains status <hostname>` to check now.");
8984
+ }));
8985
+ domains.command("status <hostname>").description("Recheck a custom domain against Cloudflare and show status").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (hostname2, opts) => {
8986
+ const organizationId = await resolveOrgId(opts.org);
8987
+ const domain = await api.post("/api/v1/domains/recheck", { organizationId, hostname: hostname2 });
8988
+ if (isJsonMode()) {
8989
+ printJson(domain);
8990
+ return;
8991
+ }
8992
+ printDomainStatus(domain);
8993
+ if (domain.status === "active") {
8994
+ printSuccess("Domain is verified and serving traffic.");
8995
+ }
8996
+ }));
8997
+ domains.command("remove <hostname>").description("Remove a custom domain — traffic on it stops immediately (admin role required)").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (hostname2, opts) => {
8998
+ const organizationId = await resolveOrgId(opts.org);
8999
+ const data = await api.delete("/api/v1/domains", {
9000
+ organizationId,
9001
+ hostname: hostname2
9002
+ });
9003
+ if (isJsonMode()) {
9004
+ printJson(data);
9005
+ return;
9006
+ }
9007
+ printSuccess(`${hostname2} removed. The platform URL is unaffected.`);
9008
+ }));
9009
+ domains.command("transfer <hostname>").description("Move a custom domain to another server without certificate churn (admin role required)").requiredOption("--server <serverId>", "Target server id").option("--org <orgId>", "Organization id (defaults to your default org)").action(runAction(async (hostname2, opts) => {
9010
+ const organizationId = await resolveOrgId(opts.org);
9011
+ const domain = await api.post("/api/v1/domains/transfer", { organizationId, serverId: opts.server, hostname: hostname2 });
9012
+ if (isJsonMode()) {
9013
+ printJson(domain);
9014
+ return;
9015
+ }
9016
+ printSuccess(`${domain.hostname} now serves server ${domain.serverId}.`);
9017
+ if (domain.status === "active") {
9018
+ printInfo("Routing re-pointed — no DNS or certificate changes needed.");
9019
+ }
9020
+ }));
9021
+ }
9022
+
8819
9023
  // src/commands/config.ts
8820
9024
  import { homedir as homedir2 } from "node:os";
8821
9025
  import { join as join11 } from "node:path";
@@ -35573,6 +35777,7 @@ function createProgram() {
35573
35777
  registerToolCommands(program2);
35574
35778
  registerSkillCommands(program2);
35575
35779
  registerApiKeyCommands(program2);
35780
+ registerDomainCommands(program2);
35576
35781
  registerDeploymentCommands(program2);
35577
35782
  registerOrgCommands(program2);
35578
35783
  registerUsageCommands(program2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpcloud/cli",
3
- "version": "0.8.0-next-20260701231709",
3
+ "version": "0.9.1",
4
4
  "description": "The official CLI for MCPCloud — manage projects, servers, skills, and API keys from the terminal",
5
5
  "type": "module",
6
6
  "bin": {