@myapihq/cli 1.1.0-wip.4 → 1.2.0

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 (127) hide show
  1. package/dist/commands/{email.d.ts → audience.d.ts} +2 -0
  2. package/dist/commands/audience.js +245 -0
  3. package/dist/commands/auth.d.ts +5 -2
  4. package/dist/commands/auth.js +133 -5
  5. package/dist/commands/billing.d.ts +2 -0
  6. package/dist/commands/billing.js +18 -1
  7. package/dist/commands/company.d.ts +6 -0
  8. package/dist/commands/company.js +149 -0
  9. package/dist/commands/config.d.ts +2 -0
  10. package/dist/commands/config.js +20 -0
  11. package/dist/commands/crm/companies.d.ts +6 -0
  12. package/dist/commands/crm/companies.js +193 -0
  13. package/dist/commands/crm/contacts.d.ts +6 -0
  14. package/dist/commands/crm/contacts.js +241 -0
  15. package/dist/commands/crm/index.d.ts +6 -0
  16. package/dist/commands/crm/index.js +74 -0
  17. package/dist/commands/database.d.ts +6 -0
  18. package/dist/commands/database.js +259 -0
  19. package/dist/commands/domain.d.ts +3 -0
  20. package/dist/commands/domain.js +67 -1
  21. package/dist/commands/email/campaign.d.ts +2 -0
  22. package/dist/commands/email/campaign.js +34 -1
  23. package/dist/commands/email/index.d.ts +2 -0
  24. package/dist/commands/email/index.js +9 -0
  25. package/dist/commands/email/mailbox.d.ts +2 -0
  26. package/dist/commands/email/mailbox.js +5 -0
  27. package/dist/commands/email/message.d.ts +2 -0
  28. package/dist/commands/email/message.js +8 -0
  29. package/dist/commands/email/template.d.ts +2 -0
  30. package/dist/commands/email/template.js +54 -0
  31. package/dist/commands/email/verify.d.ts +7 -0
  32. package/dist/commands/email/verify.js +52 -0
  33. package/dist/commands/email/warmup.d.ts +2 -0
  34. package/dist/commands/email/warmup.js +7 -0
  35. package/dist/commands/funnel.d.ts +3 -0
  36. package/dist/commands/funnel.js +31 -0
  37. package/dist/commands/image.d.ts +2 -0
  38. package/dist/commands/image.js +43 -9
  39. package/dist/commands/keys.d.ts +2 -0
  40. package/dist/commands/keys.js +5 -0
  41. package/dist/commands/llm.d.ts +6 -0
  42. package/dist/commands/llm.js +156 -0
  43. package/dist/commands/org.d.ts +3 -0
  44. package/dist/commands/org.js +55 -0
  45. package/dist/commands/people.d.ts +6 -0
  46. package/dist/commands/people.js +136 -0
  47. package/dist/commands/pixel.d.ts +11 -3
  48. package/dist/commands/pixel.js +93 -0
  49. package/dist/commands/setup.d.ts +2 -0
  50. package/dist/commands/setup.js +57 -5
  51. package/dist/commands/status.d.ts +7 -0
  52. package/dist/commands/status.js +154 -0
  53. package/dist/commands/storage.d.ts +2 -0
  54. package/dist/commands/storage.js +14 -2
  55. package/dist/commands/update.d.ts +2 -0
  56. package/dist/commands/update.js +3 -0
  57. package/dist/commands/url.d.ts +7 -2
  58. package/dist/commands/url.js +6 -0
  59. package/dist/commands/verify.d.ts +7 -0
  60. package/dist/commands/verify.js +56 -0
  61. package/dist/commands/webhook.d.ts +2 -0
  62. package/dist/commands/webhook.js +31 -6
  63. package/dist/commands/workflow.d.ts +2 -0
  64. package/dist/commands/workflow.js +19 -1
  65. package/dist/completion.d.ts +3 -0
  66. package/dist/completion.js +78 -0
  67. package/dist/config.d.ts +2 -0
  68. package/dist/exposes.d.ts +2 -0
  69. package/dist/exposes.js +13 -0
  70. package/dist/exposes.test.js +99 -0
  71. package/dist/flags.test.js +84 -0
  72. package/dist/index.js +106 -14
  73. package/dist/prompt.d.ts +15 -0
  74. package/dist/prompt.js +27 -0
  75. package/dist/registrant.d.ts +6 -0
  76. package/dist/registrant.js +155 -0
  77. package/dist/services-sync.test.d.ts +1 -0
  78. package/dist/services-sync.test.js +32 -0
  79. package/dist/skills/my-api-hq/SKILL.md +51 -45
  80. package/dist/skills/my-crm-api/README.md +42 -0
  81. package/dist/skills/my-crm-api/SKILL.md +165 -0
  82. package/dist/skills/my-crm-api/claude/.claude-plugin/plugin.json +6 -0
  83. package/dist/skills/my-database-api/README.md +41 -0
  84. package/dist/skills/my-database-api/SKILL.md +107 -0
  85. package/dist/skills/my-database-api/claude/.claude-plugin/plugin.json +6 -0
  86. package/dist/skills/my-domain-api/SKILL.md +53 -26
  87. package/dist/skills/my-email-verify-api/README.md +33 -0
  88. package/dist/skills/my-email-verify-api/SKILL.md +91 -0
  89. package/dist/skills/my-email-verify-api/claude/.claude-plugin/plugin.json +6 -0
  90. package/dist/skills/my-funnel-api/SKILL.md +41 -37
  91. package/dist/skills/my-image-api/SKILL.md +48 -44
  92. package/dist/skills/my-llm-api/README.md +35 -0
  93. package/dist/skills/my-llm-api/SKILL.md +125 -0
  94. package/dist/skills/my-llm-api/claude/.claude-plugin/plugin.json +6 -0
  95. package/dist/skills/my-storage-api/README.md +1 -1
  96. package/dist/skills/my-storage-api/SKILL.md +44 -54
  97. package/dist/skills/my-webhook-api/README.md +1 -1
  98. package/dist/skills/my-webhook-api/SKILL.md +48 -92
  99. package/dist/skills/my-workflow-api/SKILL.md +46 -115
  100. package/dist/telemetry.d.ts +12 -0
  101. package/dist/telemetry.js +80 -0
  102. package/dist/telemetry.test.d.ts +1 -0
  103. package/dist/telemetry.test.js +101 -0
  104. package/package.json +13 -8
  105. package/dist/commands/email.js +0 -586
  106. package/dist/skills/my-email-api/README.md +0 -45
  107. package/dist/skills/my-email-api/SKILL.md +0 -104
  108. package/dist/skills/my-email-api/claude/.claude-plugin/plugin.json +0 -6
  109. package/dist/skills/my-email-api/make/.gitkeep +0 -0
  110. package/dist/skills/my-email-api/n8n/.gitkeep +0 -0
  111. package/dist/skills/my-email-api/openapi/.gitkeep +0 -0
  112. package/dist/skills/my-funnel-api/make/.gitkeep +0 -0
  113. package/dist/skills/my-funnel-api/n8n/.gitkeep +0 -0
  114. package/dist/skills/my-image-api/make/.gitkeep +0 -0
  115. package/dist/skills/my-image-api/n8n/.gitkeep +0 -0
  116. package/dist/skills/my-storage-api/make/.gitkeep +0 -0
  117. package/dist/skills/my-storage-api/n8n/.gitkeep +0 -0
  118. package/dist/skills/my-webhook-api/make/.gitkeep +0 -0
  119. package/dist/skills/my-webhook-api/n8n/.gitkeep +0 -0
  120. package/dist/skills/my-workflow-api/make/.gitkeep +0 -0
  121. package/dist/skills/my-workflow-api/n8n/.gitkeep +0 -0
  122. package/dist/utils.test.js +0 -48
  123. /package/dist/{utils.test.d.ts → exposes.test.d.ts} +0 -0
  124. /package/dist/skills/{my-api-hq/make → my-crm-api/openapi}/.gitkeep +0 -0
  125. /package/dist/skills/{my-api-hq/n8n → my-database-api/openapi}/.gitkeep +0 -0
  126. /package/dist/skills/{my-domain-api/make → my-email-verify-api/openapi}/.gitkeep +0 -0
  127. /package/dist/skills/{my-domain-api/n8n → my-llm-api/openapi}/.gitkeep +0 -0
@@ -3,6 +3,16 @@ import { requireConfig } from '../../config.js';
3
3
  import { success, error, printTable, printJson, info } from '../../output.js';
4
4
  import { pollJob } from '../../utils.js';
5
5
  import { requireOrg } from '../../helpers.js';
6
+ export const EXPOSES = [
7
+ 'POST /email/orgs/{org_id}/templates/generate',
8
+ 'GET /email/orgs/{org_id}/template-jobs/{job_id}',
9
+ 'GET /email/orgs/{org_id}/templates',
10
+ 'GET /email/orgs/{org_id}/templates/{template_id}',
11
+ 'POST /email/orgs/{org_id}/templates/{template_id}/edit',
12
+ 'POST /email/orgs/{org_id}/templates/{template_id}/send-test',
13
+ 'DELETE /email/orgs/{org_id}/templates/{template_id}',
14
+ 'GET /email/templates/{template_id}/preview',
15
+ ];
6
16
  async function generate(nameArg, flags) {
7
17
  const config = requireConfig();
8
18
  const orgId = requireOrg(flags, config, 'myapi email template generate <name> --prompt <str> [--org <id>]');
@@ -39,6 +49,44 @@ async function list(flags) {
39
49
  empty: 'No templates yet. Generate one with: myapi email template generate --prompt <p> --name <n>',
40
50
  });
41
51
  }
52
+ async function get(id, flags) {
53
+ const config = requireConfig();
54
+ const orgId = requireOrg(flags, config, 'myapi email template get <id> [--org <id>]');
55
+ if (!id)
56
+ error('Missing required arguments.\nUsage: myapi email template get <id> [--org <id>]');
57
+ const tmpl = await sdkEmail.getTemplate(config.api_key, orgId, id);
58
+ if (flags.json) {
59
+ printJson(tmpl);
60
+ return;
61
+ }
62
+ info(`ID: ${tmpl.id}`);
63
+ info(`Name: ${tmpl.name}`);
64
+ info(`Subject: ${tmpl.subject}`);
65
+ info(`Preview: ${tmpl.preview_url}`);
66
+ info(`Created: ${tmpl.created_at}`);
67
+ info(`Updated: ${tmpl.updated_at}`);
68
+ }
69
+ async function preview(id, flags) {
70
+ if (!id)
71
+ error('Missing required arguments.\nUsage: myapi email template preview <id> [--json]');
72
+ // Endpoint is unauthenticated by design — access is gated by the unguessable
73
+ // template_id, so anyone with the id can render the preview (this matches
74
+ // the "share-this-link-with-your-marketer" pattern).
75
+ const res = await sdkEmail.getTemplatePreview(id);
76
+ if (flags.json) {
77
+ printJson(res);
78
+ return;
79
+ }
80
+ if (res.preview_url)
81
+ info(`Preview URL: ${res.preview_url}`);
82
+ if (res.subject)
83
+ info(`Subject: ${res.subject}`);
84
+ if (res.html)
85
+ info(`\n--- HTML ---\n${res.html}`);
86
+ // Fall back to dumping the whole response if we got something unfamiliar.
87
+ if (!res.preview_url && !res.subject && !res.html)
88
+ printJson(res);
89
+ }
42
90
  async function edit(id, flags) {
43
91
  const config = requireConfig();
44
92
  const orgId = requireOrg(flags, config, 'myapi email template edit <id> --prompt <str> [--org <id>]');
@@ -69,6 +117,8 @@ const USAGE = {
69
117
 
70
118
  Either form works; the positional name is the recommended shape.`,
71
119
  'list': 'myapi email template list [--org <id>] [--json]',
120
+ 'get': 'myapi email template get <id> [--org <id>] [--json]',
121
+ 'preview': 'myapi email template preview <id> [--json]',
72
122
  'edit': 'myapi email template edit <id> --prompt <str> [--org <id>]',
73
123
  'send-test': 'myapi email template send-test <template_id> --to <email> [--org <id>]',
74
124
  'delete': 'myapi email template delete <id> [--org <id>]',
@@ -80,6 +130,8 @@ export async function run(sub, args, flags) {
80
130
  Subcommands:
81
131
  generate <name> Generate AI template (--prompt)
82
132
  list List templates
133
+ get <id> Get a template's metadata (subject, preview URL, ...)
134
+ preview <id> Get a template's rendered preview (no auth required)
83
135
  edit <id> Edit a template via prompt
84
136
  send-test <id> Send a test email for a template (--to)
85
137
  delete <id> Delete a template
@@ -98,6 +150,8 @@ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
98
150
  switch (sub) {
99
151
  case 'generate': return generate(args[0], flags);
100
152
  case 'list': return list(flags);
153
+ case 'get': return get(args[0], flags);
154
+ case 'preview': return preview(args[0], flags);
101
155
  case 'edit': return edit(args[0], flags);
102
156
  case 'send-test': return sendTest(args[0], flags);
103
157
  case 'delete': return del(args[0], flags);
@@ -0,0 +1,7 @@
1
+ import type { FlagSchema } from '../../flags.js';
2
+ import { type Flags } from '../../helpers.js';
3
+ import type { Exposes } from '../../exposes.js';
4
+ export declare const EXPOSES: Exposes;
5
+ export declare const SCHEMA: FlagSchema;
6
+ export declare const VERIFY_HELP = "Usage: myapi email verify <email> [--org <id>] [--json]\n\nSync single-address email verification. Cheap layer only: syntax + DNS +\nMicrosoft GetCredentialType. Returns a verdict in <1s for ~50% of inputs;\nthe rest get verdict='unknown' with smtp_recommended=true.\n\nVerdicts:\n deliverable high-confidence \u2014 the address accepts mail\n undeliverable high-confidence \u2014 syntax bad, DNS missing, or Microsoft rejects\n unknown not enough signal; consider an SMTP probe (not in this API)\n\nUse --json for the full check breakdown (syntax / DNS / Microsoft probes).\n";
7
+ export declare function run(emailArg: string | undefined, _rest: string[], flags?: Flags): Promise<void>;
@@ -0,0 +1,52 @@
1
+ import { email as sdkEmail } from '@myapihq/sdk';
2
+ import { requireConfig } from '../../config.js';
3
+ import { error, info, printJson } from '../../output.js';
4
+ import { requireOrg } from '../../helpers.js';
5
+ export const EXPOSES = [
6
+ 'POST /email/orgs/{org_id}/verify',
7
+ ];
8
+ export const SCHEMA = {};
9
+ export const VERIFY_HELP = `Usage: myapi email verify <email> [--org <id>] [--json]
10
+
11
+ Sync single-address email verification. Cheap layer only: syntax + DNS +
12
+ Microsoft GetCredentialType. Returns a verdict in <1s for ~50% of inputs;
13
+ the rest get verdict='unknown' with smtp_recommended=true.
14
+
15
+ Verdicts:
16
+ deliverable high-confidence — the address accepts mail
17
+ undeliverable high-confidence — syntax bad, DNS missing, or Microsoft rejects
18
+ unknown not enough signal; consider an SMTP probe (not in this API)
19
+
20
+ Use --json for the full check breakdown (syntax / DNS / Microsoft probes).
21
+ `;
22
+ export async function run(emailArg, _rest, flags = {}) {
23
+ if (flags.help) {
24
+ info(VERIFY_HELP);
25
+ return;
26
+ }
27
+ if (!emailArg)
28
+ error('Missing required argument <email>.\nUsage: myapi email verify <email> [--org <id>] [--json]');
29
+ const config = requireConfig();
30
+ const orgId = requireOrg(flags, config, 'myapi email verify <email> [--org <id>]');
31
+ const res = await sdkEmail.verifyEmail(config.api_key, orgId, emailArg);
32
+ if (flags.json) {
33
+ printJson(res);
34
+ return;
35
+ }
36
+ const verdictLabel = res.verdict === 'deliverable' ? '✓ deliverable'
37
+ : res.verdict === 'undeliverable' ? '✗ undeliverable'
38
+ : '? unknown';
39
+ info(`Email: ${res.email}`);
40
+ info(`Verdict: ${verdictLabel} (confidence ${res.confidence.toFixed(2)})`);
41
+ info(`SMTP next: ${res.smtp_recommended ? 'yes — consider an SMTP probe' : 'no — verdict is definitive'}`);
42
+ info(`Took: ${res.elapsed_ms}ms`);
43
+ if (res.checks.syntax.detail)
44
+ info(`Syntax: ${res.checks.syntax.detail}`);
45
+ if (res.checks.dns && res.checks.dns.mx_records && res.checks.dns.mx_records.length > 0) {
46
+ const mx = res.checks.dns.mx_records.filter(Boolean);
47
+ if (mx.length > 0)
48
+ info(`MX: ${mx.slice(0, 3).join(', ')}${mx.length > 3 ? ` (+${mx.length - 3} more)` : ''}`);
49
+ }
50
+ if (res.checks.microsoft)
51
+ info(`Microsoft: ${res.checks.microsoft.verdict}`);
52
+ }
@@ -1,2 +1,4 @@
1
1
  import type { Flags } from '../../helpers.js';
2
+ import type { Exposes } from '../../exposes.js';
3
+ export declare const EXPOSES: Exposes;
2
4
  export declare function run(sub: string | undefined, args: string[], flags: Flags): Promise<void>;
@@ -1,6 +1,13 @@
1
1
  import { email as sdkEmail } from '@myapihq/sdk';
2
2
  import { requireConfig } from '../../config.js';
3
3
  import { success, error, printJson, info } from '../../output.js';
4
+ export const EXPOSES = [
5
+ 'POST /email/warmup/start',
6
+ 'POST /email/warmup/pause',
7
+ 'POST /email/warmup/resume',
8
+ 'POST /email/warmup/stop',
9
+ 'GET /email/warmup/stats/{address}',
10
+ ];
4
11
  export async function run(sub, args, flags) {
5
12
  if (!sub || (flags.help && !sub)) {
6
13
  info('Usage: myapi email warmup <start|pause|resume|stop|stats> --address <email>');
@@ -1,10 +1,13 @@
1
1
  import type { FlagSchema } from '../flags.js';
2
2
  import { type Flags } from '../helpers.js';
3
+ import type { Exposes } from '../exposes.js';
4
+ export declare const EXPOSES: Exposes;
3
5
  export declare const SCHEMA: FlagSchema;
4
6
  export declare function list(flags: Flags): Promise<void>;
5
7
  export declare function create(flags: Flags): Promise<void>;
6
8
  export declare function get(id: string, flags: Flags): Promise<void>;
7
9
  export declare function del(id: string, flags: Flags): Promise<void>;
10
+ export declare function pages(funnelArg: string, flags: Flags): Promise<void>;
8
11
  export declare function push(slug: string, flags: Flags): Promise<void>;
9
12
  export declare function verify(slug: string, flags: Flags): Promise<void>;
10
13
  export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
@@ -3,6 +3,16 @@ import { requireConfig } from '../config.js';
3
3
  import { success, error, printTable, info, printJson } from '../output.js';
4
4
  import { formatDate } from '../utils.js';
5
5
  import { requireOrg } from '../helpers.js';
6
+ export const EXPOSES = [
7
+ 'POST /funnel/orgs/{org_id}/funnels',
8
+ 'GET /funnel/orgs/{org_id}/funnels',
9
+ 'GET /funnel/orgs/{org_id}/funnels/{funnel_id}',
10
+ 'DELETE /funnel/orgs/{org_id}/funnels/{funnel_id}',
11
+ 'POST /funnel/orgs/{org_id}/funnels/{funnel_id}/push-page',
12
+ 'POST /funnel/orgs/{org_id}/funnels/{funnel_id}/verify',
13
+ 'GET /funnel/orgs/{org_id}/funnels/{funnel_id}/pages',
14
+ 'GET /hq/orgs/{org_id}',
15
+ ];
6
16
  export const SCHEMA = {
7
17
  org: 'string',
8
18
  funnel: 'string',
@@ -74,6 +84,24 @@ export async function del(id, flags) {
74
84
  await sdkFunnel.deleteFunnel(config.api_key, orgId, id);
75
85
  success(`Funnel ${id} deleted`);
76
86
  }
87
+ // List the pages currently published to a funnel. Resolves the funnel id
88
+ // from positional arg, --funnel flag, or the user's default funnel.
89
+ export async function pages(funnelArg, flags) {
90
+ const config = requireConfig();
91
+ const orgId = requireOrg(flags, config, 'myapi funnel pages [funnel_id] [--funnel <id>] [--org <id>]');
92
+ const funnelId = funnelArg || flags.funnel || config.default_funnel;
93
+ if (!funnelId)
94
+ error('Missing funnel id. Pass it as a positional arg, --funnel <id>, or set: myapi config set-funnel <id>');
95
+ const list = await sdkFunnel.listFunnelPages(config.api_key, orgId, funnelId);
96
+ if (flags.json) {
97
+ printJson(list);
98
+ return;
99
+ }
100
+ printTable(list, {
101
+ flags,
102
+ empty: 'No pages published to this funnel yet. Push one with: echo "<h1>Hello</h1>" | myapi funnel push /',
103
+ });
104
+ }
77
105
  export async function push(slug, flags) {
78
106
  const config = requireConfig();
79
107
  const orgId = requireOrg(flags, config, 'myapi funnel push [slug] [--funnel <id>] [--org <id>]');
@@ -158,6 +186,7 @@ const SUBCOMMAND_USAGE = {
158
186
  'create': 'myapi funnel create [--org <id>]',
159
187
  'get': 'myapi funnel get <id> [--org <id>] [--json]',
160
188
  'delete': 'myapi funnel delete <id> [--org <id>]',
189
+ 'pages': 'myapi funnel pages [funnel_id] [--funnel <id>] [--org <id>] [--json]',
161
190
  'push': `myapi funnel push [slug] [--funnel <id>] [--slug <path>] [--org <id>] < page.html
162
191
 
163
192
  Reads HTML from stdin and publishes to <slug> on your funnel. Funnel is resolved
@@ -194,6 +223,7 @@ Subcommands:
194
223
  get <id> Get funnel details
195
224
  delete Delete a funnel
196
225
  push Push a raw HTML page from stdin to a slug
226
+ pages List the pages currently published to a funnel
197
227
  verify Verify a published page is reachable
198
228
 
199
229
  All commands accept --org <id> (or set default: myapi config set-org <id>).`);
@@ -214,6 +244,7 @@ All commands accept --org <id> (or set default: myapi config set-org <id>).`);
214
244
  case 'delete': return del(args[0], flags);
215
245
  case 'push': return push(args[0], flags);
216
246
  case 'verify': return verify(args[0], flags);
247
+ case 'pages': return pages(args[0], flags);
217
248
  default: error(`Unknown subcommand: ${subcommand}. Run "myapi funnel --help" for a list of valid subcommands.`);
218
249
  }
219
250
  }
@@ -1,4 +1,6 @@
1
1
  import type { FlagSchema } from '../flags.js';
2
2
  import { type Flags } from '../helpers.js';
3
+ import type { Exposes } from '../exposes.js';
4
+ export declare const EXPOSES: Exposes;
3
5
  export declare const SCHEMA: FlagSchema;
4
6
  export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
@@ -3,8 +3,16 @@ import { requireConfig } from '../config.js';
3
3
  import { success, error, printTable, info, printJson, banner } from '../output.js';
4
4
  import { formatDate, pollJob } from '../utils.js';
5
5
  import { requireOrg, requireArg } from '../helpers.js';
6
+ export const EXPOSES = [
7
+ 'POST /image/orgs/{org_id}/generate',
8
+ 'GET /image/orgs/{org_id}/jobs/{job_id}',
9
+ 'GET /image/orgs/{org_id}/list',
10
+ 'GET /image/orgs/{org_id}/models',
11
+ 'DELETE /image/orgs/{org_id}/images/{image_id}',
12
+ ];
6
13
  export const SCHEMA = {
7
14
  org: 'string',
15
+ model: 'string',
8
16
  prompt: 'string',
9
17
  ratio: 'string',
10
18
  style: 'string',
@@ -14,7 +22,6 @@ export const SCHEMA = {
14
22
  const VALID_RATIOS = new Set(['1:1', '16:9', '9:16', '4:3', '3:4']);
15
23
  // Hex list: optional leading #, 3 or 6 hex digits, comma-separated.
16
24
  const HEX_LIST_RE = /^#?[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?(?:\s*,\s*#?[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?)*$/;
17
- const PRICE_USD = 0.05;
18
25
  function summarizeImage(j) {
19
26
  const prompt = (j.prompt || '');
20
27
  const truncated = prompt.length > 60 ? prompt.slice(0, 60) + '...' : prompt;
@@ -29,11 +36,11 @@ function summarizeImage(j) {
29
36
  }
30
37
  async function generate(promptArg, flags) {
31
38
  const config = requireConfig();
32
- const orgId = requireOrg(flags, config, 'myapi image generate <prompt> [--ratio 1:1|16:9|9:16|4:3|3:4] [--style <s>] [--colors <hex,hex>] [--text] [--org <id>]');
39
+ const orgId = requireOrg(flags, config, 'myapi image generate <prompt> [--model <id>] [--ratio 1:1|16:9|9:16|4:3|3:4] [--style <s>] [--colors <hex,hex>] [--text] [--org <id>]');
33
40
  // Convention: first required arg is positional. --prompt still works for back-compat.
34
41
  const prompt = promptArg || flags.prompt;
35
42
  if (!prompt) {
36
- error('Missing required arguments.\nUsage: myapi image generate <prompt> [--ratio <ratio>] [--style <s>] [--colors <c>] [--text] [--org <id>]\n or: myapi image generate --prompt "<text>" ...');
43
+ error('Missing required arguments.\nUsage: myapi image generate <prompt> [--model <id>] [--ratio <ratio>] [--style <s>] [--colors <c>] [--text] [--org <id>]\n or: myapi image generate --prompt "<text>" ...');
37
44
  }
38
45
  // Client-side validation: catch typos before they round-trip.
39
46
  if (flags.ratio && !VALID_RATIOS.has(flags.ratio)) {
@@ -43,6 +50,8 @@ async function generate(promptArg, flags) {
43
50
  error(`Invalid --colors "${flags.colors}". Expected comma-separated hex like "#ff6600,#003366" (3- or 6-digit, # optional).`);
44
51
  }
45
52
  const payload = { prompt };
53
+ if (flags.model)
54
+ payload.model = flags.model;
46
55
  if (flags.ratio)
47
56
  payload.aspect_ratio = flags.ratio;
48
57
  if (flags.style)
@@ -51,9 +60,9 @@ async function generate(promptArg, flags) {
51
60
  payload.colors = flags.colors;
52
61
  if (flags.text)
53
62
  payload.has_text = true;
54
- // Cost preview before kickoff. Goes to stderr (banner) so --json output
55
- // stays clean for piping.
56
- banner(`› Charging $${PRICE_USD.toFixed(2)} for this image generation…`);
63
+ // Cost is per-model see `myapi image models`. Banner shown on stderr so
64
+ // --json output stays clean for piping.
65
+ banner(`› Generating image${payload.model ? ` (${payload.model})` : ''}…`);
57
66
  const job = await sdkImage.generateImage(config.api_key, orgId, payload);
58
67
  const final = await pollJob({
59
68
  label: 'Generating image',
@@ -124,10 +133,26 @@ async function del(id, flags) {
124
133
  await sdkImage.deleteImage(config.api_key, orgId, id);
125
134
  success(`Image ${id} deleted (job history retained, URL nullified)`);
126
135
  }
136
+ async function models(flags) {
137
+ const config = requireConfig();
138
+ const orgId = requireOrg(flags, config, 'myapi image models [--org <id>]');
139
+ const res = await sdkImage.listModels(config.api_key, orgId);
140
+ if (flags.json) {
141
+ printJson(res);
142
+ return;
143
+ }
144
+ printTable(res.models.map(m => ({
145
+ id: m.id,
146
+ kind: m.kind,
147
+ default_size: m.default_size,
148
+ aspect_ratios: m.aspect_ratios.join(', '),
149
+ cost_per_image: `$${m.cost_per_image_usd}`,
150
+ })), { flags, empty: 'No image models available.' });
151
+ }
127
152
  // ── Dispatcher ───────────────────────────────────────────────────────────────
128
153
  const SUBCOMMAND_USAGE = {
129
154
  'list': 'myapi image list [--org <id>] [--json]',
130
- 'generate': `myapi image generate <prompt> [--ratio 1:1|16:9|9:16|4:3|3:4] [--style <s>] [--colors <hex,hex>] [--text] [--org <id>]
155
+ 'generate': `myapi image generate <prompt> [--model <id>] [--ratio 1:1|16:9|9:16|4:3|3:4] [--style <s>] [--colors <hex,hex>] [--text] [--org <id>]
131
156
  myapi image generate --prompt "<text>" ...
132
157
 
133
158
  Either form works; the positional prompt is the recommended shape.
@@ -136,9 +161,11 @@ Generation is asynchronous — the CLI polls for up to 90s. If it times out
136
161
  the job keeps running server-side; re-fetch with:
137
162
  myapi image get <job_id>
138
163
 
139
- Cost: $${PRICE_USD.toFixed(2)} per generation. Failed jobs aren't charged.
164
+ Cost is per-model; run "myapi image models" for the catalog and rates.
165
+ Failed jobs aren't charged.
140
166
 
141
167
  Flags:
168
+ --model Model id from the catalog (default: gemini-2.5-flash-image)
142
169
  --ratio Aspect ratio (allowed: ${[...VALID_RATIOS].join(', ')}; default 1:1)
143
170
  --style Free-form style hint (e.g. "watercolor", "cyberpunk neon")
144
171
  --colors Hex colors comma-separated (e.g. "#ff6600,#003366")
@@ -153,6 +180,11 @@ Prints just the asset URL. Errors if the job hasn't completed yet.
153
180
  Curl-friendly:
154
181
  curl -O "$(myapi image get-url <id>)"`,
155
182
  'delete': 'myapi image delete <job_id> [--org <id>]',
183
+ 'models': `myapi image models [--org <id>] [--json]
184
+
185
+ Lists available image-generation models with per-image pricing and
186
+ supported aspect ratios. Mirrors "myapi llm models" for the image
187
+ primitive.`,
156
188
  };
157
189
  export async function run(subcommand, args, flags) {
158
190
  if (!subcommand || (flags.help && !subcommand)) {
@@ -160,9 +192,10 @@ export async function run(subcommand, args, flags) {
160
192
 
161
193
  Subcommands:
162
194
  list List all your generated images
163
- generate <prompt> Generate a new AI image (async, polls up to 90s, $${PRICE_USD.toFixed(2)})
195
+ generate <prompt> Generate a new AI image (async, polls up to 90s; pricing per model — see "image models")
164
196
  get <job_id> Fetch full job metadata (JSON or human-readable)
165
197
  get-url <job_id> Print just the asset URL (curl-friendly)
198
+ models List available image models with per-image pricing
166
199
  delete <job_id> Delete the asset (job history retained)
167
200
 
168
201
  All commands accept --org <id> (or set default: myapi config set-org <id>).
@@ -182,6 +215,7 @@ The asset lands in your org's storage and is also visible via "myapi storage lis
182
215
  case 'generate': return generate(args[0], flags);
183
216
  case 'get': return get(args[0], flags);
184
217
  case 'get-url': return getUrl(args[0], flags);
218
+ case 'models': return models(flags);
185
219
  case 'delete': return del(args[0], flags);
186
220
  default: error(`Unknown subcommand: ${subcommand}. Run "myapi image --help" for available subcommands.`);
187
221
  }
@@ -1,6 +1,8 @@
1
1
  import type { FlagSchema } from '../flags.js';
2
2
  import type { Flags } from '../helpers.js';
3
+ import type { Exposes } from '../exposes.js';
3
4
  export declare const SCHEMA: FlagSchema;
5
+ export declare const EXPOSES: Exposes;
4
6
  export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
5
7
  export declare function runApiKeys(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
6
8
  export declare function createNew(flags: Flags): Promise<void>;
@@ -7,6 +7,11 @@ import { requireArg } from '../helpers.js';
7
7
  export const SCHEMA = {
8
8
  name: 'string',
9
9
  };
10
+ export const EXPOSES = [
11
+ 'POST /hq/account/create/key',
12
+ 'GET /hq/account/keys',
13
+ 'DELETE /hq/account/delete/key/{key_id}',
14
+ ];
10
15
  const KEYS_HEADER = `Usage: myapi keys <subcommand>
11
16
 
12
17
  Manage programmatic API keys for your account.
@@ -0,0 +1,6 @@
1
+ import type { FlagSchema } from '../flags.js';
2
+ import { type Flags } from '../helpers.js';
3
+ import type { Exposes } from '../exposes.js';
4
+ export declare const EXPOSES: Exposes;
5
+ export declare const SCHEMA: FlagSchema;
6
+ export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;
@@ -0,0 +1,156 @@
1
+ import * as fs from 'fs';
2
+ import { llm as sdkLlm } from '@myapihq/sdk';
3
+ import { requireConfig } from '../config.js';
4
+ import { error, info, printTable, printJson } from '../output.js';
5
+ import { requireOrg } from '../helpers.js';
6
+ export const EXPOSES = [
7
+ 'POST /llm/orgs/{org_id}/complete',
8
+ 'POST /llm/orgs/{org_id}/embed',
9
+ 'GET /llm/orgs/{org_id}/models',
10
+ ];
11
+ export const SCHEMA = {
12
+ org: 'string',
13
+ model: 'string',
14
+ system: 'string',
15
+ 'max-tokens': 'number',
16
+ temperature: 'number',
17
+ stop: 'string',
18
+ file: 'string',
19
+ kind: 'string',
20
+ };
21
+ function readPromptArg(promptArg, flags) {
22
+ if (typeof flags.file === 'string' && flags.file) {
23
+ return fs.readFileSync(flags.file, 'utf-8');
24
+ }
25
+ if (promptArg === '-') {
26
+ return fs.readFileSync(0, 'utf-8');
27
+ }
28
+ return promptArg ?? '';
29
+ }
30
+ const DEFAULT_CHAT_MODEL = 'gemini-3.1-flash-lite-preview';
31
+ async function complete(promptArg, flags) {
32
+ const config = requireConfig();
33
+ const orgId = requireOrg(flags, config, 'myapi llm complete "<prompt>" [--model <id>] [--system <s>] [--max-tokens N] [--temperature 0..1] [--stop <csv>] [--org <id>]');
34
+ const model = typeof flags.model === 'string' && flags.model ? flags.model : DEFAULT_CHAT_MODEL;
35
+ const prompt = readPromptArg(promptArg, flags);
36
+ if (!prompt.trim())
37
+ error('Empty prompt. Pass <prompt> as an argument, "-" to read stdin, or --file <path>.');
38
+ const messages = [];
39
+ if (typeof flags.system === 'string' && flags.system) {
40
+ messages.push({ role: 'system', content: flags.system });
41
+ }
42
+ messages.push({ role: 'user', content: prompt });
43
+ const stop = typeof flags.stop === 'string' && flags.stop
44
+ ? flags.stop.split(',').map(s => s.trim()).filter(Boolean)
45
+ : undefined;
46
+ const res = await sdkLlm.complete(config.api_key, orgId, {
47
+ model,
48
+ messages,
49
+ max_tokens: typeof flags['max-tokens'] === 'number' ? flags['max-tokens'] : undefined,
50
+ temperature: typeof flags.temperature === 'number' ? flags.temperature : undefined,
51
+ stop,
52
+ });
53
+ if (flags.json) {
54
+ printJson(res);
55
+ return;
56
+ }
57
+ info(res.content);
58
+ // Usage footer on stderr so it doesn't pollute piped output.
59
+ process.stderr.write(`\n— ${res.model} · ${res.usage.input_tokens}+${res.usage.output_tokens} tokens · $${res.usage.cost_usd.toFixed(6)} · ${res.finish_reason}\n`);
60
+ }
61
+ async function embed(inputArg, flags) {
62
+ const config = requireConfig();
63
+ const orgId = requireOrg(flags, config, 'myapi llm embed "<text>" --model <id> [--org <id>]');
64
+ const model = typeof flags.model === 'string' ? flags.model : '';
65
+ if (!model)
66
+ error('Missing required flag: --model. Run "myapi llm models" to list embed models.');
67
+ const text = readPromptArg(inputArg, flags);
68
+ if (!text.trim())
69
+ error('Empty input. Pass <text> as an argument, "-" to read stdin, or --file <path>.');
70
+ const res = await sdkLlm.embed(config.api_key, orgId, { model, input: text });
71
+ if (flags.json) {
72
+ printJson(res);
73
+ return;
74
+ }
75
+ const first = res.embeddings[0] ?? [];
76
+ info(`${res.model} · dim=${first.length} · ${res.usage.input_tokens} tokens · $${res.usage.cost_usd.toFixed(6)}`);
77
+ info(`first 5: [${first.slice(0, 5).map(n => n.toFixed(6)).join(', ')}${first.length > 5 ? ', ...' : ''}]`);
78
+ info(`(pass --json for the full vector)`);
79
+ }
80
+ async function listModels(flags) {
81
+ const config = requireConfig();
82
+ const orgId = requireOrg(flags, config, 'myapi llm models [--kind chat|embed] [--org <id>]');
83
+ const res = await sdkLlm.listModels(config.api_key, orgId);
84
+ const kind = typeof flags.kind === 'string' ? flags.kind : '';
85
+ const models = kind ? res.models.filter(m => m.kind === kind) : res.models;
86
+ if (flags.json) {
87
+ printJson({ models });
88
+ return;
89
+ }
90
+ printTable(models.map(m => ({
91
+ id: m.id,
92
+ kind: m.kind,
93
+ context: m.context ?? '',
94
+ dimensions: m.dimensions ?? '',
95
+ in_per_1m: `$${m.input_per_1m}`,
96
+ out_per_1m: m.output_per_1m != null ? `$${m.output_per_1m}` : '',
97
+ })), { flags, empty: 'No models available.' });
98
+ }
99
+ const SUBCOMMAND_USAGE = {
100
+ complete: `myapi llm complete "<prompt>" [--model <id>]
101
+ [--system "<system msg>"] [--max-tokens N] [--temperature 0..1]
102
+ [--stop <csv>] [--file <path>] [--org <id>] [--json]
103
+
104
+ Default model: gemini-3.1-flash-lite-preview (cheap + fast). Pass --model
105
+ to override; run "myapi llm models" to see the catalog.
106
+
107
+ Pass "-" as the prompt to read from stdin. The reply goes to stdout;
108
+ a one-line usage footer (tokens + cost) goes to stderr so it doesn't
109
+ pollute piped output.
110
+
111
+ Examples:
112
+ myapi llm complete "summarize: $(cat README.md)"
113
+ cat draft.md | myapi llm complete - --model gemini-3.1-pro-preview --system "You are an editor"
114
+ myapi llm complete --file prompt.txt --max-tokens 200`,
115
+ embed: `myapi llm embed "<text>" --model <id> [--file <path>] [--org <id>] [--json]
116
+
117
+ Returns a vector summary by default; pass --json for the full vector.
118
+
119
+ Examples:
120
+ myapi llm embed "the quick brown fox" --model gemini-embedding-001
121
+ myapi llm embed --file doc.txt --model gemini-embedding-001 --json > doc.vec.json`,
122
+ models: `myapi llm models [--kind chat|embed] [--org <id>] [--json]
123
+
124
+ Lists the model catalog with per-1M-token pricing at upstream rates.
125
+ Models prefixed with vendor name pass through to that vendor; un-prefixed
126
+ models (when available) run on MyAPI's own inference.`,
127
+ };
128
+ export async function run(subcommand, args, flags) {
129
+ if (!subcommand || (flags.help && !subcommand)) {
130
+ info(`Usage: myapi llm <subcommand>
131
+
132
+ Subcommands:
133
+ complete Chat completion — returns reply + usage (default model: gemini-3.1-flash-lite-preview)
134
+ embed Text embedding — returns vector + usage
135
+ models List available models (chat + embed) with pricing
136
+
137
+ All commands accept --org <id> (or set default: myapi config set-org <id>).
138
+ Use this for workflow steps and scripted pipelines — not as a replacement
139
+ for your own reasoning. The agent has its own model already.`);
140
+ return;
141
+ }
142
+ if (flags.help) {
143
+ const usage = SUBCOMMAND_USAGE[subcommand];
144
+ if (usage)
145
+ info(`Usage: ${usage}`);
146
+ else
147
+ info(`Unknown subcommand: ${subcommand}. Run "myapi llm --help" for the list.`);
148
+ return;
149
+ }
150
+ switch (subcommand) {
151
+ case 'complete': return complete(args[0], flags);
152
+ case 'embed': return embed(args[0], flags);
153
+ case 'models': return listModels(flags);
154
+ default: error(`Unknown subcommand: ${subcommand}. Run "myapi llm --help" for valid subcommands.`);
155
+ }
156
+ }
@@ -1,9 +1,12 @@
1
1
  import type { FlagSchema } from '../flags.js';
2
2
  import { type Flags } from '../helpers.js';
3
+ import type { Exposes } from '../exposes.js';
4
+ export declare const EXPOSES: Exposes;
3
5
  export declare const SCHEMA: FlagSchema;
4
6
  export declare function create(restArgs: string[], flags: Flags): Promise<void>;
5
7
  export declare function list(flags: Flags): Promise<void>;
6
8
  export declare function get(id: string, flags: Flags): Promise<void>;
7
9
  export declare function del(id: string, _flags: Flags): Promise<void>;
10
+ export declare function update(restArgs: string[], flags: Flags): Promise<void>;
8
11
  export declare function importOrg(args: string[], flags: Flags): Promise<void>;
9
12
  export declare function run(subcommand: string | undefined, args: string[], flags: Flags): Promise<void>;