@mailmodo/cli 0.0.54-beta.pr56.90 → 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.
@@ -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.`;
@@ -76,15 +76,15 @@
76
76
  "index.js"
77
77
  ]
78
78
  },
79
- "deploy": {
79
+ "contacts": {
80
80
  "aliases": [],
81
81
  "args": {},
82
- "description": "Deploy, pause, or resume an email sequence",
82
+ "description": "Manage contacts — search, export, or delete",
83
83
  "examples": [
84
- "<%= config.bin %> deploy",
85
- "<%= config.bin %> deploy --yes",
86
- "<%= config.bin %> deploy --pause seq_abc123",
87
- "<%= config.bin %> deploy --resume seq_abc123 --json"
84
+ "<%= config.bin %> contacts",
85
+ "<%= config.bin %> contacts --search sarah@example.com",
86
+ "<%= config.bin %> contacts --export # GDPR CSV → contacts.csv",
87
+ "<%= config.bin %> contacts --delete sarah@example.com"
88
88
  ],
89
89
  "flags": {
90
90
  "json": {
@@ -100,69 +100,30 @@
100
100
  "allowNo": false,
101
101
  "type": "boolean"
102
102
  },
103
- "pause": {
104
- "description": "Pause a deployed sequence by ID (stops scheduled + triggered sends)",
105
- "exclusive": [
106
- "resume"
107
- ],
108
- "name": "pause",
103
+ "delete": {
104
+ "description": "GDPR hard delete a contact by email",
105
+ "name": "delete",
109
106
  "hasDynamicHelp": false,
110
107
  "multiple": false,
111
108
  "type": "option"
112
109
  },
113
- "resume": {
114
- "description": "Resume a paused sequence by ID",
115
- "exclusive": [
116
- "pause"
117
- ],
118
- "name": "resume",
119
- "hasDynamicHelp": false,
120
- "multiple": false,
121
- "type": "option"
122
- }
123
- },
124
- "hasDynamicHelp": false,
125
- "hiddenAliases": [],
126
- "id": "deploy",
127
- "pluginAlias": "@mailmodo/cli",
128
- "pluginName": "@mailmodo/cli",
129
- "pluginType": "core",
130
- "strict": true,
131
- "enableJsonFlag": false,
132
- "isESM": true,
133
- "relativePath": [
134
- "dist",
135
- "commands",
136
- "deploy",
137
- "index.js"
138
- ]
139
- },
140
- "deployments": {
141
- "aliases": [],
142
- "args": {},
143
- "description": "List every deployed sequence on this account, with the IDs needed for deploy --pause / --resume",
144
- "examples": [
145
- "<%= config.bin %> deployments",
146
- "<%= config.bin %> deployments --json"
147
- ],
148
- "flags": {
149
- "json": {
150
- "description": "Output as JSON",
151
- "name": "json",
110
+ "export": {
111
+ "description": "Export all contacts as GDPR-compliant CSV (writes contacts.csv in the current directory)",
112
+ "name": "export",
152
113
  "allowNo": false,
153
114
  "type": "boolean"
154
115
  },
155
- "yes": {
156
- "char": "y",
157
- "description": "Skip confirmation prompts",
158
- "name": "yes",
159
- "allowNo": false,
160
- "type": "boolean"
116
+ "search": {
117
+ "description": "Search for a contact by email",
118
+ "name": "search",
119
+ "hasDynamicHelp": false,
120
+ "multiple": false,
121
+ "type": "option"
161
122
  }
162
123
  },
163
124
  "hasDynamicHelp": false,
164
125
  "hiddenAliases": [],
165
- "id": "deployments",
126
+ "id": "contacts",
166
127
  "pluginAlias": "@mailmodo/cli",
167
128
  "pluginName": "@mailmodo/cli",
168
129
  "pluginType": "core",
@@ -172,19 +133,19 @@
172
133
  "relativePath": [
173
134
  "dist",
174
135
  "commands",
175
- "deployments",
136
+ "contacts",
176
137
  "index.js"
177
138
  ]
178
139
  },
179
- "contacts": {
140
+ "deploy": {
180
141
  "aliases": [],
181
142
  "args": {},
182
- "description": "Manage contacts — search, export, or delete",
143
+ "description": "Deploy, pause, or resume an email sequence",
183
144
  "examples": [
184
- "<%= config.bin %> contacts",
185
- "<%= config.bin %> contacts --search sarah@example.com",
186
- "<%= config.bin %> contacts --export # GDPR CSV → contacts.csv",
187
- "<%= config.bin %> contacts --delete sarah@example.com"
145
+ "<%= config.bin %> deploy",
146
+ "<%= config.bin %> deploy --yes",
147
+ "<%= config.bin %> deploy --pause seq_abc123",
148
+ "<%= config.bin %> deploy --resume seq_abc123 --json"
188
149
  ],
189
150
  "flags": {
190
151
  "json": {
@@ -200,22 +161,22 @@
200
161
  "allowNo": false,
201
162
  "type": "boolean"
202
163
  },
203
- "delete": {
204
- "description": "GDPR hard delete a contact by email",
205
- "name": "delete",
164
+ "pause": {
165
+ "description": "Pause a deployed sequence by ID (stops scheduled + triggered sends)",
166
+ "exclusive": [
167
+ "resume"
168
+ ],
169
+ "name": "pause",
206
170
  "hasDynamicHelp": false,
207
171
  "multiple": false,
208
172
  "type": "option"
209
173
  },
210
- "export": {
211
- "description": "Export all contacts as GDPR-compliant CSV (writes contacts.csv in the current directory)",
212
- "name": "export",
213
- "allowNo": false,
214
- "type": "boolean"
215
- },
216
- "search": {
217
- "description": "Search for a contact by email",
218
- "name": "search",
174
+ "resume": {
175
+ "description": "Resume a paused sequence by ID",
176
+ "exclusive": [
177
+ "pause"
178
+ ],
179
+ "name": "resume",
219
180
  "hasDynamicHelp": false,
220
181
  "multiple": false,
221
182
  "type": "option"
@@ -223,7 +184,7 @@
223
184
  },
224
185
  "hasDynamicHelp": false,
225
186
  "hiddenAliases": [],
226
- "id": "contacts",
187
+ "id": "deploy",
227
188
  "pluginAlias": "@mailmodo/cli",
228
189
  "pluginName": "@mailmodo/cli",
229
190
  "pluginType": "core",
@@ -233,7 +194,7 @@
233
194
  "relativePath": [
234
195
  "dist",
235
196
  "commands",
236
- "contacts",
197
+ "deploy",
237
198
  "index.js"
238
199
  ]
239
200
  },
@@ -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": {},
@@ -765,5 +765,5 @@
765
765
  ]
766
766
  }
767
767
  },
768
- "version": "0.0.54-beta.pr56.90"
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.90",
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>;