@mailmodo/cli 0.0.8 → 0.0.9

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.
@@ -34,15 +34,13 @@ export default class Login extends BaseCommand {
34
34
  validate(value) {
35
35
  if (!value?.trim())
36
36
  return 'API key is required';
37
- if (!value.startsWith('mm_'))
38
- return 'Invalid API key format. Keys start with mm_';
39
37
  return true;
40
38
  },
41
39
  });
42
40
  }
43
41
  const trimmedKey = apiKey.trim();
44
42
  const client = new ApiClient(trimmedKey);
45
- const response = await client.get(API_ENDPOINTS.AUTH_VALIDATE);
43
+ const response = await client.post(API_ENDPOINTS.AUTH_VALIDATE, {});
46
44
  if (!response.ok) {
47
45
  this.handleApiError(response);
48
46
  }
@@ -1,26 +1,29 @@
1
+ /**
2
+ * Request context attached to API responses for troubleshooting failed calls.
3
+ * Only the resolved URL is stored; it encodes origin, path, and query string.
4
+ */
5
+ export interface ApiRequestDebugInfo {
6
+ /** Node/DNS/network error code when `fetch` throws before an HTTP response. */
7
+ causeCode?: string;
8
+ /** Fully resolved request URL (origin, path, and query string). */
9
+ fullUrl: string;
10
+ /** Truncated JSON summary of a non-empty error response body, when available. */
11
+ responseSummary?: string;
12
+ }
1
13
  export interface ApiResponse<T = Record<string, unknown>> {
2
14
  data: T;
15
+ /** Populated for tracing; especially useful when `ok` is false. */
16
+ debug?: ApiRequestDebugInfo;
3
17
  error?: string;
4
18
  ok: boolean;
5
19
  status: number;
6
20
  }
7
- /**
8
- * HTTP client for the Mailmodo CLI API.
9
- * Wraps the native fetch API with Bearer token authentication,
10
- * consistent error handling, and typed responses.
11
- *
12
- * All requests include:
13
- * - Authorization header with the user's API key
14
- * - Content-Type: application/json
15
- * - User-Agent: @mailmodo/cli
16
- *
17
- * Network errors (ECONNREFUSED, ENOTFOUND) return a friendly message
18
- * indicating the API may not be available, rather than a raw stack trace.
19
- */
20
21
  export declare class ApiClient {
21
22
  private apiKey;
22
23
  private baseUrl;
23
24
  constructor(apiKey: string);
25
+ private resolveUrl;
26
+ private requestDebug;
24
27
  /**
25
28
  * Sends an HTTP request to the Mailmodo API and returns a typed response.
26
29
  *
@@ -12,6 +12,22 @@ import { API_BASE_URL } from './constants.js';
12
12
  * Network errors (ECONNREFUSED, ENOTFOUND) return a friendly message
13
13
  * indicating the API may not be available, rather than a raw stack trace.
14
14
  */
15
+ const RESPONSE_BODY_DEBUG_MAX = 800;
16
+ function summarizeResponseBody(data) {
17
+ if (data === null || data === undefined)
18
+ return undefined;
19
+ try {
20
+ const s = JSON.stringify(data);
21
+ if (s === '{}' || s === '[]')
22
+ return undefined;
23
+ return s.length > RESPONSE_BODY_DEBUG_MAX
24
+ ? `${s.slice(0, RESPONSE_BODY_DEBUG_MAX)}…`
25
+ : s;
26
+ }
27
+ catch {
28
+ return undefined;
29
+ }
30
+ }
15
31
  export class ApiClient {
16
32
  apiKey;
17
33
  baseUrl;
@@ -19,6 +35,18 @@ export class ApiClient {
19
35
  this.baseUrl = API_BASE_URL;
20
36
  this.apiKey = apiKey;
21
37
  }
38
+ resolveUrl(path, params) {
39
+ const url = new URL(`${this.baseUrl}${path}`);
40
+ if (params) {
41
+ for (const [key, value] of Object.entries(params)) {
42
+ url.searchParams.set(key, value);
43
+ }
44
+ }
45
+ return url;
46
+ }
47
+ requestDebug(url) {
48
+ return { fullUrl: url.toString() };
49
+ }
22
50
  /**
23
51
  * Sends an HTTP request to the Mailmodo API and returns a typed response.
24
52
  *
@@ -31,12 +59,8 @@ export class ApiClient {
31
59
  * data (parsed JSON body), and optional error (string message on failure).
32
60
  */
33
61
  async request(method, path, body, params) {
34
- const url = new URL(`${this.baseUrl}${path}`);
35
- if (params) {
36
- for (const [key, value] of Object.entries(params)) {
37
- url.searchParams.set(key, value);
38
- }
39
- }
62
+ const url = this.resolveUrl(path, params);
63
+ const debug = this.requestDebug(url);
40
64
  const headers = {
41
65
  Authorization: `Bearer ${this.apiKey}`,
42
66
  'Content-Type': 'application/json',
@@ -51,8 +75,13 @@ export class ApiClient {
51
75
  const data = await response.json().catch(() => ({}));
52
76
  if (!response.ok) {
53
77
  const errorData = data;
78
+ const summary = summarizeResponseBody(data);
54
79
  return {
55
80
  data: data,
81
+ debug: {
82
+ ...debug,
83
+ responseSummary: summary,
84
+ },
56
85
  error: errorData?.message ||
57
86
  errorData?.error ||
58
87
  `Request failed with status ${response.status}`,
@@ -65,8 +94,13 @@ export class ApiClient {
65
94
  catch (error) {
66
95
  const err = error;
67
96
  const isConnectionError = err?.cause?.code === 'ECONNREFUSED' || err?.cause?.code === 'ENOTFOUND';
97
+ const causeCode = err?.cause?.code;
68
98
  return {
69
99
  data: {},
100
+ debug: {
101
+ ...debug,
102
+ ...(causeCode ? { causeCode } : {}),
103
+ },
70
104
  error: isConnectionError
71
105
  ? 'Cannot connect to Mailmodo API. The API service may not be available yet.'
72
106
  : err?.message || 'An unexpected network error occurred.',
@@ -88,7 +122,8 @@ export class ApiClient {
88
122
  return this.request('POST', path, body);
89
123
  }
90
124
  async postFormData(path, formData) {
91
- const url = new URL(`${this.baseUrl}${path}`);
125
+ const url = this.resolveUrl(path);
126
+ const debug = this.requestDebug(url);
92
127
  try {
93
128
  const response = await fetch(url.toString(), {
94
129
  body: formData,
@@ -101,8 +136,13 @@ export class ApiClient {
101
136
  const data = await response.json().catch(() => ({}));
102
137
  if (!response.ok) {
103
138
  const errorData = data;
139
+ const summary = summarizeResponseBody(data);
104
140
  return {
105
141
  data: data,
142
+ debug: {
143
+ ...debug,
144
+ responseSummary: summary,
145
+ },
106
146
  error: errorData?.message ||
107
147
  errorData?.error ||
108
148
  `Upload failed with status ${response.status}`,
@@ -114,8 +154,13 @@ export class ApiClient {
114
154
  }
115
155
  catch (error) {
116
156
  const err = error;
157
+ const causeCode = err?.cause?.code;
117
158
  return {
118
159
  data: {},
160
+ debug: {
161
+ ...debug,
162
+ ...(causeCode ? { causeCode } : {}),
163
+ },
119
164
  error: err?.message || 'File upload failed.',
120
165
  ok: false,
121
166
  status: 0,
@@ -1,5 +1,5 @@
1
1
  import { Command } from '@oclif/core';
2
- import { ApiClient } from './api-client.js';
2
+ import { ApiClient, type ApiRequestDebugInfo } from './api-client.js';
3
3
  import { type MailmodoConfig } from './config.js';
4
4
  import { type MailmodoYaml } from './yaml-config.js';
5
5
  /**
@@ -34,12 +34,24 @@ export declare abstract class BaseCommand extends Command {
34
34
  * Handles a failed API response by mapping HTTP status codes to
35
35
  * user-friendly error messages and exiting the process.
36
36
  *
37
- * @param {{ status: number; error?: string }} response - The API response object with ok=false.
37
+ * @param {{ status: number; error?: string; debug?: ApiRequestDebugInfo }} response - The API response object with ok=false.
38
38
  * Status 401 prompts re-authentication, 429 indicates rate limiting,
39
39
  * all others display the server's error message or a generic fallback.
40
+ * When `debug` is present, extra lines list Full URL, Status, optional Response
41
+ * body summary, and optional Error Code (network failures).
40
42
  */
41
43
  protected handleApiError(response: {
44
+ debug?: ApiRequestDebugInfo;
42
45
  error?: string;
43
46
  status: number;
44
47
  }): never;
48
+ /**
49
+ * Builds the terminal error string for a failed API call, appending request
50
+ * metadata when {@link ApiRequestDebugInfo} is available.
51
+ *
52
+ * @param {string} message - Primary error text (HTTP message or generic).
53
+ * @param {{ status: number; debug?: ApiRequestDebugInfo }} response - Failed API response.
54
+ * @returns {string} Message plus indented Request details for troubleshooting.
55
+ */
56
+ private formatApiFailure;
45
57
  }
@@ -57,17 +57,48 @@ export class BaseCommand extends Command {
57
57
  * Handles a failed API response by mapping HTTP status codes to
58
58
  * user-friendly error messages and exiting the process.
59
59
  *
60
- * @param {{ status: number; error?: string }} response - The API response object with ok=false.
60
+ * @param {{ status: number; error?: string; debug?: ApiRequestDebugInfo }} response - The API response object with ok=false.
61
61
  * Status 401 prompts re-authentication, 429 indicates rate limiting,
62
62
  * all others display the server's error message or a generic fallback.
63
+ * When `debug` is present, extra lines list Full URL, Status, optional Response
64
+ * body summary, and optional Error Code (network failures).
63
65
  */
64
66
  handleApiError(response) {
65
67
  if (response.status === 401) {
66
- this.error(`Invalid API key. Run ${chalk.cyan('mailmodo login')} to re-authenticate.`);
68
+ this.error(this.formatApiFailure(`Invalid API key. Run ${chalk.cyan('mailmodo login')} to re-authenticate.`, response));
67
69
  }
68
70
  if (response.status === 429) {
69
- this.error('Rate limit exceeded. Please try again later.');
71
+ this.error(this.formatApiFailure('Rate limit exceeded. Please try again later.', response));
70
72
  }
71
- this.error(response.error || 'An unexpected API error occurred.');
73
+ this.error(this.formatApiFailure(response.error || 'An unexpected API error occurred.', response));
74
+ }
75
+ /**
76
+ * Builds the terminal error string for a failed API call, appending request
77
+ * metadata when {@link ApiRequestDebugInfo} is available.
78
+ *
79
+ * @param {string} message - Primary error text (HTTP message or generic).
80
+ * @param {{ status: number; debug?: ApiRequestDebugInfo }} response - Failed API response.
81
+ * @returns {string} Message plus indented Request details for troubleshooting.
82
+ */
83
+ formatApiFailure(message, response) {
84
+ const { debug, status } = response;
85
+ if (!debug) {
86
+ return message;
87
+ }
88
+ return [
89
+ message,
90
+ '',
91
+ chalk.dim('Request:'),
92
+ chalk.dim(` URL: ${debug.fullUrl}`),
93
+ status > 0
94
+ ? chalk.dim(` Status: ${String(status)}`)
95
+ : chalk.dim(' Status: (No HTTP response — network or client error)'),
96
+ ...(debug.responseSummary
97
+ ? [chalk.dim(` Response: ${debug.responseSummary}`)]
98
+ : []),
99
+ ...(debug.causeCode
100
+ ? [chalk.dim(` Error Code: ${debug.causeCode}`)]
101
+ : []),
102
+ ].join('\n');
72
103
  }
73
104
  }
@@ -1,22 +1,22 @@
1
1
  export declare const API_BASE_URL: string;
2
2
  export declare const API_ENDPOINTS: Readonly<{
3
- ANALYTICS: "/analytics";
4
- ANALYZE: "/analyze";
5
- ASSETS_LOGO: "/assets/logo";
6
- AUTH_VALIDATE: "/auth/validate";
7
- BILLING_CAP: "/billing/cap";
8
- BILLING_STATUS: "/billing/status";
9
- CONTACTS: "/contacts";
10
- CONTACTS_EXPORT: "/contacts/export";
11
- DOMAIN: "/domain";
12
- DOMAIN_STATUS: "/domain/status";
13
- DOMAIN_VERIFY: "/domain/verify";
14
- EDIT: "/edit";
15
- EVENTS: "/events";
16
- GENERATE: "/generate";
17
- LOGS: "/logs";
18
- PREVIEW: "/preview";
19
- SEQUENCES: "/sequences";
3
+ ANALYTICS: "/api/analytics";
4
+ ANALYZE: "/api/analyze";
5
+ ASSETS_LOGO: "/api/assets/logo";
6
+ AUTH_VALIDATE: "/api/auth/validate";
7
+ BILLING_CAP: "/api/billing/cap";
8
+ BILLING_STATUS: "/api/billing/status";
9
+ CONTACTS: "/api/contacts";
10
+ CONTACTS_EXPORT: "/api/contacts/export";
11
+ DOMAIN: "/api/domain";
12
+ DOMAIN_STATUS: "/api/domain/status";
13
+ DOMAIN_VERIFY: "/api/domain/verify";
14
+ EDIT: "/api/edit";
15
+ EVENTS: "/api/events";
16
+ GENERATE: "/api/generate";
17
+ LOGS: "/api/logs";
18
+ PREVIEW: "/api/preview";
19
+ SEQUENCES: "/api/sequences";
20
20
  }>;
21
21
  export declare const SIGNUP_URL = "https://mailmodo.com/cli";
22
22
  export declare const DOCS_URL = "https://mailmodo.com/docs/cli";
@@ -1,22 +1,27 @@
1
- export const API_BASE_URL = process.env.MAILMODO_API_URL || 'https://api.mailmodo.com/cli/v1';
1
+ /** Set by `bin/dev.js` when running the CLI locally (tsx bootstrap). */
2
+ const DEV_API_BASE_URL = 'https://app-vertex-debug.azurewebsites.net';
3
+ const PRODUCTION_API_BASE_URL = 'https://api.mailmodo.com';
4
+ export const API_BASE_URL = process.env.MAILMODO_DEV_TSX
5
+ ? DEV_API_BASE_URL
6
+ : PRODUCTION_API_BASE_URL;
2
7
  export const API_ENDPOINTS = Object.freeze({
3
- ANALYTICS: '/analytics',
4
- ANALYZE: '/analyze',
5
- ASSETS_LOGO: '/assets/logo',
6
- AUTH_VALIDATE: '/auth/validate',
7
- BILLING_CAP: '/billing/cap',
8
- BILLING_STATUS: '/billing/status',
9
- CONTACTS: '/contacts',
10
- CONTACTS_EXPORT: '/contacts/export',
11
- DOMAIN: '/domain',
12
- DOMAIN_STATUS: '/domain/status',
13
- DOMAIN_VERIFY: '/domain/verify',
14
- EDIT: '/edit',
15
- EVENTS: '/events',
16
- GENERATE: '/generate',
17
- LOGS: '/logs',
18
- PREVIEW: '/preview',
19
- SEQUENCES: '/sequences',
8
+ ANALYTICS: '/api/analytics',
9
+ ANALYZE: '/api/analyze',
10
+ ASSETS_LOGO: '/api/assets/logo',
11
+ AUTH_VALIDATE: '/api/auth/validate',
12
+ BILLING_CAP: '/api/billing/cap',
13
+ BILLING_STATUS: '/api/billing/status',
14
+ CONTACTS: '/api/contacts',
15
+ CONTACTS_EXPORT: '/api/contacts/export',
16
+ DOMAIN: '/api/domain',
17
+ DOMAIN_STATUS: '/api/domain/status',
18
+ DOMAIN_VERIFY: '/api/domain/verify',
19
+ EDIT: '/api/edit',
20
+ EVENTS: '/api/events',
21
+ GENERATE: '/api/generate',
22
+ LOGS: '/api/logs',
23
+ PREVIEW: '/api/preview',
24
+ SEQUENCES: '/api/sequences',
20
25
  });
21
26
  export const SIGNUP_URL = 'https://mailmodo.com/cli';
22
27
  export const DOCS_URL = 'https://mailmodo.com/docs/cli';
@@ -205,13 +205,19 @@
205
205
  "index.js"
206
206
  ]
207
207
  },
208
- "emails": {
208
+ "edit": {
209
209
  "aliases": [],
210
- "args": {},
211
- "description": "List and view configured email sequences",
210
+ "args": {
211
+ "id": {
212
+ "description": "Email ID to edit",
213
+ "name": "id",
214
+ "required": true
215
+ }
216
+ },
217
+ "description": "Edit an email using AI-assisted natural language changes",
212
218
  "examples": [
213
- "<%= config.bin %> emails",
214
- "<%= config.bin %> emails --json"
219
+ "<%= config.bin %> edit welcome",
220
+ "<%= config.bin %> edit welcome --change \"make subject more urgent\" --yes"
215
221
  ],
216
222
  "flags": {
217
223
  "json": {
@@ -226,11 +232,18 @@
226
232
  "name": "yes",
227
233
  "allowNo": false,
228
234
  "type": "boolean"
235
+ },
236
+ "change": {
237
+ "description": "Natural language description of the change",
238
+ "name": "change",
239
+ "hasDynamicHelp": false,
240
+ "multiple": false,
241
+ "type": "option"
229
242
  }
230
243
  },
231
244
  "hasDynamicHelp": false,
232
245
  "hiddenAliases": [],
233
- "id": "emails",
246
+ "id": "edit",
234
247
  "pluginAlias": "@mailmodo/cli",
235
248
  "pluginName": "@mailmodo/cli",
236
249
  "pluginType": "core",
@@ -240,23 +253,17 @@
240
253
  "relativePath": [
241
254
  "dist",
242
255
  "commands",
243
- "emails",
256
+ "edit",
244
257
  "index.js"
245
258
  ]
246
259
  },
247
- "edit": {
260
+ "emails": {
248
261
  "aliases": [],
249
- "args": {
250
- "id": {
251
- "description": "Email ID to edit",
252
- "name": "id",
253
- "required": true
254
- }
255
- },
256
- "description": "Edit an email using AI-assisted natural language changes",
262
+ "args": {},
263
+ "description": "List and view configured email sequences",
257
264
  "examples": [
258
- "<%= config.bin %> edit welcome",
259
- "<%= config.bin %> edit welcome --change \"make subject more urgent\" --yes"
265
+ "<%= config.bin %> emails",
266
+ "<%= config.bin %> emails --json"
260
267
  ],
261
268
  "flags": {
262
269
  "json": {
@@ -271,18 +278,11 @@
271
278
  "name": "yes",
272
279
  "allowNo": false,
273
280
  "type": "boolean"
274
- },
275
- "change": {
276
- "description": "Natural language description of the change",
277
- "name": "change",
278
- "hasDynamicHelp": false,
279
- "multiple": false,
280
- "type": "option"
281
281
  }
282
282
  },
283
283
  "hasDynamicHelp": false,
284
284
  "hiddenAliases": [],
285
- "id": "edit",
285
+ "id": "emails",
286
286
  "pluginAlias": "@mailmodo/cli",
287
287
  "pluginName": "@mailmodo/cli",
288
288
  "pluginType": "core",
@@ -292,7 +292,7 @@
292
292
  "relativePath": [
293
293
  "dist",
294
294
  "commands",
295
- "edit",
295
+ "emails",
296
296
  "index.js"
297
297
  ]
298
298
  },
@@ -435,19 +435,14 @@
435
435
  "index.js"
436
436
  ]
437
437
  },
438
- "preview": {
438
+ "settings": {
439
439
  "aliases": [],
440
- "args": {
441
- "id": {
442
- "description": "Email ID to preview",
443
- "name": "id"
444
- }
445
- },
446
- "description": "Preview an email in browser, as text, or send a test",
440
+ "args": {},
441
+ "description": "View and update project settings",
447
442
  "examples": [
448
- "<%= config.bin %> preview welcome",
449
- "<%= config.bin %> preview welcome --text",
450
- "<%= config.bin %> preview welcome --send me@example.com"
443
+ "<%= config.bin %> settings",
444
+ "<%= config.bin %> settings --set brand_color=#0F3460",
445
+ "<%= config.bin %> settings --json"
451
446
  ],
452
447
  "flags": {
453
448
  "json": {
@@ -463,23 +458,17 @@
463
458
  "allowNo": false,
464
459
  "type": "boolean"
465
460
  },
466
- "send": {
467
- "description": "Send test email to this address",
468
- "name": "send",
461
+ "set": {
462
+ "description": "Set a setting (format: key=value)",
463
+ "name": "set",
469
464
  "hasDynamicHelp": false,
470
465
  "multiple": false,
471
466
  "type": "option"
472
- },
473
- "text": {
474
- "description": "Output plain text version (for AI agents)",
475
- "name": "text",
476
- "allowNo": false,
477
- "type": "boolean"
478
467
  }
479
468
  },
480
469
  "hasDynamicHelp": false,
481
470
  "hiddenAliases": [],
482
- "id": "preview",
471
+ "id": "settings",
483
472
  "pluginAlias": "@mailmodo/cli",
484
473
  "pluginName": "@mailmodo/cli",
485
474
  "pluginType": "core",
@@ -489,18 +478,17 @@
489
478
  "relativePath": [
490
479
  "dist",
491
480
  "commands",
492
- "preview",
481
+ "settings",
493
482
  "index.js"
494
483
  ]
495
484
  },
496
- "settings": {
485
+ "status": {
497
486
  "aliases": [],
498
487
  "args": {},
499
- "description": "View and update project settings",
488
+ "description": "View email performance metrics and quota usage",
500
489
  "examples": [
501
- "<%= config.bin %> settings",
502
- "<%= config.bin %> settings --set brand_color=#0F3460",
503
- "<%= config.bin %> settings --json"
490
+ "<%= config.bin %> status",
491
+ "<%= config.bin %> status --json"
504
492
  ],
505
493
  "flags": {
506
494
  "json": {
@@ -515,18 +503,11 @@
515
503
  "name": "yes",
516
504
  "allowNo": false,
517
505
  "type": "boolean"
518
- },
519
- "set": {
520
- "description": "Set a setting (format: key=value)",
521
- "name": "set",
522
- "hasDynamicHelp": false,
523
- "multiple": false,
524
- "type": "option"
525
506
  }
526
507
  },
527
508
  "hasDynamicHelp": false,
528
509
  "hiddenAliases": [],
529
- "id": "settings",
510
+ "id": "status",
530
511
  "pluginAlias": "@mailmodo/cli",
531
512
  "pluginName": "@mailmodo/cli",
532
513
  "pluginType": "core",
@@ -536,17 +517,23 @@
536
517
  "relativePath": [
537
518
  "dist",
538
519
  "commands",
539
- "settings",
520
+ "status",
540
521
  "index.js"
541
522
  ]
542
523
  },
543
- "status": {
524
+ "preview": {
544
525
  "aliases": [],
545
- "args": {},
546
- "description": "View email performance metrics and quota usage",
526
+ "args": {
527
+ "id": {
528
+ "description": "Email ID to preview",
529
+ "name": "id"
530
+ }
531
+ },
532
+ "description": "Preview an email in browser, as text, or send a test",
547
533
  "examples": [
548
- "<%= config.bin %> status",
549
- "<%= config.bin %> status --json"
534
+ "<%= config.bin %> preview welcome",
535
+ "<%= config.bin %> preview welcome --text",
536
+ "<%= config.bin %> preview welcome --send me@example.com"
550
537
  ],
551
538
  "flags": {
552
539
  "json": {
@@ -561,11 +548,24 @@
561
548
  "name": "yes",
562
549
  "allowNo": false,
563
550
  "type": "boolean"
551
+ },
552
+ "send": {
553
+ "description": "Send test email to this address",
554
+ "name": "send",
555
+ "hasDynamicHelp": false,
556
+ "multiple": false,
557
+ "type": "option"
558
+ },
559
+ "text": {
560
+ "description": "Output plain text version (for AI agents)",
561
+ "name": "text",
562
+ "allowNo": false,
563
+ "type": "boolean"
564
564
  }
565
565
  },
566
566
  "hasDynamicHelp": false,
567
567
  "hiddenAliases": [],
568
- "id": "status",
568
+ "id": "preview",
569
569
  "pluginAlias": "@mailmodo/cli",
570
570
  "pluginName": "@mailmodo/cli",
571
571
  "pluginType": "core",
@@ -575,10 +575,10 @@
575
575
  "relativePath": [
576
576
  "dist",
577
577
  "commands",
578
- "status",
578
+ "preview",
579
579
  "index.js"
580
580
  ]
581
581
  }
582
582
  },
583
- "version": "0.0.8"
583
+ "version": "0.0.9"
584
584
  }
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.8",
4
+ "version": "0.0.9",
5
5
  "author": "provishalk",
6
6
  "bin": {
7
7
  "mailmodo": "bin/run.js"