@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.
- package/.claude/settings.json +7 -0
- package/.claude/settings.local.json +24 -0
- package/FEATURE_ROADMAP.md +343 -0
- package/README.md +205 -0
- package/TESTING.md +131 -0
- package/bin/create-agility-app.js +48 -0
- package/dist/agility/api-keys/generateApiKeys.d.ts +9 -0
- package/dist/agility/api-keys/generateApiKeys.d.ts.map +1 -0
- package/dist/agility/api-keys/generateApiKeys.js +99 -0
- package/dist/agility/api-keys/generateApiKeys.js.map +1 -0
- package/dist/agility/api-keys/getApiKeys.d.ts +9 -0
- package/dist/agility/api-keys/getApiKeys.d.ts.map +1 -0
- package/dist/agility/api-keys/getApiKeys.js +14 -0
- package/dist/agility/api-keys/getApiKeys.js.map +1 -0
- package/dist/agility/index.d.ts +3 -0
- package/dist/agility/index.d.ts.map +1 -0
- package/dist/agility/index.js +8 -0
- package/dist/agility/index.js.map +1 -0
- package/dist/agility/instance/createNewInstance.d.ts +8 -0
- package/dist/agility/instance/createNewInstance.d.ts.map +1 -0
- package/dist/agility/instance/createNewInstance.js +65 -0
- package/dist/agility/instance/createNewInstance.js.map +1 -0
- package/dist/agility/instance/getAvailableInstances.d.ts +8 -0
- package/dist/agility/instance/getAvailableInstances.d.ts.map +1 -0
- package/dist/agility/instance/getAvailableInstances.js +43 -0
- package/dist/agility/instance/getAvailableInstances.js.map +1 -0
- package/dist/agility/instance/manageInstance.d.ts +9 -0
- package/dist/agility/instance/manageInstance.d.ts.map +1 -0
- package/dist/agility/instance/manageInstance.js +82 -0
- package/dist/agility/instance/manageInstance.js.map +1 -0
- package/dist/agility/utils/getMgmtAPIUrl.d.ts +20 -0
- package/dist/agility/utils/getMgmtAPIUrl.d.ts.map +1 -0
- package/dist/agility/utils/getMgmtAPIUrl.js +61 -0
- package/dist/agility/utils/getMgmtAPIUrl.js.map +1 -0
- package/dist/auth/api-key/authenticateWithApiKey.d.ts +6 -0
- package/dist/auth/api-key/authenticateWithApiKey.d.ts.map +1 -0
- package/dist/auth/api-key/authenticateWithApiKey.js +28 -0
- package/dist/auth/api-key/authenticateWithApiKey.js.map +1 -0
- package/dist/auth/index.d.ts +3 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +8 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth/authenticate.d.ts +6 -0
- package/dist/auth/oauth/authenticate.d.ts.map +1 -0
- package/dist/auth/oauth/authenticate.js +162 -0
- package/dist/auth/oauth/authenticate.js.map +1 -0
- package/dist/auth/oauth/constants.d.ts +5 -0
- package/dist/auth/oauth/constants.d.ts.map +1 -0
- package/dist/auth/oauth/constants.js +9 -0
- package/dist/auth/oauth/constants.js.map +1 -0
- package/dist/auth/oauth/exchangeCodeForToken.d.ts +7 -0
- package/dist/auth/oauth/exchangeCodeForToken.d.ts.map +1 -0
- package/dist/auth/oauth/exchangeCodeForToken.js +39 -0
- package/dist/auth/oauth/exchangeCodeForToken.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +290 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/promptForMissingOptions.d.ts +8 -0
- package/dist/cli/promptForMissingOptions.d.ts.map +1 -0
- package/dist/cli/promptForMissingOptions.js +92 -0
- package/dist/cli/promptForMissingOptions.js.map +1 -0
- package/dist/config/env/createEnvFile.d.ts +6 -0
- package/dist/config/env/createEnvFile.d.ts.map +1 -0
- package/dist/config/env/createEnvFile.js +31 -0
- package/dist/config/env/createEnvFile.js.map +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/mcp/createMcpConfig.d.ts +5 -0
- package/dist/config/mcp/createMcpConfig.d.ts.map +1 -0
- package/dist/config/mcp/createMcpConfig.js +32 -0
- package/dist/config/mcp/createMcpConfig.js.map +1 -0
- package/dist/config/packages/installAgilityPackages.d.ts +6 -0
- package/dist/config/packages/installAgilityPackages.d.ts.map +1 -0
- package/dist/config/packages/installAgilityPackages.js +61 -0
- package/dist/config/packages/installAgilityPackages.js.map +1 -0
- package/dist/config/setupProject.d.ts +8 -0
- package/dist/config/setupProject.d.ts.map +1 -0
- package/dist/config/setupProject.js +32 -0
- package/dist/config/setupProject.js.map +1 -0
- package/dist/create-next-app/createNextApp.d.ts +9 -0
- package/dist/create-next-app/createNextApp.d.ts.map +1 -0
- package/dist/create-next-app/createNextApp.js +83 -0
- package/dist/create-next-app/createNextApp.js.map +1 -0
- package/dist/create-next-app/index.d.ts +3 -0
- package/dist/create-next-app/index.d.ts.map +1 -0
- package/dist/create-next-app/index.js +8 -0
- package/dist/create-next-app/index.js.map +1 -0
- package/dist/scaffold/components/createPageComponents.d.ts +6 -0
- package/dist/scaffold/components/createPageComponents.d.ts.map +1 -0
- package/dist/scaffold/components/createPageComponents.js +62 -0
- package/dist/scaffold/components/createPageComponents.js.map +1 -0
- package/dist/scaffold/containers/createContainers.d.ts +6 -0
- package/dist/scaffold/containers/createContainers.d.ts.map +1 -0
- package/dist/scaffold/containers/createContainers.js +48 -0
- package/dist/scaffold/containers/createContainers.js.map +1 -0
- package/dist/scaffold/index.d.ts +2 -0
- package/dist/scaffold/index.d.ts.map +1 -0
- package/dist/scaffold/index.js +6 -0
- package/dist/scaffold/index.js.map +1 -0
- package/dist/scaffold/instance/createBlankInstance.d.ts +8 -0
- package/dist/scaffold/instance/createBlankInstance.d.ts.map +1 -0
- package/dist/scaffold/instance/createBlankInstance.js +51 -0
- package/dist/scaffold/instance/createBlankInstance.js.map +1 -0
- package/dist/scaffold/models/createContentModels.d.ts +6 -0
- package/dist/scaffold/models/createContentModels.d.ts.map +1 -0
- package/dist/scaffold/models/createContentModels.js +70 -0
- package/dist/scaffold/models/createContentModels.js.map +1 -0
- package/dist/templates/copyDirectory.d.ts +5 -0
- package/dist/templates/copyDirectory.d.ts.map +1 -0
- package/dist/templates/copyDirectory.js +28 -0
- package/dist/templates/copyDirectory.js.map +1 -0
- package/dist/templates/copyTemplates.d.ts +8 -0
- package/dist/templates/copyTemplates.d.ts.map +1 -0
- package/dist/templates/copyTemplates.js +58 -0
- package/dist/templates/copyTemplates.js.map +1 -0
- package/dist/templates/index.d.ts +2 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +6 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/types/index.d.ts +50 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/git.d.ts +9 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +71 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/validation.d.ts +45 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +180 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +45 -0
- package/src/agility/api-keys/generateApiKeys.ts +100 -0
- package/src/agility/api-keys/getApiKeys.ts +13 -0
- package/src/agility/index.ts +3 -0
- package/src/agility/instance/createNewInstance.ts +67 -0
- package/src/agility/instance/getAvailableInstances.ts +49 -0
- package/src/agility/instance/manageInstance.ts +90 -0
- package/src/agility/utils/getMgmtAPIUrl.ts +68 -0
- package/src/auth/api-key/authenticateWithApiKey.ts +24 -0
- package/src/auth/index.ts +3 -0
- package/src/auth/oauth/authenticate.ts +165 -0
- package/src/auth/oauth/constants.ts +6 -0
- package/src/auth/oauth/exchangeCodeForToken.ts +43 -0
- package/src/cli/index.ts +281 -0
- package/src/cli/promptForMissingOptions.ts +104 -0
- package/src/config/env/createEnvFile.ts +30 -0
- package/src/config/index.ts +2 -0
- package/src/config/mcp/createMcpConfig.ts +30 -0
- package/src/config/packages/installAgilityPackages.ts +63 -0
- package/src/config/setupProject.ts +31 -0
- package/src/create-next-app/createNextApp.ts +75 -0
- package/src/create-next-app/index.ts +3 -0
- package/src/scaffold/components/createPageComponents.ts +74 -0
- package/src/scaffold/containers/createContainers.ts +55 -0
- package/src/scaffold/index.ts +2 -0
- package/src/scaffold/instance/createBlankInstance.ts +55 -0
- package/src/scaffold/models/createContentModels.ts +83 -0
- package/src/templates/copyDirectory.ts +24 -0
- package/src/templates/copyTemplates.ts +57 -0
- package/src/templates/index.ts +2 -0
- package/src/types/index.ts +55 -0
- package/src/utils/git.ts +74 -0
- package/src/utils/validation.ts +184 -0
- package/templates/.claude/QUICK-START.md +230 -0
- package/templates/.claude/README.md +32 -0
- package/templates/.claude/settings.json +8 -0
- package/templates/BLANK-INSTANCE-SETUP.md +375 -0
- package/templates/DEVELOPMENT.md +160 -0
- package/templates/EXAMPLE-PROMPTS.md +643 -0
- package/templates/PROMPTS.md +410 -0
- package/templates/README.md +281 -0
- package/templates/agents.md +429 -0
- package/templates/app/[locale]/[...slug]/error.tsx +17 -0
- package/templates/app/[locale]/[...slug]/not-found.tsx +9 -0
- package/templates/app/[locale]/[...slug]/page.tsx +102 -0
- package/templates/app/[locale]/layout.tsx +22 -0
- package/templates/app/[locale]/page.tsx +12 -0
- package/templates/app/api/dynamic-redirect/route.ts +24 -0
- package/templates/app/api/preview/exit/route.ts +34 -0
- package/templates/app/api/preview/route.ts +63 -0
- package/templates/app/api/revalidate/route.ts +118 -0
- package/templates/components/agility-components/RichTextArea.tsx +66 -0
- package/templates/components/agility-components/index.ts +30 -0
- package/templates/components/agility-pages/MainTemplate.tsx +36 -0
- package/templates/components/agility-pages/index.ts +11 -0
- package/templates/docs/01-agility-cms-overview.md +139 -0
- package/templates/docs/02-page-routing.md +251 -0
- package/templates/docs/03-creating-components.md +462 -0
- package/templates/docs/04-data-fetching.md +484 -0
- package/templates/docs/05-containers-and-lists.md +596 -0
- package/templates/docs/06-localization.md +561 -0
- package/templates/docs/07-caching-strategies.md +410 -0
- package/templates/docs/08-common-components.md +756 -0
- package/templates/docs/09-whats-included.md +279 -0
- package/templates/docs/10-mcp-server-setup.md +153 -0
- package/templates/docs/11-linked-nested-content.md +611 -0
- package/templates/docs/README.md +164 -0
- package/templates/lib/cms/getAgilityContext.ts +28 -0
- package/templates/lib/cms/getAgilityPage.ts +51 -0
- package/templates/lib/cms/getAgilitySDK.ts +22 -0
- package/templates/lib/cms/getContentItem.ts +20 -0
- package/templates/lib/cms/getContentList.ts +19 -0
- package/templates/lib/cms/getRedirections.ts +85 -0
- package/templates/lib/cms/getSitemapFlat.ts +19 -0
- package/templates/lib/cms/getSitemapNested.ts +19 -0
- package/templates/lib/env.ts +99 -0
- package/templates/lib/i18n/config.ts +28 -0
- package/templates/proxy.ts +101 -0
- 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,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,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,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
|
+
|
package/src/utils/git.ts
ADDED
|
@@ -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
|
+
}
|