@actuate-media/cli 0.4.0 → 0.4.2

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 (79) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +21 -10
  3. package/CHANGELOG.md +34 -0
  4. package/dist/__tests__/deployment-diagnostics.test.js +40 -0
  5. package/dist/__tests__/deployment-diagnostics.test.js.map +1 -1
  6. package/dist/__tests__/init.test.js.map +1 -1
  7. package/dist/__tests__/schema-fragment.test.js +1 -1
  8. package/dist/__tests__/schema-fragment.test.js.map +1 -1
  9. package/dist/__tests__/seed.test.js.map +1 -1
  10. package/dist/commands/db-init.d.ts +2 -2
  11. package/dist/commands/db-init.d.ts.map +1 -1
  12. package/dist/commands/db-init.js +32 -32
  13. package/dist/commands/db-init.js.map +1 -1
  14. package/dist/commands/db-status.d.ts +1 -1
  15. package/dist/commands/db-status.d.ts.map +1 -1
  16. package/dist/commands/db-status.js +33 -33
  17. package/dist/commands/db-status.js.map +1 -1
  18. package/dist/commands/doctor.d.ts +1 -1
  19. package/dist/commands/doctor.d.ts.map +1 -1
  20. package/dist/commands/doctor.js +55 -38
  21. package/dist/commands/doctor.js.map +1 -1
  22. package/dist/commands/export.d.ts +1 -1
  23. package/dist/commands/export.d.ts.map +1 -1
  24. package/dist/commands/export.js +32 -32
  25. package/dist/commands/export.js.map +1 -1
  26. package/dist/commands/generate.d.ts +1 -1
  27. package/dist/commands/generate.d.ts.map +1 -1
  28. package/dist/commands/generate.js +8 -8
  29. package/dist/commands/generate.js.map +1 -1
  30. package/dist/commands/import.d.ts +1 -1
  31. package/dist/commands/import.d.ts.map +1 -1
  32. package/dist/commands/import.js +55 -58
  33. package/dist/commands/import.js.map +1 -1
  34. package/dist/commands/init.d.ts.map +1 -1
  35. package/dist/commands/init.js.map +1 -1
  36. package/dist/commands/migrate.d.ts +1 -1
  37. package/dist/commands/migrate.d.ts.map +1 -1
  38. package/dist/commands/migrate.js +18 -24
  39. package/dist/commands/migrate.js.map +1 -1
  40. package/dist/commands/seed.d.ts +1 -1
  41. package/dist/commands/seed.d.ts.map +1 -1
  42. package/dist/commands/seed.js +156 -157
  43. package/dist/commands/seed.js.map +1 -1
  44. package/dist/commands/update-check.d.ts +1 -1
  45. package/dist/commands/update-check.d.ts.map +1 -1
  46. package/dist/commands/update-check.js +34 -27
  47. package/dist/commands/update-check.js.map +1 -1
  48. package/dist/commands/upgrade.d.ts +1 -1
  49. package/dist/commands/upgrade.d.ts.map +1 -1
  50. package/dist/commands/upgrade.js +41 -34
  51. package/dist/commands/upgrade.js.map +1 -1
  52. package/dist/deployment/diagnostics.d.ts +2 -0
  53. package/dist/deployment/diagnostics.d.ts.map +1 -1
  54. package/dist/deployment/diagnostics.js +50 -1
  55. package/dist/deployment/diagnostics.js.map +1 -1
  56. package/dist/index.js +15 -15
  57. package/dist/index.js.map +1 -1
  58. package/dist/utils/logger.d.ts.map +1 -1
  59. package/dist/utils/logger.js +5 -5
  60. package/dist/utils/logger.js.map +1 -1
  61. package/package.json +3 -3
  62. package/src/__tests__/deployment-diagnostics.test.ts +100 -50
  63. package/src/__tests__/init.test.ts +17 -17
  64. package/src/__tests__/schema-fragment.test.ts +29 -25
  65. package/src/__tests__/seed.test.ts +25 -25
  66. package/src/commands/db-init.ts +59 -59
  67. package/src/commands/db-status.ts +70 -68
  68. package/src/commands/doctor.ts +110 -86
  69. package/src/commands/export.ts +65 -75
  70. package/src/commands/generate.ts +14 -16
  71. package/src/commands/import.ts +125 -140
  72. package/src/commands/init.ts +14 -14
  73. package/src/commands/migrate.ts +29 -35
  74. package/src/commands/seed.ts +294 -300
  75. package/src/commands/update-check.ts +77 -72
  76. package/src/commands/upgrade.ts +92 -85
  77. package/src/deployment/diagnostics.ts +124 -61
  78. package/src/index.ts +30 -30
  79. package/src/utils/logger.ts +10 -10
@@ -1,17 +1,17 @@
1
- export type DiagnosticStatus = 'pass' | 'warn' | 'fail';
1
+ export type DiagnosticStatus = 'pass' | 'warn' | 'fail'
2
2
 
3
3
  export interface DiagnosticCheck {
4
- id: string;
5
- label: string;
6
- status: DiagnosticStatus;
7
- message: string;
8
- fix?: string;
9
- docs?: string;
4
+ id: string
5
+ label: string
6
+ status: DiagnosticStatus
7
+ message: string
8
+ fix?: string
9
+ docs?: string
10
10
  }
11
11
 
12
12
  export interface DiagnosticReport {
13
- status: DiagnosticStatus;
14
- checks: DiagnosticCheck[];
13
+ status: DiagnosticStatus
14
+ checks: DiagnosticCheck[]
15
15
  }
16
16
 
17
17
  export const REQUIRED_CMS_MODELS = [
@@ -29,100 +29,127 @@ export const REQUIRED_CMS_MODELS = [
29
29
  'ScriptTag',
30
30
  'PageTemplate',
31
31
  'SavedSection',
32
- ] as const;
32
+ ] as const
33
33
 
34
34
  export const REQUIRED_ENV_VARS = [
35
35
  'DATABASE_URL',
36
36
  'CMS_SECRET',
37
37
  'CMS_ENCRYPTION_KEY',
38
38
  'NEXT_PUBLIC_SITE_URL',
39
- ] as const;
39
+ ] as const
40
40
 
41
41
  export interface DiagnosticInput {
42
- schemaModels: Set<string>;
43
- schemaContent?: string;
44
- env: Record<string, string | undefined>;
45
- packageManager: string;
46
- schemaPath: string;
47
- mode?: 'doctor' | 'deploy';
42
+ schemaModels: Set<string>
43
+ schemaContent?: string
44
+ configContent?: string
45
+ env: Record<string, string | undefined>
46
+ packageManager: string
47
+ schemaPath: string
48
+ mode?: 'doctor' | 'deploy'
48
49
  }
49
50
 
50
51
  export function missingModels(schemaModels: Set<string>): string[] {
51
- return REQUIRED_CMS_MODELS.filter((model) => !schemaModels.has(model));
52
+ return REQUIRED_CMS_MODELS.filter((model) => !schemaModels.has(model))
52
53
  }
53
54
 
54
55
  export function missingEnvVars(env: Record<string, string | undefined>): string[] {
55
- return REQUIRED_ENV_VARS.filter((name) => !env[name]);
56
+ return REQUIRED_ENV_VARS.filter((name) => !env[name])
56
57
  }
57
58
 
58
59
  export function detectPackageManager(lockfiles: Set<string>): string {
59
- if (lockfiles.has('pnpm-lock.yaml')) return 'pnpm';
60
- if (lockfiles.has('yarn.lock')) return 'yarn';
61
- if (lockfiles.has('package-lock.json')) return 'npm';
62
- return 'npm';
60
+ if (lockfiles.has('pnpm-lock.yaml')) return 'pnpm'
61
+ if (lockfiles.has('yarn.lock')) return 'yarn'
62
+ if (lockfiles.has('package-lock.json')) return 'npm'
63
+ return 'npm'
63
64
  }
64
65
 
65
66
  export function createDiagnosticReport(input: DiagnosticInput): DiagnosticReport {
66
- const checks: DiagnosticCheck[] = [];
67
- const models = missingModels(input.schemaModels);
68
- const envVars = input.mode === 'deploy'
69
- ? [...missingEnvVars(input.env), ...(!input.env.DIRECT_DATABASE_URL ? ['DIRECT_DATABASE_URL'] : [])]
70
- : missingEnvVars(input.env);
71
- const fieldProblems = input.schemaContent ? missingCriticalFields(input.schemaContent) : [];
67
+ const checks: DiagnosticCheck[] = []
68
+ const models = missingModels(input.schemaModels)
69
+ const envVars =
70
+ input.mode === 'deploy'
71
+ ? [
72
+ ...missingEnvVars(input.env),
73
+ ...(!input.env.DIRECT_DATABASE_URL ? ['DIRECT_DATABASE_URL'] : []),
74
+ ]
75
+ : missingEnvVars(input.env)
76
+ const fieldProblems = input.schemaContent ? missingCriticalFields(input.schemaContent) : []
77
+ const pageBuilderRisk = input.configContent
78
+ ? detectsFlatMarketingPageModel(input.configContent)
79
+ : false
72
80
 
73
81
  checks.push({
74
82
  id: 'schema-models',
75
83
  label: 'Prisma schema models',
76
84
  status: models.length === 0 ? 'pass' : 'fail',
77
- message: models.length === 0
78
- ? 'All deploy-critical Actuate models are present.'
79
- : `Missing deploy-critical Actuate models: ${models.join(', ')}.`,
80
- fix: models.length === 0
81
- ? undefined
82
- : `Run \`actuate db:init --schema ${input.schemaPath}\` for new schemas, or update the existing Actuate block from the database setup docs, then create and apply a Prisma migration.`,
85
+ message:
86
+ models.length === 0
87
+ ? 'All deploy-critical Actuate models are present.'
88
+ : `Missing deploy-critical Actuate models: ${models.join(', ')}.`,
89
+ fix:
90
+ models.length === 0
91
+ ? undefined
92
+ : `Run \`actuate db:init --schema ${input.schemaPath}\` for new schemas, or update the existing Actuate block from the database setup docs, then create and apply a Prisma migration.`,
83
93
  docs: 'https://actuatecms.dev/docs/database-setup',
84
- });
94
+ })
85
95
 
86
96
  checks.push({
87
97
  id: 'schema-fields',
88
98
  label: 'Prisma schema fields',
89
99
  status: fieldProblems.length === 0 ? 'pass' : 'fail',
90
- message: fieldProblems.length === 0
91
- ? 'Deploy-critical model fields are present.'
92
- : `Missing deploy-critical model fields: ${fieldProblems.join(', ')}.`,
93
- fix: fieldProblems.length === 0
94
- ? undefined
95
- : 'Update the Actuate Prisma models from the database setup docs, then create and apply a Prisma migration.',
100
+ message:
101
+ fieldProblems.length === 0
102
+ ? 'Deploy-critical model fields are present.'
103
+ : `Missing deploy-critical model fields: ${fieldProblems.join(', ')}.`,
104
+ fix:
105
+ fieldProblems.length === 0
106
+ ? undefined
107
+ : 'Update the Actuate Prisma models from the database setup docs, then create and apply a Prisma migration.',
96
108
  docs: 'https://actuatecms.dev/docs/database-setup',
97
- });
109
+ })
98
110
 
99
111
  checks.push({
100
112
  id: 'environment',
101
113
  label: 'Required environment variables',
102
114
  status: envVars.length === 0 ? 'pass' : 'fail',
103
- message: envVars.length === 0
104
- ? 'Required deployment environment variables are set.'
105
- : `Missing required environment variables: ${envVars.join(', ')}.`,
106
- fix: envVars.length === 0
107
- ? undefined
108
- : `Set missing environment variables before deploying: ${envVars.join(', ')}.`,
115
+ message:
116
+ envVars.length === 0
117
+ ? 'Required deployment environment variables are set.'
118
+ : `Missing required environment variables: ${envVars.join(', ')}.`,
119
+ fix:
120
+ envVars.length === 0
121
+ ? undefined
122
+ : `Set missing environment variables before deploying: ${envVars.join(', ')}.`,
109
123
  docs: 'https://actuatecms.dev/docs/environment-variables',
110
- });
124
+ })
111
125
 
112
126
  checks.push({
113
127
  id: 'package-manager',
114
128
  label: 'Package manager',
115
129
  status: 'pass',
116
130
  message: `Detected ${input.packageManager}. Use the same package manager for install, build, and deploy checks.`,
117
- });
131
+ })
132
+
133
+ checks.push({
134
+ id: 'design-first-page-builder',
135
+ label: 'Design-first page builder fit',
136
+ status: pageBuilderRisk ? 'warn' : 'pass',
137
+ message: pageBuilderRisk
138
+ ? 'A pages collection appears to model a designed marketing page as flat hero/body/CTA fields. For marketing, service, location, landing, and homepage routes, prefer a page-builder template with blocks, saved sections, forms, media, and seeded layout content unless field-mapped mode was explicitly approved.'
139
+ : 'No obvious flat marketing-page model detected in the Actuate config.',
140
+ fix: pageBuilderRisk
141
+ ? 'Create a design inventory and block coverage plan, then model section-based pages with page-builder content or document why field-mapped mode is intentional.'
142
+ : undefined,
143
+ docs: pageBuilderRisk ? 'https://actuatecms.dev/docs/design-first-page-builder' : undefined,
144
+ })
118
145
 
119
146
  const status: DiagnosticStatus = checks.some((check) => check.status === 'fail')
120
147
  ? 'fail'
121
148
  : checks.some((check) => check.status === 'warn')
122
- ? 'warn'
123
- : 'pass';
149
+ ? 'warn'
150
+ : 'pass'
124
151
 
125
- return { status, checks };
152
+ return { status, checks }
126
153
  }
127
154
 
128
155
  export function buildDeploymentManifest() {
@@ -162,7 +189,7 @@ export function buildDeploymentManifest() {
162
189
  environmentVariables: 'https://actuatecms.dev/docs/environment-variables',
163
190
  aiRunbook: 'https://actuatecms.dev/docs/ai-runbook',
164
191
  },
165
- };
192
+ }
166
193
  }
167
194
 
168
195
  export function missingCriticalFields(schemaContent: string): string[] {
@@ -172,18 +199,54 @@ export function missingCriticalFields(schemaContent: string): string[] {
172
199
  SavedSection: ['tree', 'usageCount', 'category'],
173
200
  PasswordResetToken: ['tokenHash', 'expiresAt', 'usedAt'],
174
201
  MediaUsage: ['mediaId', 'documentId', 'fieldPath'],
175
- };
176
- const missing: string[] = [];
202
+ }
203
+ const missing: string[] = []
177
204
 
178
205
  for (const [model, fields] of Object.entries(requiredFields)) {
179
- const body = schemaContent.match(new RegExp(`model\\s+${model}\\s+\\{([\\s\\S]*?)\\n\\}`))?.[1] ?? '';
180
- if (!body) continue;
206
+ const body =
207
+ schemaContent.match(new RegExp(`model\\s+${model}\\s+\\{([\\s\\S]*?)\\n\\}`))?.[1] ?? ''
208
+ if (!body) continue
181
209
  for (const field of fields) {
182
210
  if (!new RegExp(`^\\s*${field}\\s+`, 'm').test(body)) {
183
- missing.push(`${model}.${field}`);
211
+ missing.push(`${model}.${field}`)
184
212
  }
185
213
  }
186
214
  }
187
215
 
188
- return missing;
216
+ return missing
217
+ }
218
+
219
+ export function detectsFlatMarketingPageModel(configContent: string): boolean {
220
+ const normalized = configContent.toLowerCase()
221
+ const hasPagesCollection =
222
+ /\bpages\b/.test(normalized) || /slug\s*:\s*['"]pages['"]/.test(normalized)
223
+ if (!hasPagesCollection) return false
224
+
225
+ const hasPageBuilderSignals = [
226
+ 'pagebuilder',
227
+ 'page-builder',
228
+ "type: 'blocks'",
229
+ 'type: "blocks"',
230
+ 'layout:',
231
+ 'savedsections',
232
+ 'pagetemplate',
233
+ ].some((signal) => normalized.includes(signal.toLowerCase()))
234
+
235
+ if (hasPageBuilderSignals) return false
236
+
237
+ const flatMarketingSignals = [
238
+ 'heroheadline',
239
+ 'herosubheadline',
240
+ 'herotitle',
241
+ 'heroimage',
242
+ 'bodycontent',
243
+ 'ctabuttontext',
244
+ 'ctabuttonurl',
245
+ 'servicecards',
246
+ 'testimonial',
247
+ 'reviews',
248
+ ]
249
+
250
+ const signalCount = flatMarketingSignals.filter((signal) => normalized.includes(signal)).length
251
+ return signalCount >= 3
189
252
  }
package/src/index.ts CHANGED
@@ -1,40 +1,40 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from "commander";
3
- import { registerMigrateCommand } from "./commands/migrate.js";
4
- import { registerGenerateCommand } from "./commands/generate.js";
5
- import { registerSeedCommand } from "./commands/seed.js";
6
- import { registerImportCommand } from "./commands/import.js";
7
- import { registerExportCommand } from "./commands/export.js";
8
- import { registerUpgradeCommand } from "./commands/upgrade.js";
9
- import { registerUpdateCheckCommand } from "./commands/update-check.js";
10
- import { registerDbInitCommand } from "./commands/db-init.js";
11
- import { registerDbStatusCommand } from "./commands/db-status.js";
12
- import { registerInitCommand } from "./commands/init.js";
2
+ import { Command } from 'commander'
3
+ import { registerMigrateCommand } from './commands/migrate.js'
4
+ import { registerGenerateCommand } from './commands/generate.js'
5
+ import { registerSeedCommand } from './commands/seed.js'
6
+ import { registerImportCommand } from './commands/import.js'
7
+ import { registerExportCommand } from './commands/export.js'
8
+ import { registerUpgradeCommand } from './commands/upgrade.js'
9
+ import { registerUpdateCheckCommand } from './commands/update-check.js'
10
+ import { registerDbInitCommand } from './commands/db-init.js'
11
+ import { registerDbStatusCommand } from './commands/db-status.js'
12
+ import { registerInitCommand } from './commands/init.js'
13
13
  import {
14
14
  registerDeployCheckCommand,
15
15
  registerDoctorCommand,
16
16
  registerVerifyCommand,
17
- } from "./commands/doctor.js";
17
+ } from './commands/doctor.js'
18
18
 
19
- const program = new Command();
19
+ const program = new Command()
20
20
 
21
21
  program
22
- .name("actuate")
23
- .description("Actuate CMS — CLI toolkit for migrations, codegen, and more")
24
- .version("0.1.0");
22
+ .name('actuate')
23
+ .description('Actuate CMS — CLI toolkit for migrations, codegen, and more')
24
+ .version('0.1.0')
25
25
 
26
- registerMigrateCommand(program);
27
- registerGenerateCommand(program);
28
- registerSeedCommand(program);
29
- registerImportCommand(program);
30
- registerExportCommand(program);
31
- registerUpgradeCommand(program);
32
- registerUpdateCheckCommand(program);
33
- registerDbInitCommand(program);
34
- registerDbStatusCommand(program);
35
- registerInitCommand(program);
36
- registerDoctorCommand(program);
37
- registerDeployCheckCommand(program);
38
- registerVerifyCommand(program);
26
+ registerMigrateCommand(program)
27
+ registerGenerateCommand(program)
28
+ registerSeedCommand(program)
29
+ registerImportCommand(program)
30
+ registerExportCommand(program)
31
+ registerUpgradeCommand(program)
32
+ registerUpdateCheckCommand(program)
33
+ registerDbInitCommand(program)
34
+ registerDbStatusCommand(program)
35
+ registerInitCommand(program)
36
+ registerDoctorCommand(program)
37
+ registerDeployCheckCommand(program)
38
+ registerVerifyCommand(program)
39
39
 
40
- program.parse();
40
+ program.parse()
@@ -1,26 +1,26 @@
1
- import chalk from "chalk";
1
+ import chalk from 'chalk'
2
2
 
3
3
  export interface Logger {
4
- info(message: string): void;
5
- success(message: string): void;
6
- warn(message: string): void;
7
- error(message: string): void;
4
+ info(message: string): void
5
+ success(message: string): void
6
+ warn(message: string): void
7
+ error(message: string): void
8
8
  }
9
9
 
10
10
  export const logger: Logger = {
11
11
  info(message: string): void {
12
- console.log(chalk.blue(""), message);
12
+ console.log(chalk.blue(''), message)
13
13
  },
14
14
 
15
15
  success(message: string): void {
16
- console.log(chalk.green(""), message);
16
+ console.log(chalk.green(''), message)
17
17
  },
18
18
 
19
19
  warn(message: string): void {
20
- console.warn(chalk.yellow(""), message);
20
+ console.warn(chalk.yellow(''), message)
21
21
  },
22
22
 
23
23
  error(message: string): void {
24
- console.error(chalk.red(""), message);
24
+ console.error(chalk.red(''), message)
25
25
  },
26
- };
26
+ }