@@ -55,7 +55,6 @@ twenty app dev [options]
|
||||
-p, --path <path> Application directory path (default: current directory)
|
||||
-w, --workspace-id <id> Workspace ID
|
||||
-d, --debounce <ms> Debounce delay in milliseconds (default: 1000)
|
||||
--verbose Enable verbose logging
|
||||
|
||||
# Deploy application
|
||||
twenty app deploy [options]
|
||||
|
||||
@@ -13,13 +13,11 @@ program
|
||||
.description('CLI for Twenty application development')
|
||||
.version('0.1.0');
|
||||
|
||||
program
|
||||
.option('-v, --verbose', 'Enable verbose logging')
|
||||
.option(
|
||||
'--api-url <url>',
|
||||
'Twenty API URL',
|
||||
process.env.TWENTY_API_URL || 'http://localhost:3000',
|
||||
);
|
||||
program.option(
|
||||
'--api-url <url>',
|
||||
'Twenty API URL',
|
||||
process.env.TWENTY_API_URL || 'http://localhost:3000',
|
||||
);
|
||||
|
||||
program.addCommand(new AuthCommand().getCommand());
|
||||
program.addCommand(new AppCommand().getCommand());
|
||||
|
||||
@@ -7,24 +7,16 @@ import { syncApp } from '../utils/app-sync';
|
||||
export class AppDevCommand {
|
||||
private apiService = new ApiService();
|
||||
|
||||
async execute(options: {
|
||||
path?: string;
|
||||
debounce: string;
|
||||
verbose?: boolean;
|
||||
}): Promise<void> {
|
||||
async execute(options: { path?: string; debounce: string }): Promise<void> {
|
||||
try {
|
||||
const appPath = await resolveAppPath(options.path, options.verbose);
|
||||
const appPath = await resolveAppPath(options.path);
|
||||
const debounceMs = parseInt(options.debounce, 10);
|
||||
|
||||
this.logStartupInfo(appPath, debounceMs, options.verbose);
|
||||
this.logStartupInfo(appPath, debounceMs);
|
||||
|
||||
await syncApp(appPath, this.apiService);
|
||||
|
||||
const watcher = this.setupFileWatcher(
|
||||
appPath,
|
||||
debounceMs,
|
||||
options.verbose,
|
||||
);
|
||||
const watcher = this.setupFileWatcher(appPath, debounceMs);
|
||||
|
||||
this.setupGracefulShutdown(watcher);
|
||||
} catch (error) {
|
||||
@@ -36,22 +28,16 @@ export class AppDevCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private logStartupInfo(
|
||||
appPath: string,
|
||||
debounceMs: number,
|
||||
verbose?: boolean,
|
||||
): void {
|
||||
private logStartupInfo(appPath: string, debounceMs: number): void {
|
||||
console.log(chalk.blue('🚀 Starting Twenty Application Development Mode'));
|
||||
console.log(chalk.gray(`📁 App Path: ${appPath}`));
|
||||
console.log(chalk.gray(`⏱️ Debounce: ${debounceMs}ms`));
|
||||
console.log(chalk.gray(`🔧 Verbose: ${verbose ? 'On' : 'Off'}`));
|
||||
console.log('');
|
||||
}
|
||||
|
||||
private setupFileWatcher(
|
||||
appPath: string,
|
||||
debounceMs: number,
|
||||
verbose?: boolean,
|
||||
): chokidar.FSWatcher {
|
||||
const watcher = chokidar.watch(appPath, {
|
||||
ignored: /node_modules|\.git/,
|
||||
@@ -74,10 +60,7 @@ export class AppDevCommand {
|
||||
}, debounceMs);
|
||||
};
|
||||
|
||||
watcher.on('change', (filePath) => {
|
||||
if (verbose) {
|
||||
console.log(chalk.gray(`📝 ${filePath} changed`));
|
||||
}
|
||||
watcher.on('change', () => {
|
||||
debouncedSync();
|
||||
});
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ export class AppCommand {
|
||||
'Application directory path (auto-detected if not specified)',
|
||||
)
|
||||
.option('-d, --debounce <ms>', 'Debounce delay in milliseconds', '1000')
|
||||
.option('--verbose', 'Enable verbose logging')
|
||||
.action(async (options) => {
|
||||
await this.devCommand.execute(options);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import chalk from 'chalk';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import {
|
||||
@@ -9,17 +8,16 @@ import {
|
||||
|
||||
export const resolveAppPath = async (
|
||||
providedPath?: string,
|
||||
verbose = false,
|
||||
): Promise<string> => {
|
||||
if (providedPath && path.isAbsolute(providedPath)) {
|
||||
return validateAppPath(providedPath, verbose);
|
||||
return validateAppPath(providedPath);
|
||||
}
|
||||
|
||||
if (providedPath) {
|
||||
return resolveRelativePath(providedPath);
|
||||
}
|
||||
|
||||
return autoDetectAppPath(verbose);
|
||||
return autoDetectAppPath();
|
||||
};
|
||||
|
||||
const resolveRelativePath = async (providedPath: string): Promise<string> => {
|
||||
@@ -43,16 +41,13 @@ const resolveRelativePath = async (providedPath: string): Promise<string> => {
|
||||
Please check the path or run from the correct directory.`);
|
||||
};
|
||||
|
||||
const autoDetectAppPath = async (verbose = false): Promise<string> => {
|
||||
const autoDetectAppPath = async (): Promise<string> => {
|
||||
let currentDir = process.cwd();
|
||||
const maxDepth = 10;
|
||||
let depth = 0;
|
||||
|
||||
while (depth < maxDepth) {
|
||||
if (await isValidAppPath(currentDir)) {
|
||||
if (verbose) {
|
||||
console.log(chalk.gray(`Auto-detected app path: ${currentDir}`));
|
||||
}
|
||||
return currentDir;
|
||||
}
|
||||
|
||||
@@ -81,14 +76,7 @@ const autoDetectAppPath = async (verbose = false): Promise<string> => {
|
||||
throw new Error(errorMessage);
|
||||
};
|
||||
|
||||
const validateAppPath = async (
|
||||
appPath: string,
|
||||
verbose = false,
|
||||
): Promise<string> => {
|
||||
if (verbose) {
|
||||
console.log(chalk.gray(`Checking app path: ${appPath}`));
|
||||
}
|
||||
|
||||
const validateAppPath = async (appPath: string): Promise<string> => {
|
||||
const jsoncManifestPath = path.join(appPath, 'twenty-app.jsonc');
|
||||
const jsonManifestPath = path.join(appPath, 'twenty-app.json');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user