@knocklabs/cli 0.3.1 → 1.0.0

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.
Files changed (69) hide show
  1. package/README.md +343 -55
  2. package/dist/commands/branch/delete.js +4 -1
  3. package/dist/commands/branch/merge.js +82 -0
  4. package/dist/commands/channel/list.js +73 -0
  5. package/dist/commands/environment/list.js +73 -0
  6. package/dist/commands/guide/new.js +276 -0
  7. package/dist/commands/guide/open.js +106 -0
  8. package/dist/commands/guide/pull.js +5 -6
  9. package/dist/commands/guide/push.js +1 -1
  10. package/dist/commands/guide/validate.js +1 -1
  11. package/dist/commands/init.js +108 -0
  12. package/dist/commands/layout/new.js +228 -0
  13. package/dist/commands/layout/open.js +106 -0
  14. package/dist/commands/layout/pull.js +5 -6
  15. package/dist/commands/layout/push.js +1 -1
  16. package/dist/commands/layout/validate.js +1 -1
  17. package/dist/commands/message-type/new.js +228 -0
  18. package/dist/commands/message-type/open.js +106 -0
  19. package/dist/commands/message-type/pull.js +5 -6
  20. package/dist/commands/message-type/push.js +1 -1
  21. package/dist/commands/message-type/validate.js +1 -1
  22. package/dist/commands/partial/new.js +274 -0
  23. package/dist/commands/partial/open.js +106 -0
  24. package/dist/commands/partial/pull.js +5 -6
  25. package/dist/commands/partial/push.js +1 -1
  26. package/dist/commands/partial/validate.js +1 -1
  27. package/dist/commands/pull.js +7 -2
  28. package/dist/commands/push.js +6 -4
  29. package/dist/commands/translation/pull.js +1 -1
  30. package/dist/commands/translation/push.js +1 -1
  31. package/dist/commands/translation/validate.js +1 -1
  32. package/dist/commands/workflow/new.js +179 -54
  33. package/dist/commands/workflow/open.js +106 -0
  34. package/dist/commands/workflow/pull.js +6 -8
  35. package/dist/commands/workflow/push.js +1 -1
  36. package/dist/commands/workflow/validate.js +1 -1
  37. package/dist/lib/api-v1.js +23 -2
  38. package/dist/lib/auth.js +1 -1
  39. package/dist/lib/base-command.js +18 -15
  40. package/dist/lib/helpers/project-config.js +158 -0
  41. package/dist/lib/helpers/request.js +1 -2
  42. package/dist/lib/helpers/string.js +4 -4
  43. package/dist/lib/helpers/typegen.js +1 -1
  44. package/dist/lib/marshal/email-layout/generator.js +152 -0
  45. package/dist/lib/marshal/email-layout/helpers.js +6 -9
  46. package/dist/lib/marshal/email-layout/index.js +1 -0
  47. package/dist/lib/marshal/email-layout/writer.js +15 -3
  48. package/dist/lib/marshal/guide/generator.js +163 -0
  49. package/dist/lib/marshal/guide/helpers.js +6 -10
  50. package/dist/lib/marshal/guide/index.js +1 -0
  51. package/dist/lib/marshal/guide/writer.js +5 -9
  52. package/dist/lib/marshal/message-type/generator.js +139 -0
  53. package/dist/lib/marshal/message-type/helpers.js +6 -10
  54. package/dist/lib/marshal/message-type/index.js +1 -0
  55. package/dist/lib/marshal/message-type/writer.js +5 -1
  56. package/dist/lib/marshal/partial/generator.js +159 -0
  57. package/dist/lib/marshal/partial/helpers.js +6 -10
  58. package/dist/lib/marshal/partial/index.js +1 -0
  59. package/dist/lib/marshal/partial/writer.js +3 -0
  60. package/dist/lib/marshal/translation/helpers.js +6 -10
  61. package/dist/lib/marshal/translation/processor.isomorphic.js +4 -4
  62. package/dist/lib/marshal/translation/writer.js +2 -2
  63. package/dist/lib/marshal/workflow/generator.js +175 -19
  64. package/dist/lib/marshal/workflow/helpers.js +7 -10
  65. package/dist/lib/run-context/loader.js +5 -0
  66. package/dist/lib/templates.js +131 -0
  67. package/dist/lib/urls.js +16 -0
  68. package/oclif.manifest.json +1446 -547
  69. package/package.json +11 -9
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return Init;
9
+ }
10
+ });
11
+ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
12
+ const _enquirer = /*#__PURE__*/ _interop_require_default(require("enquirer"));
13
+ const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
14
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
15
+ const _projectconfig = require("../lib/helpers/project-config");
16
+ function _define_property(obj, key, value) {
17
+ if (key in obj) {
18
+ Object.defineProperty(obj, key, {
19
+ value: value,
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true
23
+ });
24
+ } else {
25
+ obj[key] = value;
26
+ }
27
+ return obj;
28
+ }
29
+ function _interop_require_default(obj) {
30
+ return obj && obj.__esModule ? obj : {
31
+ default: obj
32
+ };
33
+ }
34
+ function _getRequireWildcardCache(nodeInterop) {
35
+ if (typeof WeakMap !== "function") return null;
36
+ var cacheBabelInterop = new WeakMap();
37
+ var cacheNodeInterop = new WeakMap();
38
+ return (_getRequireWildcardCache = function(nodeInterop) {
39
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
40
+ })(nodeInterop);
41
+ }
42
+ function _interop_require_wildcard(obj, nodeInterop) {
43
+ if (!nodeInterop && obj && obj.__esModule) {
44
+ return obj;
45
+ }
46
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
47
+ return {
48
+ default: obj
49
+ };
50
+ }
51
+ var cache = _getRequireWildcardCache(nodeInterop);
52
+ if (cache && cache.has(obj)) {
53
+ return cache.get(obj);
54
+ }
55
+ var newObj = {
56
+ __proto__: null
57
+ };
58
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
59
+ for(var key in obj){
60
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
61
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
62
+ if (desc && (desc.get || desc.set)) {
63
+ Object.defineProperty(newObj, key, desc);
64
+ } else {
65
+ newObj[key] = obj[key];
66
+ }
67
+ }
68
+ }
69
+ newObj.default = obj;
70
+ if (cache) {
71
+ cache.set(obj, newObj);
72
+ }
73
+ return newObj;
74
+ }
75
+ class Init extends _basecommand.default {
76
+ async run() {
77
+ const configPath = _nodepath.resolve(process.cwd(), _projectconfig.PROJECT_CONFIG_FILE_NAME);
78
+ // 1. Check if knock.json already exists
79
+ const configExists = await _fsextra.pathExists(configPath);
80
+ if (configExists) {
81
+ this.error(`A ${_projectconfig.PROJECT_CONFIG_FILE_NAME} file already exists in this directory. Aborting.`);
82
+ }
83
+ // 2. Prompt user for the knock directory location
84
+ const { knockDir } = await _enquirer.default.prompt({
85
+ type: "input",
86
+ name: "knockDir",
87
+ message: "Where do you want to store your Knock resources?",
88
+ initial: ".knock"
89
+ });
90
+ // 3. Create the knock directory and resource subdirectories
91
+ const knockDirPath = _nodepath.resolve(process.cwd(), knockDir);
92
+ await _fsextra.ensureDir(knockDirPath);
93
+ // 4. Write the knock.json configuration file
94
+ await _fsextra.outputJson(configPath, {
95
+ $schema: "https://schemas.knock.app/cli/knock.json",
96
+ knockDir
97
+ }, {
98
+ spaces: 2
99
+ });
100
+ this.log(`‣ Successfully initialized Knock project at ${process.cwd()}`);
101
+ this.log(`‣ Resources directory: ${knockDir}`);
102
+ }
103
+ constructor(...args){
104
+ super(...args), _define_property(this, "requiresAuth", false);
105
+ }
106
+ }
107
+ _define_property(Init, "summary", "Initialize a new Knock project with a knock.json configuration file.");
108
+ _define_property(Init, "description", "Creates a knock.json configuration file in the current directory " + "to store project-level settings like the knock resources directory.");
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return EmailLayoutNew;
9
+ }
10
+ });
11
+ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
12
+ const _core = require("@oclif/core");
13
+ const _enquirer = require("enquirer");
14
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
15
+ const _const = require("../../lib/helpers/const");
16
+ const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
17
+ const _projectconfig = require("../../lib/helpers/project-config");
18
+ const _string = require("../../lib/helpers/string");
19
+ const _ux = require("../../lib/helpers/ux");
20
+ const _emaillayout = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/marshal/email-layout"));
21
+ const _runcontext = require("../../lib/run-context");
22
+ const _push = /*#__PURE__*/ _interop_require_default(require("./push"));
23
+ function _define_property(obj, key, value) {
24
+ if (key in obj) {
25
+ Object.defineProperty(obj, key, {
26
+ value: value,
27
+ enumerable: true,
28
+ configurable: true,
29
+ writable: true
30
+ });
31
+ } else {
32
+ obj[key] = value;
33
+ }
34
+ return obj;
35
+ }
36
+ function _interop_require_default(obj) {
37
+ return obj && obj.__esModule ? obj : {
38
+ default: obj
39
+ };
40
+ }
41
+ function _getRequireWildcardCache(nodeInterop) {
42
+ if (typeof WeakMap !== "function") return null;
43
+ var cacheBabelInterop = new WeakMap();
44
+ var cacheNodeInterop = new WeakMap();
45
+ return (_getRequireWildcardCache = function(nodeInterop) {
46
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
47
+ })(nodeInterop);
48
+ }
49
+ function _interop_require_wildcard(obj, nodeInterop) {
50
+ if (!nodeInterop && obj && obj.__esModule) {
51
+ return obj;
52
+ }
53
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
54
+ return {
55
+ default: obj
56
+ };
57
+ }
58
+ var cache = _getRequireWildcardCache(nodeInterop);
59
+ if (cache && cache.has(obj)) {
60
+ return cache.get(obj);
61
+ }
62
+ var newObj = {
63
+ __proto__: null
64
+ };
65
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
66
+ for(var key in obj){
67
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
68
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
69
+ if (desc && (desc.get || desc.set)) {
70
+ Object.defineProperty(newObj, key, desc);
71
+ } else {
72
+ newObj[key] = obj[key];
73
+ }
74
+ }
75
+ }
76
+ newObj.default = obj;
77
+ if (cache) {
78
+ cache.set(obj, newObj);
79
+ }
80
+ return newObj;
81
+ }
82
+ class EmailLayoutNew extends _basecommand.default {
83
+ async run() {
84
+ const { flags } = this.props;
85
+ const { resourceDir } = this.runContext;
86
+ // 1. Ensure we aren't in any existing resource directory already.
87
+ if (resourceDir) {
88
+ return this.error(`Cannot create a new email layout inside an existing ${resourceDir.type} directory`);
89
+ }
90
+ // 2. Prompt for name and key if not provided
91
+ let name = flags.name;
92
+ let key = flags.key;
93
+ if (!name) {
94
+ const nameResponse = await (0, _enquirer.prompt)({
95
+ type: "input",
96
+ name: "name",
97
+ message: "Email layout name",
98
+ validate: (value)=>{
99
+ if (!value || value.trim().length === 0) {
100
+ return "Email layout name is required";
101
+ }
102
+ return true;
103
+ }
104
+ });
105
+ name = nameResponse.name;
106
+ }
107
+ if (!key) {
108
+ const keyResponse = await (0, _enquirer.prompt)({
109
+ type: "input",
110
+ name: "key",
111
+ message: "Email layout key (immutable slug)",
112
+ initial: (0, _string.slugify)(name),
113
+ validate: (value)=>{
114
+ if (!value || value.trim().length === 0) {
115
+ return "Email layout key is required";
116
+ }
117
+ const keyError = _emaillayout.validateEmailLayoutKey(value);
118
+ if (keyError) {
119
+ return `Invalid email layout key: ${keyError}`;
120
+ }
121
+ return true;
122
+ }
123
+ });
124
+ key = keyResponse.key;
125
+ }
126
+ // Validate the email layout key
127
+ const emailLayoutKeyError = _emaillayout.validateEmailLayoutKey(key);
128
+ if (emailLayoutKeyError) {
129
+ return this.error(`Invalid email layout key \`${key}\` (${emailLayoutKeyError})`);
130
+ }
131
+ const emailLayoutDirCtx = await this.getEmailLayoutDirContext(key);
132
+ const promptMessage = emailLayoutDirCtx.exists ? `Found \`${emailLayoutDirCtx.key}\` at ${emailLayoutDirCtx.abspath}, overwrite?` : `Create a new email layout directory \`${emailLayoutDirCtx.key}\` at ${emailLayoutDirCtx.abspath}?`;
133
+ // Check if the email layout directory already exists, and prompt to confirm if not.
134
+ const input = flags.force || await (0, _ux.promptToConfirm)(promptMessage);
135
+ if (!input) return;
136
+ // Generate the email layout either from a template or from scratch
137
+ await (flags.template ? this.fromTemplate(emailLayoutDirCtx, name, flags.template) : this.fromScratch(emailLayoutDirCtx, name));
138
+ if (flags.push) {
139
+ _ux.spinner.start("‣ Pushing email layout to Knock");
140
+ try {
141
+ await _push.default.run([
142
+ key
143
+ ]);
144
+ } catch (error) {
145
+ this.error(`Failed to push email layout to Knock: ${error}`);
146
+ } finally{
147
+ _ux.spinner.stop();
148
+ }
149
+ }
150
+ this.log(`‣ Successfully created email layout \`${key}\``);
151
+ }
152
+ async fromTemplate(emailLayoutDirCtx, name, templateString) {
153
+ // When being called from the template string, we want to try and generate
154
+ // the email layout from the provided template.
155
+ _ux.spinner.start(`‣ Generating email layout from template \`${templateString}\``);
156
+ try {
157
+ await _emaillayout.generateEmailLayoutFromTemplate(emailLayoutDirCtx, templateString, {
158
+ name
159
+ });
160
+ } catch (error) {
161
+ this.error(`Failed to generate email layout from template: ${error}`);
162
+ } finally{
163
+ _ux.spinner.stop();
164
+ }
165
+ }
166
+ async fromScratch(emailLayoutDirCtx, name) {
167
+ // Generate the email layout directory with scaffolded content
168
+ await _emaillayout.generateEmailLayoutDir(emailLayoutDirCtx, {
169
+ name
170
+ });
171
+ }
172
+ async getEmailLayoutDirContext(emailLayoutKey) {
173
+ const { resourceDir, cwd: runCwd } = this.runContext;
174
+ // Inside an existing resource dir, use it if valid for the target email layout.
175
+ if (resourceDir) {
176
+ const target = {
177
+ commandId: _basecommand.default.id,
178
+ type: "email_layout",
179
+ key: emailLayoutKey
180
+ };
181
+ return (0, _runcontext.ensureResourceDirForTarget)(resourceDir, target);
182
+ }
183
+ // Default to knock project config first if present, otherwise cwd.
184
+ const dirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "email_layout", runCwd);
185
+ // Not inside any existing email layout directory, which means either create a
186
+ // new email layout directory in the cwd, or update it if there is one already.
187
+ if (emailLayoutKey) {
188
+ const dirPath = _nodepath.resolve(dirCtx.abspath, emailLayoutKey);
189
+ const exists = await _emaillayout.isEmailLayoutDir(dirPath);
190
+ return {
191
+ type: "email_layout",
192
+ key: emailLayoutKey,
193
+ abspath: dirPath,
194
+ exists
195
+ };
196
+ }
197
+ // Not in any email layout directory, nor an email layout key arg was given so error.
198
+ return this.error("Missing 1 required arg:\nemailLayoutKey");
199
+ }
200
+ }
201
+ _define_property(EmailLayoutNew, "summary", "Create a new email layout with a minimal configuration.");
202
+ _define_property(EmailLayoutNew, "flags", {
203
+ name: _core.Flags.string({
204
+ summary: "The name of the email layout",
205
+ char: "n"
206
+ }),
207
+ key: _core.Flags.string({
208
+ summary: "The key of the email layout",
209
+ char: "k"
210
+ }),
211
+ environment: _core.Flags.string({
212
+ summary: "The environment to create the email layout in. Defaults to development.",
213
+ default: _const.KnockEnv.Development
214
+ }),
215
+ branch: _flag.branch,
216
+ force: _core.Flags.boolean({
217
+ summary: "Force the creation of the email layout directory without confirmation."
218
+ }),
219
+ push: _core.Flags.boolean({
220
+ summary: "Whether or not to push the email layout to Knock after creation.",
221
+ default: false,
222
+ char: "p"
223
+ }),
224
+ template: _core.Flags.string({
225
+ summary: "The template to use for the email layout. Should be `email-layouts/{key}`."
226
+ })
227
+ });
228
+ _define_property(EmailLayoutNew, "args", {});
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return LayoutOpen;
9
+ }
10
+ });
11
+ const _core = require("@oclif/core");
12
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
13
+ const _browser = require("../../lib/helpers/browser");
14
+ const _error = require("../../lib/helpers/error");
15
+ const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
16
+ const _request = require("../../lib/helpers/request");
17
+ const _urls = require("../../lib/urls");
18
+ function _define_property(obj, key, value) {
19
+ if (key in obj) {
20
+ Object.defineProperty(obj, key, {
21
+ value: value,
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true
25
+ });
26
+ } else {
27
+ obj[key] = value;
28
+ }
29
+ return obj;
30
+ }
31
+ function _interop_require_default(obj) {
32
+ return obj && obj.__esModule ? obj : {
33
+ default: obj
34
+ };
35
+ }
36
+ function _getRequireWildcardCache(nodeInterop) {
37
+ if (typeof WeakMap !== "function") return null;
38
+ var cacheBabelInterop = new WeakMap();
39
+ var cacheNodeInterop = new WeakMap();
40
+ return (_getRequireWildcardCache = function(nodeInterop) {
41
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
42
+ })(nodeInterop);
43
+ }
44
+ function _interop_require_wildcard(obj, nodeInterop) {
45
+ if (!nodeInterop && obj && obj.__esModule) {
46
+ return obj;
47
+ }
48
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
49
+ return {
50
+ default: obj
51
+ };
52
+ }
53
+ var cache = _getRequireWildcardCache(nodeInterop);
54
+ if (cache && cache.has(obj)) {
55
+ return cache.get(obj);
56
+ }
57
+ var newObj = {
58
+ __proto__: null
59
+ };
60
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
61
+ for(var key in obj){
62
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
63
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
64
+ if (desc && (desc.get || desc.set)) {
65
+ Object.defineProperty(newObj, key, desc);
66
+ } else {
67
+ newObj[key] = obj[key];
68
+ }
69
+ }
70
+ }
71
+ newObj.default = obj;
72
+ if (cache) {
73
+ cache.set(obj, newObj);
74
+ }
75
+ return newObj;
76
+ }
77
+ class LayoutOpen extends _basecommand.default {
78
+ async run() {
79
+ const whoamiResp = await this.apiV1.whoami();
80
+ if (!(0, _request.isSuccessResp)(whoamiResp)) {
81
+ const message = (0, _request.formatErrorRespMessage)(whoamiResp);
82
+ _core.ux.error(new _error.ApiError(message));
83
+ }
84
+ const { account_slug } = whoamiResp.data;
85
+ const { layoutKey } = this.props.args;
86
+ const { environment, branch } = this.props.flags;
87
+ const envOrBranch = branch !== null && branch !== void 0 ? branch : environment;
88
+ const url = (0, _urls.viewLayoutUrl)(this.sessionContext.dashboardOrigin, account_slug, envOrBranch, layoutKey);
89
+ this.log(`‣ Opening layout \`${layoutKey}\` in the Knock dashboard...`);
90
+ this.log(` ${url}`);
91
+ await _browser.browser.openUrl(url);
92
+ }
93
+ }
94
+ _define_property(LayoutOpen, "summary", "Open a layout in the Knock dashboard.");
95
+ _define_property(LayoutOpen, "flags", {
96
+ environment: _core.Flags.string({
97
+ default: "development",
98
+ summary: "The environment to use."
99
+ }),
100
+ branch: _flag.branch
101
+ });
102
+ _define_property(LayoutOpen, "args", {
103
+ layoutKey: _core.Args.string({
104
+ required: true
105
+ })
106
+ });
@@ -16,6 +16,7 @@ const _error = require("../../lib/helpers/error");
16
16
  const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers/flag"));
17
17
  const _objectisomorphic = require("../../lib/helpers/object.isomorphic");
18
18
  const _page = require("../../lib/helpers/page");
19
+ const _projectconfig = require("../../lib/helpers/project-config");
19
20
  const _request = require("../../lib/helpers/request");
20
21
  const _ux = require("../../lib/helpers/ux");
21
22
  const _emaillayout = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/marshal/email-layout"));
@@ -119,11 +120,8 @@ class EmailLayoutPull extends _basecommand.default {
119
120
  // Pull all email layouts
120
121
  async pullAllEmailLayouts() {
121
122
  const { flags } = this.props;
122
- const defaultToCwd = {
123
- abspath: this.runContext.cwd,
124
- exists: true
125
- };
126
- const targetDirCtx = flags["layouts-dir"] || defaultToCwd;
123
+ const layoutsIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "email_layout", this.runContext.cwd);
124
+ const targetDirCtx = flags["layouts-dir"] || layoutsIndexDirCtx;
127
125
  const prompt = targetDirCtx.exists ? `Pull latest layouts into ${targetDirCtx.abspath}?\n This will overwrite the contents of this directory.` : `Create a new layouts directory at ${targetDirCtx.abspath}?`;
128
126
  const input = flags.force || await (0, _ux.promptToConfirm)(prompt);
129
127
  if (!input) return;
@@ -171,10 +169,11 @@ class EmailLayoutPull extends _basecommand.default {
171
169
  };
172
170
  return (0, _runcontext.ensureResourceDirForTarget)(resourceDir, target);
173
171
  }
172
+ const layoutsIndexDirCtx = await (0, _projectconfig.resolveResourceDir)(this.projectConfig, "email_layout", runCwd);
174
173
  // Not inside any existing email layout directory, which means either create a
175
174
  // new email layout directory in the cwd, or update it if there is one already.
176
175
  if (emailLayoutKey) {
177
- const dirPath = _nodepath.resolve(runCwd, emailLayoutKey);
176
+ const dirPath = _nodepath.resolve(layoutsIndexDirCtx.abspath, emailLayoutKey);
178
177
  const exists = await _emaillayout.isEmailLayoutDir(dirPath);
179
178
  return {
180
179
  type: "email_layout",
@@ -83,7 +83,7 @@ class EmailLayoutPush extends _basecommand.default {
83
83
  async run() {
84
84
  const { flags } = this.props;
85
85
  // 1. First read all layout directories found for the given command.
86
- const target = await _emaillayout.ensureValidCommandTarget(this.props, this.runContext);
86
+ const target = await _emaillayout.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
87
87
  const [layouts, readErrors] = await _emaillayout.readAllForCommandTarget(target, {
88
88
  withExtractedFiles: true
89
89
  });
@@ -80,7 +80,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
80
80
  class EmailLayoutValidate extends _basecommand.default {
81
81
  async run() {
82
82
  // 1. Read all layout directories found for the given command.
83
- const target = await _emaillayout.ensureValidCommandTarget(this.props, this.runContext);
83
+ const target = await _emaillayout.ensureValidCommandTarget(this.props, this.runContext, this.projectConfig);
84
84
  const [layouts, readErrors] = await _emaillayout.readAllForCommandTarget(target, {
85
85
  withExtractedFiles: true
86
86
  });