@mailmodo/cli 0.0.7 → 0.0.8
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.
- package/bin/dev.js +16 -10
- package/bin/run.js +2 -2
- package/dist/commands/billing/index.js +10 -3
- package/dist/commands/contacts/index.js +7 -2
- package/dist/commands/deploy/index.js +6 -3
- package/dist/commands/domain/index.js +9 -3
- package/dist/commands/edit/index.js +12 -5
- package/dist/commands/emails/index.js +3 -1
- package/dist/commands/init/index.js +48 -15
- package/dist/commands/logs/index.js +4 -1
- package/dist/commands/preview/index.js +10 -3
- package/dist/commands/settings/index.js +2 -1
- package/dist/lib/api-client.js +3 -3
- package/dist/lib/base-command.js +5 -1
- package/dist/lib/config.js +1 -0
- package/dist/lib/yaml-config.js +5 -1
- package/oclif.manifest.json +28 -28
- package/package.json +1 -1
package/bin/dev.js
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {spawnSync} from 'node:child_process'
|
|
4
|
-
import {fileURLToPath} from 'node:url'
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
5
|
|
|
6
|
-
import {execute} from '@oclif/core'
|
|
6
|
+
import { execute } from '@oclif/core';
|
|
7
7
|
|
|
8
8
|
if (process.env.MAILMODO_DEV_TSX) {
|
|
9
|
-
await execute({development: true, dir: import.meta.url})
|
|
9
|
+
await execute({ development: true, dir: import.meta.url });
|
|
10
10
|
} else {
|
|
11
|
-
const scriptPath = fileURLToPath(import.meta.url)
|
|
12
|
-
const result = spawnSync(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
const scriptPath = fileURLToPath(import.meta.url);
|
|
12
|
+
const result = spawnSync(
|
|
13
|
+
process.execPath,
|
|
14
|
+
['--import', 'tsx', scriptPath, ...process.argv.slice(2)],
|
|
15
|
+
{
|
|
16
|
+
env: { ...process.env, MAILMODO_DEV_TSX: '1' },
|
|
17
|
+
stdio: 'inherit',
|
|
18
|
+
}
|
|
19
|
+
);
|
|
16
20
|
|
|
17
21
|
if (result.status !== 0) {
|
|
18
|
-
throw new Error(
|
|
22
|
+
throw new Error(
|
|
23
|
+
`dev bootstrap failed with exit code ${result.status ?? 1}`
|
|
24
|
+
);
|
|
19
25
|
}
|
|
20
26
|
}
|
package/bin/run.js
CHANGED
|
@@ -12,8 +12,13 @@ export default class Billing extends BaseCommand {
|
|
|
12
12
|
];
|
|
13
13
|
static flags = {
|
|
14
14
|
...BaseCommand.baseFlags,
|
|
15
|
-
cap: Flags.integer({
|
|
16
|
-
|
|
15
|
+
cap: Flags.integer({
|
|
16
|
+
description: 'Set monthly block cap (max blocks to auto-charge)',
|
|
17
|
+
}),
|
|
18
|
+
status: Flags.boolean({
|
|
19
|
+
default: false,
|
|
20
|
+
description: 'Show billing status only',
|
|
21
|
+
}),
|
|
17
22
|
};
|
|
18
23
|
async run() {
|
|
19
24
|
const { flags } = await this.parse(Billing);
|
|
@@ -79,7 +84,9 @@ export default class Billing extends BaseCommand {
|
|
|
79
84
|
* @param {boolean} jsonOutput - Whether to output JSON instead of formatted text.
|
|
80
85
|
*/
|
|
81
86
|
async setCap(cap, jsonOutput) {
|
|
82
|
-
const response = await this.apiClient.patch(API_ENDPOINTS.BILLING_CAP, {
|
|
87
|
+
const response = await this.apiClient.patch(API_ENDPOINTS.BILLING_CAP, {
|
|
88
|
+
cap,
|
|
89
|
+
});
|
|
83
90
|
if (!response.ok) {
|
|
84
91
|
this.handleApiError(response);
|
|
85
92
|
}
|
|
@@ -13,8 +13,13 @@ export default class Contacts extends BaseCommand {
|
|
|
13
13
|
];
|
|
14
14
|
static flags = {
|
|
15
15
|
...BaseCommand.baseFlags,
|
|
16
|
-
delete: Flags.string({
|
|
17
|
-
|
|
16
|
+
delete: Flags.string({
|
|
17
|
+
description: 'GDPR hard delete a contact by email',
|
|
18
|
+
}),
|
|
19
|
+
export: Flags.boolean({
|
|
20
|
+
default: false,
|
|
21
|
+
description: 'Export all contacts as CSV',
|
|
22
|
+
}),
|
|
18
23
|
search: Flags.string({ description: 'Search for a contact by email' }),
|
|
19
24
|
};
|
|
20
25
|
async run() {
|
|
@@ -28,7 +28,10 @@ export default class Deploy extends BaseCommand {
|
|
|
28
28
|
this.log(` This is a one-time setup. Takes about 5 minutes.\n`);
|
|
29
29
|
}
|
|
30
30
|
if (!flags.yes) {
|
|
31
|
-
const setupNow = await confirm({
|
|
31
|
+
const setupNow = await confirm({
|
|
32
|
+
default: true,
|
|
33
|
+
message: 'Set up your sending domain now?',
|
|
34
|
+
});
|
|
32
35
|
if (!setupNow) {
|
|
33
36
|
this.log(`\n Sequences saved but ${chalk.yellow('NOT deployed')}.`);
|
|
34
37
|
this.log(` Emails will not send until your domain is verified.`);
|
|
@@ -83,7 +86,7 @@ export default class Deploy extends BaseCommand {
|
|
|
83
86
|
this.log(` ${chalk.dim('// On user signup:')}`);
|
|
84
87
|
this.log(` ${chalk.dim("track('user.signup', { email, first_name, app_url })")}\n`);
|
|
85
88
|
this.log(` ${chalk.dim('// When user creates a project:')}`);
|
|
86
|
-
this.log(` ${chalk.dim(
|
|
89
|
+
this.log(` ${chalk.dim('identify(email, { has_created_project: true })')}\n`);
|
|
87
90
|
this.log(` ${chalk.dim('// On trial expiry:')}`);
|
|
88
91
|
this.log(` ${chalk.dim("track('user.trial_expiry', { email, first_name })")}\n`);
|
|
89
92
|
this.log(` Full SDK docs: ${chalk.cyan('mailmodo.com/docs/sdk')}\n`);
|
|
@@ -115,7 +118,7 @@ export default class Deploy extends BaseCommand {
|
|
|
115
118
|
});
|
|
116
119
|
senderEmail = await input({
|
|
117
120
|
message: 'Sender email address:',
|
|
118
|
-
validate: (v) =>
|
|
121
|
+
validate: (v) => v?.includes('@') ? true : 'Please enter a valid email',
|
|
119
122
|
});
|
|
120
123
|
address = await input({
|
|
121
124
|
message: 'Business address (required by law for email footers):',
|
|
@@ -13,8 +13,14 @@ export default class Domain extends BaseCommand {
|
|
|
13
13
|
];
|
|
14
14
|
static flags = {
|
|
15
15
|
...BaseCommand.baseFlags,
|
|
16
|
-
status: Flags.boolean({
|
|
17
|
-
|
|
16
|
+
status: Flags.boolean({
|
|
17
|
+
default: false,
|
|
18
|
+
description: 'Show domain health status',
|
|
19
|
+
}),
|
|
20
|
+
verify: Flags.boolean({
|
|
21
|
+
default: false,
|
|
22
|
+
description: 'Verify DNS records',
|
|
23
|
+
}),
|
|
18
24
|
};
|
|
19
25
|
async run() {
|
|
20
26
|
const { flags } = await this.parse(Domain);
|
|
@@ -58,7 +64,7 @@ export default class Domain extends BaseCommand {
|
|
|
58
64
|
senderEmail = await input({
|
|
59
65
|
default: yamlConfig.project?.fromEmail,
|
|
60
66
|
message: 'Sender email address:',
|
|
61
|
-
validate: (v) =>
|
|
67
|
+
validate: (v) => v?.includes('@') ? true : 'Please enter a valid email',
|
|
62
68
|
});
|
|
63
69
|
address = await input({
|
|
64
70
|
default: yamlConfig.project?.address,
|
|
@@ -3,7 +3,7 @@ import { confirm, input } from '@inquirer/prompts';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { BaseCommand } from '../../lib/base-command.js';
|
|
5
5
|
import { API_ENDPOINTS } from '../../lib/constants.js';
|
|
6
|
-
import { loadTemplate, saveTemplate, saveYaml } from '../../lib/yaml-config.js';
|
|
6
|
+
import { loadTemplate, saveTemplate, saveYaml, } from '../../lib/yaml-config.js';
|
|
7
7
|
export default class Edit extends BaseCommand {
|
|
8
8
|
static args = {
|
|
9
9
|
id: Args.string({ description: 'Email ID to edit', required: true }),
|
|
@@ -15,7 +15,9 @@ export default class Edit extends BaseCommand {
|
|
|
15
15
|
];
|
|
16
16
|
static flags = {
|
|
17
17
|
...BaseCommand.baseFlags,
|
|
18
|
-
change: Flags.string({
|
|
18
|
+
change: Flags.string({
|
|
19
|
+
description: 'Natural language description of the change',
|
|
20
|
+
}),
|
|
19
21
|
};
|
|
20
22
|
async run() {
|
|
21
23
|
const { args, flags } = await this.parse(Edit);
|
|
@@ -34,7 +36,7 @@ export default class Edit extends BaseCommand {
|
|
|
34
36
|
if (!changeDescription) {
|
|
35
37
|
changeDescription = await input({
|
|
36
38
|
message: 'What do you want to change?',
|
|
37
|
-
validate: (value) =>
|
|
39
|
+
validate: (value) => value?.trim() ? true : 'Please describe the change',
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
42
|
const response = await this.apiClient.post(API_ENDPOINTS.EDIT, {
|
|
@@ -61,7 +63,10 @@ export default class Edit extends BaseCommand {
|
|
|
61
63
|
this.log(` ${chalk.green(`+ ${newSubject}`)}`);
|
|
62
64
|
}
|
|
63
65
|
if (!flags.yes) {
|
|
64
|
-
const accepted = await confirm({
|
|
66
|
+
const accepted = await confirm({
|
|
67
|
+
default: true,
|
|
68
|
+
message: 'Accept changes?',
|
|
69
|
+
});
|
|
65
70
|
if (!accepted) {
|
|
66
71
|
this.log('\n Changes discarded.\n');
|
|
67
72
|
return;
|
|
@@ -83,7 +88,9 @@ export default class Edit extends BaseCommand {
|
|
|
83
88
|
if (flags.json) {
|
|
84
89
|
this.log(JSON.stringify({
|
|
85
90
|
diff: {
|
|
86
|
-
subject: oldSubject === newSubject
|
|
91
|
+
subject: oldSubject === newSubject
|
|
92
|
+
? undefined
|
|
93
|
+
: { new: newSubject, old: oldSubject },
|
|
87
94
|
},
|
|
88
95
|
email,
|
|
89
96
|
status: 'updated',
|
|
@@ -25,7 +25,9 @@ export default class Emails extends BaseCommand {
|
|
|
25
25
|
const id = email.id.padEnd(maxIdLen + 2);
|
|
26
26
|
const trigger = `trigger: ${email.trigger}`.padEnd(maxTriggerLen + 12);
|
|
27
27
|
const delay = `delay: ${email.delay}`;
|
|
28
|
-
const condition = email.condition
|
|
28
|
+
const condition = email.condition
|
|
29
|
+
? chalk.dim(` [if ${email.condition}]`)
|
|
30
|
+
: '';
|
|
29
31
|
this.log(` ${chalk.cyan(id)} ${trigger} ${delay}${condition}`);
|
|
30
32
|
}
|
|
31
33
|
this.log('');
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
|
-
import {
|
|
2
|
+
import { editor, input, select } from '@inquirer/prompts';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { BaseCommand } from '../../lib/base-command.js';
|
|
5
5
|
import { API_ENDPOINTS, DEFAULT_BRAND_COLOR } from '../../lib/constants.js';
|
|
6
|
-
import { saveTemplate, saveYaml } from '../../lib/yaml-config.js';
|
|
6
|
+
import { saveTemplate, saveYaml, } from '../../lib/yaml-config.js';
|
|
7
7
|
function isValidUrl(value) {
|
|
8
8
|
try {
|
|
9
9
|
return Boolean(new URL(value));
|
|
@@ -55,20 +55,51 @@ export default class Init extends BaseCommand {
|
|
|
55
55
|
}
|
|
56
56
|
this.log('');
|
|
57
57
|
}
|
|
58
|
+
let analysisPayload = analysis;
|
|
58
59
|
if (!flags.yes) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
const userAction = await select({
|
|
61
|
+
choices: [
|
|
62
|
+
{ name: 'Yes - continue with this result', value: 'yes' },
|
|
63
|
+
{ name: 'No - stop here', value: 'no' },
|
|
64
|
+
{ name: 'Edit - update the result before continuing', value: 'edit' },
|
|
65
|
+
],
|
|
66
|
+
message: 'Does this look right?',
|
|
67
|
+
});
|
|
68
|
+
if (userAction === 'no') {
|
|
69
|
+
this.log(`\n Stopped. Run ${chalk.cyan('mailmodo init')} again when you are ready.\n`);
|
|
62
70
|
return;
|
|
63
71
|
}
|
|
72
|
+
if (userAction === 'edit') {
|
|
73
|
+
const editedAnalysis = await editor({
|
|
74
|
+
default: JSON.stringify(analysis, null, 2),
|
|
75
|
+
message: 'Edit the analysis JSON. Save and close to continue.',
|
|
76
|
+
postfix: '.json',
|
|
77
|
+
validate(value) {
|
|
78
|
+
if (!value?.trim())
|
|
79
|
+
return 'Edited analysis cannot be empty';
|
|
80
|
+
try {
|
|
81
|
+
JSON.parse(value);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return 'Please provide valid JSON';
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
analysisPayload = JSON.parse(editedAnalysis);
|
|
90
|
+
}
|
|
64
91
|
}
|
|
92
|
+
this.log('analysisPayload', analysisPayload);
|
|
65
93
|
this.log('\n Generating emails...\n');
|
|
66
|
-
const generateResponse = await this.apiClient.post(API_ENDPOINTS.GENERATE, {
|
|
94
|
+
const generateResponse = await this.apiClient.post(API_ENDPOINTS.GENERATE, {
|
|
95
|
+
analysis: analysisPayload,
|
|
96
|
+
productUrl,
|
|
97
|
+
});
|
|
67
98
|
if (!generateResponse.ok) {
|
|
68
99
|
this.handleApiError(generateResponse);
|
|
69
100
|
}
|
|
70
101
|
const generatedEmails = generateResponse.data?.emails || [];
|
|
71
|
-
const emailConfigs =
|
|
102
|
+
const emailConfigs = analysisPayload.recommendedEmails.map((rec, index) => {
|
|
72
103
|
const generated = generatedEmails[index];
|
|
73
104
|
return {
|
|
74
105
|
delay: rec.delay || '0',
|
|
@@ -77,27 +108,29 @@ export default class Init extends BaseCommand {
|
|
|
77
108
|
...(rec.condition ? { condition: rec.condition } : {}),
|
|
78
109
|
subject: generated?.subject || `Email for ${rec.id}`,
|
|
79
110
|
template: `mailmodo/${rec.id}.html`,
|
|
80
|
-
...(generated?.previewText
|
|
111
|
+
...(generated?.previewText
|
|
112
|
+
? { previewText: generated.previewText }
|
|
113
|
+
: {}),
|
|
81
114
|
goal: rec.goal,
|
|
82
115
|
};
|
|
83
116
|
});
|
|
84
117
|
const yamlConfig = {
|
|
85
118
|
emails: emailConfigs,
|
|
86
119
|
project: {
|
|
87
|
-
brandColor:
|
|
120
|
+
brandColor: analysisPayload.brand?.color || DEFAULT_BRAND_COLOR,
|
|
88
121
|
emailStyle: 'branded',
|
|
89
122
|
fromEmail: '',
|
|
90
|
-
fromName: `Team ${
|
|
91
|
-
logoUrl:
|
|
92
|
-
name:
|
|
123
|
+
fromName: `Team ${analysisPayload.productName}`,
|
|
124
|
+
logoUrl: analysisPayload.brand?.logoUrl || '',
|
|
125
|
+
name: analysisPayload.productName,
|
|
93
126
|
replyTo: '',
|
|
94
|
-
type:
|
|
127
|
+
type: analysisPayload.pricingModel,
|
|
95
128
|
url: productUrl,
|
|
96
129
|
webhookUrl: '',
|
|
97
130
|
},
|
|
98
131
|
};
|
|
99
132
|
await saveYaml(yamlConfig);
|
|
100
|
-
const templateSaves =
|
|
133
|
+
const templateSaves = analysisPayload.recommendedEmails.flatMap((rec, index) => {
|
|
101
134
|
const generated = generatedEmails[index];
|
|
102
135
|
const saves = [];
|
|
103
136
|
if (generated?.html) {
|
|
@@ -111,7 +144,7 @@ export default class Init extends BaseCommand {
|
|
|
111
144
|
await Promise.all(templateSaves);
|
|
112
145
|
if (flags.json) {
|
|
113
146
|
this.log(JSON.stringify({
|
|
114
|
-
brandDetected:
|
|
147
|
+
brandDetected: analysisPayload.brand,
|
|
115
148
|
emails: emailConfigs,
|
|
116
149
|
emailsCreated: emailConfigs.length,
|
|
117
150
|
style: yamlConfig.project.emailStyle,
|
|
@@ -13,7 +13,10 @@ export default class Logs extends BaseCommand {
|
|
|
13
13
|
static flags = {
|
|
14
14
|
...BaseCommand.baseFlags,
|
|
15
15
|
email: Flags.string({ description: 'Filter logs by contact email' }),
|
|
16
|
-
failed: Flags.boolean({
|
|
16
|
+
failed: Flags.boolean({
|
|
17
|
+
default: false,
|
|
18
|
+
description: 'Show only failed/bounced events',
|
|
19
|
+
}),
|
|
17
20
|
};
|
|
18
21
|
async run() {
|
|
19
22
|
const { flags } = await this.parse(Logs);
|
|
@@ -63,7 +63,10 @@ export default class Preview extends BaseCommand {
|
|
|
63
63
|
static flags = {
|
|
64
64
|
...BaseCommand.baseFlags,
|
|
65
65
|
send: Flags.string({ description: 'Send test email to this address' }),
|
|
66
|
-
text: Flags.boolean({
|
|
66
|
+
text: Flags.boolean({
|
|
67
|
+
default: false,
|
|
68
|
+
description: 'Output plain text version (for AI agents)',
|
|
69
|
+
}),
|
|
67
70
|
};
|
|
68
71
|
async run() {
|
|
69
72
|
const { args, flags } = await this.parse(Preview);
|
|
@@ -97,7 +100,9 @@ export default class Preview extends BaseCommand {
|
|
|
97
100
|
* and CI pipelines that cannot open a browser.
|
|
98
101
|
*/
|
|
99
102
|
async renderText(email, templateHtml, sampleData, jsonOutput) {
|
|
100
|
-
const rendered = templateHtml
|
|
103
|
+
const rendered = templateHtml
|
|
104
|
+
? renderTemplate(templateHtml, sampleData)
|
|
105
|
+
: '';
|
|
101
106
|
const plainText = htmlToText(rendered);
|
|
102
107
|
if (jsonOutput) {
|
|
103
108
|
this.log(JSON.stringify({
|
|
@@ -139,7 +144,9 @@ export default class Preview extends BaseCommand {
|
|
|
139
144
|
* template, then opens the user's default browser to view it.
|
|
140
145
|
*/
|
|
141
146
|
async startPreviewServer(email, templateHtml, sampleData, jsonOutput) {
|
|
142
|
-
const rendered = templateHtml
|
|
147
|
+
const rendered = templateHtml
|
|
148
|
+
? renderTemplate(templateHtml, sampleData)
|
|
149
|
+
: '<p>No template found.</p>';
|
|
143
150
|
const wrapperHtml = `<!DOCTYPE html>
|
|
144
151
|
<html>
|
|
145
152
|
<head>
|
|
@@ -50,7 +50,8 @@ export default class Settings extends BaseCommand {
|
|
|
50
50
|
if (!(propKey in project)) {
|
|
51
51
|
this.error(`Unknown setting: ${key}`);
|
|
52
52
|
}
|
|
53
|
-
project[propKey] =
|
|
53
|
+
project[propKey] =
|
|
54
|
+
propKey === 'monthlyCap' ? Number(value) : value;
|
|
54
55
|
await saveYaml(yamlConfig);
|
|
55
56
|
if (flags.json) {
|
|
56
57
|
this.log(JSON.stringify({ [propKey]: value, status: 'updated' }, null, 2));
|
package/dist/lib/api-client.js
CHANGED
|
@@ -38,7 +38,7 @@ export class ApiClient {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
const headers = {
|
|
41
|
-
|
|
41
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
42
42
|
'Content-Type': 'application/json',
|
|
43
43
|
'User-Agent': '@mailmodo/cli',
|
|
44
44
|
};
|
|
@@ -69,7 +69,7 @@ export class ApiClient {
|
|
|
69
69
|
data: {},
|
|
70
70
|
error: isConnectionError
|
|
71
71
|
? 'Cannot connect to Mailmodo API. The API service may not be available yet.'
|
|
72
|
-
:
|
|
72
|
+
: err?.message || 'An unexpected network error occurred.',
|
|
73
73
|
ok: false,
|
|
74
74
|
status: 0,
|
|
75
75
|
};
|
|
@@ -93,7 +93,7 @@ export class ApiClient {
|
|
|
93
93
|
const response = await fetch(url.toString(), {
|
|
94
94
|
body: formData,
|
|
95
95
|
headers: {
|
|
96
|
-
|
|
96
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
97
97
|
'User-Agent': '@mailmodo/cli',
|
|
98
98
|
},
|
|
99
99
|
method: 'POST',
|
package/dist/lib/base-command.js
CHANGED
|
@@ -11,7 +11,11 @@ import { loadYaml } from './yaml-config.js';
|
|
|
11
11
|
export class BaseCommand extends Command {
|
|
12
12
|
static baseFlags = {
|
|
13
13
|
json: Flags.boolean({ default: false, description: 'Output as JSON' }),
|
|
14
|
-
yes: Flags.boolean({
|
|
14
|
+
yes: Flags.boolean({
|
|
15
|
+
char: 'y',
|
|
16
|
+
default: false,
|
|
17
|
+
description: 'Skip confirmation prompts',
|
|
18
|
+
}),
|
|
15
19
|
};
|
|
16
20
|
apiClient;
|
|
17
21
|
/**
|
package/dist/lib/config.js
CHANGED
|
@@ -13,6 +13,7 @@ const CONFIG_FILE = join(CONFIG_DIR, 'config');
|
|
|
13
13
|
* or null if the config file does not exist or is corrupted.
|
|
14
14
|
*/
|
|
15
15
|
export async function loadConfig() {
|
|
16
|
+
console.log('Loading config from', CONFIG_FILE);
|
|
16
17
|
if (!existsSync(CONFIG_FILE))
|
|
17
18
|
return null;
|
|
18
19
|
try {
|
package/dist/lib/yaml-config.js
CHANGED
|
@@ -31,7 +31,11 @@ export async function loadYaml(cwd) {
|
|
|
31
31
|
*/
|
|
32
32
|
export async function saveYaml(config, cwd) {
|
|
33
33
|
const filePath = join(cwd || process.cwd(), YAML_FILE);
|
|
34
|
-
const content = dump(config, {
|
|
34
|
+
const content = dump(config, {
|
|
35
|
+
lineWidth: -1,
|
|
36
|
+
noRefs: true,
|
|
37
|
+
quotingType: '"',
|
|
38
|
+
});
|
|
35
39
|
await writeFile(filePath, content);
|
|
36
40
|
}
|
|
37
41
|
/**
|
package/oclif.manifest.json
CHANGED
|
@@ -205,19 +205,13 @@
|
|
|
205
205
|
"index.js"
|
|
206
206
|
]
|
|
207
207
|
},
|
|
208
|
-
"
|
|
208
|
+
"emails": {
|
|
209
209
|
"aliases": [],
|
|
210
|
-
"args": {
|
|
211
|
-
|
|
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",
|
|
210
|
+
"args": {},
|
|
211
|
+
"description": "List and view configured email sequences",
|
|
218
212
|
"examples": [
|
|
219
|
-
"<%= config.bin %>
|
|
220
|
-
"<%= config.bin %>
|
|
213
|
+
"<%= config.bin %> emails",
|
|
214
|
+
"<%= config.bin %> emails --json"
|
|
221
215
|
],
|
|
222
216
|
"flags": {
|
|
223
217
|
"json": {
|
|
@@ -232,18 +226,11 @@
|
|
|
232
226
|
"name": "yes",
|
|
233
227
|
"allowNo": false,
|
|
234
228
|
"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"
|
|
242
229
|
}
|
|
243
230
|
},
|
|
244
231
|
"hasDynamicHelp": false,
|
|
245
232
|
"hiddenAliases": [],
|
|
246
|
-
"id": "
|
|
233
|
+
"id": "emails",
|
|
247
234
|
"pluginAlias": "@mailmodo/cli",
|
|
248
235
|
"pluginName": "@mailmodo/cli",
|
|
249
236
|
"pluginType": "core",
|
|
@@ -253,17 +240,23 @@
|
|
|
253
240
|
"relativePath": [
|
|
254
241
|
"dist",
|
|
255
242
|
"commands",
|
|
256
|
-
"
|
|
243
|
+
"emails",
|
|
257
244
|
"index.js"
|
|
258
245
|
]
|
|
259
246
|
},
|
|
260
|
-
"
|
|
247
|
+
"edit": {
|
|
261
248
|
"aliases": [],
|
|
262
|
-
"args": {
|
|
263
|
-
|
|
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",
|
|
264
257
|
"examples": [
|
|
265
|
-
"<%= config.bin %>
|
|
266
|
-
"<%= config.bin %>
|
|
258
|
+
"<%= config.bin %> edit welcome",
|
|
259
|
+
"<%= config.bin %> edit welcome --change \"make subject more urgent\" --yes"
|
|
267
260
|
],
|
|
268
261
|
"flags": {
|
|
269
262
|
"json": {
|
|
@@ -278,11 +271,18 @@
|
|
|
278
271
|
"name": "yes",
|
|
279
272
|
"allowNo": false,
|
|
280
273
|
"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": "
|
|
285
|
+
"id": "edit",
|
|
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
|
-
"
|
|
295
|
+
"edit",
|
|
296
296
|
"index.js"
|
|
297
297
|
]
|
|
298
298
|
},
|
|
@@ -580,5 +580,5 @@
|
|
|
580
580
|
]
|
|
581
581
|
}
|
|
582
582
|
},
|
|
583
|
-
"version": "0.0.
|
|
583
|
+
"version": "0.0.8"
|
|
584
584
|
}
|