@myapihq/cli 1.0.74 → 1.0.79

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.
@@ -41,7 +41,7 @@ async function patch(path, body, apiKey) {
41
41
  // myapi auth link — upgrade anonymous session to registered account.
42
42
  export async function link(flags = {}, emailArg) {
43
43
  if (flags.help) {
44
- info('Usage: myapi auth link [email]\n\nUpgrades your anonymous account by attaching a verified email address.\nA one-time code will be sent to your inbox paste it at the prompt to confirm.\nThis is an interactive command; it will ask for the code before completing.\n\nIf that email already belongs to an existing MyAPI account, your anonymous\naccount is NOT merged. Instead, the existing account is added as a second\nactive session and you can switch between them with: myapi auth switch\n\nTo create a completely new account from scratch, use: myapi auth setup');
44
+ info('Usage: myapi auth link [email]\n\nBehavior depends on whether the email is new or already registered:\n\n New email: Attaches it to your current anonymous account, upgrading it\n to a registered account. A one-time code is sent to confirm.\n\n Existing email: Does NOT merge accounts. The existing account is added as a\n second active session your anonymous account stays separate.\n Switch between sessions with: myapi auth switch\n\nTo create a completely new account from scratch, use: myapi auth setup');
45
45
  return;
46
46
  }
47
47
  const config = loadConfig();
@@ -35,7 +35,7 @@ export async function setFunnel(id, flags, via = 'auth config') {
35
35
  }
36
36
  export async function setDomain(domain, flags, via = 'auth config') {
37
37
  if (!domain || flags.help) {
38
- info(`Usage: myapi ${via} set-domain <domain>\n\nSets the default domain used by domain commands when --domain is omitted.\n\nExample:\n myapi ${via} set-domain example.com`);
38
+ info(`Usage: myapi ${via} set-domain <domain>\n\nSets the default domain used by domain commands when the domain argument is omitted.\n\nExample:\n myapi ${via} set-domain example.com`);
39
39
  return;
40
40
  }
41
41
  const config = requireConfig();
@@ -6,11 +6,21 @@ export async function check(domainArg, flags) {
6
6
  const config = requireConfig();
7
7
  const orgId = flags.org || config.default_org;
8
8
  const domain = domainArg || config.default_domain;
9
- if (!orgId || !domain)
10
- error("Missing required arguments.\nUsage: myapi domain check <domain> --org <id>\n(Set defaults: myapi auth config set-org <id> / myapi auth config set-domain <domain>)");
9
+ if (!orgId || !domain) {
10
+ const hint = config.default_org
11
+ ? `(current default org: ${config.default_org})`
12
+ : '(Set defaults: myapi config set-org <id> / myapi config set-domain <domain>)';
13
+ error(`Missing required arguments.\nUsage: myapi domain check <domain>${config.default_org ? '' : ' --org <id>'}\n${hint}`);
14
+ }
11
15
  const res = await sdkDomain.checkDomain(config.api_key, orgId, domain);
12
16
  if (flags.json) {
13
- printJson(res);
17
+ const out = { domain, available: res.available };
18
+ if (res.available) {
19
+ out.price_cents = res.price_cents;
20
+ if (res.price_display)
21
+ out.price_display = res.price_display;
22
+ }
23
+ printJson(out);
14
24
  return;
15
25
  }
16
26
  if (res.available) {
@@ -120,7 +130,7 @@ export async function run(subcommand, args, flags) {
120
130
  }
121
131
  if (flags.help) {
122
132
  if (subcommand === 'list')
123
- info('Usage: myapi domain list --org <id> [--filter=all|unassigned|org] [--json]\n\nLists all registered domains in your account.\n --filter=all Lists all domains owned by the account.\n --filter=unassigned Lists domains not assigned to an org.\n --filter=org (Default) Lists domains assigned to the current org.\n --json Output raw JSON');
133
+ info('Usage: myapi domain list [--org <id>] [--filter=all|unassigned|org] [--json]\n\nLists registered domains. --org (or default org) is used to identify your account.\n\n --filter=all All domains owned by the account.\n --filter=unassigned Domains not yet assigned to any org.\n --filter=org (Default) Domains assigned to the specified org.\n --json Output raw JSON\n\nNote: --filter=all and --filter=unassigned are account-wide and do not filter by org;\nthe --org flag is only needed to authenticate the request.');
124
134
  else if (subcommand === 'check')
125
135
  info('Usage: myapi domain check <domain> --org <id> [--json]\n\nChecks if a domain name is available for registration.\n\nFlags:\n --json Output raw JSON');
126
136
  else if (subcommand === 'register')
@@ -132,7 +142,7 @@ export async function run(subcommand, args, flags) {
132
142
  else if (subcommand === 'status')
133
143
  info('Usage: myapi domain status <domain> --org <id> [--json]\n\nGets the registration status of a domain.\n\nFlags:\n --json Output raw JSON');
134
144
  else if (subcommand === 'settings')
135
- info('Usage: myapi domain settings <domain> --org <id>\n\nGets the DNS settings and configuration for a domain.');
145
+ info('Usage: myapi domain settings <domain> --org <id>\n\nGets the current edge/CDN settings for a domain (security level, browser check, cache).\nUse "myapi domain update-settings" to change them.');
136
146
  else if (subcommand === 'update-settings')
137
147
  info('Usage: myapi domain update-settings <domain> --org <id> [flags]\n\nUpdates edge/CDN settings for a domain.\n\nFlags:\n --security=<level> CDN security level. Controls bot/threat filtering.\n Values: essentially_off | low | medium | high | under_attack\n Default (if unset): medium\n --browser-check=<on|off> Enable or disable browser integrity challenge for suspicious traffic.\n Default: on\n --purge-cache Immediately clears the CDN cache for this domain.\n Use after deploying changes that are not yet visible.\n\nExample:\n myapi domain update-settings example.com --org <id> --security=high --purge-cache');
138
148
  return;
@@ -2,6 +2,6 @@ export declare function list(flags: Record<string, string | boolean>): Promise<v
2
2
  export declare function create(flags: Record<string, string | boolean>): Promise<void>;
3
3
  export declare function get(id: string, flags: Record<string, string | boolean>): Promise<void>;
4
4
  export declare function del(id: string, flags: Record<string, string | boolean>): Promise<void>;
5
- export declare function push(id: string, slug: string, flags: Record<string, string | boolean>): Promise<void>;
5
+ export declare function push(slug: string, flags: Record<string, string | boolean>): Promise<void>;
6
6
  export declare function verify(id: string, flags: Record<string, string | boolean>): Promise<void>;
7
7
  export declare function run(subcommand: string | undefined, args: string[], flags: Record<string, string | boolean>): Promise<void>;
@@ -12,7 +12,12 @@ export async function list(flags) {
12
12
  printJson(funnels);
13
13
  return;
14
14
  }
15
- const rows = funnels.map(f => ({ id: f.id, created_at: formatDate(f.created_at), updated_at: formatDate(f.updated_at) }));
15
+ const rows = funnels.map(f => ({
16
+ id: f.id,
17
+ preview_url: f.subdomain_url || '',
18
+ created_at: formatDate(f.created_at),
19
+ updated_at: formatDate(f.updated_at),
20
+ }));
16
21
  if (rows.length === 0) {
17
22
  info('No funnels found. Create one with: myapi funnel create');
18
23
  return;
@@ -38,7 +43,21 @@ export async function get(id, flags) {
38
43
  if (!orgId || !id)
39
44
  error("Missing required arguments.\nUsage: myapi funnel get <id> --org <id>\n(Or set defaults via: myapi config set-org <id>)");
40
45
  const funnel = await sdkFunnel.getFunnel(config.api_key, orgId, id);
41
- printJson(funnel);
46
+ if (flags.json) {
47
+ printJson(funnel);
48
+ return;
49
+ }
50
+ info(`ID: ${funnel.id}`);
51
+ if (funnel.domain_url)
52
+ info(`Domain: ${funnel.domain_url}`);
53
+ else if (funnel.subdomain_url)
54
+ info(`Preview: ${funnel.subdomain_url}`);
55
+ if (funnel.created_at)
56
+ info(`Created: ${formatDate(funnel.created_at)}`);
57
+ if (funnel.updated_at)
58
+ info(`Updated: ${formatDate(funnel.updated_at)}`);
59
+ if (Array.isArray(funnel.pages))
60
+ info(`Pages: ${funnel.pages.length}`);
42
61
  }
43
62
  export async function del(id, flags) {
44
63
  const config = requireConfig();
@@ -48,17 +67,14 @@ export async function del(id, flags) {
48
67
  await sdkFunnel.deleteFunnel(config.api_key, orgId, id);
49
68
  success(`Funnel ${id} deleted`);
50
69
  }
51
- export async function push(id, slug, flags) {
70
+ export async function push(slug, flags) {
52
71
  const config = requireConfig();
53
72
  const orgId = flags.org || config.default_org;
54
73
  if (!orgId)
55
- error("Missing org. Set a default with: myapi auth config set-org <id>");
56
- if (slug && flags.slug && slug !== flags.slug) {
57
- info(`› Note: positional slug "${slug}" takes precedence over --slug "${flags.slug}".`);
58
- }
74
+ error("Missing org. Set a default with: myapi config set-org <id>");
59
75
  const rawSlug = slug || flags.slug || '/';
60
76
  const finalSlug = rawSlug.startsWith('/') ? rawSlug : `/${rawSlug}`;
61
- let funnelId = id || config.default_funnel;
77
+ let funnelId = flags.funnel || config.default_funnel;
62
78
  if (!funnelId) {
63
79
  const existing = await sdkFunnel.listFunnels(config.api_key, orgId);
64
80
  if (existing.length === 0)
@@ -75,7 +91,7 @@ export async function push(id, slug, flags) {
75
91
  process.stdin.on('error', reject);
76
92
  });
77
93
  if (!html.trim())
78
- error("No content provided via stdin. Usage: echo '<h1>Hello</h1>' | myapi funnel push [id] [slug]");
94
+ error("No content provided via stdin. Usage: echo '<h1>Hello</h1>' | myapi funnel push [slug]");
79
95
  const result = await sdkFunnel.pushFunnelPage(config.api_key, orgId, funnelId, { slug: finalSlug, html });
80
96
  success(`Pushed page to ${finalSlug}`);
81
97
  if (result?.url) {
@@ -114,7 +130,7 @@ export async function run(subcommand, args, flags) {
114
130
  else if (subcommand === 'delete')
115
131
  info('Usage: myapi funnel delete <id> --org <id>\n\nDeletes a funnel permanently.\n\nFlags:\n --org <id> Organization ID (or set default via myapi auth config set-org)');
116
132
  else if (subcommand === 'push')
117
- info('Usage: myapi funnel push [funnel_id] [slug] < page.html\n\nPublishes an HTML page from stdin to a path within your funnel (website).\n\nArgument resolution:\n - If the first positional argument starts with "/", it is treated as the slug\n (funnel_id is omitted and your default funnel is used).\n - If the first positional argument looks like a UUID, it is treated as funnel_id;\n the second argument (if any) is the slug.\n - Omit both to use your configured default funnel and slug "/".\n\nFlags:\n --org <id> Organization ID (or set default via myapi auth config set-org)\n --slug <path> Alternative way to specify the slug\n\nExamples:\n echo \'<h1>Hello</h1>\' | myapi funnel push / # push to / on default funnel\n cat about.html | myapi funnel push /about # push to /about\n myapi funnel push < index.html # push to / on default funnel\n cat p.html | myapi funnel push <uuid> /pricing # explicit funnel + slug');
133
+ info('Usage: myapi funnel push [slug] < page.html\n\nPublishes an HTML page from stdin to a path within your funnel (website).\nThe funnel is always resolved from your default or --funnel flag.\n\nFlags:\n --org <id> Organization ID (or set default via myapi config set-org)\n --funnel <id> Funnel ID (or set default via myapi config set-funnel)\n --slug <path> Alternative way to specify the slug\n\nExamples:\n echo \'<h1>Hello</h1>\' | myapi funnel push / # push to /\n cat about.html | myapi funnel push /about # push to /about\n myapi funnel push < index.html # push to / on default funnel\n cat p.html | myapi funnel push /pricing --funnel <uuid>');
118
134
  else if (subcommand === 'pull')
119
135
  info('Usage: myapi funnel pull [funnel_id] [slug]\n\nFetches the HTML content of a funnel page.');
120
136
  return;
@@ -128,7 +144,7 @@ export async function run(subcommand, args, flags) {
128
144
  else if (subcommand === 'delete')
129
145
  await del(args[0], flags);
130
146
  else if (subcommand === 'push')
131
- await push(args[0], args[1], flags);
147
+ await push(args[0], flags);
132
148
  else if (subcommand === 'verify')
133
149
  await verify(args[0], flags);
134
150
  else
@@ -51,12 +51,21 @@ export async function list(flags) {
51
51
  const config = requireConfig();
52
52
  const orgs = await hq.listOrgs(config.api_key);
53
53
  if (flags.json) {
54
- printJson(orgs);
54
+ if (flags.verbose) {
55
+ printJson(orgs);
56
+ return;
57
+ }
58
+ printJson(orgs.map((o) => ({
59
+ id: o.id,
60
+ name: o.name,
61
+ preview_subdomain: o.preview_subdomain || undefined,
62
+ created_at: o.created_at || undefined,
63
+ })));
55
64
  return;
56
65
  }
57
66
  const rows = orgs.map((o) => ({
58
67
  id: o.id,
59
- name: o.name,
68
+ name: o.id === config.default_org ? `${o.name} *` : o.name,
60
69
  created_at: o.created_at ? formatDate(o.created_at) : '',
61
70
  }));
62
71
  printTable(rows);
@@ -66,12 +75,13 @@ export async function get(id, flags) {
66
75
  info('Usage: myapi org get <id> [--json]\n\nFetches details of a specific organization.\n\nFlags:\n --json Output raw JSON');
67
76
  return;
68
77
  }
69
- if (!id) {
70
- error("Missing org id. Usage: myapi org get <id>");
78
+ const config = requireConfig();
79
+ const resolvedId = id || config.default_org;
80
+ if (!resolvedId) {
81
+ error("Missing org id. Usage: myapi org get <id>\n(Or set a default: myapi config set-org <id>)");
71
82
  return;
72
83
  }
73
- const config = requireConfig();
74
- const org = await hq.getOrg(config.api_key, id);
84
+ const org = await hq.getOrg(config.api_key, resolvedId);
75
85
  if (flags.json) {
76
86
  printJson(org);
77
87
  return;
@@ -100,7 +110,7 @@ export async function del(id, flags) {
100
110
  }
101
111
  export async function importOrg(args, flags) {
102
112
  if (flags.help) {
103
- info('Usage: myapi org import <domain> --org <id>\n\nSyncs brand information from an existing website into an organization profile.\nMyAPI fetches the site and extracts name, logo, description, and other brand\nsignals, then updates the org automatically.\n\nThis does NOT register or assign the domain — it only reads from the site\nto enrich the org profile. Think of it as "brand sync", not domain setup.\n\nPrerequisite: an org must already exist. Create one first:\n myapi org create --name "My Brand" --yes');
113
+ info('Usage: myapi org sync-brand <domain> --org <id>\n\nFetches an existing website and extracts brand signals (name, logo, description,\nbusiness sector) to enrich your organization profile automatically.\n\nThis does NOT register or transfer the domain — it only reads from the site.\nThe org must already exist before running this command.\n\nPrerequisite:\n myapi org create --name "My Brand" --yes\n\nExample:\n myapi org sync-brand example.com --org <id>');
104
114
  return;
105
115
  }
106
116
  const config = requireConfig();
@@ -98,8 +98,8 @@ async function anonymousFlow() {
98
98
  // ---------------------------------------------------------------------------
99
99
  // myapi auth import-key <key> — non-interactively import a raw API key.
100
100
  export async function importKey(apiKey, flags) {
101
- if (!apiKey) {
102
- info('Usage: myapi auth import-key <api_key> [--install-skills] [--no-skills]');
101
+ if (flags.help || !apiKey) {
102
+ info('Usage: myapi auth import-key <api_key> [--install-skills] [--no-skills]\n\nImports an existing API key non-interactively. Use this in CI, Docker, or any\nenvironment where the interactive "myapi auth setup" flow is not practical.\n\nThe key is validated against the API before being saved. Your default org and\nfunnel are auto-detected from the account and written to the local config.\n\nFlags:\n --install-skills Also install the MyAPI skills pack for AI agents after importing\n --no-skills Skip skills installation even if previously installed\n\nExamples:\n myapi auth import-key hqlive_xxxxxxxxxxxxxxxxxxxx\n myapi auth import-key hqlive_xxxxxxxxxxxxxxxxxxxx --install-skills');
103
103
  return;
104
104
  }
105
105
  const auth = { Authorization: `Bearer ${apiKey}` };
@@ -1,7 +1,7 @@
1
1
  import { execSync } from 'child_process';
2
2
  import { existsSync } from 'fs';
3
3
  import { loadConfig } from '../config.js';
4
- import { info, success } from '../output.js';
4
+ import { info, success, banner } from '../output.js';
5
5
  import { installSkills } from './setup.js';
6
6
  const REGISTRY_URL = 'https://registry.npmjs.org/@myapihq/cli/latest';
7
7
  const PACKUMENT_URL = 'https://registry.npmjs.org/@myapihq/cli';
@@ -33,12 +33,12 @@ async function isVersionInstallable(version) {
33
33
  function npmInstallArgs(version) {
34
34
  const npmCandidate = process.execPath.replace(/[/\\]node(\.exe)?$/, '/npm');
35
35
  const bin = existsSync(npmCandidate) ? npmCandidate : 'npm';
36
- const baseArgs = ['install', '-g', '--prefer-online', `@myapihq/cli@${version}`];
36
+ const baseArgs = ['install', '-g', '--prefer-online', '--silent', '--no-fund', `@myapihq/cli@${version}`];
37
37
  try {
38
38
  const self = process.argv[1];
39
39
  const binDir = self.replace(/[/\\][^/\\]+$/, '');
40
40
  const prefix = binDir.replace(/[/\\]bin$/, '');
41
- return { bin, args: ['install', '-g', '--prefer-online', '--prefix', prefix, `@myapihq/cli@${version}`] };
41
+ return { bin, args: ['install', '-g', '--prefer-online', '--silent', '--no-fund', '--prefix', prefix, `@myapihq/cli@${version}`] };
42
42
  }
43
43
  catch {
44
44
  return { bin, args: baseArgs };
@@ -46,7 +46,10 @@ function npmInstallArgs(version) {
46
46
  }
47
47
  // checkForUpdate runs silently in the background on every command.
48
48
  // Auto-installs if a newer version is available.
49
+ // Suppress entirely with MYAPI_NO_UPDATE=1 or when stdout is not a TTY.
49
50
  export async function checkForUpdate(currentVersion) {
51
+ if (process.env.MYAPI_NO_UPDATE === '1' || !process.stdout.isTTY)
52
+ return;
50
53
  try {
51
54
  const res = await fetch(REGISTRY_URL, { signal: AbortSignal.timeout(3000) });
52
55
  if (!res.ok)
@@ -59,7 +62,7 @@ export async function checkForUpdate(currentVersion) {
59
62
  // (which `npm install` consults) has propagated through the CDN.
60
63
  if (!(await isVersionInstallable(latest)))
61
64
  return;
62
- info(`\n› New version available (${currentVersion} → ${latest}) — installing…`);
65
+ banner(`\n› New version available (${currentVersion} → ${latest}) — installing…`);
63
66
  try {
64
67
  const { bin, args } = npmInstallArgs(latest);
65
68
  execSync(`"${bin}" ${args.map(a => `"${a}"`).join(' ')}`, { stdio: 'pipe' });
@@ -67,12 +70,12 @@ export async function checkForUpdate(currentVersion) {
67
70
  if (config?.skills_installed) {
68
71
  await installSkills();
69
72
  }
70
- info(`› Updated to ${latest} — active after this command completes.\n`);
73
+ banner(`› Updated to ${latest} — active after this command completes.\n`);
71
74
  }
72
75
  catch (installErr) {
73
76
  const msg = installErr?.stderr?.toString?.() || installErr?.message || String(installErr);
74
- info(`› Auto-update failed: ${msg.trim()}`);
75
- info(`› Run manually: npm install -g @myapihq/cli@latest`);
77
+ banner(`› Auto-update failed: ${msg.trim()}`);
78
+ banner(`› Run manually: npm install -g @myapihq/cli@latest`);
76
79
  }
77
80
  }
78
81
  }
@@ -83,7 +86,7 @@ export async function checkForUpdate(currentVersion) {
83
86
  // myapi update — explicit update, same logic as auto-update.
84
87
  export async function update(flags = {}) {
85
88
  if (flags.help) {
86
- info('Usage: myapi update\n\nUpdates the MyAPI CLI and installed skills to the latest published version.\nEquivalent to: npm install -g @myapihq/cli@latest\n\nNotes:\n - Version pinning and rollback are not supported — always installs the latest.\n - The CLI also auto-updates silently on each command when a newer version is\n detected. If you need a stable version in CI, pin with:\n npm install -g @myapihq/cli@<version>\n and set NO_COLOR=1 to suppress ANSI output in non-TTY environments.');
89
+ info('Usage: myapi update\n\nUpdates the MyAPI CLI and installed skills to the latest published version.\nEquivalent to: npm install -g @myapihq/cli@latest\n\nNotes:\n - Version pinning and rollback are not supported — always installs the latest.\n - The CLI also auto-updates silently on each command when a newer version is\n detected (banner goes to stderr, suppressed on non-TTY stdout).\n - To disable auto-update: set MYAPI_NO_UPDATE=1 in your environment.\n - For a pinned version in CI: npm install -g @myapihq/cli@<version>');
87
90
  return;
88
91
  }
89
92
  info('› Checking for updates…');
@@ -108,7 +111,7 @@ export async function update(flags = {}) {
108
111
  }
109
112
  info('› Refreshing skills…');
110
113
  await installSkills();
111
- success('Up to date.');
114
+ success('Up to date.');
112
115
  }
113
116
  // latestVersion fetches the current published version for --version display.
114
117
  export async function latestVersion() {
package/dist/index.js CHANGED
@@ -23,25 +23,32 @@ const ERROR_MESSAGES = {
23
23
  org_not_found: 'Organization not found.',
24
24
  FUNNEL_NOT_FOUND: 'Funnel not found.',
25
25
  funnel_not_found: 'Funnel not found.',
26
+ funnel_already_exists: 'Your org already has a funnel. Use: myapi funnel list',
27
+ FUNNEL_ALREADY_EXISTS: 'Your org already has a funnel. Use: myapi funnel list',
28
+ domain_already_registered: 'This domain is already registered under your account.',
29
+ DOMAIN_ALREADY_REGISTERED: 'This domain is already registered under your account.',
30
+ domain_not_available: 'This domain is not available for registration.',
31
+ DOMAIN_NOT_AVAILABLE: 'This domain is not available for registration.',
26
32
  db_error: 'Resource not found or invalid ID.',
27
33
  NOT_FOUND: 'Resource not found.',
28
34
  FORBIDDEN: 'You do not have permission to perform this action.',
29
35
  RATE_LIMITED: 'Too many requests. Please wait a moment and try again.',
36
+ INSUFFICIENT_BALANCE: 'Insufficient balance. Run: myapi billing topup <amount>',
30
37
  };
31
38
  function friendlyError(code) {
32
39
  return ERROR_MESSAGES[code] || code;
33
40
  }
34
41
  async function main() {
35
- const updatePromise = updateCmd.checkForUpdate(pkg.version).catch(() => { });
36
42
  const { args, flags } = parseArgs(process.argv.slice(2));
37
43
  if (flags.version || flags.v || flags.V) {
38
- const [latest] = await Promise.all([updateCmd.latestVersion(), updatePromise]);
44
+ const latest = await updateCmd.latestVersion();
39
45
  const updateNote = latest && updateCmd.isNewer(latest, pkg.version)
40
46
  ? ` (update available: ${latest})`
41
47
  : '';
42
48
  info(`myapi ${pkg.version}${updateNote}`);
43
49
  return;
44
50
  }
51
+ const updatePromise = updateCmd.checkForUpdate(pkg.version).catch(() => { });
45
52
  if (flags.help && args.length === 0) {
46
53
  printHelp();
47
54
  return;
@@ -54,7 +61,7 @@ async function main() {
54
61
  }
55
62
  printHelp();
56
63
  await updatePromise;
57
- return;
64
+ process.exit(1);
58
65
  }
59
66
  const [command, subcommand, ...restArgs] = args;
60
67
  try {
@@ -86,7 +93,7 @@ async function main() {
86
93
  await configCmd.run(restArgs[0], restArgs.slice(1), flags);
87
94
  else if (subcommand === 'api-keys') {
88
95
  if (flags.help && !restArgs[0]) {
89
- info('Usage: myapi auth api-keys <subcommand>\n\nManage programmatic API keys for your account. API keys are used to authenticate\nrequests to the MyAPI SDK and REST API.\n\nSubcommands:\n list List all API keys with their IDs and creation dates\n create Create a new API key (the key value is shown once)\n revoke <id> Permanently revoke an API key by ID\n\nExamples:\n myapi auth api-keys list\n myapi auth api-keys create\n myapi auth api-keys revoke xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx');
96
+ info('Usage: myapi auth api-keys <subcommand>\n\nManage programmatic API keys for your account. API keys are used to authenticate\nrequests to the MyAPI SDK and REST API.\n\nSubcommands:\n list List all API keys with their IDs and creation dates\n create Create a new API key (the key value is shown once)\n revoke <id> Permanently revoke an API key by ID\n\nExamples:\n myapi auth api-keys list\n myapi auth api-keys create\n myapi auth api-keys revoke hqlive_xxxxxxxxxxxxxxxxxxxx');
90
97
  break;
91
98
  }
92
99
  if (!restArgs[0]) {
@@ -108,7 +115,7 @@ async function main() {
108
115
  break;
109
116
  case 'org':
110
117
  if (!subcommand || (flags.help && !subcommand)) {
111
- info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization (use --yes to auto-set it as your default org and funnel)\n get Get details of an organization\n delete Delete an organization\n import Extract org from domain');
118
+ info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization (use --yes to auto-set it as your default org and funnel)\n get Get details of an organization\n delete Delete an organization\n sync-brand Sync brand info (name, logo, description) from an existing website into an org');
112
119
  break;
113
120
  }
114
121
  if (subcommand === 'list')
@@ -119,8 +126,12 @@ async function main() {
119
126
  await orgCmd.get(restArgs[0], flags);
120
127
  else if (subcommand === 'delete')
121
128
  await orgCmd.del(restArgs[0], flags);
122
- else if (subcommand === 'import')
129
+ else if (subcommand === 'sync-brand')
123
130
  await orgCmd.importOrg(restArgs, flags);
131
+ else if (subcommand === 'import') {
132
+ process.stderr.write('› Note: "org import" is deprecated — use "org sync-brand" instead.\n');
133
+ await orgCmd.importOrg(restArgs, flags);
134
+ }
124
135
  else
125
136
  printHelp();
126
137
  break;
@@ -154,8 +165,8 @@ async function main() {
154
165
  await authCmd.whoami(flags);
155
166
  break;
156
167
  case 'keys':
157
- if (!subcommand || flags.help) {
158
- info('Usage: myapi keys <subcommand>\n\nManage programmatic API keys for your account. API keys are used to authenticate\nrequests to the MyAPI SDK and REST API.\n\nSubcommands:\n list List all API keys with their IDs and creation dates\n create Create a new API key (the key value is shown once)\n revoke <id> Permanently revoke an API key by ID\n\nExamples:\n myapi keys list\n myapi keys create\n myapi keys revoke xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n\nAlias for: myapi auth api-keys');
168
+ if (!subcommand || (flags.help && !subcommand)) {
169
+ info('Usage: myapi keys <subcommand>\n\nManage programmatic API keys for your account. API keys are used to authenticate\nrequests to the MyAPI SDK and REST API.\n\nSubcommands:\n list List all API keys with their IDs and creation dates\n create Create a new API key (the key value is shown once)\n revoke <id> Permanently revoke an API key by ID\n\nExamples:\n myapi keys list\n myapi keys create\n myapi keys revoke hqlive_xxxxxxxxxxxxxxxxxxxx\n\nAlias for: myapi auth api-keys');
159
170
  break;
160
171
  }
161
172
  if (subcommand === 'create')
@@ -177,7 +188,22 @@ async function main() {
177
188
  success('› Skills installed.');
178
189
  break;
179
190
  case 'help':
180
- printHelp();
191
+ if (subcommand === 'funnel')
192
+ await funnelCmd.run(undefined, [], { help: true });
193
+ else if (subcommand === 'domain')
194
+ await domainCmd.run(undefined, [], { help: true });
195
+ else if (subcommand === 'auth')
196
+ info('Usage: myapi auth <subcommand>\n\nSubcommands:\n setup Configure your account\n import-key Import an existing API key non-interactively\n whoami Show current account · supports --json\n link [email] Upgrade anonymous account to registered (or add a second session)\n switch [index] Switch active account by index or email\n config Manage CLI defaults (org, funnel, domain)\n install-skills Install or update the MyAPI skills pack for AI agents\n api-keys Manage API keys · list / create / revoke');
197
+ else if (subcommand === 'org')
198
+ info('Usage: myapi org <subcommand>\n\nSubcommands:\n list List organizations\n create Create an organization\n get Get details of an organization\n delete Delete an organization\n sync-brand Sync brand info from an existing website into an org');
199
+ else if (subcommand === 'billing')
200
+ info('Usage: myapi billing <subcommand>\n\nSubcommands:\n balance Check balance\n history View billing history\n topup Top up your balance\n setup Setup a payment method');
201
+ else if (subcommand === 'keys')
202
+ info('Usage: myapi keys <subcommand>\n\nSubcommands:\n list List all API keys\n create Create a new API key\n revoke <id> Revoke an API key\n\nAlias for: myapi auth api-keys');
203
+ else if (subcommand)
204
+ info(`Run: myapi ${subcommand} --help`);
205
+ else
206
+ printHelp();
181
207
  break;
182
208
  default:
183
209
  error(`Unknown command: ${command}. Run "myapi" for available commands.`);
package/dist/output.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export declare function success(message: string): void;
2
2
  export declare function error(message: string): never;
3
3
  export declare function info(message: string): void;
4
+ export declare function banner(message: string): void;
4
5
  export declare function printJson(data: unknown): void;
5
6
  export declare function printTable(rows: Record<string, unknown>[]): void;
package/dist/output.js CHANGED
@@ -9,6 +9,9 @@ export function error(message) {
9
9
  export function info(message) {
10
10
  console.log(message);
11
11
  }
12
+ export function banner(message) {
13
+ process.stderr.write(message + '\n');
14
+ }
12
15
  export function printJson(data) {
13
16
  console.log(JSON.stringify(data, null, 2));
14
17
  }
package/dist/utils.js CHANGED
@@ -43,5 +43,5 @@ export function formatDate(str) {
43
43
  const date = new Date(clean);
44
44
  if (isNaN(date.getTime()))
45
45
  return str;
46
- return date.toISOString().replace('T', ' ').slice(0, 16);
46
+ return date.toISOString().replace('T', ' ').slice(0, 16) + ' UTC';
47
47
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myapihq/cli",
3
- "version": "1.0.74",
3
+ "version": "1.0.79",
4
4
  "description": "MyAPI command-line interface",
5
5
  "type": "module",
6
6
  "files": [