@mailmodo/cli 0.0.19-beta.pr21.31 → 0.0.19

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.
@@ -10,15 +10,9 @@ export default class Deploy extends BaseCommand {
10
10
  * Fetches current DNS verification status for the deploy flow.
11
11
  *
12
12
  * @param jsonOutput - When true, spinner uses stderr for stdout-safe JSON runs.
13
- * @param domain - Sending domain to check. If empty, request will fail and trigger setup flow.
14
13
  */
15
14
  private fetchDomainVerifyForDeploy;
16
15
  run(): Promise<void>;
17
- private buildDeployPayload;
18
- private mapEmailToPayload;
19
- private buildProjectPayload;
20
- private confirmDeploy;
21
- private ensureDomainReady;
22
16
  /**
23
17
  * Lists emails about to be deployed (skipped when `--json` is set).
24
18
  *
@@ -38,11 +32,9 @@ export default class Deploy extends BaseCommand {
38
32
  * @returns {Promise<boolean>} true if domain was verified, false if skipped.
39
33
  */
40
34
  private runDomainSetup;
41
- private collectDomainInputs;
42
- private showDnsRecords;
43
35
  /**
44
36
  * Calls the domain verification API endpoint and reports pass/fail
45
- * status for each DNS record (DKIM, DMARC, Return-Path).
37
+ * status for each DNS record (SPF, DKIM, DMARC).
46
38
  *
47
39
  * @returns {Promise<boolean>} true if all records pass.
48
40
  */
@@ -1,8 +1,8 @@
1
1
  import { confirm, input } from '@inquirer/prompts';
2
2
  import chalk from 'chalk';
3
3
  import { BaseCommand } from '../../lib/base-command.js';
4
- import { API_ENDPOINTS, DEFAULT_BRAND_COLOR, DEFAULT_MONTHLY_CAP, DNS_GUIDE_URL, } from '../../lib/constants.js';
5
- import { loadTemplate, saveYaml, } from '../../lib/yaml-config.js';
4
+ import { API_ENDPOINTS, DNS_GUIDE_URL } from '../../lib/constants.js';
5
+ import { saveYaml } from '../../lib/yaml-config.js';
6
6
  export default class Deploy extends BaseCommand {
7
7
  static description = 'Deploy email sequences and verify sending domain';
8
8
  static examples = [
@@ -16,130 +16,69 @@ export default class Deploy extends BaseCommand {
16
16
  * Fetches current DNS verification status for the deploy flow.
17
17
  *
18
18
  * @param jsonOutput - When true, spinner uses stderr for stdout-safe JSON runs.
19
- * @param domain - Sending domain to check. If empty, request will fail and trigger setup flow.
20
19
  */
21
- fetchDomainVerifyForDeploy(jsonOutput, domain) {
22
- return this.withApiSpinner({ json: jsonOutput, text: ' Checking domain verification...' }, () => this.apiClient.get(API_ENDPOINTS.DOMAIN_VERIFY, {
23
- domain: domain || '',
24
- }));
20
+ fetchDomainVerifyForDeploy(jsonOutput) {
21
+ return this.withApiSpinner({ json: jsonOutput, text: ' Checking domain verification...' }, () => this.apiClient.get(API_ENDPOINTS.DOMAIN_VERIFY));
25
22
  }
26
23
  async run() {
27
24
  const { flags } = await this.parse(Deploy);
28
25
  await this.ensureAuth();
29
26
  const yamlConfig = await this.ensureYaml();
30
- const domainReady = await this.ensureDomainReady(yamlConfig, flags);
31
- if (!domainReady)
32
- return;
27
+ const domainVerify = await this.fetchDomainVerifyForDeploy(flags.json);
28
+ const domainVerified = domainVerify.ok &&
29
+ domainVerify.data?.spf === 'pass' &&
30
+ domainVerify.data?.dkim === 'pass' &&
31
+ domainVerify.data?.dmarc === 'pass';
32
+ if (!domainVerified) {
33
+ if (!flags.json) {
34
+ this.log(`\n No sending domain verified yet.`);
35
+ this.log(` You need to verify a domain before sending emails.`);
36
+ this.log(` This is a one-time setup. Takes about 5 minutes.\n`);
37
+ }
38
+ if (!flags.yes) {
39
+ const setupNow = await confirm({
40
+ default: true,
41
+ message: 'Set up your sending domain now?',
42
+ });
43
+ if (!setupNow) {
44
+ this.log(`\n Sequences saved but ${chalk.yellow('NOT deployed')}.`);
45
+ this.log(` Emails will not send until your domain is verified.`);
46
+ this.log(` When ready, run: ${chalk.cyan('mailmodo domain')}`);
47
+ this.log(` Then: ${chalk.cyan('mailmodo deploy')}\n`);
48
+ return;
49
+ }
50
+ }
51
+ const completed = await this.runDomainSetup(yamlConfig, flags);
52
+ if (!completed)
53
+ return;
54
+ }
33
55
  this.logPreDeploySummary(yamlConfig, flags.json);
34
- const confirmed = await this.confirmDeploy(yamlConfig, flags);
35
- if (!confirmed)
36
- return;
37
- const payload = await this.buildDeployPayload(yamlConfig);
38
- const response = await this.withApiSpinner({ json: flags.json, text: ' Deploying email sequences...' }, () => this.apiClient.post(API_ENDPOINTS.SEQUENCES_DEPLOY, payload));
56
+ if (!flags.yes) {
57
+ const proceed = await confirm({
58
+ default: true,
59
+ message: `Deploy ${yamlConfig.emails.length} emails?`,
60
+ });
61
+ if (!proceed) {
62
+ this.log('\n Deploy cancelled.\n');
63
+ return;
64
+ }
65
+ }
66
+ const response = await this.withApiSpinner({ json: flags.json, text: ' Deploying email sequences...' }, () => this.apiClient.post(API_ENDPOINTS.SEQUENCES, {
67
+ emails: yamlConfig.emails,
68
+ project: yamlConfig.project,
69
+ }));
39
70
  if (!response.ok) {
40
71
  this.handleApiError(response);
41
72
  }
42
73
  if (flags.json) {
43
74
  this.log(JSON.stringify({
44
- deployed: response.data.deployed,
45
- diff: response.data.diff,
46
- emailsLive: response.data.emailsLive,
47
- sdkSnippet: response.data.sdkSnippet,
48
- sequenceId: response.data.sequenceId,
75
+ deployed: true,
76
+ emailsLive: yamlConfig.emails.length,
77
+ sdkSnippet: response.data?.sdkSnippet,
49
78
  }, null, 2));
50
79
  return;
51
80
  }
52
- this.logDeploySuccessInstructions(response.data.sdkSnippet);
53
- }
54
- async buildDeployPayload(yamlConfig) {
55
- const emailsWithHtml = await Promise.all(yamlConfig.emails.map(async (email) => {
56
- const html = (await loadTemplate(`${email.id}.html`)) || '';
57
- return { ...this.mapEmailToPayload(email), html, plainHtml: html };
58
- }));
59
- return {
60
- ...this.buildProjectPayload(yamlConfig.project),
61
- emails: emailsWithHtml,
62
- };
63
- }
64
- mapEmailToPayload(email) {
65
- return {
66
- condition: email.condition || null,
67
- ctaText: '',
68
- delay: typeof email.delay === 'string'
69
- ? Number.parseInt(email.delay, 10) || 0
70
- : email.delay,
71
- goal: email.goal || '',
72
- id: email.id,
73
- isReminder: false,
74
- previewText: email.previewText || '',
75
- priority: 'medium',
76
- subject: email.subject,
77
- trigger: email.trigger,
78
- };
79
- }
80
- buildProjectPayload(project) {
81
- return {
82
- brand: {
83
- colors: [project?.brandColor || DEFAULT_BRAND_COLOR],
84
- logoUrl: project?.logoUrl || '',
85
- },
86
- emailStyle: project?.emailStyle || 'branded',
87
- monthlyCap: project?.monthlyCap ?? DEFAULT_MONTHLY_CAP,
88
- product: {
89
- businessType: project?.type || '',
90
- description: '',
91
- pricingModel: '',
92
- productName: project?.name || '',
93
- saasModel: '',
94
- targetUser: '',
95
- url: project?.url || '',
96
- },
97
- senderDetails: {
98
- address: project?.address || '',
99
- domain: project?.domain || '',
100
- fromEmail: project?.fromEmail || '',
101
- fromName: project?.fromName || '',
102
- replyTo: project?.replyTo || project?.fromEmail || '',
103
- },
104
- webhookUrl: project?.webhookUrl || '',
105
- };
106
- }
107
- async confirmDeploy(yamlConfig, flags) {
108
- if (flags.yes)
109
- return true;
110
- const proceed = await confirm({
111
- default: true,
112
- message: `Deploy ${yamlConfig.emails.length} emails?`,
113
- });
114
- if (!proceed) {
115
- this.log('\n Deploy cancelled.\n');
116
- }
117
- return proceed;
118
- }
119
- async ensureDomainReady(yamlConfig, flags) {
120
- const domainVerify = await this.fetchDomainVerifyForDeploy(flags.json, yamlConfig.project?.domain);
121
- if (domainVerify.ok && domainVerify.data?.domainStatus === 'VERIFIED') {
122
- return true;
123
- }
124
- if (!flags.json) {
125
- this.log(`\n No sending domain verified yet.`);
126
- this.log(` You need to verify a domain before sending emails.`);
127
- this.log(` This is a one-time setup. Takes about 5 minutes.\n`);
128
- }
129
- if (!flags.yes) {
130
- const setupNow = await confirm({
131
- default: true,
132
- message: 'Set up your sending domain now?',
133
- });
134
- if (!setupNow) {
135
- this.log(`\n Sequences saved but ${chalk.yellow('NOT deployed')}.`);
136
- this.log(` Emails will not send until your domain is verified.`);
137
- this.log(` When ready, run: ${chalk.cyan('mailmodo domain')}`);
138
- this.log(` Then: ${chalk.cyan('mailmodo deploy')}\n`);
139
- return false;
140
- }
141
- }
142
- return this.runDomainSetup(yamlConfig, flags);
81
+ this.logDeploySuccessInstructions();
143
82
  }
144
83
  /**
145
84
  * Lists emails about to be deployed (skipped when `--json` is set).
@@ -160,19 +99,19 @@ export default class Deploy extends BaseCommand {
160
99
  /**
161
100
  * Prints the post-deploy success message and SDK install snippet for interactive runs.
162
101
  */
163
- logDeploySuccessInstructions(sdkSnippet) {
102
+ logDeploySuccessInstructions() {
164
103
  this.log(` ${chalk.green('Deployed.')} Emails are live.\n`);
165
104
  this.log(` ${'─'.repeat(53)}`);
166
105
  this.log(` ${chalk.bold('ADD THIS TO YOUR APP (one-time only):')}`);
167
106
  this.log(` ${'─'.repeat(53)}\n`);
168
- this.log(` ${chalk.cyan(sdkSnippet.install ?? 'npm install @mailmodo/sdk')}\n`);
107
+ this.log(` ${chalk.cyan('npm install @mailmodo/sdk')}\n`);
169
108
  this.log(` ${chalk.dim("import { track, identify } from '@mailmodo/sdk'")}\n`);
170
- for (const [key, snippet] of Object.entries(sdkSnippet)) {
171
- if (key === 'install')
172
- continue;
173
- this.log(` ${chalk.dim(snippet)}`);
174
- }
175
- this.log('');
109
+ this.log(` ${chalk.dim('// On user signup:')}`);
110
+ this.log(` ${chalk.dim("track('user.signup', { email, first_name, app_url })")}\n`);
111
+ this.log(` ${chalk.dim('// When user creates a project:')}`);
112
+ this.log(` ${chalk.dim('identify(email, { has_created_project: true })')}\n`);
113
+ this.log(` ${chalk.dim('// On trial expiry:')}`);
114
+ this.log(` ${chalk.dim("track('user.trial_expiry', { email, first_name })")}\n`);
176
115
  this.log(` Full SDK docs: ${chalk.cyan('mailmodo.com/docs/sdk')}\n`);
177
116
  this.log(` ${'─'.repeat(53)}\n`);
178
117
  }
@@ -184,7 +123,31 @@ export default class Deploy extends BaseCommand {
184
123
  * @returns {Promise<boolean>} true if domain was verified, false if skipped.
185
124
  */
186
125
  async runDomainSetup(yamlConfig, flags) {
187
- const { address, domain, senderEmail } = await this.collectDomainInputs(yamlConfig, flags);
126
+ let domain;
127
+ let senderEmail;
128
+ let address;
129
+ if (flags.yes) {
130
+ domain = yamlConfig.project?.domain || '';
131
+ senderEmail = yamlConfig.project?.fromEmail || '';
132
+ address = yamlConfig.project?.address || '';
133
+ }
134
+ else {
135
+ this.log(`\n ${'─'.repeat(53)}`);
136
+ this.log(` ${chalk.bold('DOMAIN SETUP')}`);
137
+ this.log(` ${'─'.repeat(53)}\n`);
138
+ domain = await input({
139
+ message: 'What domain will you send from?',
140
+ validate: (v) => (v?.trim() ? true : 'Domain is required'),
141
+ });
142
+ senderEmail = await input({
143
+ message: 'Sender email address:',
144
+ validate: (v) => v?.includes('@') ? true : 'Please enter a valid email',
145
+ });
146
+ address = await input({
147
+ message: 'Business address (required by law for email footers):',
148
+ validate: (v) => (v?.trim() ? true : 'Address is required'),
149
+ });
150
+ }
188
151
  const domainResponse = await this.withApiSpinner({ json: flags.json, text: ' Configuring domain...' }, () => this.apiClient.post(API_ENDPOINTS.DOMAIN, {
189
152
  address,
190
153
  domain,
@@ -197,9 +160,20 @@ export default class Deploy extends BaseCommand {
197
160
  yamlConfig.project.fromEmail = senderEmail;
198
161
  yamlConfig.project.address = address;
199
162
  await saveYaml(yamlConfig);
200
- this.showDnsRecords(domainResponse.data?.dnsRecords || [], flags.json);
163
+ const dnsRecords = domainResponse.data?.dnsRecords || [];
164
+ if (!flags.json) {
165
+ this.log(`\n Add these ${dnsRecords.length} DNS records to your domain provider:\n`);
166
+ for (const [i, record] of dnsRecords.entries()) {
167
+ this.log(` ${chalk.bold(`RECORD ${i + 1}`)}`);
168
+ this.log(` Type: ${record.type}`);
169
+ this.log(` Host: ${record.host}`);
170
+ this.log(` Value: ${record.value}\n`);
171
+ }
172
+ this.log(` DNS changes take 5–30 minutes to propagate.`);
173
+ this.log(` Full guide: ${chalk.cyan(DNS_GUIDE_URL)}\n`);
174
+ }
201
175
  if (flags.yes) {
202
- return this.verifyDomain(flags.json, domain);
176
+ return this.verifyDomain(flags.json);
203
177
  }
204
178
  const action = await input({
205
179
  default: '',
@@ -211,65 +185,25 @@ export default class Deploy extends BaseCommand {
211
185
  this.log(` Then: ${chalk.cyan('mailmodo deploy')}\n`);
212
186
  return false;
213
187
  }
214
- return this.verifyDomain(flags.json, domain);
215
- }
216
- async collectDomainInputs(yamlConfig, flags) {
217
- if (flags.yes) {
218
- return {
219
- address: yamlConfig.project?.address || '',
220
- domain: yamlConfig.project?.domain || '',
221
- senderEmail: yamlConfig.project?.fromEmail || '',
222
- };
223
- }
224
- this.log(`\n ${'─'.repeat(53)}`);
225
- this.log(` ${chalk.bold('DOMAIN SETUP')}`);
226
- this.log(` ${'─'.repeat(53)}\n`);
227
- const domain = await input({
228
- message: 'What domain will you send from?',
229
- validate: (v) => (v?.trim() ? true : 'Domain is required'),
230
- });
231
- const senderEmail = await input({
232
- message: 'Sender email address:',
233
- validate: (v) => (v?.includes('@') ? true : 'Please enter a valid email'),
234
- });
235
- const address = await input({
236
- message: 'Business address (required by law for email footers):',
237
- validate: (v) => (v?.trim() ? true : 'Address is required'),
238
- });
239
- return { address, domain, senderEmail };
240
- }
241
- showDnsRecords(dnsRecords, jsonOutput) {
242
- if (jsonOutput)
243
- return;
244
- this.log(`\n Add these ${dnsRecords.length} DNS records to your domain provider:\n`);
245
- for (const [i, record] of dnsRecords.entries()) {
246
- this.log(` ${chalk.bold(`RECORD ${i + 1}`)}`);
247
- this.log(` Type: ${record.type}`);
248
- this.log(` Host: ${record.host}`);
249
- this.log(` Value: ${record.value}\n`);
250
- }
251
- this.log(` DNS changes take 5–30 minutes to propagate.`);
252
- this.log(` Full guide: ${chalk.cyan(DNS_GUIDE_URL)}\n`);
188
+ return this.verifyDomain(flags.json);
253
189
  }
254
190
  /**
255
191
  * Calls the domain verification API endpoint and reports pass/fail
256
- * status for each DNS record (DKIM, DMARC, Return-Path).
192
+ * status for each DNS record (SPF, DKIM, DMARC).
257
193
  *
258
194
  * @returns {Promise<boolean>} true if all records pass.
259
195
  */
260
- async verifyDomain(jsonOutput, domain) {
261
- const verify = await this.withApiSpinner({ json: jsonOutput, text: ' Checking DNS...' }, () => this.apiClient.get(API_ENDPOINTS.DOMAIN_VERIFY, {
262
- domain,
263
- }));
196
+ async verifyDomain(jsonOutput) {
197
+ const verify = await this.withApiSpinner({ json: jsonOutput, text: ' Checking DNS...' }, () => this.apiClient.get(API_ENDPOINTS.DOMAIN_VERIFY));
264
198
  if (!verify.ok) {
265
199
  this.handleApiError(verify);
266
200
  }
267
- const { dkim, dmarc, domainStatus, returnPath } = verify.data;
268
- const allPassed = domainStatus === 'VERIFIED';
201
+ const { dkim, dmarc, spf } = verify.data;
202
+ const allPassed = spf === 'pass' && dkim === 'pass' && dmarc === 'pass';
269
203
  if (!jsonOutput) {
270
- this.log(` DKIM ${dkim ? chalk.green('✓') : chalk.red('✗')}`);
271
- this.log(` DMARC ${dmarc ? chalk.green('✓') : chalk.red('✗')}`);
272
- this.log(` Return-Path ${returnPath ? chalk.green('✓') : chalk.red('✗')}`);
204
+ this.log(` SPF ${spf === 'pass' ? chalk.green('✓') : chalk.red('✗')}`);
205
+ this.log(` DKIM ${dkim === 'pass' ? chalk.green('✓') : chalk.red('✗')}`);
206
+ this.log(` DMARC ${dmarc === 'pass' ? chalk.green('✓') : chalk.red('✗')}`);
273
207
  if (allPassed) {
274
208
  this.log(`\n ${chalk.green('Domain verified.')} Continuing deploy...\n`);
275
209
  }
@@ -84,14 +84,11 @@ export default class Preview extends BaseCommand {
84
84
  app_url: yamlConfig.project?.url || 'https://yourapp.com', // eslint-disable-line camelcase
85
85
  product_name: yamlConfig.project?.name || 'YourApp', // eslint-disable-line camelcase
86
86
  };
87
- const templateHtml = await loadTemplate(`${email.id}.html`);
88
87
  if (flags.send) {
89
- const rendered = templateHtml
90
- ? renderTemplate(templateHtml, sampleData)
91
- : '';
92
- await this.sendTestEmail(email, rendered, yamlConfig.project?.domain, flags.send, flags.json);
88
+ await this.sendTestEmail(templateId, flags.send, flags.json);
93
89
  return;
94
90
  }
91
+ const templateHtml = await loadTemplate(`${email.id}.html`);
95
92
  if (flags.text) {
96
93
  await this.renderText(email, templateHtml, sampleData, flags.json);
97
94
  return;
@@ -126,27 +123,21 @@ export default class Preview extends BaseCommand {
126
123
  * Calls the API to send a test email to the specified address.
127
124
  * Before domain verification, tests send via the mailmodo.com domain.
128
125
  */
129
- async sendTestEmail(email, html, domain, toAddress, jsonOutput) {
126
+ async sendTestEmail(templateId, toAddress, jsonOutput) {
130
127
  await this.ensureAuth();
131
- const response = await this.withApiSpinner({ json: jsonOutput, text: ' Sending test email...' }, () => this.apiClient.post(`${API_ENDPOINTS.PREVIEW}/send`, {
132
- domain,
133
- html,
134
- subject: email.subject,
128
+ const response = await this.withApiSpinner({ json: jsonOutput, text: ' Sending test email...' }, () => this.apiClient.post(`${API_ENDPOINTS.PREVIEW}/${templateId}/send`, {
135
129
  to: toAddress,
136
130
  }));
137
131
  if (!response.ok) {
138
132
  this.handleApiError(response);
139
133
  }
140
- const { note, sentTo, sentVia, status } = response.data;
141
134
  if (jsonOutput) {
142
- this.log(JSON.stringify({ note, sentTo, sentVia, status }, null, 2));
135
+ this.log(JSON.stringify({ templateId, sentTo: toAddress, status: 'sent' }, null, 2));
143
136
  return;
144
137
  }
145
- this.log(`\n ${chalk.green('✓')} Test email sent to ${chalk.cyan(sentTo)} via ${chalk.cyan(sentVia)}.`);
146
- if (note) {
147
- this.log(` ${chalk.dim(note)}`);
148
- }
149
- this.log('');
138
+ this.log(`\n Sending test to ${chalk.cyan(toAddress)}...`);
139
+ this.log(` ${chalk.dim('Note: If domain is not yet verified, test sends via mailmodo.com domain.')}`);
140
+ this.log(` ${chalk.green('✓')} Sent.\n`);
150
141
  }
151
142
  /**
152
143
  * Starts a local HTTP server on PREVIEW_PORT to serve the rendered email
@@ -17,8 +17,6 @@ export declare const API_ENDPOINTS: Readonly<{
17
17
  LOGS: "/logs";
18
18
  PREVIEW: "/preview";
19
19
  SEQUENCES: "/sequences";
20
- SEQUENCES_DEPLOY: "/sequences/deploy";
21
- SEQUENCES_VALIDATE: "/sequences/validate";
22
20
  }>;
23
21
  export declare const LOGIN_URL = "https://app-vertex-debug.azurewebsites.net/login.html";
24
22
  export declare const DOCS_URL = "https://mailmodo.com/docs/cli";
@@ -23,8 +23,6 @@ export const API_ENDPOINTS = Object.freeze({
23
23
  LOGS: '/logs',
24
24
  PREVIEW: '/preview',
25
25
  SEQUENCES: '/sequences',
26
- SEQUENCES_DEPLOY: '/sequences/deploy',
27
- SEQUENCES_VALIDATE: '/sequences/validate',
28
26
  });
29
27
  const DEV_LOGIN_URL = 'https://app-vertex-debug.azurewebsites.net/login.html';
30
28
  // const PRODUCTION_LOGIN_URL = 'https://mailmodo.com/cli';
@@ -114,6 +114,45 @@
114
114
  "index.js"
115
115
  ]
116
116
  },
117
+ "deploy": {
118
+ "aliases": [],
119
+ "args": {},
120
+ "description": "Deploy email sequences and verify sending domain",
121
+ "examples": [
122
+ "<%= config.bin %> deploy",
123
+ "<%= config.bin %> deploy --yes"
124
+ ],
125
+ "flags": {
126
+ "json": {
127
+ "description": "Output as JSON",
128
+ "name": "json",
129
+ "allowNo": false,
130
+ "type": "boolean"
131
+ },
132
+ "yes": {
133
+ "char": "y",
134
+ "description": "Skip confirmation prompts",
135
+ "name": "yes",
136
+ "allowNo": false,
137
+ "type": "boolean"
138
+ }
139
+ },
140
+ "hasDynamicHelp": false,
141
+ "hiddenAliases": [],
142
+ "id": "deploy",
143
+ "pluginAlias": "@mailmodo/cli",
144
+ "pluginName": "@mailmodo/cli",
145
+ "pluginType": "core",
146
+ "strict": true,
147
+ "enableJsonFlag": false,
148
+ "isESM": true,
149
+ "relativePath": [
150
+ "dist",
151
+ "commands",
152
+ "deploy",
153
+ "index.js"
154
+ ]
155
+ },
117
156
  "domain": {
118
157
  "aliases": [],
119
158
  "args": {},
@@ -218,45 +257,6 @@
218
257
  "index.js"
219
258
  ]
220
259
  },
221
- "deploy": {
222
- "aliases": [],
223
- "args": {},
224
- "description": "Deploy email sequences and verify sending domain",
225
- "examples": [
226
- "<%= config.bin %> deploy",
227
- "<%= config.bin %> deploy --yes"
228
- ],
229
- "flags": {
230
- "json": {
231
- "description": "Output as JSON",
232
- "name": "json",
233
- "allowNo": false,
234
- "type": "boolean"
235
- },
236
- "yes": {
237
- "char": "y",
238
- "description": "Skip confirmation prompts",
239
- "name": "yes",
240
- "allowNo": false,
241
- "type": "boolean"
242
- }
243
- },
244
- "hasDynamicHelp": false,
245
- "hiddenAliases": [],
246
- "id": "deploy",
247
- "pluginAlias": "@mailmodo/cli",
248
- "pluginName": "@mailmodo/cli",
249
- "pluginType": "core",
250
- "strict": true,
251
- "enableJsonFlag": false,
252
- "isESM": true,
253
- "relativePath": [
254
- "dist",
255
- "commands",
256
- "deploy",
257
- "index.js"
258
- ]
259
- },
260
260
  "emails": {
261
261
  "aliases": [],
262
262
  "args": {},
@@ -618,5 +618,5 @@
618
618
  ]
619
619
  }
620
620
  },
621
- "version": "0.0.19-beta.pr21.31"
621
+ "version": "0.0.19"
622
622
  }
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.19-beta.pr21.31",
4
+ "version": "0.0.19",
5
5
  "author": "provishalk",
6
6
  "bin": {
7
7
  "mailmodo": "bin/run.js"