@mailmodo/cli 0.0.54-beta.pr56.91 → 0.0.54

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.
@@ -6,7 +6,6 @@ import { BaseCommand } from '../../lib/base-command.js';
6
6
  import { API_ENDPOINTS, PREVIEW_PORT } from '../../lib/constants.js';
7
7
  import { INFO } from '../../lib/messages.js';
8
8
  import { loadTemplate, getEmailStyle, getTemplateFilename, } from '../../lib/yaml-config.js';
9
- import { handleMissingTemplates } from '../../lib/templates/missing-templates.js';
10
9
  /* eslint-disable camelcase */
11
10
  const SAMPLE_DATA = Object.freeze({
12
11
  app_url: 'https://yourapp.com',
@@ -87,28 +86,12 @@ export default class Preview extends BaseCommand {
87
86
  product_name: yamlConfig.project?.name || 'YourApp', // eslint-disable-line camelcase
88
87
  };
89
88
  const effectiveStyle = getEmailStyle(email.style, yamlConfig.project?.emailStyle);
90
- const templateFilename = getTemplateFilename(email.id, email.style, yamlConfig.project?.emailStyle);
91
- let templateHtml = await loadTemplate(templateFilename);
92
- if (!templateHtml) {
93
- await this.ensureAuth();
94
- const regenCtx = {
95
- error: (msg) => this.error(msg),
96
- exit: (code) => this.exit(code),
97
- log: (msg) => this.log(msg),
98
- onApiError: (r) => this.handleApiError(r),
99
- post: (path, body) => this.apiClient.post(path, body),
100
- spinner: (text, json, work) => this.withApiSpinner({ json, text }, work),
101
- syncYaml: () => this.syncYamlToServer(),
102
- };
103
- const regenerated = await handleMissingTemplates(regenCtx, yamlConfig, [email.id], { json: flags.json, yes: flags.yes });
104
- if (!regenerated)
105
- return;
106
- templateHtml = await loadTemplate(templateFilename);
107
- if (!templateHtml)
108
- this.error('Template regeneration failed.');
109
- }
89
+ const templateHtml = await loadTemplate(getTemplateFilename(email.id, email.style, yamlConfig.project?.emailStyle));
110
90
  if (flags.send) {
111
- await this.sendTestEmail(email, renderTemplate(templateHtml, sampleData), {
91
+ const rendered = templateHtml
92
+ ? renderTemplate(templateHtml, sampleData)
93
+ : '';
94
+ await this.sendTestEmail(email, rendered, {
112
95
  domain: yamlConfig.project?.domain,
113
96
  jsonOutput: flags.json,
114
97
  toAddress: flags.send,
@@ -129,7 +112,10 @@ export default class Preview extends BaseCommand {
129
112
  * and CI pipelines that cannot open a browser.
130
113
  */
131
114
  async renderText(email, templateHtml, sampleData, jsonOutput) {
132
- const plainText = htmlToText(renderTemplate(templateHtml, sampleData));
115
+ const rendered = templateHtml
116
+ ? renderTemplate(templateHtml, sampleData)
117
+ : '';
118
+ const plainText = htmlToText(rendered);
133
119
  if (jsonOutput) {
134
120
  this.log(JSON.stringify({
135
121
  body: plainText,
@@ -195,7 +181,9 @@ export default class Preview extends BaseCommand {
195
181
  */
196
182
  async startPreviewServer(email, templateHtml, sampleData, opts) {
197
183
  const { effectiveStyle, jsonOutput } = opts;
198
- const rendered = renderTemplate(templateHtml, sampleData);
184
+ const rendered = templateHtml
185
+ ? renderTemplate(templateHtml, sampleData)
186
+ : '<p>No template found.</p>';
199
187
  const wrapperHtml = `<!DOCTYPE html>
200
188
  <html>
201
189
  <head>
@@ -50,7 +50,6 @@ export default class Settings extends BaseCommand {
50
50
  if (capFromApi !== null) {
51
51
  yamlConfig.project.monthlyCap = capFromApi;
52
52
  await saveYaml(yamlConfig);
53
- await this.syncYamlToServer();
54
53
  }
55
54
  if (flags.json) {
56
55
  this.log(JSON.stringify({ settings: yamlConfig.project }, null, 2));
@@ -84,7 +83,6 @@ export default class Settings extends BaseCommand {
84
83
  }
85
84
  project[propKey] = value;
86
85
  await saveYaml(yamlConfig);
87
- await this.syncYamlToServer();
88
86
  if (isJson) {
89
87
  this.log(JSON.stringify({ [propKey]: value, status: 'updated' }, null, 2));
90
88
  return;
@@ -106,7 +104,6 @@ export default class Settings extends BaseCommand {
106
104
  const data = await this.applyBillingCap({ cap: parsed, json: isJson });
107
105
  yamlConfig.project.monthlyCap = data.capBlocks;
108
106
  await saveYaml(yamlConfig);
109
- await this.syncYamlToServer();
110
107
  if (isJson) {
111
108
  this.log(JSON.stringify({ monthlyCap: data.capBlocks, status: 'updated' }, null, 2));
112
109
  return;
@@ -210,7 +207,6 @@ export default class Settings extends BaseCommand {
210
207
  });
211
208
  project.emailStyle = style;
212
209
  await saveYaml(yamlConfig);
213
- await this.syncYamlToServer();
214
210
  this.log(`\n ${chalk.green('✓')} email_style updated to ${chalk.cyan(style)}`);
215
211
  this.log(` ${INFO.DEPLOY_TO_APPLY}\n`);
216
212
  return;
@@ -220,7 +216,6 @@ export default class Settings extends BaseCommand {
220
216
  });
221
217
  project[editPropKey] = newValue;
222
218
  await saveYaml(yamlConfig);
223
- await this.syncYamlToServer();
224
219
  this.log(`\n ${chalk.green('✓')} Updated. ${INFO.DEPLOY_TO_APPLY}\n`);
225
220
  }
226
221
  /**
@@ -286,7 +281,6 @@ export default class Settings extends BaseCommand {
286
281
  yamlConfig.project.logoUrl = response.data?.url || '';
287
282
  yamlConfig.project.logoFile = logoPath;
288
283
  await saveYaml(yamlConfig);
289
- await this.syncYamlToServer();
290
284
  this.log(`\n Logo uploaded and hosted at:`);
291
285
  this.log(` ${chalk.cyan(String(response.data?.url))}`);
292
286
  this.log(` Run ${chalk.cyan("'mailmodo deploy'")} to apply to all branded emails.\n`);
@@ -46,11 +46,6 @@ export declare class ApiClient {
46
46
  * Bearer auth as other requests; does not parse JSON.
47
47
  */
48
48
  getFile(url: string): Promise<FileFetchResult>;
49
- /**
50
- * GET an endpoint and return the raw response body as a string (e.g. YAML files).
51
- * Uses Bearer auth; does not parse JSON.
52
- */
53
- getRawText(path: string): Promise<ApiResponse<string>>;
54
49
  /**
55
50
  * GET an external URL (e.g. blob storage) without auth headers.
56
51
  */
@@ -135,51 +135,6 @@ export class ApiClient {
135
135
  async getFile(url) {
136
136
  return fetchFileWithBearerAuth(url, this.apiKey);
137
137
  }
138
- /**
139
- * GET an endpoint and return the raw response body as a string (e.g. YAML files).
140
- * Uses Bearer auth; does not parse JSON.
141
- */
142
- async getRawText(path) {
143
- const url = this.resolveUrl(path);
144
- const debug = this.requestDebug(url);
145
- try {
146
- const response = await fetch(url.toString(), {
147
- headers: {
148
- Authorization: `Bearer ${this.apiKey}`,
149
- 'User-Agent': '@mailmodo/cli',
150
- },
151
- method: 'GET',
152
- });
153
- const text = await response.text().catch(() => '');
154
- if (!response.ok) {
155
- return {
156
- data: '',
157
- debug: {
158
- ...debug,
159
- ...(text ? { responseSummary: text.slice(0, 200) } : {}),
160
- },
161
- error: text || `Request failed with status ${response.status}`,
162
- ok: false,
163
- status: response.status,
164
- };
165
- }
166
- return { data: text, ok: true, status: response.status };
167
- }
168
- catch (error) {
169
- const err = error;
170
- const isConnectionError = err?.cause?.code === 'ECONNREFUSED' || err?.cause?.code === 'ENOTFOUND';
171
- const causeCode = err?.cause?.code;
172
- return {
173
- data: '',
174
- debug: { ...debug, ...(causeCode ? { causeCode } : {}) },
175
- error: isConnectionError
176
- ? 'Cannot connect to Mailmodo API. The API service may not be available yet.'
177
- : err?.message || 'An unexpected network error occurred.',
178
- ok: false,
179
- status: 0,
180
- };
181
- }
182
- }
183
138
  /**
184
139
  * GET an external URL (e.g. blob storage) without auth headers.
185
140
  */
@@ -60,36 +60,12 @@ export declare abstract class BaseCommand extends Command {
60
60
  }, work: () => Promise<T>): Promise<T>;
61
61
  /**
62
62
  * Loads and returns the mailmodo.yaml configuration from the current directory.
63
- * If the file is not found locally and the API client is available, attempts to
64
- * restore it from the server. Exits with an error if the file cannot be found
65
- * or restored, directing the user to run init.
63
+ * Exits with an error if the file is not found, directing the user to run init.
66
64
  *
67
65
  * @returns {Promise<MailmodoYaml>} The parsed mailmodo.yaml containing project
68
66
  * settings and all email sequence definitions.
69
67
  */
70
68
  protected ensureYaml(): Promise<MailmodoYaml>;
71
- private fetchAndWriteYaml;
72
- /**
73
- * Attempts to fetch mailmodo.yaml from the server and save it locally.
74
- * Returns null silently on any failure so callers can fall through to an error.
75
- */
76
- private restoreYamlFromServer;
77
- /**
78
- * If `mailmodo.yaml` is absent from the current directory, attempts to restore
79
- * it from the server using the given client. Returns `true` if the file was
80
- * successfully written, `false` otherwise (file already present, server 404,
81
- * or any network error). Silent — never throws.
82
- *
83
- * Used by `mailmodo login` right after the API key is validated so a returning
84
- * user automatically gets their config back without having to run `init` again.
85
- */
86
- protected recoverYamlAfterLogin(client: ApiClient): Promise<boolean>;
87
- /**
88
- * Uploads the current local mailmodo.yaml to the server as a backup.
89
- * Best-effort: silently ignores all errors so the originating command
90
- * always succeeds regardless of sync failures.
91
- */
92
- protected syncYamlToServer(): Promise<void>;
93
69
  /**
94
70
  * Handles a failed API response by mapping HTTP status codes to
95
71
  * user-friendly error messages and exiting the process.
@@ -1,13 +1,10 @@
1
- import { existsSync } from 'node:fs';
2
- import { readFile, writeFile } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
1
  import { input } from '@inquirer/prompts';
5
2
  import { Command, Flags } from '@oclif/core';
6
3
  import chalk from 'chalk';
7
4
  import ora from 'ora';
8
5
  import { ApiClient } from './api-client.js';
9
6
  import { loadConfig } from './config.js';
10
- import { API_ENDPOINTS, IS_DEV_MODE, YAML_FILE } from './constants.js';
7
+ import { API_ENDPOINTS, IS_DEV_MODE } from './constants.js';
11
8
  import { ERRORS, INFO, PROMPTS, quotaExhaustedMessage, recordLabel, VALIDATION, } from './messages.js';
12
9
  import { loadYaml, saveYaml } from './yaml-config.js';
13
10
  export const FREE_TIER = 'free';
@@ -79,99 +76,17 @@ export class BaseCommand extends Command {
79
76
  }
80
77
  /**
81
78
  * Loads and returns the mailmodo.yaml configuration from the current directory.
82
- * If the file is not found locally and the API client is available, attempts to
83
- * restore it from the server. Exits with an error if the file cannot be found
84
- * or restored, directing the user to run init.
79
+ * Exits with an error if the file is not found, directing the user to run init.
85
80
  *
86
81
  * @returns {Promise<MailmodoYaml>} The parsed mailmodo.yaml containing project
87
82
  * settings and all email sequence definitions.
88
83
  */
89
84
  async ensureYaml() {
90
85
  const config = await loadYaml();
91
- if (config)
92
- return config;
93
- const restored = await this.restoreYamlFromServer();
94
- if (restored)
95
- return restored;
96
- this.error(ERRORS.NO_YAML);
97
- }
98
- async fetchAndWriteYaml(client) {
99
- try {
100
- const response = await client.getRawText(API_ENDPOINTS.ASSETS_YAML);
101
- if (!response.ok || !response.data)
102
- return false;
103
- await writeFile(join(process.cwd(), YAML_FILE), response.data);
104
- return true;
105
- }
106
- catch {
107
- return false;
108
- }
109
- }
110
- /**
111
- * Attempts to fetch mailmodo.yaml from the server and save it locally.
112
- * Returns null silently on any failure so callers can fall through to an error.
113
- */
114
- async restoreYamlFromServer() {
115
- try {
116
- let client = this.apiClient;
117
- if (!client) {
118
- const envKey = process.env.MAILMODO_API_KEY;
119
- const apiKey = envKey ?? (await loadConfig())?.apiKey;
120
- if (!apiKey)
121
- return null;
122
- client = new ApiClient(apiKey);
123
- }
124
- const written = await this.fetchAndWriteYaml(client);
125
- if (!written)
126
- return null;
127
- this.logToStderr(INFO.YAML_RESTORED_FROM_SERVER);
128
- return loadYaml();
129
- }
130
- catch {
131
- return null;
132
- }
133
- }
134
- /**
135
- * If `mailmodo.yaml` is absent from the current directory, attempts to restore
136
- * it from the server using the given client. Returns `true` if the file was
137
- * successfully written, `false` otherwise (file already present, server 404,
138
- * or any network error). Silent — never throws.
139
- *
140
- * Used by `mailmodo login` right after the API key is validated so a returning
141
- * user automatically gets their config back without having to run `init` again.
142
- */
143
- async recoverYamlAfterLogin(client) {
144
- if (existsSync(join(process.cwd(), YAML_FILE)))
145
- return false;
146
- return this.fetchAndWriteYaml(client);
147
- }
148
- /**
149
- * Uploads the current local mailmodo.yaml to the server as a backup.
150
- * Best-effort: silently ignores all errors so the originating command
151
- * always succeeds regardless of sync failures.
152
- */
153
- async syncYamlToServer() {
154
- try {
155
- let client = this.apiClient;
156
- if (!client) {
157
- const envKey = process.env.MAILMODO_API_KEY;
158
- const apiKey = envKey ?? (await loadConfig())?.apiKey;
159
- if (!apiKey)
160
- return;
161
- client = new ApiClient(apiKey);
162
- }
163
- const filePath = join(process.cwd(), YAML_FILE);
164
- if (!existsSync(filePath))
165
- return;
166
- const content = await readFile(filePath, 'utf8');
167
- const blob = new Blob([content], { type: 'application/yaml' });
168
- const formData = new FormData();
169
- formData.append('yaml', blob, YAML_FILE);
170
- await client.postFormData(API_ENDPOINTS.ASSETS_YAML, formData);
171
- }
172
- catch {
173
- // Silently ignore — local file remains authoritative
86
+ if (!config) {
87
+ this.error(ERRORS.NO_YAML);
174
88
  }
89
+ return config;
175
90
  }
176
91
  /**
177
92
  * Handles a failed API response by mapping HTTP status codes to
@@ -361,7 +276,6 @@ export class BaseCommand extends Command {
361
276
  if (inputs.replyTo)
362
277
  yamlConfig.project.replyTo = inputs.replyTo;
363
278
  await saveYaml(yamlConfig);
364
- await this.syncYamlToServer();
365
279
  return {
366
280
  dnsGuideUrl: response.data?.dnsGuideUrl,
367
281
  dnsRecords: response.data?.dnsRecords || [],
@@ -9,7 +9,6 @@ export declare const API_ENDPOINTS: Readonly<{
9
9
  ANALYTICS: "/analytics";
10
10
  ANALYZE: "/analyze";
11
11
  ASSETS_LOGO: "/assets/logo";
12
- ASSETS_YAML: "/assets/yaml";
13
12
  AUTH_VALIDATE: "/auth/validate";
14
13
  BILLING_CAP: "/billing/cap";
15
14
  BILLING_CHECKOUT: "/billing/checkout";
@@ -15,7 +15,6 @@ export const API_ENDPOINTS = Object.freeze({
15
15
  ANALYTICS: '/analytics',
16
16
  ANALYZE: '/analyze',
17
17
  ASSETS_LOGO: '/assets/logo',
18
- ASSETS_YAML: '/assets/yaml',
19
18
  AUTH_VALIDATE: '/auth/validate',
20
19
  BILLING_CAP: '/billing/cap',
21
20
  BILLING_CHECKOUT: '/billing/checkout',
@@ -13,17 +13,6 @@ export declare const PROMPTS: {
13
13
  readonly REPLY_TO: "Reply-to address (optional, press Enter to use sender email):";
14
14
  readonly SENDER_EMAIL: "Sender email address:";
15
15
  };
16
- export declare const MISSING_TEMPLATES: {
17
- readonly ABORT_HINT: `Restore the missing files from version control, then run ${string} again.`;
18
- readonly CHOICE_ABORT: "Abort (restore from version control)";
19
- readonly CHOICE_REGENERATE: "Re-generate via AI";
20
- readonly HEADER: `Some email templates are missing from ${string}:`;
21
- readonly PROMPT_ACTION: "What would you like to do?";
22
- readonly REGENERATE_NOTE: string;
23
- readonly REGENERATE_SPINNER: "Regenerating email templates...";
24
- readonly REVIEW_HINT: `Templates regenerated. Review them with ${string}, then run ${string} again.`;
25
- readonly YES_ERROR: `Missing templates cannot be resolved with ${string}. Run ${string} without ${string} to regenerate via AI or restore from version control.`;
26
- };
27
16
  export declare const ERRORS: {
28
17
  readonly DOMAIN_NOT_CONFIGURED: `No domain configured. Run ${string} to set up your sending domain.`;
29
18
  readonly DOMAIN_NOT_REGISTERED: `Sending domain not registered. Run: ${string}`;
@@ -51,17 +40,6 @@ export declare const INFO: {
51
40
  readonly FREE_TIER_CAP_BLOCKED: `Monthly cap is a paid-tier setting and is not available on the free tier. Run ${string} to add a payment method, then set a cap.`;
52
41
  readonly PAUSE_CANCELLED: "Pause cancelled. Sequence is still live.";
53
42
  readonly SEQUENCES_NOT_DEPLOYED: `Sequences saved but ${string}.`;
54
- readonly YAML_RESTORED_FROM_SERVER: string;
55
- readonly YAML_RESTORED_ON_LOGIN: ` mailmodo.yaml restored from server. Run ${string} to re-deploy your sequences.`;
56
- };
57
- export declare const DEPLOY: {
58
- readonly CHANGES_HEADER: "Changes vs. last deployment:";
59
- readonly DEPLOYING_HEADER: "Deploying:";
60
- readonly NO_CHANGES: "No changes from last deployment.";
61
- readonly SDK_DOCS_HINT: `Full SDK docs: ${string}`;
62
- readonly SDK_EXAMPLE_COMMENT: string;
63
- readonly SDK_ONBOARDING_HEADER: string;
64
- readonly SUCCESS: `${string} Emails are live.`;
65
43
  };
66
44
  export declare function pauseSuccess(sequenceId: string): string;
67
45
  export declare function pauseAlready(sequenceId: string): string;
@@ -14,17 +14,6 @@ export const PROMPTS = {
14
14
  REPLY_TO: 'Reply-to address (optional, press Enter to use sender email):',
15
15
  SENDER_EMAIL: 'Sender email address:',
16
16
  };
17
- export const MISSING_TEMPLATES = {
18
- ABORT_HINT: `Restore the missing files from version control, then run ${chalk.cyan('mailmodo deploy')} again.`,
19
- CHOICE_ABORT: 'Abort (restore from version control)',
20
- CHOICE_REGENERATE: 'Re-generate via AI',
21
- HEADER: `Some email templates are missing from ${chalk.cyan('./mailmodo/')}:`,
22
- PROMPT_ACTION: 'What would you like to do?',
23
- REGENERATE_NOTE: chalk.yellow(' Note: any previous manual edits to these files will be replaced with a new AI draft.'),
24
- REGENERATE_SPINNER: 'Regenerating email templates...',
25
- REVIEW_HINT: `Templates regenerated. Review them with ${chalk.cyan('mailmodo preview')}, then run ${chalk.cyan('mailmodo deploy')} again.`,
26
- YES_ERROR: `Missing templates cannot be resolved with ${chalk.cyan('--yes')}. Run ${chalk.cyan('mailmodo deploy')} without ${chalk.cyan('--yes')} to regenerate via AI or restore from version control.`,
27
- };
28
17
  export const ERRORS = {
29
18
  DOMAIN_NOT_CONFIGURED: `No domain configured. Run ${chalk.cyan('mailmodo domain')} to set up your sending domain.`,
30
19
  DOMAIN_NOT_REGISTERED: `Sending domain not registered. Run: ${chalk.cyan('mailmodo domain')}`,
@@ -51,17 +40,6 @@ export const INFO = {
51
40
  FREE_TIER_CAP_BLOCKED: `Monthly cap is a paid-tier setting and is not available on the free tier. Run ${chalk.cyan("'mailmodo billing --checkout'")} to add a payment method, then set a cap.`,
52
41
  PAUSE_CANCELLED: 'Pause cancelled. Sequence is still live.',
53
42
  SEQUENCES_NOT_DEPLOYED: `Sequences saved but ${chalk.yellow('NOT deployed')}.`,
54
- YAML_RESTORED_FROM_SERVER: chalk.dim(' mailmodo.yaml not found locally — restored from server.'),
55
- YAML_RESTORED_ON_LOGIN: ` mailmodo.yaml restored from server. Run ${chalk.cyan("'mailmodo deploy'")} to re-deploy your sequences.`,
56
- };
57
- export const DEPLOY = {
58
- CHANGES_HEADER: 'Changes vs. last deployment:',
59
- DEPLOYING_HEADER: 'Deploying:',
60
- NO_CHANGES: 'No changes from last deployment.',
61
- SDK_DOCS_HINT: `Full SDK docs: ${chalk.cyan('mailmodo.com/docs/sdk')}`,
62
- SDK_EXAMPLE_COMMENT: chalk.dim('// Example usage:'),
63
- SDK_ONBOARDING_HEADER: chalk.bold('ADD THIS TO YOUR APP (one-time only):'),
64
- SUCCESS: `${chalk.green('Deployed.')} Emails are live.`,
65
43
  };
66
44
  export function pauseSuccess(sequenceId) {
67
45
  return `Sequence ${chalk.cyan(sequenceId)} paused. Run ${chalk.cyan(`mailmodo deploy --resume ${sequenceId}`)} to resume.`;
@@ -198,45 +198,6 @@
198
198
  "index.js"
199
199
  ]
200
200
  },
201
- "deployments": {
202
- "aliases": [],
203
- "args": {},
204
- "description": "List every deployed sequence on this account, with the IDs needed for deploy --pause / --resume",
205
- "examples": [
206
- "<%= config.bin %> deployments",
207
- "<%= config.bin %> deployments --json"
208
- ],
209
- "flags": {
210
- "json": {
211
- "description": "Output as JSON",
212
- "name": "json",
213
- "allowNo": false,
214
- "type": "boolean"
215
- },
216
- "yes": {
217
- "char": "y",
218
- "description": "Skip confirmation prompts",
219
- "name": "yes",
220
- "allowNo": false,
221
- "type": "boolean"
222
- }
223
- },
224
- "hasDynamicHelp": false,
225
- "hiddenAliases": [],
226
- "id": "deployments",
227
- "pluginAlias": "@mailmodo/cli",
228
- "pluginName": "@mailmodo/cli",
229
- "pluginType": "core",
230
- "strict": true,
231
- "enableJsonFlag": false,
232
- "isESM": true,
233
- "relativePath": [
234
- "dist",
235
- "commands",
236
- "deployments",
237
- "index.js"
238
- ]
239
- },
240
201
  "domain": {
241
202
  "aliases": [],
242
203
  "args": {},
@@ -503,6 +464,45 @@
503
464
  "index.js"
504
465
  ]
505
466
  },
467
+ "deployments": {
468
+ "aliases": [],
469
+ "args": {},
470
+ "description": "List every deployed sequence on this account, with the IDs needed for deploy --pause / --resume",
471
+ "examples": [
472
+ "<%= config.bin %> deployments",
473
+ "<%= config.bin %> deployments --json"
474
+ ],
475
+ "flags": {
476
+ "json": {
477
+ "description": "Output as JSON",
478
+ "name": "json",
479
+ "allowNo": false,
480
+ "type": "boolean"
481
+ },
482
+ "yes": {
483
+ "char": "y",
484
+ "description": "Skip confirmation prompts",
485
+ "name": "yes",
486
+ "allowNo": false,
487
+ "type": "boolean"
488
+ }
489
+ },
490
+ "hasDynamicHelp": false,
491
+ "hiddenAliases": [],
492
+ "id": "deployments",
493
+ "pluginAlias": "@mailmodo/cli",
494
+ "pluginName": "@mailmodo/cli",
495
+ "pluginType": "core",
496
+ "strict": true,
497
+ "enableJsonFlag": false,
498
+ "isESM": true,
499
+ "relativePath": [
500
+ "dist",
501
+ "commands",
502
+ "deployments",
503
+ "index.js"
504
+ ]
505
+ },
506
506
  "logs": {
507
507
  "aliases": [],
508
508
  "args": {},
@@ -631,13 +631,14 @@
631
631
  "index.js"
632
632
  ]
633
633
  },
634
- "status": {
634
+ "sdk": {
635
635
  "aliases": [],
636
636
  "args": {},
637
- "description": "View email performance metrics and quota usage",
637
+ "description": "Show the SDK track() / identify() reference for deployed sequences",
638
638
  "examples": [
639
- "<%= config.bin %> status",
640
- "<%= config.bin %> status --json"
639
+ "<%= config.bin %> sdk",
640
+ "<%= config.bin %> sdk --sequence-id a1b2c3d4",
641
+ "<%= config.bin %> sdk --json"
641
642
  ],
642
643
  "flags": {
643
644
  "json": {
@@ -652,11 +653,18 @@
652
653
  "name": "yes",
653
654
  "allowNo": false,
654
655
  "type": "boolean"
656
+ },
657
+ "sequence-id": {
658
+ "description": "Limit output to a single active sequence by ID (default: all active sequences)",
659
+ "name": "sequence-id",
660
+ "hasDynamicHelp": false,
661
+ "multiple": false,
662
+ "type": "option"
655
663
  }
656
664
  },
657
665
  "hasDynamicHelp": false,
658
666
  "hiddenAliases": [],
659
- "id": "status",
667
+ "id": "sdk",
660
668
  "pluginAlias": "@mailmodo/cli",
661
669
  "pluginName": "@mailmodo/cli",
662
670
  "pluginType": "core",
@@ -666,7 +674,7 @@
666
674
  "relativePath": [
667
675
  "dist",
668
676
  "commands",
669
- "status",
677
+ "sdk",
670
678
  "index.js"
671
679
  ]
672
680
  },
@@ -717,14 +725,13 @@
717
725
  "index.js"
718
726
  ]
719
727
  },
720
- "sdk": {
728
+ "status": {
721
729
  "aliases": [],
722
730
  "args": {},
723
- "description": "Show the SDK track() / identify() reference for deployed sequences",
731
+ "description": "View email performance metrics and quota usage",
724
732
  "examples": [
725
- "<%= config.bin %> sdk",
726
- "<%= config.bin %> sdk --sequence-id a1b2c3d4",
727
- "<%= config.bin %> sdk --json"
733
+ "<%= config.bin %> status",
734
+ "<%= config.bin %> status --json"
728
735
  ],
729
736
  "flags": {
730
737
  "json": {
@@ -739,18 +746,11 @@
739
746
  "name": "yes",
740
747
  "allowNo": false,
741
748
  "type": "boolean"
742
- },
743
- "sequence-id": {
744
- "description": "Limit output to a single active sequence by ID (default: all active sequences)",
745
- "name": "sequence-id",
746
- "hasDynamicHelp": false,
747
- "multiple": false,
748
- "type": "option"
749
749
  }
750
750
  },
751
751
  "hasDynamicHelp": false,
752
752
  "hiddenAliases": [],
753
- "id": "sdk",
753
+ "id": "status",
754
754
  "pluginAlias": "@mailmodo/cli",
755
755
  "pluginName": "@mailmodo/cli",
756
756
  "pluginType": "core",
@@ -760,10 +760,10 @@
760
760
  "relativePath": [
761
761
  "dist",
762
762
  "commands",
763
- "sdk",
763
+ "status",
764
764
  "index.js"
765
765
  ]
766
766
  }
767
767
  },
768
- "version": "0.0.54-beta.pr56.91"
768
+ "version": "0.0.54"
769
769
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mailmodo/cli",
3
3
  "description": "Email lifecycle automation for the AI-native builder generation.",
4
- "version": "0.0.54-beta.pr56.91",
4
+ "version": "0.0.54",
5
5
  "author": "provishalk",
6
6
  "bin": {
7
7
  "mailmodo": "bin/run.js"
@@ -1,8 +0,0 @@
1
- import type { MailmodoYaml } from '../yaml-config.js';
2
- import type { DeployCtx, DeployFlags, ValidateResponse } from './types.js';
3
- export declare function validateDeploySequence(ctx: DeployCtx, payload: object, flags: {
4
- json: boolean;
5
- }): Promise<ValidateResponse>;
6
- export declare function verifyDomain(ctx: DeployCtx, jsonOutput: boolean, domain: string): Promise<boolean>;
7
- export declare function runDomainSetup(ctx: DeployCtx, yamlConfig: MailmodoYaml, flags: DeployFlags): Promise<boolean>;
8
- export declare function ensureDomainReady(ctx: DeployCtx, yamlConfig: MailmodoYaml, flags: DeployFlags): Promise<boolean>;