Fix twenty app dev image (#18852)

as title
This commit is contained in:
martmull
2026-03-24 10:31:05 +01:00
committed by GitHub
parent 493830204a
commit cc2be505c0
21 changed files with 255 additions and 127 deletions
@@ -15,8 +15,7 @@ export class AppBuildCommand {
await checkSdkVersionCompatibility(appPath);
console.log(chalk.blue('Building application...'));
console.log(chalk.gray(`App path: ${appPath}`));
console.log('');
console.log(chalk.gray(`App path: ${appPath}\n`));
const result = await appBuild({
appPath,
@@ -36,8 +36,7 @@ export class DeployCommand {
const remoteName = options.remote ?? ConfigService.getActiveRemote();
console.log(chalk.blue(`Deploying to ${remoteName} (${serverUrl})...`));
console.log(chalk.gray(`App path: ${appPath}`));
console.log('');
console.log(chalk.gray(`App path: ${appPath}\n`));
const result = await appDeploy({
appPath,
+4 -10
View File
@@ -33,8 +33,7 @@ export class LogicFunctionExecuteCommand {
: (functionUniversalIdentifier ?? functionName);
console.log(chalk.blue(`🚀 Executing function "${identifier}"...`));
console.log(chalk.gray(` Payload: ${JSON.stringify(parsedPayload)}`));
console.log('');
console.log(chalk.gray(` Payload: ${JSON.stringify(parsedPayload)}\n`));
const executeOptions = postInstall
? { appPath, postInstall: true as const, payload: parsedPayload }
@@ -58,8 +57,7 @@ export class LogicFunctionExecuteCommand {
break;
}
case FUNCTION_ERROR_CODES.FUNCTION_NOT_FOUND: {
console.error(chalk.red(result.error.message));
console.log('');
console.error(chalk.red(result.error.message), '\n');
const availableFunctions = (result.error.details
?.availableFunctions ?? []) as Array<{
@@ -106,30 +104,26 @@ export class LogicFunctionExecuteCommand {
`${chalk.bold('Status:')} ${statusColor(executionResult.status)}`,
);
console.log(`${chalk.bold('Duration:')} ${executionResult.duration}ms`);
console.log(`${chalk.bold('Duration:')} ${executionResult.duration}ms\n`);
if (isDefined(executionResult.data)) {
console.log('');
console.log(chalk.bold('Data:'));
console.log(chalk.white(JSON.stringify(executionResult.data, null, 2)));
}
if (executionResult.error) {
console.log('');
console.log(chalk.bold.red('Error:'));
console.log(chalk.red(` Type: ${executionResult.error.errorType}`));
console.log(
chalk.red(` Message: ${executionResult.error.errorMessage}`),
chalk.red(` Message: ${executionResult.error.errorMessage}\n`),
);
if (executionResult.error.stackTrace) {
console.log('');
console.log(chalk.gray('Stack trace:'));
console.log(chalk.gray(executionResult.error.stackTrace));
}
}
if (executionResult.logs) {
console.log('');
console.log(chalk.bold('Logs:'));
console.log(chalk.gray(executionResult.logs));
}
+1 -3
View File
@@ -59,9 +59,7 @@ export class LogicFunctionLogsCommand {
: 'functions';
console.log(
chalk.blue(`🚀 Watching ${appPath} ${functionIdentifier} logs:`),
chalk.blue(`🚀 Watching ${appPath} ${functionIdentifier} logs:\n`),
);
console.log('');
}
}
@@ -15,8 +15,7 @@ export class AppPublishCommand {
await checkSdkVersionCompatibility(appPath);
console.log(chalk.blue('Publishing to npm...'));
console.log(chalk.gray(`App path: ${appPath}`));
console.log('');
console.log(chalk.gray(`App path: ${appPath}\n`));
const result = await appPublish({
appPath,
@@ -70,6 +70,7 @@ export const registerRemoteCommands = (program: Command): void => {
.description('Add a new remote or re-authenticate an existing one')
.option('--as <name>', 'Name for this remote')
.option('--local', 'Connect to local development server')
.option('--port <port>', 'Port for local server (use with --local)')
.option('--token <token>', 'API key for non-interactive auth')
.option('--url <url>', 'Server URL (alternative to positional arg)')
.action(
@@ -78,6 +79,7 @@ export const registerRemoteCommands = (program: Command): void => {
options: {
as?: string;
local?: boolean;
port?: string;
token?: string;
url?: string;
},
@@ -87,7 +89,12 @@ export const registerRemoteCommands = (program: Command): void => {
if (options.local) {
const remoteName = options.as ?? 'local';
const localUrl = await detectLocalServer();
const preferredPort = options.port
? parseInt(options.port, 10)
: undefined;
const localUrl = preferredPort
? `http://localhost:${preferredPort}`
: await detectLocalServer();
if (!localUrl) {
console.error(
@@ -102,7 +109,6 @@ export const registerRemoteCommands = (program: Command): void => {
console.log(chalk.gray(`Found server at ${localUrl}`));
ConfigService.setActiveRemote(remoteName);
await authenticate(localUrl, options.token);
console.log(chalk.green(`✓ Authenticated remote "${remoteName}".`));
return;
}
@@ -116,7 +122,6 @@ export const registerRemoteCommands = (program: Command): void => {
ConfigService.setActiveRemote(nameOrUrl);
await authenticate(config.apiUrl, options.token);
console.log(chalk.green(`✓ Re-authenticated remote "${nameOrUrl}".`));
return;
}
@@ -156,8 +161,6 @@ export const registerRemoteCommands = (program: Command): void => {
if (defaultRemote === 'local') {
await configService.setDefaultRemote(name);
}
console.log(chalk.green(`✓ Authenticated remote "${name}".`));
},
);
@@ -196,8 +199,8 @@ export const registerRemoteCommands = (program: Command): void => {
);
}
console.log('');
console.log(
'\n',
chalk.gray("Use 'twenty remote switch <name>' to change default"),
);
});
+36 -27
View File
@@ -1,3 +1,4 @@
import { ConfigService } from '@/cli/utilities/config/config-service';
import { checkServerHealth } from '@/cli/utilities/server/detect-local-server';
import chalk from 'chalk';
import type { Command } from 'commander';
@@ -45,6 +46,20 @@ const containerExists = (): boolean => {
}
};
const checkDockerRunning = (): boolean => {
try {
execSync('docker info', { stdio: 'ignore' });
return true;
} catch {
console.error(
chalk.red('Docker is not running. Please start Docker and try again.'),
);
return false;
}
};
const validatePort = (value: string): number => {
const port = parseInt(value, 10);
@@ -69,6 +84,12 @@ export const registerServerCommands = (program: Command): void => {
let port = validatePort(options.port);
if (await checkServerHealth(port)) {
const localUrl = `http://localhost:${port}`;
const configService = new ConfigService();
ConfigService.setActiveRemote('local');
await configService.setConfig({ apiUrl: localUrl });
console.log(
chalk.green(`Twenty server is already running on localhost:${port}.`),
);
@@ -76,6 +97,10 @@ export const registerServerCommands = (program: Command): void => {
return;
}
if (!checkDockerRunning()) {
process.exit(1);
}
if (isContainerRunning()) {
console.log(chalk.gray('Container is running but not healthy yet.'));
@@ -93,30 +118,13 @@ export const registerServerCommands = (program: Command): void => {
);
}
port = existingPort;
console.log(chalk.gray('Starting existing container...'));
execSync(`docker start ${CONTAINER_NAME}`, { stdio: 'ignore' });
port = existingPort;
} else {
try {
execSync('docker info', { stdio: 'ignore' });
} catch {
console.error(
chalk.red(
'Docker is not running. Please start Docker and try again.',
),
);
process.exit(1);
}
console.log(chalk.gray(`Pulling ${IMAGE}...`));
try {
execSync(`docker pull ${IMAGE}`, { stdio: 'inherit' });
} catch {
console.log(chalk.gray('Pull failed, trying local image...'));
}
console.log(chalk.gray('Starting Twenty container...'));
const runResult = spawnSync(
'docker',
[
@@ -136,17 +144,18 @@ export const registerServerCommands = (program: Command): void => {
);
if (runResult.status !== 0) {
console.error(chalk.red('Failed to start Twenty container.'));
console.error(chalk.red('\nFailed to start Twenty container.'));
process.exit(runResult.status ?? 1);
}
}
console.log(
chalk.green(`Twenty server starting on http://localhost:${port}`),
);
console.log(
chalk.gray('Run `yarn twenty server logs` to follow startup progress.'),
);
const localUrl = `http://localhost:${port}`;
const configService = new ConfigService();
ConfigService.setActiveRemote('local');
await configService.setConfig({ apiUrl: localUrl });
console.log(chalk.green(`\nLocal remote configured → ${localUrl}`));
});
server
@@ -18,8 +18,7 @@ export class AppTypecheckCommand {
const appPath = options.appPath ?? CURRENT_EXECUTION_DIRECTORY;
console.log(chalk.blue('Running type check...'));
console.log(chalk.gray(`App path: ${appPath}`));
console.log('');
console.log(chalk.gray(`App path: ${appPath}\n`));
const errors = await runTypecheck(appPath);
@@ -32,8 +31,8 @@ export class AppTypecheckCommand {
console.log(formatTypecheckError(error));
}
console.log('');
console.log(
'\n',
chalk.red(
`✗ Found ${errors.length} type error${errors.length === 1 ? '' : 's'}`,
),
@@ -13,8 +13,7 @@ export class AppUninstallCommand {
askForConfirmation: boolean;
}): Promise<ApiResponse<any>> {
console.log(chalk.blue('🚀 Uninstall Twenty Application'));
console.log(chalk.gray(`📁 App Path: ${appPath}`));
console.log('');
console.log(chalk.gray(`📁 App Path: ${appPath}\n`));
if (askForConfirmation && !(await this.confirmationPrompt())) {
console.error(chalk.red('⛔️ Aborting uninstall'));