@agility/create-next-app 1.0.0-beta.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 (213) hide show
  1. package/.claude/settings.json +7 -0
  2. package/.claude/settings.local.json +24 -0
  3. package/FEATURE_ROADMAP.md +343 -0
  4. package/README.md +205 -0
  5. package/TESTING.md +131 -0
  6. package/bin/create-agility-app.js +48 -0
  7. package/dist/agility/api-keys/generateApiKeys.d.ts +9 -0
  8. package/dist/agility/api-keys/generateApiKeys.d.ts.map +1 -0
  9. package/dist/agility/api-keys/generateApiKeys.js +99 -0
  10. package/dist/agility/api-keys/generateApiKeys.js.map +1 -0
  11. package/dist/agility/api-keys/getApiKeys.d.ts +9 -0
  12. package/dist/agility/api-keys/getApiKeys.d.ts.map +1 -0
  13. package/dist/agility/api-keys/getApiKeys.js +14 -0
  14. package/dist/agility/api-keys/getApiKeys.js.map +1 -0
  15. package/dist/agility/index.d.ts +3 -0
  16. package/dist/agility/index.d.ts.map +1 -0
  17. package/dist/agility/index.js +8 -0
  18. package/dist/agility/index.js.map +1 -0
  19. package/dist/agility/instance/createNewInstance.d.ts +8 -0
  20. package/dist/agility/instance/createNewInstance.d.ts.map +1 -0
  21. package/dist/agility/instance/createNewInstance.js +65 -0
  22. package/dist/agility/instance/createNewInstance.js.map +1 -0
  23. package/dist/agility/instance/getAvailableInstances.d.ts +8 -0
  24. package/dist/agility/instance/getAvailableInstances.d.ts.map +1 -0
  25. package/dist/agility/instance/getAvailableInstances.js +43 -0
  26. package/dist/agility/instance/getAvailableInstances.js.map +1 -0
  27. package/dist/agility/instance/manageInstance.d.ts +9 -0
  28. package/dist/agility/instance/manageInstance.d.ts.map +1 -0
  29. package/dist/agility/instance/manageInstance.js +82 -0
  30. package/dist/agility/instance/manageInstance.js.map +1 -0
  31. package/dist/agility/utils/getMgmtAPIUrl.d.ts +20 -0
  32. package/dist/agility/utils/getMgmtAPIUrl.d.ts.map +1 -0
  33. package/dist/agility/utils/getMgmtAPIUrl.js +61 -0
  34. package/dist/agility/utils/getMgmtAPIUrl.js.map +1 -0
  35. package/dist/auth/api-key/authenticateWithApiKey.d.ts +6 -0
  36. package/dist/auth/api-key/authenticateWithApiKey.d.ts.map +1 -0
  37. package/dist/auth/api-key/authenticateWithApiKey.js +28 -0
  38. package/dist/auth/api-key/authenticateWithApiKey.js.map +1 -0
  39. package/dist/auth/index.d.ts +3 -0
  40. package/dist/auth/index.d.ts.map +1 -0
  41. package/dist/auth/index.js +8 -0
  42. package/dist/auth/index.js.map +1 -0
  43. package/dist/auth/oauth/authenticate.d.ts +6 -0
  44. package/dist/auth/oauth/authenticate.d.ts.map +1 -0
  45. package/dist/auth/oauth/authenticate.js +162 -0
  46. package/dist/auth/oauth/authenticate.js.map +1 -0
  47. package/dist/auth/oauth/constants.d.ts +5 -0
  48. package/dist/auth/oauth/constants.d.ts.map +1 -0
  49. package/dist/auth/oauth/constants.js +9 -0
  50. package/dist/auth/oauth/constants.js.map +1 -0
  51. package/dist/auth/oauth/exchangeCodeForToken.d.ts +7 -0
  52. package/dist/auth/oauth/exchangeCodeForToken.d.ts.map +1 -0
  53. package/dist/auth/oauth/exchangeCodeForToken.js +39 -0
  54. package/dist/auth/oauth/exchangeCodeForToken.js.map +1 -0
  55. package/dist/cli/index.d.ts +3 -0
  56. package/dist/cli/index.d.ts.map +1 -0
  57. package/dist/cli/index.js +290 -0
  58. package/dist/cli/index.js.map +1 -0
  59. package/dist/cli/promptForMissingOptions.d.ts +8 -0
  60. package/dist/cli/promptForMissingOptions.d.ts.map +1 -0
  61. package/dist/cli/promptForMissingOptions.js +92 -0
  62. package/dist/cli/promptForMissingOptions.js.map +1 -0
  63. package/dist/config/env/createEnvFile.d.ts +6 -0
  64. package/dist/config/env/createEnvFile.d.ts.map +1 -0
  65. package/dist/config/env/createEnvFile.js +31 -0
  66. package/dist/config/env/createEnvFile.js.map +1 -0
  67. package/dist/config/index.d.ts +2 -0
  68. package/dist/config/index.d.ts.map +1 -0
  69. package/dist/config/index.js +6 -0
  70. package/dist/config/index.js.map +1 -0
  71. package/dist/config/mcp/createMcpConfig.d.ts +5 -0
  72. package/dist/config/mcp/createMcpConfig.d.ts.map +1 -0
  73. package/dist/config/mcp/createMcpConfig.js +32 -0
  74. package/dist/config/mcp/createMcpConfig.js.map +1 -0
  75. package/dist/config/packages/installAgilityPackages.d.ts +6 -0
  76. package/dist/config/packages/installAgilityPackages.d.ts.map +1 -0
  77. package/dist/config/packages/installAgilityPackages.js +61 -0
  78. package/dist/config/packages/installAgilityPackages.js.map +1 -0
  79. package/dist/config/setupProject.d.ts +8 -0
  80. package/dist/config/setupProject.d.ts.map +1 -0
  81. package/dist/config/setupProject.js +32 -0
  82. package/dist/config/setupProject.js.map +1 -0
  83. package/dist/create-next-app/createNextApp.d.ts +9 -0
  84. package/dist/create-next-app/createNextApp.d.ts.map +1 -0
  85. package/dist/create-next-app/createNextApp.js +83 -0
  86. package/dist/create-next-app/createNextApp.js.map +1 -0
  87. package/dist/create-next-app/index.d.ts +3 -0
  88. package/dist/create-next-app/index.d.ts.map +1 -0
  89. package/dist/create-next-app/index.js +8 -0
  90. package/dist/create-next-app/index.js.map +1 -0
  91. package/dist/scaffold/components/createPageComponents.d.ts +6 -0
  92. package/dist/scaffold/components/createPageComponents.d.ts.map +1 -0
  93. package/dist/scaffold/components/createPageComponents.js +62 -0
  94. package/dist/scaffold/components/createPageComponents.js.map +1 -0
  95. package/dist/scaffold/containers/createContainers.d.ts +6 -0
  96. package/dist/scaffold/containers/createContainers.d.ts.map +1 -0
  97. package/dist/scaffold/containers/createContainers.js +48 -0
  98. package/dist/scaffold/containers/createContainers.js.map +1 -0
  99. package/dist/scaffold/index.d.ts +2 -0
  100. package/dist/scaffold/index.d.ts.map +1 -0
  101. package/dist/scaffold/index.js +6 -0
  102. package/dist/scaffold/index.js.map +1 -0
  103. package/dist/scaffold/instance/createBlankInstance.d.ts +8 -0
  104. package/dist/scaffold/instance/createBlankInstance.d.ts.map +1 -0
  105. package/dist/scaffold/instance/createBlankInstance.js +51 -0
  106. package/dist/scaffold/instance/createBlankInstance.js.map +1 -0
  107. package/dist/scaffold/models/createContentModels.d.ts +6 -0
  108. package/dist/scaffold/models/createContentModels.d.ts.map +1 -0
  109. package/dist/scaffold/models/createContentModels.js +70 -0
  110. package/dist/scaffold/models/createContentModels.js.map +1 -0
  111. package/dist/templates/copyDirectory.d.ts +5 -0
  112. package/dist/templates/copyDirectory.d.ts.map +1 -0
  113. package/dist/templates/copyDirectory.js +28 -0
  114. package/dist/templates/copyDirectory.js.map +1 -0
  115. package/dist/templates/copyTemplates.d.ts +8 -0
  116. package/dist/templates/copyTemplates.d.ts.map +1 -0
  117. package/dist/templates/copyTemplates.js +58 -0
  118. package/dist/templates/copyTemplates.js.map +1 -0
  119. package/dist/templates/index.d.ts +2 -0
  120. package/dist/templates/index.d.ts.map +1 -0
  121. package/dist/templates/index.js +6 -0
  122. package/dist/templates/index.js.map +1 -0
  123. package/dist/types/index.d.ts +50 -0
  124. package/dist/types/index.d.ts.map +1 -0
  125. package/dist/types/index.js +3 -0
  126. package/dist/types/index.js.map +1 -0
  127. package/dist/utils/git.d.ts +9 -0
  128. package/dist/utils/git.d.ts.map +1 -0
  129. package/dist/utils/git.js +71 -0
  130. package/dist/utils/git.js.map +1 -0
  131. package/dist/utils/validation.d.ts +45 -0
  132. package/dist/utils/validation.d.ts.map +1 -0
  133. package/dist/utils/validation.js +180 -0
  134. package/dist/utils/validation.js.map +1 -0
  135. package/package.json +45 -0
  136. package/src/agility/api-keys/generateApiKeys.ts +100 -0
  137. package/src/agility/api-keys/getApiKeys.ts +13 -0
  138. package/src/agility/index.ts +3 -0
  139. package/src/agility/instance/createNewInstance.ts +67 -0
  140. package/src/agility/instance/getAvailableInstances.ts +49 -0
  141. package/src/agility/instance/manageInstance.ts +90 -0
  142. package/src/agility/utils/getMgmtAPIUrl.ts +68 -0
  143. package/src/auth/api-key/authenticateWithApiKey.ts +24 -0
  144. package/src/auth/index.ts +3 -0
  145. package/src/auth/oauth/authenticate.ts +165 -0
  146. package/src/auth/oauth/constants.ts +6 -0
  147. package/src/auth/oauth/exchangeCodeForToken.ts +43 -0
  148. package/src/cli/index.ts +281 -0
  149. package/src/cli/promptForMissingOptions.ts +104 -0
  150. package/src/config/env/createEnvFile.ts +30 -0
  151. package/src/config/index.ts +2 -0
  152. package/src/config/mcp/createMcpConfig.ts +30 -0
  153. package/src/config/packages/installAgilityPackages.ts +63 -0
  154. package/src/config/setupProject.ts +31 -0
  155. package/src/create-next-app/createNextApp.ts +75 -0
  156. package/src/create-next-app/index.ts +3 -0
  157. package/src/scaffold/components/createPageComponents.ts +74 -0
  158. package/src/scaffold/containers/createContainers.ts +55 -0
  159. package/src/scaffold/index.ts +2 -0
  160. package/src/scaffold/instance/createBlankInstance.ts +55 -0
  161. package/src/scaffold/models/createContentModels.ts +83 -0
  162. package/src/templates/copyDirectory.ts +24 -0
  163. package/src/templates/copyTemplates.ts +57 -0
  164. package/src/templates/index.ts +2 -0
  165. package/src/types/index.ts +55 -0
  166. package/src/utils/git.ts +74 -0
  167. package/src/utils/validation.ts +184 -0
  168. package/templates/.claude/QUICK-START.md +230 -0
  169. package/templates/.claude/README.md +32 -0
  170. package/templates/.claude/settings.json +8 -0
  171. package/templates/BLANK-INSTANCE-SETUP.md +375 -0
  172. package/templates/DEVELOPMENT.md +160 -0
  173. package/templates/EXAMPLE-PROMPTS.md +643 -0
  174. package/templates/PROMPTS.md +410 -0
  175. package/templates/README.md +281 -0
  176. package/templates/agents.md +429 -0
  177. package/templates/app/[locale]/[...slug]/error.tsx +17 -0
  178. package/templates/app/[locale]/[...slug]/not-found.tsx +9 -0
  179. package/templates/app/[locale]/[...slug]/page.tsx +102 -0
  180. package/templates/app/[locale]/layout.tsx +22 -0
  181. package/templates/app/[locale]/page.tsx +12 -0
  182. package/templates/app/api/dynamic-redirect/route.ts +24 -0
  183. package/templates/app/api/preview/exit/route.ts +34 -0
  184. package/templates/app/api/preview/route.ts +63 -0
  185. package/templates/app/api/revalidate/route.ts +118 -0
  186. package/templates/components/agility-components/RichTextArea.tsx +66 -0
  187. package/templates/components/agility-components/index.ts +30 -0
  188. package/templates/components/agility-pages/MainTemplate.tsx +36 -0
  189. package/templates/components/agility-pages/index.ts +11 -0
  190. package/templates/docs/01-agility-cms-overview.md +139 -0
  191. package/templates/docs/02-page-routing.md +251 -0
  192. package/templates/docs/03-creating-components.md +462 -0
  193. package/templates/docs/04-data-fetching.md +484 -0
  194. package/templates/docs/05-containers-and-lists.md +596 -0
  195. package/templates/docs/06-localization.md +561 -0
  196. package/templates/docs/07-caching-strategies.md +410 -0
  197. package/templates/docs/08-common-components.md +756 -0
  198. package/templates/docs/09-whats-included.md +279 -0
  199. package/templates/docs/10-mcp-server-setup.md +153 -0
  200. package/templates/docs/11-linked-nested-content.md +611 -0
  201. package/templates/docs/README.md +164 -0
  202. package/templates/lib/cms/getAgilityContext.ts +28 -0
  203. package/templates/lib/cms/getAgilityPage.ts +51 -0
  204. package/templates/lib/cms/getAgilitySDK.ts +22 -0
  205. package/templates/lib/cms/getContentItem.ts +20 -0
  206. package/templates/lib/cms/getContentList.ts +19 -0
  207. package/templates/lib/cms/getRedirections.ts +85 -0
  208. package/templates/lib/cms/getSitemapFlat.ts +19 -0
  209. package/templates/lib/cms/getSitemapNested.ts +19 -0
  210. package/templates/lib/env.ts +99 -0
  211. package/templates/lib/i18n/config.ts +28 -0
  212. package/templates/proxy.ts +101 -0
  213. package/tsconfig.json +21 -0
@@ -0,0 +1,63 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { spawn } from 'child_process';
4
+ import ora from 'ora';
5
+ import type { ProjectConfig } from '../../types';
6
+
7
+ /**
8
+ * Installs Agility packages
9
+ */
10
+ export async function installAgilityPackages(projectPath: string, config: ProjectConfig): Promise<void> {
11
+ const spinner = ora('Installing Agility packages...').start();
12
+
13
+ return new Promise((resolve, reject) => {
14
+ // Determine package manager
15
+ let packageManager = 'npm';
16
+ let installCommand = 'install';
17
+
18
+ if (fs.existsSync(path.join(projectPath, 'yarn.lock'))) {
19
+ packageManager = 'yarn';
20
+ installCommand = 'add';
21
+ } else if (fs.existsSync(path.join(projectPath, 'pnpm-lock.yaml'))) {
22
+ packageManager = 'pnpm';
23
+ installCommand = 'add';
24
+ } else if (fs.existsSync(path.join(projectPath, 'bun.lockb'))) {
25
+ packageManager = 'bun';
26
+ installCommand = 'add';
27
+ }
28
+
29
+ const packages = [
30
+ '@agility/nextjs@latest',
31
+ '@agility/content-fetch@latest'
32
+ ];
33
+
34
+ // Install latest versions of @agility/nextjs (v16+) and @agility/content-fetch
35
+ // @agility/nextjs v16+ supports Next.js 16
36
+ const installArgs = packageManager === 'npm'
37
+ ? [installCommand, ...packages]
38
+ : [installCommand, ...packages];
39
+
40
+ const child = spawn(packageManager, installArgs, {
41
+ stdio: 'inherit',
42
+ shell: true,
43
+ cwd: projectPath
44
+ });
45
+
46
+ child.on('error', (error: Error) => {
47
+ spinner.fail('Failed to install packages');
48
+ reject(error);
49
+ });
50
+
51
+ child.on('exit', (code: number | null) => {
52
+ if (code !== 0) {
53
+ spinner.fail('Failed to install packages');
54
+ reject(new Error(`Package installation exited with code ${code}`));
55
+ return;
56
+ }
57
+
58
+ spinner.succeed('Agility packages installed');
59
+ resolve();
60
+ });
61
+ });
62
+ }
63
+
@@ -0,0 +1,31 @@
1
+ import ora from 'ora';
2
+ import type { ProjectConfig } from '../types';
3
+ import { createEnvFile } from './env/createEnvFile';
4
+ import { createMcpConfig } from './mcp/createMcpConfig';
5
+ import { installAgilityPackages } from './packages/installAgilityPackages';
6
+
7
+ /**
8
+ * Sets up the project configuration
9
+ * @param projectPath - Path to the project
10
+ * @param config - Configuration object
11
+ */
12
+ export async function setupProject(projectPath: string, config: ProjectConfig): Promise<void> {
13
+ const spinner = ora('Configuring Agility CMS integration...').start();
14
+
15
+ try {
16
+ // Create .env.local file
17
+ await createEnvFile(projectPath, config);
18
+
19
+ // Create .vscode/mcp.json file
20
+ await createMcpConfig(projectPath);
21
+
22
+ // Install Agility packages
23
+ await installAgilityPackages(projectPath, config);
24
+
25
+ spinner.succeed('Project configured successfully');
26
+ } catch (error) {
27
+ spinner.fail('Failed to configure project');
28
+ throw error;
29
+ }
30
+ }
31
+
@@ -0,0 +1,75 @@
1
+ import { spawn } from 'child_process';
2
+ import path from 'path';
3
+ import chalk from 'chalk';
4
+ import type { CreateNextAppOptions } from '../types';
5
+
6
+ /**
7
+ * Creates a Next.js app using create-next-app programmatically
8
+ * @param projectName - Name of the project
9
+ * @param options - Options to pass to create-next-app
10
+ * @returns Path to the created project
11
+ */
12
+ export async function createNextApp(projectName: string, options: CreateNextAppOptions): Promise<string> {
13
+ // Show a simple message instead of a spinner to avoid conflicts with create-next-app output
14
+ console.log(chalk.blue('Setting up your Next.js project...\n'));
15
+
16
+ return new Promise((resolve, reject) => {
17
+ const args: string[] = [];
18
+
19
+ // Add project name if provided
20
+ if (projectName) {
21
+ args.push(projectName);
22
+ }
23
+
24
+ // Build create-next-app arguments
25
+ // Use the options provided (from prompts or flags)
26
+ if (options.typescript) args.push('--ts', '--typescript');
27
+ if (options.javascript) args.push('--js', '--javascript');
28
+ if (options.tailwind === true) args.push('--tailwind');
29
+ if (options.tailwind === false) args.push('--no-tailwind');
30
+ if (options.eslint === true) args.push('--eslint');
31
+ if (options.eslint === false) args.push('--no-eslint');
32
+ if (options.app) args.push('--app');
33
+ if (options.srcDir) args.push('--src-dir');
34
+ if (options.importAlias) args.push('--import-alias', options.importAlias);
35
+ if (options.useNpm) args.push('--use-npm');
36
+ if (options.usePnpm) args.push('--use-pnpm');
37
+ if (options.useYarn) args.push('--use-yarn');
38
+ if (options.useBun) args.push('--use-bun');
39
+ if (options.skipInstall) args.push('--skip-install');
40
+
41
+ // Always use latest version
42
+ // Use -y flag to auto-confirm package installation
43
+ const command = 'npx';
44
+ const createNextAppArgs = ['-y', 'create-next-app@latest', ...args];
45
+
46
+ const child = spawn(command, createNextAppArgs, {
47
+ stdio: 'inherit',
48
+ shell: true,
49
+ cwd: process.cwd()
50
+ });
51
+
52
+ child.on('error', (error: Error) => {
53
+ console.error(chalk.red('Failed to create Next.js app'));
54
+ reject(new Error(`Failed to create Next.js app: ${error.message}`));
55
+ });
56
+
57
+ child.on('exit', (code: number | null) => {
58
+ if (code !== 0) {
59
+ console.error(chalk.red('Failed to create Next.js app'));
60
+ reject(new Error(`create-next-app exited with code ${code}`));
61
+ return;
62
+ }
63
+
64
+ console.log(chalk.green('\n✓ Base Next.js project created successfully\n'));
65
+
66
+ // Determine project path
67
+ const projectPath = projectName
68
+ ? path.resolve(process.cwd(), projectName)
69
+ : path.resolve(process.cwd(), 'my-app');
70
+
71
+ resolve(projectPath);
72
+ });
73
+ });
74
+ }
75
+
@@ -0,0 +1,3 @@
1
+ export { createNextApp } from './createNextApp';
2
+ export { createNextApp as default } from './createNextApp';
3
+
@@ -0,0 +1,74 @@
1
+ import chalk from 'chalk';
2
+ import type { ApiKeys } from '../../types';
3
+
4
+ /**
5
+ * Creates basic page components
6
+ */
7
+ export async function createPageComponents(instanceGuid: string, apiKeys: ApiKeys | null): Promise<void> {
8
+ interface Field {
9
+ type: string;
10
+ name: string;
11
+ label: string;
12
+ required?: boolean;
13
+ }
14
+
15
+ interface Component {
16
+ displayName: string;
17
+ referenceName: string;
18
+ description: string;
19
+ fields: Field[];
20
+ }
21
+
22
+ const components: Component[] = [
23
+ {
24
+ displayName: 'Hero',
25
+ referenceName: 'Hero',
26
+ description: 'Hero section component',
27
+ fields: [
28
+ { type: 'Text', name: 'headline', label: 'Headline', required: true },
29
+ { type: 'LongText', name: 'subheadline', label: 'Subheadline' },
30
+ { type: 'ImageAttachment', name: 'backgroundImage', label: 'Background Image' },
31
+ { type: 'Link', name: 'ctaLink', label: 'CTA Link' }
32
+ ]
33
+ },
34
+ {
35
+ displayName: 'RichTextArea',
36
+ referenceName: 'RichTextArea',
37
+ description: 'Rich text content component',
38
+ fields: [
39
+ { type: 'Html', name: 'content', label: 'Content', required: true }
40
+ ]
41
+ },
42
+ {
43
+ displayName: 'TextBlock',
44
+ referenceName: 'TextBlock',
45
+ description: 'Simple text block component',
46
+ fields: [
47
+ { type: 'Text', name: 'title', label: 'Title' },
48
+ { type: 'LongText', name: 'content', label: 'Content', required: true }
49
+ ]
50
+ },
51
+ {
52
+ displayName: 'Image',
53
+ referenceName: 'Image',
54
+ description: 'Image component',
55
+ fields: [
56
+ { type: 'ImageAttachment', name: 'image', label: 'Image', required: true },
57
+ { type: 'Text', name: 'altText', label: 'Alt Text' },
58
+ { type: 'Text', name: 'caption', label: 'Caption' }
59
+ ]
60
+ }
61
+ ];
62
+
63
+ // In a real implementation, this would use the MCP tool:
64
+ // for (const component of components) {
65
+ // await mcp_Agility_CMS_save_component_model({ instanceGuid, model: component });
66
+ // }
67
+
68
+ console.log(chalk.cyan('\n🧩 Page components to create:'));
69
+ components.forEach(component => {
70
+ console.log(chalk.white(` - ${component.displayName} (${component.referenceName})`));
71
+ });
72
+ console.log(chalk.yellow('\n⚠️ Please create these components in Agility CMS manually, or use the API.'));
73
+ }
74
+
@@ -0,0 +1,55 @@
1
+ import chalk from 'chalk';
2
+ import type { ApiKeys } from '../../types';
3
+
4
+ /**
5
+ * Creates containers for content
6
+ */
7
+ export async function createContainers(instanceGuid: string, apiKeys: ApiKeys | null): Promise<void> {
8
+ interface Container {
9
+ displayName: string;
10
+ referenceName: string;
11
+ modelTypeID: number;
12
+ isShared: boolean;
13
+ isDynamicPageList: boolean;
14
+ modelID: number | null;
15
+ }
16
+
17
+ const containers: Container[] = [
18
+ {
19
+ displayName: 'Pages',
20
+ referenceName: 'pages',
21
+ modelTypeID: 0, // Single item
22
+ isShared: false,
23
+ isDynamicPageList: true,
24
+ modelID: null // Would be set after creating Page model
25
+ },
26
+ {
27
+ displayName: 'Posts',
28
+ referenceName: 'posts',
29
+ modelTypeID: 1, // List
30
+ isShared: true,
31
+ isDynamicPageList: false,
32
+ modelID: null // Would be set after creating Post model
33
+ },
34
+ {
35
+ displayName: 'Categories',
36
+ referenceName: 'categories',
37
+ modelTypeID: 1, // List
38
+ isShared: true,
39
+ isDynamicPageList: false,
40
+ modelID: null // Would be set after creating Category model
41
+ }
42
+ ];
43
+
44
+ // In a real implementation, this would use the MCP tool:
45
+ // for (const container of containers) {
46
+ // await mcp_Agility_CMS_save_container({ instanceGuid, container });
47
+ // }
48
+
49
+ console.log(chalk.cyan('\n📦 Containers to create:'));
50
+ containers.forEach(container => {
51
+ console.log(chalk.white(` - ${container.displayName} (${container.referenceName})`));
52
+ });
53
+ console.log(chalk.yellow('\n⚠️ Please create these containers in Agility CMS manually, or use the API.'));
54
+ }
55
+
@@ -0,0 +1,2 @@
1
+ export { createBlankInstance } from './instance/createBlankInstance';
2
+
@@ -0,0 +1,55 @@
1
+ import ora from 'ora';
2
+ import chalk from 'chalk';
3
+ import inquirer from 'inquirer';
4
+ import type { ApiKeys } from '../../types';
5
+ import { createContentModels } from '../models/createContentModels';
6
+ import { createPageComponents } from '../components/createPageComponents';
7
+ import { createContainers } from '../containers/createContainers';
8
+
9
+ /**
10
+ * Creates a blank Agility instance with basic content models and components
11
+ * @param instanceGuid - Instance GUID
12
+ * @param apiKeys - API keys object
13
+ */
14
+ export async function createBlankInstance(instanceGuid: string, apiKeys: ApiKeys | null): Promise<void> {
15
+ const spinner = ora('Scaffolding blank Agility instance...').start();
16
+
17
+ try {
18
+ // Ask user if they want to scaffold
19
+ const answer = await inquirer.prompt<{ scaffold: boolean }>([
20
+ {
21
+ type: 'confirm',
22
+ name: 'scaffold',
23
+ message: 'Would you like to scaffold a blank instance with basic content models and components?',
24
+ default: true
25
+ }
26
+ ]);
27
+
28
+ if (!answer.scaffold) {
29
+ spinner.info('Skipping instance scaffolding');
30
+ return;
31
+ }
32
+
33
+ spinner.text = 'Creating content models...';
34
+
35
+ // Create content models
36
+ await createContentModels(instanceGuid, apiKeys);
37
+
38
+ spinner.text = 'Creating page components...';
39
+
40
+ // Create page components
41
+ await createPageComponents(instanceGuid, apiKeys);
42
+
43
+ spinner.text = 'Creating containers...';
44
+
45
+ // Create containers
46
+ await createContainers(instanceGuid, apiKeys);
47
+
48
+ spinner.succeed('Blank instance scaffolded successfully');
49
+ } catch (error) {
50
+ spinner.fail('Failed to scaffold instance');
51
+ console.error(chalk.red((error as Error).message));
52
+ // Don't throw - allow project creation to continue
53
+ }
54
+ }
55
+
@@ -0,0 +1,83 @@
1
+ import chalk from 'chalk';
2
+ import type { ApiKeys } from '../../types';
3
+
4
+ /**
5
+ * Creates basic content models
6
+ */
7
+ export async function createContentModels(instanceGuid: string, apiKeys: ApiKeys | null): Promise<void> {
8
+ // Note: This would use the MCP Agility CMS tools or direct API calls
9
+ // For now, we'll provide instructions to the user
10
+
11
+ interface Field {
12
+ type: string;
13
+ name: string;
14
+ label: string;
15
+ required?: boolean;
16
+ }
17
+
18
+ interface Model {
19
+ displayName: string;
20
+ referenceName: string;
21
+ description: string;
22
+ fields: Field[];
23
+ }
24
+
25
+ const models: Model[] = [
26
+ {
27
+ displayName: 'Page',
28
+ referenceName: 'Page',
29
+ description: 'Page content model with SEO fields',
30
+ fields: [
31
+ { type: 'Text', name: 'title', label: 'Title', required: true },
32
+ { type: 'LongText', name: 'description', label: 'Description' },
33
+ { type: 'Html', name: 'content', label: 'Content' },
34
+ { type: 'Text', name: 'seoTitle', label: 'SEO Title' },
35
+ { type: 'LongText', name: 'seoDescription', label: 'SEO Description' },
36
+ { type: 'Text', name: 'seoKeywords', label: 'SEO Keywords' }
37
+ ]
38
+ },
39
+ {
40
+ displayName: 'Post',
41
+ referenceName: 'Post',
42
+ description: 'Blog post content model',
43
+ fields: [
44
+ { type: 'Text', name: 'title', label: 'Title', required: true },
45
+ { type: 'LongText', name: 'excerpt', label: 'Excerpt' },
46
+ { type: 'Html', name: 'content', label: 'Content' },
47
+ { type: 'Date', name: 'publishDate', label: 'Publish Date' },
48
+ { type: 'ImageAttachment', name: 'featuredImage', label: 'Featured Image' }
49
+ ]
50
+ },
51
+ {
52
+ displayName: 'Category',
53
+ referenceName: 'Category',
54
+ description: 'Category content model',
55
+ fields: [
56
+ { type: 'Text', name: 'title', label: 'Title', required: true },
57
+ { type: 'LongText', name: 'description', label: 'Description' }
58
+ ]
59
+ },
60
+ {
61
+ displayName: 'Author',
62
+ referenceName: 'Author',
63
+ description: 'Author content model',
64
+ fields: [
65
+ { type: 'Text', name: 'name', label: 'Name', required: true },
66
+ { type: 'LongText', name: 'bio', label: 'Bio' },
67
+ { type: 'ImageAttachment', name: 'avatar', label: 'Avatar' }
68
+ ]
69
+ }
70
+ ];
71
+
72
+ // In a real implementation, this would use the MCP tool:
73
+ // for (const model of models) {
74
+ // await mcp_Agility_CMS_save_content_model({ instanceGuid, model });
75
+ // }
76
+
77
+ console.log(chalk.cyan('\n📋 Content models to create:'));
78
+ models.forEach(model => {
79
+ console.log(chalk.white(` - ${model.displayName} (${model.referenceName})`));
80
+ });
81
+ console.log(chalk.yellow('\n⚠️ Please create these content models in Agility CMS manually, or use the API.'));
82
+ }
83
+
@@ -0,0 +1,24 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Recursively copies a directory
6
+ */
7
+ export async function copyDirectory(src: string, dest: string): Promise<void> {
8
+ const entries = fs.readdirSync(src, { withFileTypes: true });
9
+
10
+ for (const entry of entries) {
11
+ const srcPath = path.join(src, entry.name);
12
+ const destPath = path.join(dest, entry.name);
13
+
14
+ if (entry.isDirectory()) {
15
+ if (!fs.existsSync(destPath)) {
16
+ fs.mkdirSync(destPath, { recursive: true });
17
+ }
18
+ await copyDirectory(srcPath, destPath);
19
+ } else {
20
+ fs.copyFileSync(srcPath, destPath);
21
+ }
22
+ }
23
+ }
24
+
@@ -0,0 +1,57 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import ora from 'ora';
4
+ import type { CliOptions } from '../types';
5
+ import { copyDirectory } from './copyDirectory';
6
+
7
+ /**
8
+ * Copies template files to the project
9
+ * @param projectPath - Path to the project
10
+ * @param options - Options
11
+ */
12
+ export async function copyTemplates(projectPath: string, options: CliOptions): Promise<void> {
13
+ const spinner = ora('Adding Agility CMS template files...').start();
14
+
15
+ try {
16
+ const templatesDir = path.join(__dirname, '..', '..', 'templates');
17
+ const srcDir = path.join(projectPath, 'src');
18
+
19
+ // Ensure src directory exists
20
+ if (!fs.existsSync(srcDir)) {
21
+ fs.mkdirSync(srcDir, { recursive: true });
22
+ }
23
+
24
+ // Copy all template files to src directory, except .claude
25
+ const entries = fs.readdirSync(templatesDir, { withFileTypes: true });
26
+
27
+ for (const entry of entries) {
28
+ const srcPath = path.join(templatesDir, entry.name);
29
+
30
+ // .claude folder should be copied to project root, not src
31
+ if (entry.name === '.claude') {
32
+ const destPath = path.join(projectPath, '.claude');
33
+ if (!fs.existsSync(destPath)) {
34
+ fs.mkdirSync(destPath, { recursive: true });
35
+ }
36
+ await copyDirectory(srcPath, destPath);
37
+ } else {
38
+ // All other files go to src directory
39
+ const destPath = path.join(srcDir, entry.name);
40
+ if (entry.isDirectory()) {
41
+ if (!fs.existsSync(destPath)) {
42
+ fs.mkdirSync(destPath, { recursive: true });
43
+ }
44
+ await copyDirectory(srcPath, destPath);
45
+ } else {
46
+ fs.copyFileSync(srcPath, destPath);
47
+ }
48
+ }
49
+ }
50
+
51
+ spinner.succeed('Template files copied');
52
+ } catch (error) {
53
+ spinner.fail('Failed to copy template files');
54
+ throw error;
55
+ }
56
+ }
57
+
@@ -0,0 +1,2 @@
1
+ export { copyTemplates } from './copyTemplates';
2
+
@@ -0,0 +1,55 @@
1
+ export interface Instance {
2
+ name: string;
3
+ guid: string;
4
+ org?: string;
5
+ }
6
+
7
+ export interface ApiKeys {
8
+ fetchKey: string;
9
+ previewKey: string;
10
+ securityKey: string;
11
+ }
12
+
13
+ export interface InstanceData {
14
+ guid: string;
15
+ name: string;
16
+ apiKeys: ApiKeys;
17
+ }
18
+
19
+ export interface CliOptions {
20
+ typescript?: boolean;
21
+ javascript?: boolean;
22
+ tailwind?: boolean;
23
+ eslint?: boolean;
24
+ app?: boolean;
25
+ srcDir?: boolean;
26
+ importAlias?: string;
27
+ useNpm?: boolean;
28
+ usePnpm?: boolean;
29
+ useYarn?: boolean;
30
+ useBun?: boolean;
31
+ skipInstall?: boolean;
32
+ [key: string]: unknown;
33
+ }
34
+
35
+ export interface ProjectConfig {
36
+ instanceGuid?: string;
37
+ apiKeys?: ApiKeys | null;
38
+ [key: string]: unknown;
39
+ }
40
+
41
+ export interface CreateNextAppOptions {
42
+ typescript?: boolean;
43
+ javascript?: boolean;
44
+ tailwind?: boolean;
45
+ eslint?: boolean;
46
+ app?: boolean;
47
+ srcDir?: boolean;
48
+ importAlias?: string;
49
+ useNpm?: boolean;
50
+ usePnpm?: boolean;
51
+ useYarn?: boolean;
52
+ useBun?: boolean;
53
+ skipInstall?: boolean;
54
+ }
55
+
@@ -0,0 +1,74 @@
1
+ import { spawn } from 'child_process';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+
5
+ /**
6
+ * Initialize a git repository
7
+ */
8
+ export async function initializeGit(projectPath: string): Promise<boolean> {
9
+ const spinner = ora('Initializing git repository...').start();
10
+
11
+ try {
12
+ // Initialize git
13
+ await runGitCommand(['init'], projectPath);
14
+
15
+ // Add all files
16
+ await runGitCommand(['add', '.'], projectPath);
17
+
18
+ // Create initial commit
19
+ await runGitCommand(
20
+ ['commit', '-m', 'Initial commit from create-next-agility-app'],
21
+ projectPath
22
+ );
23
+
24
+ spinner.succeed('Git repository initialized');
25
+ return true;
26
+ } catch (error) {
27
+ spinner.fail('Failed to initialize git repository');
28
+ console.log(chalk.yellow(' You can initialize git manually later with: git init'));
29
+ return false;
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Run a git command
35
+ */
36
+ function runGitCommand(args: string[], cwd: string): Promise<void> {
37
+ return new Promise((resolve, reject) => {
38
+ const child = spawn('git', args, {
39
+ cwd,
40
+ stdio: 'pipe',
41
+ });
42
+
43
+ let stderr = '';
44
+
45
+ child.stderr?.on('data', (data) => {
46
+ stderr += data.toString();
47
+ });
48
+
49
+ child.on('error', (error) => {
50
+ reject(error);
51
+ });
52
+
53
+ child.on('exit', (code) => {
54
+ if (code !== 0) {
55
+ reject(new Error(stderr || `Git command failed with code ${code}`));
56
+ } else {
57
+ resolve();
58
+ }
59
+ });
60
+ });
61
+ }
62
+
63
+ /**
64
+ * Check if git is available
65
+ */
66
+ export function isGitAvailable(): boolean {
67
+ try {
68
+ const { execSync } = require('child_process');
69
+ execSync('git --version', { stdio: 'ignore' });
70
+ return true;
71
+ } catch {
72
+ return false;
73
+ }
74
+ }