directus-template-cli 0.7.3 → 0.7.5

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 CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env -S node --loader ts-node/esm --disable-warning=ExperimentalWarning
2
2
 
3
- // eslint-disable-next-line n/shebang
4
3
  import {execute} from '@oclif/core'
5
4
 
6
5
  await execute({development: true, dir: import.meta.url})
package/bin/run.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ /* eslint-disable n/no-unpublished-bin */
2
3
 
3
4
  import {execute} from '@oclif/core'
4
5
 
@@ -7,6 +7,7 @@ export default class ApplyCommand extends BaseCommand {
7
7
  dashboards: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
8
  directusToken: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
9
  directusUrl: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ disableTelemetry: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
11
  extensions: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
12
  files: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
13
  flows: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -20,7 +21,6 @@ export default class ApplyCommand extends BaseCommand {
20
21
  userEmail: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
21
22
  userPassword: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
22
23
  users: import("@oclif/core/interfaces").BooleanFlag<boolean>;
23
- disableTelemetry: import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
24
  };
25
25
  /**
26
26
  * MAIN
@@ -1,20 +1,19 @@
1
+ import { intro, log, select, text } from '@clack/prompts';
1
2
  import { Flags, ux } from '@oclif/core';
2
- import { text, select, log, intro } from '@clack/prompts';
3
+ import chalk from 'chalk';
3
4
  import * as path from 'pathe';
4
- import { animatedBunny } from '../lib/utils/animated-bunny.js';
5
5
  import * as customFlags from '../flags/common.js';
6
- import { DIRECTUS_PINK, DIRECTUS_PURPLE, SEPARATOR } from '../lib/constants.js';
6
+ import { BSL_LICENSE_CTA, BSL_LICENSE_HEADLINE, BSL_LICENSE_TEXT, DIRECTUS_PINK, DIRECTUS_PURPLE, SEPARATOR } from '../lib/constants.js';
7
7
  import { validateInteractiveFlags, validateProgrammaticFlags } from '../lib/load/apply-flags.js';
8
8
  import apply from '../lib/load/index.js';
9
- import { getDirectusToken, getDirectusUrl, initializeDirectusApi, getDirectusEmailAndPassword } from '../lib/utils/auth.js';
9
+ import { animatedBunny } from '../lib/utils/animated-bunny.js';
10
+ import { getDirectusEmailAndPassword, getDirectusToken, getDirectusUrl, initializeDirectusApi } from '../lib/utils/auth.js';
10
11
  import catchError from '../lib/utils/catch-error.js';
11
12
  import { getCommunityTemplates, getGithubTemplate, getInteractiveLocalTemplate, getLocalTemplate } from '../lib/utils/get-template.js';
12
13
  import { logger } from '../lib/utils/logger.js';
13
14
  import openUrl from '../lib/utils/open-url.js';
14
- import chalk from 'chalk';
15
+ import { shutdown, track } from '../services/posthog.js';
15
16
  import { BaseCommand } from './base.js';
16
- import { track, shutdown } from '../services/posthog.js';
17
- import { BSL_LICENSE_HEADLINE, BSL_LICENSE_TEXT, BSL_LICENSE_CTA } from '../lib/constants.js';
18
17
  export default class ApplyCommand extends BaseCommand {
19
18
  static description = 'Apply a template to a blank Directus instance.';
20
19
  static examples = [
@@ -35,6 +34,7 @@ export default class ApplyCommand extends BaseCommand {
35
34
  }),
36
35
  directusToken: customFlags.directusToken,
37
36
  directusUrl: customFlags.directusUrl,
37
+ disableTelemetry: customFlags.disableTelemetry,
38
38
  extensions: Flags.boolean({
39
39
  allowNo: true,
40
40
  default: undefined,
@@ -88,7 +88,6 @@ export default class ApplyCommand extends BaseCommand {
88
88
  default: undefined,
89
89
  description: 'Load users',
90
90
  }),
91
- disableTelemetry: customFlags.disableTelemetry,
92
91
  };
93
92
  /**
94
93
  * MAIN
@@ -112,32 +111,25 @@ export default class ApplyCommand extends BaseCommand {
112
111
  await animatedBunny('Let\'s apply a template!');
113
112
  intro(`${chalk.bgHex(DIRECTUS_PURPLE).white.bold('Directus Template CLI')} - Apply Template`);
114
113
  const templateType = await select({
114
+ message: 'What type of template would you like to apply?',
115
115
  options: [
116
116
  { label: 'Community templates', value: 'community' },
117
117
  { label: 'From a local directory', value: 'local' },
118
118
  { label: 'From a public GitHub repository', value: 'github' },
119
119
  { label: 'Get premium templates', value: 'directus-plus' },
120
120
  ],
121
- message: 'What type of template would you like to apply?',
122
121
  });
123
122
  let template;
124
123
  switch (templateType) {
125
124
  case 'community': {
126
125
  const templates = await getCommunityTemplates();
127
126
  const selectedTemplate = await select({
128
- options: templates.map(t => ({ label: t.templateName, value: t })),
129
127
  message: 'Select a template.',
128
+ options: templates.map(t => ({ label: t.templateName, value: t })),
130
129
  });
131
130
  template = selectedTemplate;
132
131
  break;
133
132
  }
134
- case 'local': {
135
- const localTemplateDir = await text({
136
- message: 'What is the local template directory?',
137
- });
138
- template = await this.selectLocalTemplate(localTemplateDir);
139
- break;
140
- }
141
133
  case 'github': {
142
134
  const ghTemplateUrl = await text({
143
135
  message: 'What is the public GitHub repository URL?',
@@ -145,6 +137,13 @@ export default class ApplyCommand extends BaseCommand {
145
137
  template = await getGithubTemplate(ghTemplateUrl);
146
138
  break;
147
139
  }
140
+ case 'local': {
141
+ const localTemplateDir = await text({
142
+ message: 'What is the local template directory?',
143
+ });
144
+ template = await this.selectLocalTemplate(localTemplateDir);
145
+ break;
146
+ }
148
147
  case 'directus-plus': {
149
148
  openUrl('https://directus.io/plus?utm_source=directus-template-cli&utm_content=apply-command');
150
149
  log.info('Redirecting to Directus website.');
@@ -157,11 +156,11 @@ export default class ApplyCommand extends BaseCommand {
157
156
  validatedFlags.directusUrl = directusUrl;
158
157
  // Prompt for login method
159
158
  const loginMethod = await select({
159
+ message: 'How do you want to log in?',
160
160
  options: [
161
161
  { label: 'Directus Access Token', value: 'token' },
162
162
  { label: 'Email and Password', value: 'email' },
163
163
  ],
164
- message: 'How do you want to log in?',
165
164
  });
166
165
  if (loginMethod === 'token') {
167
166
  const directusToken = await getDirectusToken(directusUrl);
@@ -179,7 +178,7 @@ export default class ApplyCommand extends BaseCommand {
179
178
  if (!validatedFlags.disableTelemetry) {
180
179
  await track({
181
180
  command: 'apply',
182
- lifecycle: 'start',
181
+ config: this.config,
183
182
  distinctId: this.userConfig.distinctId,
184
183
  flags: {
185
184
  programmatic: false,
@@ -188,8 +187,8 @@ export default class ApplyCommand extends BaseCommand {
188
187
  // Include other relevant flags from validatedFlags if needed
189
188
  ...validatedFlags,
190
189
  },
190
+ lifecycle: 'start',
191
191
  runId: this.runId,
192
- config: this.config,
193
192
  });
194
193
  }
195
194
  await apply(template.directoryPath, validatedFlags);
@@ -198,15 +197,15 @@ export default class ApplyCommand extends BaseCommand {
198
197
  if (!validatedFlags.disableTelemetry) {
199
198
  await track({
200
199
  command: 'apply',
201
- lifecycle: 'complete',
200
+ config: this.config,
202
201
  distinctId: this.userConfig.distinctId,
203
202
  flags: {
204
203
  templateName: template.templateName,
205
204
  templateType,
206
205
  ...validatedFlags,
207
206
  },
207
+ lifecycle: 'complete',
208
208
  runId: this.runId,
209
- config: this.config,
210
209
  });
211
210
  await shutdown();
212
211
  }
@@ -233,14 +232,14 @@ export default class ApplyCommand extends BaseCommand {
233
232
  template = templates.find(t => t.templateName === validatedFlags.templateLocation) || templates[0];
234
233
  break;
235
234
  }
236
- case 'local': {
237
- template = await getLocalTemplate(validatedFlags.templateLocation);
238
- break;
239
- }
240
235
  case 'github': {
241
236
  template = await getGithubTemplate(validatedFlags.templateLocation);
242
237
  break;
243
238
  }
239
+ case 'local': {
240
+ template = await getLocalTemplate(validatedFlags.templateLocation);
241
+ break;
242
+ }
244
243
  default: {
245
244
  catchError('Invalid template type. Please check your template type.', {
246
245
  fatal: true,
@@ -255,7 +254,7 @@ export default class ApplyCommand extends BaseCommand {
255
254
  if (!validatedFlags.disableTelemetry) {
256
255
  await track({
257
256
  command: 'apply',
258
- lifecycle: 'start',
257
+ config: this.config,
259
258
  distinctId: this.userConfig.distinctId,
260
259
  flags: {
261
260
  programmatic: true,
@@ -263,8 +262,8 @@ export default class ApplyCommand extends BaseCommand {
263
262
  // Include other relevant flags from validatedFlags
264
263
  ...validatedFlags,
265
264
  },
265
+ lifecycle: 'start',
266
266
  runId: this.runId,
267
- config: this.config,
268
267
  });
269
268
  }
270
269
  await apply(template.directoryPath, validatedFlags);
@@ -273,15 +272,15 @@ export default class ApplyCommand extends BaseCommand {
273
272
  if (!validatedFlags.disableTelemetry) {
274
273
  await track({
275
274
  command: 'apply',
276
- lifecycle: 'complete',
275
+ config: this.config,
277
276
  distinctId: this.userConfig.distinctId,
278
277
  flags: {
279
278
  templateName: template.templateName,
280
279
  // Include other relevant flags from validatedFlags
281
280
  ...validatedFlags,
282
281
  },
282
+ lifecycle: 'complete',
283
283
  runId: this.runId,
284
- config: this.config,
285
284
  });
286
285
  await shutdown();
287
286
  }
@@ -306,11 +305,11 @@ export default class ApplyCommand extends BaseCommand {
306
305
  return templates[0];
307
306
  }
308
307
  const selectedTemplate = await select({
308
+ message: 'Multiple templates found. Please select one:',
309
309
  options: templates.map(t => ({
310
310
  label: `${t.templateName} (${path.basename(t.directoryPath)})`,
311
311
  value: t,
312
312
  })),
313
- message: 'Multiple templates found. Please select one:',
314
313
  });
315
314
  return selectedTemplate;
316
315
  }
@@ -1,16 +1,16 @@
1
1
  import { Command, type Config } from '@oclif/core';
2
2
  interface UserConfig {
3
- distinctId?: string | null;
3
+ distinctId?: null | string;
4
4
  }
5
5
  export declare abstract class BaseCommand extends Command {
6
6
  runId: string;
7
7
  userConfig: UserConfig;
8
8
  constructor(argv: string[], config: Config);
9
9
  init(): Promise<void>;
10
- private loadUserConfig;
11
10
  /**
12
11
  * Save the current user configuration to disk
13
12
  */
14
13
  protected saveUserConfig(): void;
14
+ private loadUserConfig;
15
15
  }
16
16
  export {};
@@ -14,15 +14,27 @@ export class BaseCommand extends Command {
14
14
  async init() {
15
15
  await super.init();
16
16
  const { flags } = await this.parse({
17
- flags: this.ctor.flags,
18
17
  args: this.ctor.args,
18
+ flags: this.ctor.flags,
19
19
  strict: false,
20
20
  });
21
21
  setExecutionContext({
22
- distinctId: this.userConfig.distinctId ?? undefined,
23
22
  disableTelemetry: flags?.disableTelemetry ?? false,
23
+ distinctId: this.userConfig.distinctId ?? undefined,
24
24
  });
25
25
  }
26
+ /**
27
+ * Save the current user configuration to disk
28
+ */
29
+ saveUserConfig() {
30
+ try {
31
+ const configPath = path.join(this.config.configDir, 'config.json');
32
+ fs.writeFileSync(configPath, JSON.stringify(this.userConfig, null, 2));
33
+ }
34
+ catch (error) {
35
+ this.warn(`Failed to save user config: ${error}`);
36
+ }
37
+ }
26
38
  loadUserConfig() {
27
39
  try {
28
40
  const configPath = path.join(this.config.configDir, 'config.json');
@@ -43,16 +55,4 @@ export class BaseCommand extends Command {
43
55
  this.warn(`Failed to load user config: ${error}`);
44
56
  }
45
57
  }
46
- /**
47
- * Save the current user configuration to disk
48
- */
49
- saveUserConfig() {
50
- try {
51
- const configPath = path.join(this.config.configDir, 'config.json');
52
- fs.writeFileSync(configPath, JSON.stringify(this.userConfig, null, 2));
53
- }
54
- catch (error) {
55
- this.warn(`Failed to save user config: ${error}`);
56
- }
57
- }
58
58
  }
@@ -2,12 +2,12 @@ import { BaseCommand } from './base.js';
2
2
  export interface ExtractFlags {
3
3
  directusToken: string;
4
4
  directusUrl: string;
5
+ disableTelemetry?: boolean;
5
6
  programmatic: boolean;
6
7
  templateLocation: string;
7
8
  templateName: string;
8
9
  userEmail: string;
9
10
  userPassword: string;
10
- disableTelemetry?: boolean;
11
11
  }
12
12
  export default class ExtractCommand extends BaseCommand {
13
13
  static description: string;
@@ -15,12 +15,12 @@ export default class ExtractCommand extends BaseCommand {
15
15
  static flags: {
16
16
  directusToken: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
17
17
  directusUrl: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
18
+ disableTelemetry: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
19
  programmatic: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
20
  templateLocation: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
20
21
  templateName: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
21
22
  userEmail: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
22
23
  userPassword: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
23
- disableTelemetry: import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
24
  };
25
25
  /**
26
26
  * Main run method for the ExtractCommand
@@ -1,18 +1,18 @@
1
- import { text, select, intro, log } from '@clack/prompts';
1
+ import { intro, log, select, text } from '@clack/prompts';
2
2
  import { ux } from '@oclif/core';
3
3
  import slugify from '@sindresorhus/slugify';
4
4
  import chalk from 'chalk';
5
5
  import fs from 'node:fs';
6
6
  import path from 'pathe';
7
7
  import * as customFlags from '../flags/common.js';
8
- import { DIRECTUS_PINK, DIRECTUS_PURPLE, SEPARATOR, BSL_LICENSE_TEXT, BSL_LICENSE_CTA, BSL_LICENSE_HEADLINE } from '../lib/constants.js';
9
- import { animatedBunny } from '../lib/utils/animated-bunny.js';
10
- import { BaseCommand } from './base.js';
11
- import { track, shutdown } from '../services/posthog.js';
8
+ import { BSL_LICENSE_CTA, BSL_LICENSE_HEADLINE, BSL_LICENSE_TEXT, DIRECTUS_PINK, DIRECTUS_PURPLE, SEPARATOR } from '../lib/constants.js';
12
9
  import extract from '../lib/extract/index.js';
13
- import { getDirectusToken, getDirectusUrl, initializeDirectusApi, validateAuthFlags, getDirectusEmailAndPassword } from '../lib/utils/auth.js';
10
+ import { animatedBunny } from '../lib/utils/animated-bunny.js';
11
+ import { getDirectusEmailAndPassword, getDirectusToken, getDirectusUrl, initializeDirectusApi, validateAuthFlags } from '../lib/utils/auth.js';
14
12
  import catchError from '../lib/utils/catch-error.js';
15
13
  import { generatePackageJsonContent, generateReadmeContent, } from '../lib/utils/template-defaults.js';
14
+ import { shutdown, track } from '../services/posthog.js';
15
+ import { BaseCommand } from './base.js';
16
16
  export default class ExtractCommand extends BaseCommand {
17
17
  static description = 'Extract a template from a Directus instance.';
18
18
  static examples = [
@@ -22,12 +22,12 @@ export default class ExtractCommand extends BaseCommand {
22
22
  static flags = {
23
23
  directusToken: customFlags.directusToken,
24
24
  directusUrl: customFlags.directusUrl,
25
+ disableTelemetry: customFlags.disableTelemetry,
25
26
  programmatic: customFlags.programmatic,
26
27
  templateLocation: customFlags.templateLocation,
27
28
  templateName: customFlags.templateName,
28
29
  userEmail: customFlags.userEmail,
29
30
  userPassword: customFlags.userPassword,
30
- disableTelemetry: customFlags.disableTelemetry,
31
31
  };
32
32
  /**
33
33
  * Main run method for the ExtractCommand
@@ -50,16 +50,16 @@ export default class ExtractCommand extends BaseCommand {
50
50
  if (!flags.disableTelemetry) {
51
51
  await track({
52
52
  command: 'extract',
53
- lifecycle: 'start',
53
+ config: this.config,
54
54
  distinctId: this.userConfig.distinctId,
55
55
  flags: {
56
- templateName,
57
- templateLocation: directory,
58
56
  directusUrl: flags.directusUrl,
59
57
  programmatic: flags.programmatic,
58
+ templateLocation: directory,
59
+ templateName,
60
60
  },
61
+ lifecycle: 'start',
61
62
  runId: this.runId,
62
- config: this.config,
63
63
  });
64
64
  }
65
65
  try {
@@ -88,16 +88,16 @@ export default class ExtractCommand extends BaseCommand {
88
88
  if (!flags.disableTelemetry) {
89
89
  await track({
90
90
  command: 'extract',
91
- lifecycle: 'complete',
91
+ config: this.config,
92
92
  distinctId: this.userConfig.distinctId,
93
93
  flags: {
94
- templateName,
95
- templateLocation: directory,
96
94
  directusUrl: flags.directusUrl,
97
95
  programmatic: flags.programmatic,
96
+ templateLocation: directory,
97
+ templateName,
98
98
  },
99
+ lifecycle: 'complete',
99
100
  runId: this.runId,
100
- config: this.config,
101
101
  });
102
102
  await shutdown();
103
103
  }
@@ -121,9 +121,9 @@ export default class ExtractCommand extends BaseCommand {
121
121
  placeholder: 'My Template',
122
122
  });
123
123
  const directory = await text({
124
- placeholder: `templates/${slugify(templateName)}`,
125
124
  defaultValue: `templates/${slugify(templateName)}`,
126
125
  message: "What directory would you like to extract the template to? If it doesn't exist, it will be created.",
126
+ placeholder: `templates/${slugify(templateName)}`,
127
127
  });
128
128
  ux.stdout(`You selected ${ux.colorize(DIRECTUS_PINK, directory)}`);
129
129
  ux.stdout(SEPARATOR);
@@ -132,11 +132,11 @@ export default class ExtractCommand extends BaseCommand {
132
132
  flags.directusUrl = directusUrl;
133
133
  // Prompt for login method
134
134
  const loginMethod = await select({
135
+ message: 'How do you want to log in?',
135
136
  options: [
136
137
  { label: 'Directus Access Token', value: 'token' },
137
138
  { label: 'Email and Password', value: 'email' },
138
139
  ],
139
- message: 'How do you want to log in?',
140
140
  });
141
141
  if (loginMethod === 'token') {
142
142
  const directusToken = await getDirectusToken(directusUrl);
@@ -1,11 +1,11 @@
1
1
  import { BaseCommand } from './base.js';
2
2
  export interface InitFlags {
3
+ disableTelemetry?: boolean;
3
4
  frontend?: string;
4
5
  gitInit?: boolean;
5
6
  installDeps?: boolean;
6
7
  overwriteDir?: boolean;
7
8
  template?: string;
8
- disableTelemetry?: boolean;
9
9
  }
10
10
  export interface InitArgs {
11
11
  directory: string;
@@ -19,12 +19,12 @@ export default class InitCommand extends BaseCommand {
19
19
  static description: string;
20
20
  static examples: string[];
21
21
  static flags: {
22
+ disableTelemetry: import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
23
  frontend: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
23
24
  gitInit: import("@oclif/core/interfaces").BooleanFlag<boolean>;
24
25
  installDeps: import("@oclif/core/interfaces").BooleanFlag<boolean>;
25
26
  overwriteDir: import("@oclif/core/interfaces").BooleanFlag<boolean>;
26
27
  template: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
27
- disableTelemetry: import("@oclif/core/interfaces").BooleanFlag<boolean>;
28
28
  };
29
29
  private targetDir;
30
30
  /**
@@ -1,6 +1,7 @@
1
- import { confirm, intro, select, text, isCancel, cancel, log as clackLog } from '@clack/prompts';
1
+ import { cancel, log as clackLog, confirm, intro, isCancel, select, text } from '@clack/prompts';
2
2
  import { Args, Flags, ux } from '@oclif/core';
3
3
  import chalk from 'chalk';
4
+ import { downloadTemplate } from 'giget';
4
5
  import fs from 'node:fs';
5
6
  import os from 'node:os';
6
7
  import path from 'pathe';
@@ -8,12 +9,11 @@ import { disableTelemetry } from '../flags/common.js';
8
9
  import { DIRECTUS_PURPLE } from '../lib/constants.js';
9
10
  import { init } from '../lib/init/index.js';
10
11
  import { animatedBunny } from '../lib/utils/animated-bunny.js';
11
- import { createGitHub } from '../services/github.js';
12
- import { readTemplateConfig } from '../lib/utils/template-config.js';
13
12
  import { createGigetString, parseGitHubUrl } from '../lib/utils/parse-github-url.js';
14
- import { downloadTemplate } from 'giget';
13
+ import { readTemplateConfig } from '../lib/utils/template-config.js';
14
+ import { createGitHub } from '../services/github.js';
15
+ import { shutdown, track } from '../services/posthog.js';
15
16
  import { BaseCommand } from './base.js';
16
- import { track, shutdown } from '../services/posthog.js';
17
17
  export default class InitCommand extends BaseCommand {
18
18
  static args = {
19
19
  directory: Args.directory({
@@ -30,6 +30,7 @@ export default class InitCommand extends BaseCommand {
30
30
  '$ directus-template-cli init my-project --frontend=nextjs --template=simple-cms',
31
31
  ];
32
32
  static flags = {
33
+ disableTelemetry,
33
34
  frontend: Flags.string({
34
35
  description: 'Frontend framework to use (e.g., nextjs, nuxt, astro)',
35
36
  }),
@@ -54,7 +55,6 @@ export default class InitCommand extends BaseCommand {
54
55
  template: Flags.string({
55
56
  description: 'Template name (e.g., simple-cms) or GitHub URL (e.g., https://github.com/directus-labs/starters/tree/main/simple-cms)',
56
57
  }),
57
- disableTelemetry: disableTelemetry,
58
58
  };
59
59
  targetDir = '.';
60
60
  /**
@@ -79,6 +79,15 @@ export default class InitCommand extends BaseCommand {
79
79
  // Show animated intro
80
80
  await animatedBunny('Let\'s create a new Directus project!');
81
81
  intro(`${chalk.bgHex(DIRECTUS_PURPLE).white.bold('Directus Template CLI')} - Create Project`);
82
+ // Check Docker availability before proceeding
83
+ const { createDocker } = await import('../services/docker.js');
84
+ const { DOCKER_CONFIG } = await import('../lib/init/config.js');
85
+ const dockerService = createDocker(DOCKER_CONFIG);
86
+ const dockerStatus = await dockerService.checkDocker();
87
+ if (!dockerStatus.installed || !dockerStatus.running) {
88
+ cancel(dockerStatus.message || 'Docker is required to initialize a Directus project.');
89
+ process.exit(1);
90
+ }
82
91
  // Create GitHub service
83
92
  const github = createGitHub();
84
93
  // If no dir is provided, ask for it
@@ -100,8 +109,8 @@ export default class InitCommand extends BaseCommand {
100
109
  }
101
110
  if (fs.existsSync(this.targetDir) && !flags.overwriteDir) {
102
111
  const overwriteDirResponse = await confirm({
103
- message: 'Directory already exists. Would you like to overwrite it?',
104
112
  initialValue: false,
113
+ message: 'Directory already exists. Would you like to overwrite it?',
105
114
  });
106
115
  if (isCancel(overwriteDirResponse) || overwriteDirResponse === false) {
107
116
  cancel('Project creation cancelled.');
@@ -120,9 +129,9 @@ export default class InitCommand extends BaseCommand {
120
129
  const templateResponse = await select({
121
130
  message: 'Which Directus backend template would you like to use?',
122
131
  options: availableTemplates.map(tmpl => ({
123
- value: tmpl.id, // The value submitted will be the ID (directory name)
124
- label: tmpl.name, // Display the friendly name
125
132
  hint: tmpl.description, // Show the description as a hint
133
+ label: tmpl.name, // Display the friendly name
134
+ value: tmpl.id, // The value submitted will be the ID (directory name)
126
135
  })),
127
136
  });
128
137
  if (isCancel(templateResponse)) {
@@ -164,13 +173,12 @@ export default class InitCommand extends BaseCommand {
164
173
  if (templateInfo?.frontendOptions.length > 0 && (!chosenFrontend || !templateInfo.frontendOptions.find(f => f.id === chosenFrontend))) {
165
174
  const frontendResponse = await select({
166
175
  message: 'Which frontend framework do you want to use?',
167
- options: [
168
- ...templateInfo.frontendOptions.map(frontend => ({
169
- label: frontend.name,
170
- value: frontend.id,
171
- })),
172
- // { label: 'No frontend', value: '' },
173
- ],
176
+ options: templateInfo.frontendOptions.map(frontend => ({
177
+ label: frontend.name,
178
+ value: frontend.id,
179
+ }))
180
+ // { label: 'No frontend', value: '' },
181
+ ,
174
182
  });
175
183
  if (isCancel(frontendResponse)) {
176
184
  cancel('Project creation cancelled.');
@@ -183,7 +191,7 @@ export default class InitCommand extends BaseCommand {
183
191
  finally {
184
192
  // Clean up temporary directory
185
193
  if (fs.existsSync(tempDir)) {
186
- fs.rmSync(tempDir, { recursive: true, force: true });
194
+ fs.rmSync(tempDir, { force: true, recursive: true });
187
195
  }
188
196
  }
189
197
  const installDepsResponse = await confirm({
@@ -207,17 +215,17 @@ export default class InitCommand extends BaseCommand {
207
215
  // Track the command start unless telemetry is disabled
208
216
  if (!flags.disableTelemetry) {
209
217
  await track({
210
- lifecycle: 'start',
211
- distinctId: this.userConfig.distinctId,
212
218
  command: 'init',
219
+ config: this.config,
220
+ distinctId: this.userConfig.distinctId,
213
221
  flags: {
214
222
  frontend: chosenFrontend,
215
223
  gitInit: initGit,
216
224
  installDeps,
217
225
  template,
218
226
  },
227
+ lifecycle: 'start',
219
228
  runId: this.runId,
220
- config: this.config,
221
229
  });
222
230
  }
223
231
  // Initialize the project
@@ -227,25 +235,25 @@ export default class InitCommand extends BaseCommand {
227
235
  frontend: chosenFrontend,
228
236
  gitInit: initGit,
229
237
  installDeps,
230
- template,
231
238
  overwriteDir: flags.overwriteDir,
239
+ template,
232
240
  },
233
241
  });
234
242
  // Track the command completion unless telemetry is disabled
235
243
  if (!flags.disableTelemetry) {
236
244
  await track({
237
245
  command: 'init',
238
- lifecycle: 'complete',
246
+ config: this.config,
239
247
  distinctId: this.userConfig.distinctId,
240
248
  flags: {
241
249
  frontend: chosenFrontend,
242
250
  gitInit: initGit,
243
251
  installDeps,
244
- template,
245
252
  overwriteDir: flags.overwriteDir,
253
+ template,
246
254
  },
255
+ lifecycle: 'complete',
247
256
  runId: this.runId,
248
- config: this.config,
249
257
  });
250
258
  await shutdown();
251
259
  }