Merge twenty-cli into twenty-sdk (#16150)

- Moves twenty-cli content into twenty-sdk
- add a new twenty-sdk:0.1.0 version
- this new twenty-sdk exports a cli command called 'twenty' (like
twenty-cli before)
- deprecates twenty-cli
- simplify app init command base-project
- use `twenty-sdk:0.1.0` in base project
- move the "twenty-sdk/application" barrel to "twenty-sdk"
- add `create-twenty-app` package

<img width="1512" height="919" alt="image"
src="https://github.com/user-attachments/assets/007bef45-4e71-419a-9213-cebed376adbf"
/>

<img width="1506" height="929" alt="image"
src="https://github.com/user-attachments/assets/3de2fec6-1624-4923-ae13-f4e1cf165eb5"
/>
This commit is contained in:
martmull
2025-12-01 11:44:35 +01:00
committed by GitHub
parent 3f08a0c901
commit e498367e2f
85 changed files with 1077 additions and 1560 deletions
@@ -0,0 +1,137 @@
import chalk from 'chalk';
import * as fs from 'fs-extra';
import inquirer from 'inquirer';
import * as path from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';
import { copyBaseApplicationProject } from './utils/app-template';
import kebabCase from 'lodash.kebabcase';
import { convertToLabel } from './utils/convert-to-label';
const CURRENT_EXECUTION_DIRECTORY = process.env.INIT_CWD || process.cwd();
const execPromise = promisify(exec);
export class CreateAppCommand {
async execute(directory?: string): Promise<void> {
try {
const { appName, appDisplayName, appDirectory, appDescription } =
await this.getAppInfos(directory);
await this.validateDirectory(appDirectory);
this.logCreationInfo({ appDirectory, appName });
await fs.ensureDir(appDirectory);
await copyBaseApplicationProject({
appName,
appDisplayName,
appDescription,
appDirectory,
});
try {
const result = await execPromise('yarn --version', {
cwd: appDirectory,
});
console.log('Installing dependencies using yarn', result.stdout);
await execPromise('yarn', { cwd: appDirectory });
} catch (error: any) {
console.error(chalk.red('yarn install failed:'), error.stdout);
process.exit(1);
}
await this.logSuccess(appDirectory);
} catch (error) {
console.error(
chalk.red('Initialization failed:'),
error instanceof Error ? error.message : error,
);
process.exit(1);
}
}
private async getAppInfos(directory?: string): Promise<{
appName: string;
appDisplayName: string;
appDescription: string;
appDirectory: string;
}> {
const { name, displayName, description } = await inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'Application name:',
when: () => !directory,
default: 'my-awesome-app',
validate: (input) => {
if (input.length === 0) return 'Application name is required';
return true;
},
},
{
type: 'input',
name: 'displayName',
message: 'Application display name:',
default: (answers: any) => {
return convertToLabel(answers?.name ?? directory);
},
},
{
type: 'input',
name: 'description',
message: 'Application description (optional):',
default: '',
},
]);
const computedName = name ?? directory;
const appName = computedName.trim();
const appDisplayName = displayName.trim();
const appDescription = description.trim();
const appDirectory = directory
? path.join(CURRENT_EXECUTION_DIRECTORY, directory)
: path.join(CURRENT_EXECUTION_DIRECTORY, kebabCase(appName));
return { appName, appDisplayName, appDirectory, appDescription };
}
private async validateDirectory(appDirectory: string): Promise<void> {
if (!(await fs.pathExists(appDirectory))) {
return;
}
const files = await fs.readdir(appDirectory);
if (files.length > 0) {
throw new Error(
`Directory ${appDirectory} already exists and is not empty`,
);
}
}
private logCreationInfo({
appDirectory,
appName,
}: {
appDirectory: string;
appName: string;
}): void {
console.log(chalk.blue('🎯 Creating Twenty Application'));
console.log(chalk.gray(`📁 Directory: ${appDirectory}`));
console.log(chalk.gray(`📝 Name: ${appName}`));
console.log('');
}
private logSuccess(appDirectory: string): void {
console.log(chalk.green('✅ Application created successfully!'));
console.log('');
console.log(chalk.blue('Next steps:'));
console.log(` cd ${appDirectory.split('/').reverse()[0] ?? ''}`);
console.log(' twenty app dev');
}
}