@launchframe/cli 1.0.0 → 1.0.1
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/package.json +1 -1
- package/src/commands/cache.js +19 -14
- package/src/commands/database-console.js +42 -2
- package/src/commands/deploy-sync-features.js +14 -12
- package/src/commands/dev-logo.js +3 -2
- package/src/commands/docker-logs.js +26 -7
- package/src/commands/docker-up.js +17 -3
- package/src/commands/migration-create.js +1 -3
- package/src/commands/module.js +15 -13
- package/src/commands/service.js +22 -12
- package/src/commands/waitlist-logs.js +20 -3
- package/src/index.js +12 -12
package/package.json
CHANGED
package/src/commands/cache.js
CHANGED
|
@@ -3,24 +3,29 @@ const { clearCache, getCacheInfo } = require('../utils/service-cache');
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Clear service cache
|
|
6
|
+
* @param {Object} flags - Optional flags
|
|
7
|
+
* @param {boolean} flags.yes - Skip confirmation prompt
|
|
8
|
+
* @param {boolean} flags.y - Skip confirmation prompt (short form)
|
|
6
9
|
*/
|
|
7
|
-
async function cacheClear() {
|
|
10
|
+
async function cacheClear(flags = {}) {
|
|
8
11
|
console.log(chalk.yellow('\n⚠️ This will delete all cached services'));
|
|
9
12
|
console.log(chalk.gray('You will need to re-download on next init or service:add\n'));
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
|
|
14
|
+
if (!(flags.yes || flags.y)) {
|
|
15
|
+
const inquirer = require('inquirer');
|
|
16
|
+
const { confirmed } = await inquirer.prompt([{
|
|
17
|
+
type: 'confirm',
|
|
18
|
+
name: 'confirmed',
|
|
19
|
+
message: 'Continue with cache clear?',
|
|
20
|
+
default: false
|
|
21
|
+
}]);
|
|
22
|
+
|
|
23
|
+
if (!confirmed) {
|
|
24
|
+
console.log('Cancelled');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
22
27
|
}
|
|
23
|
-
|
|
28
|
+
|
|
24
29
|
await clearCache();
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -5,7 +5,7 @@ const inquirer = require('inquirer');
|
|
|
5
5
|
const { spawnSync } = require('child_process');
|
|
6
6
|
const { requireProject, getProjectConfig } = require('../utils/project-helpers');
|
|
7
7
|
|
|
8
|
-
async function databaseConsole({ remote = false } = {}) {
|
|
8
|
+
async function databaseConsole({ remote = false, query = null } = {}) {
|
|
9
9
|
requireProject();
|
|
10
10
|
|
|
11
11
|
const infrastructurePath = path.join(process.cwd(), 'infrastructure');
|
|
@@ -28,7 +28,24 @@ async function databaseConsole({ remote = false } = {}) {
|
|
|
28
28
|
|
|
29
29
|
const { vpsUser, vpsHost, vpsAppFolder } = config.deployment;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
if (query) {
|
|
32
|
+
// Non-interactive query mode — pipe SQL via stdin, skip confirmation
|
|
33
|
+
const remoteCmd = `cd ${vpsAppFolder}/infrastructure && docker compose -f docker-compose.yml -f docker-compose.prod.yml exec -T database sh -c 'psql -U $POSTGRES_USER $POSTGRES_DB'`;
|
|
34
|
+
const result = spawnSync('ssh', [`${vpsUser}@${vpsHost}`, remoteCmd], {
|
|
35
|
+
input: query,
|
|
36
|
+
stdio: ['pipe', 'inherit', 'inherit'],
|
|
37
|
+
encoding: 'utf8'
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (result.status !== 0) {
|
|
41
|
+
console.error(chalk.red('\n❌ Could not execute query on the production database.'));
|
|
42
|
+
console.log(chalk.gray('Check that the VPS is reachable and services are running.\n'));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 2. Warn before connecting to production (interactive mode only)
|
|
32
49
|
console.log(chalk.yellow.bold('\n⚠️ You are about to connect to the PRODUCTION database.\n'));
|
|
33
50
|
console.log(chalk.gray(` Host: ${vpsHost}`));
|
|
34
51
|
console.log(chalk.gray(` Folder: ${vpsAppFolder}\n`));
|
|
@@ -62,6 +79,29 @@ async function databaseConsole({ remote = false } = {}) {
|
|
|
62
79
|
process.exit(1);
|
|
63
80
|
}
|
|
64
81
|
} else {
|
|
82
|
+
if (query) {
|
|
83
|
+
// Non-interactive local query mode — pipe SQL via stdin
|
|
84
|
+
const psqlCmd = [
|
|
85
|
+
'compose', '-f', 'docker-compose.yml', '-f', 'docker-compose.dev.yml',
|
|
86
|
+
'exec', '-T', 'database', 'sh', '-c', 'psql -U $POSTGRES_USER $POSTGRES_DB'
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const result = spawnSync('docker', psqlCmd, {
|
|
90
|
+
cwd: infrastructurePath,
|
|
91
|
+
input: query,
|
|
92
|
+
stdio: ['pipe', 'inherit', 'inherit'],
|
|
93
|
+
encoding: 'utf8'
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (result.status !== 0) {
|
|
97
|
+
console.error(chalk.red('\n❌ Could not execute query on the local database container.'));
|
|
98
|
+
console.log(chalk.gray('Make sure services are running:'));
|
|
99
|
+
console.log(chalk.white(' launchframe docker:up\n'));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
65
105
|
console.log(chalk.blue.bold('\n🗄️ Opening local database console...\n'));
|
|
66
106
|
|
|
67
107
|
// Let the shell inside the container expand $POSTGRES_USER / $POSTGRES_DB
|
|
@@ -34,7 +34,7 @@ function sqlBool(val) {
|
|
|
34
34
|
return val ? 'true' : 'false';
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
async function deploySyncFeatures() {
|
|
37
|
+
async function deploySyncFeatures(flags = {}) {
|
|
38
38
|
requireProject();
|
|
39
39
|
|
|
40
40
|
// Step 1 — Project + infrastructure check
|
|
@@ -162,18 +162,20 @@ async function deploySyncFeatures() {
|
|
|
162
162
|
console.log(chalk.gray(` Remote host: ${vpsHost}\n`));
|
|
163
163
|
console.log(chalk.red('This will TRUNCATE subscription_plan_features (cascades to feature values).\n'));
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
{
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
165
|
+
if (!flags.yes) {
|
|
166
|
+
const { confirmed } = await inquirer.prompt([
|
|
167
|
+
{
|
|
168
|
+
type: 'confirm',
|
|
169
|
+
name: 'confirmed',
|
|
170
|
+
message: 'Are you sure you want to sync features to production?',
|
|
171
|
+
default: false
|
|
172
|
+
}
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
if (!confirmed) {
|
|
176
|
+
console.log(chalk.gray('\nAborted.\n'));
|
|
177
|
+
process.exit(0);
|
|
171
178
|
}
|
|
172
|
-
]);
|
|
173
|
-
|
|
174
|
-
if (!confirmed) {
|
|
175
|
-
console.log(chalk.gray('\nAborted.\n'));
|
|
176
|
-
process.exit(0);
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
// Step 9 — Build sync SQL transaction
|
package/src/commands/dev-logo.js
CHANGED
|
@@ -30,12 +30,13 @@ function writeFile(filePath, data) {
|
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Generate and inject logo/favicon assets across all relevant frontend services
|
|
33
|
+
* @param {string} svgPath - Optional path to SVG file (defaults to <projectRoot>/logo.svg)
|
|
33
34
|
*/
|
|
34
|
-
async function devLogo() {
|
|
35
|
+
async function devLogo(svgPath) {
|
|
35
36
|
requireProject();
|
|
36
37
|
|
|
37
38
|
const cwd = process.cwd();
|
|
38
|
-
const logoPath = path.join(cwd, 'logo.svg');
|
|
39
|
+
const logoPath = svgPath || path.join(cwd, 'logo.svg');
|
|
39
40
|
|
|
40
41
|
if (!fs.existsSync(logoPath)) {
|
|
41
42
|
console.error(chalk.red('\n❌ Error: logo.svg not found'));
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
|
-
const { spawn } = require('child_process');
|
|
4
|
+
const { spawn, execSync } = require('child_process');
|
|
5
5
|
const { requireProject } = require('../utils/project-helpers');
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* View logs from Docker services
|
|
9
|
+
* @param {string} service - Optional service name to filter logs
|
|
10
|
+
* @param {Object} flags - Optional flags
|
|
11
|
+
* @param {boolean} flags['no-follow'] - Snapshot mode: print lines and exit (non-interactive)
|
|
12
|
+
* @param {number} flags.tail - Number of lines to show (default 100, only used with --no-follow)
|
|
9
13
|
*/
|
|
10
|
-
async function dockerLogs() {
|
|
14
|
+
async function dockerLogs(service, flags = {}) {
|
|
11
15
|
requireProject();
|
|
12
16
|
|
|
13
17
|
const infrastructurePath = path.join(process.cwd(), 'infrastructure');
|
|
@@ -18,9 +22,24 @@ async function dockerLogs() {
|
|
|
18
22
|
process.exit(1);
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
const service = process.argv[3];
|
|
25
|
+
const noFollow = flags['no-follow'];
|
|
23
26
|
|
|
27
|
+
if (noFollow) {
|
|
28
|
+
// Snapshot mode — print tail and exit (non-interactive, suitable for MCP)
|
|
29
|
+
const tail = flags.tail || 100;
|
|
30
|
+
const args = ['-f', 'docker-compose.yml', '-f', 'docker-compose.dev.yml', 'logs', '--no-follow', '--tail', String(tail)];
|
|
31
|
+
if (service) args.push(service);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
execSync(`docker-compose ${args.join(' ')}`, { cwd: infrastructurePath, stdio: 'inherit' });
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error(chalk.red('\n❌ Error viewing logs:'), error.message);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Streaming mode (interactive)
|
|
24
43
|
console.log(chalk.blue.bold('\n📋 Docker Service Logs\n'));
|
|
25
44
|
|
|
26
45
|
if (service) {
|
|
@@ -34,14 +53,14 @@ async function dockerLogs() {
|
|
|
34
53
|
|
|
35
54
|
try {
|
|
36
55
|
const logsCommand = 'docker-compose';
|
|
37
|
-
const
|
|
56
|
+
const spawnArgs = ['-f', 'docker-compose.yml', '-f', 'docker-compose.dev.yml', 'logs', '-f'];
|
|
38
57
|
|
|
39
58
|
if (service) {
|
|
40
|
-
|
|
59
|
+
spawnArgs.push(service);
|
|
41
60
|
}
|
|
42
61
|
|
|
43
62
|
// Use spawn to stream output in real-time
|
|
44
|
-
const child = spawn(logsCommand,
|
|
63
|
+
const child = spawn(logsCommand, spawnArgs, {
|
|
45
64
|
cwd: infrastructurePath,
|
|
46
65
|
stdio: 'inherit',
|
|
47
66
|
shell: true
|
|
@@ -7,8 +7,10 @@ const { requireProject, getProjectConfig } = require('../utils/project-helpers')
|
|
|
7
7
|
/**
|
|
8
8
|
* Start Docker services (all or specific service)
|
|
9
9
|
* @param {string} serviceName - Optional service name to start (e.g., 'docs', 'backend')
|
|
10
|
+
* @param {Object} flags - Optional flags
|
|
11
|
+
* @param {boolean} flags.detach - Run detached (docker-compose up -d) instead of watch mode
|
|
10
12
|
*/
|
|
11
|
-
async function dockerUp(serviceName) {
|
|
13
|
+
async function dockerUp(serviceName, flags = {}) {
|
|
12
14
|
requireProject();
|
|
13
15
|
|
|
14
16
|
const infrastructurePath = path.join(process.cwd(), 'infrastructure');
|
|
@@ -19,14 +21,26 @@ async function dockerUp(serviceName) {
|
|
|
19
21
|
process.exit(1);
|
|
20
22
|
}
|
|
21
23
|
|
|
24
|
+
if (flags.detach) {
|
|
25
|
+
// Detached mode — start services in background (no watch, no blocking)
|
|
26
|
+
const upCommand = serviceName
|
|
27
|
+
? `docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d ${serviceName}`
|
|
28
|
+
: 'docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d';
|
|
29
|
+
|
|
30
|
+
console.log(chalk.gray(`Running: ${upCommand}\n`));
|
|
31
|
+
execSync(upCommand, { cwd: infrastructurePath, stdio: 'inherit' });
|
|
32
|
+
console.log(chalk.green.bold('\n✅ Services started in detached mode.\n'));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
22
36
|
// Check Docker Compose version for watch support
|
|
23
37
|
try {
|
|
24
38
|
const composeVersion = execSync('docker compose version', { encoding: 'utf8' });
|
|
25
39
|
const versionMatch = composeVersion.match(/v?(\d+)\.(\d+)\.(\d+)/);
|
|
26
|
-
|
|
40
|
+
|
|
27
41
|
if (versionMatch) {
|
|
28
42
|
const [, major, minor] = versionMatch.map(Number);
|
|
29
|
-
|
|
43
|
+
|
|
30
44
|
if (major < 2 || (major === 2 && minor < 22)) {
|
|
31
45
|
console.error(chalk.red('\n❌ Error: Docker Compose v2.22+ is required for watch support'));
|
|
32
46
|
console.log(chalk.yellow(`Current version: Docker Compose v${major}.${minor}`));
|
|
@@ -4,7 +4,7 @@ const chalk = require('chalk');
|
|
|
4
4
|
const { execSync } = require('child_process');
|
|
5
5
|
const { requireProject } = require('../utils/project-helpers');
|
|
6
6
|
|
|
7
|
-
async function migrateCreate() {
|
|
7
|
+
async function migrateCreate(migrationName) {
|
|
8
8
|
requireProject();
|
|
9
9
|
|
|
10
10
|
const infrastructurePath = path.join(process.cwd(), 'infrastructure');
|
|
@@ -15,8 +15,6 @@ async function migrateCreate() {
|
|
|
15
15
|
process.exit(1);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
const migrationName = process.argv[3];
|
|
19
|
-
|
|
20
18
|
if (!migrationName) {
|
|
21
19
|
console.error(chalk.red('\n❌ Error: migration name is required'));
|
|
22
20
|
console.log(chalk.gray('Usage: launchframe migrate:create <name>\n'));
|
package/src/commands/module.js
CHANGED
|
@@ -41,7 +41,7 @@ async function moduleList() {
|
|
|
41
41
|
console.log(' launchframe module:add <module-name>');
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
async function moduleAdd(moduleName) {
|
|
44
|
+
async function moduleAdd(moduleName, flags = {}) {
|
|
45
45
|
requireProject();
|
|
46
46
|
|
|
47
47
|
// Validate module exists in registry
|
|
@@ -97,16 +97,18 @@ async function moduleAdd(moduleName) {
|
|
|
97
97
|
console.log(mod.description);
|
|
98
98
|
console.log(`Affects services: ${mod.services.join(', ')}`);
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
if (!(flags.yes || flags.y)) {
|
|
101
|
+
const { confirmed } = await inquirer.prompt([{
|
|
102
|
+
type: 'confirm',
|
|
103
|
+
name: 'confirmed',
|
|
104
|
+
message: `Add module "${mod.displayName}" to your project?`,
|
|
105
|
+
default: true
|
|
106
|
+
}]);
|
|
107
|
+
|
|
108
|
+
if (!confirmed) {
|
|
109
|
+
console.log('Installation cancelled');
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
const affectedServices = [...new Set(Object.keys(MODULE_CONFIG[moduleName] || {}))].filter(s => s !== 'infrastructure');
|
|
@@ -139,8 +141,8 @@ async function moduleAdd(moduleName) {
|
|
|
139
141
|
await dockerBuild(service);
|
|
140
142
|
}
|
|
141
143
|
|
|
142
|
-
// Restart the full stack
|
|
143
|
-
await dockerUp();
|
|
144
|
+
// Restart the full stack (detached when running non-interactively, watch otherwise)
|
|
145
|
+
await dockerUp(undefined, flags.yes || flags.y ? { detach: true } : {});
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
module.exports = { moduleAdd, moduleList };
|
package/src/commands/service.js
CHANGED
|
@@ -10,7 +10,7 @@ const { updateEnvFile } = require('../utils/env-generator');
|
|
|
10
10
|
const { checkGitHubAccess, showAccessDeniedMessage } = require('../utils/github-access');
|
|
11
11
|
const { ensureCacheReady, getServicePath } = require('../utils/service-cache');
|
|
12
12
|
|
|
13
|
-
async function serviceAdd(serviceName) {
|
|
13
|
+
async function serviceAdd(serviceName, flags = {}) {
|
|
14
14
|
// STEP 1: Validation
|
|
15
15
|
console.log(chalk.blue(`Installing ${serviceName} service...`));
|
|
16
16
|
|
|
@@ -49,16 +49,18 @@ async function serviceAdd(serviceName) {
|
|
|
49
49
|
console.log(`Tech stack: ${service.techStack}`);
|
|
50
50
|
console.log(`Dependencies: ${service.dependencies.join(', ')}`);
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
if (!(flags.yes || flags.y)) {
|
|
53
|
+
const { confirmed } = await inquirer.prompt([{
|
|
54
|
+
type: 'confirm',
|
|
55
|
+
name: 'confirmed',
|
|
56
|
+
message: 'Continue with installation?',
|
|
57
|
+
default: true
|
|
58
|
+
}]);
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
if (!confirmed) {
|
|
61
|
+
console.log('Installation cancelled');
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
// STEP 3: Get service files (from cache in production, local in dev)
|
|
@@ -124,7 +126,7 @@ async function serviceAdd(serviceName) {
|
|
|
124
126
|
|
|
125
127
|
// STEP 4: Service-specific prompts (e.g., Airtable credentials)
|
|
126
128
|
console.log(chalk.blue('\nConfiguring service...'));
|
|
127
|
-
const envValues = await runServicePrompts(service);
|
|
129
|
+
const envValues = await runServicePrompts(service, flags);
|
|
128
130
|
|
|
129
131
|
// STEP 5: Replace template variables
|
|
130
132
|
console.log(chalk.blue('\nCustomizing service for your project...'));
|
|
@@ -265,9 +267,17 @@ async function serviceAdd(serviceName) {
|
|
|
265
267
|
console.log(`\n📖 See README.md in ${serviceName}/ for more details.`);
|
|
266
268
|
}
|
|
267
269
|
|
|
268
|
-
async function runServicePrompts(service) {
|
|
270
|
+
async function runServicePrompts(service, flags = {}) {
|
|
269
271
|
const envValues = {};
|
|
270
272
|
|
|
273
|
+
if (flags.yes || flags.y) {
|
|
274
|
+
// Non-interactive mode — use empty values; configure manually after install
|
|
275
|
+
for (const key of Object.keys(service.envVars)) {
|
|
276
|
+
envValues[key] = '';
|
|
277
|
+
}
|
|
278
|
+
return envValues;
|
|
279
|
+
}
|
|
280
|
+
|
|
271
281
|
// Prompt for each required env var
|
|
272
282
|
for (const [key, description] of Object.entries(service.envVars)) {
|
|
273
283
|
const { value } = await inquirer.prompt([{
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const { spawn } = require('child_process');
|
|
2
|
+
const { spawn, spawnSync } = require('child_process');
|
|
3
3
|
const { requireProject, getProjectConfig, isWaitlistInstalled } = require('../utils/project-helpers');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* View waitlist logs from VPS
|
|
6
|
+
* View waitlist logs from VPS
|
|
7
|
+
* @param {Object} flags - Optional flags
|
|
8
|
+
* @param {boolean} flags['no-follow'] - Snapshot mode: print tail and exit (non-interactive)
|
|
9
|
+
* @param {number} flags.tail - Number of lines to show (default 100, used with --no-follow)
|
|
7
10
|
*/
|
|
8
|
-
async function waitlistLogs() {
|
|
11
|
+
async function waitlistLogs(flags = {}) {
|
|
9
12
|
requireProject();
|
|
10
13
|
|
|
11
14
|
console.log(chalk.blue.bold('\n📋 Waitlist Logs\n'));
|
|
@@ -28,6 +31,20 @@ async function waitlistLogs() {
|
|
|
28
31
|
|
|
29
32
|
const { vpsHost, vpsUser, vpsAppFolder } = config.deployment;
|
|
30
33
|
|
|
34
|
+
if (flags['no-follow']) {
|
|
35
|
+
// Snapshot mode — print tail and exit (non-interactive, suitable for MCP)
|
|
36
|
+
const tail = flags.tail || 100;
|
|
37
|
+
const sshCmd = `cd ${vpsAppFolder}/waitlist && docker-compose -f docker-compose.waitlist.yml logs --no-follow --tail=${tail}`;
|
|
38
|
+
|
|
39
|
+
const result = spawnSync('ssh', [`${vpsUser}@${vpsHost}`, sshCmd], { stdio: 'inherit' });
|
|
40
|
+
|
|
41
|
+
if (result.status !== 0 && result.status !== null) {
|
|
42
|
+
console.log(chalk.yellow(`\n⚠️ Process exited with code ${result.status}\n`));
|
|
43
|
+
}
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Streaming mode (interactive)
|
|
31
48
|
console.log(chalk.gray('Connecting to VPS and streaming logs...\n'));
|
|
32
49
|
console.log(chalk.gray('Press Ctrl+C to exit\n'));
|
|
33
50
|
|
package/src/index.js
CHANGED
|
@@ -132,7 +132,7 @@ async function main() {
|
|
|
132
132
|
await deployBuild(args[1]); // Optional service name
|
|
133
133
|
break;
|
|
134
134
|
case 'deploy:sync-features':
|
|
135
|
-
await deploySyncFeatures();
|
|
135
|
+
await deploySyncFeatures(flags);
|
|
136
136
|
break;
|
|
137
137
|
case 'waitlist:deploy':
|
|
138
138
|
await waitlistDeploy();
|
|
@@ -144,19 +144,19 @@ async function main() {
|
|
|
144
144
|
await waitlistDown();
|
|
145
145
|
break;
|
|
146
146
|
case 'waitlist:logs':
|
|
147
|
-
await waitlistLogs();
|
|
147
|
+
await waitlistLogs(flags);
|
|
148
148
|
break;
|
|
149
149
|
case 'docker:build':
|
|
150
150
|
await dockerBuild(args[1]); // Optional service name
|
|
151
151
|
break;
|
|
152
152
|
case 'docker:up':
|
|
153
|
-
await dockerUp(args[1]
|
|
153
|
+
await dockerUp(args[1] || flags.service, flags);
|
|
154
154
|
break;
|
|
155
155
|
case 'docker:down':
|
|
156
156
|
await dockerDown();
|
|
157
157
|
break;
|
|
158
158
|
case 'docker:logs':
|
|
159
|
-
await dockerLogs();
|
|
159
|
+
await dockerLogs(args[1] || flags.service, flags);
|
|
160
160
|
break;
|
|
161
161
|
case 'docker:destroy':
|
|
162
162
|
await dockerDestroy({ force: flags.force || flags.f });
|
|
@@ -165,24 +165,24 @@ async function main() {
|
|
|
165
165
|
await migrateRun();
|
|
166
166
|
break;
|
|
167
167
|
case 'migration:create':
|
|
168
|
-
await migrateCreate();
|
|
168
|
+
await migrateCreate(args[1] || flags.name);
|
|
169
169
|
break;
|
|
170
170
|
case 'migration:revert':
|
|
171
171
|
await migrateRevert();
|
|
172
172
|
break;
|
|
173
173
|
case 'database:console':
|
|
174
|
-
await databaseConsole({ remote: flags.remote });
|
|
174
|
+
await databaseConsole({ remote: flags.remote, query: flags.query });
|
|
175
175
|
break;
|
|
176
176
|
case 'doctor':
|
|
177
177
|
await doctor();
|
|
178
178
|
break;
|
|
179
179
|
case 'service:add':
|
|
180
|
-
if (!args[1]) {
|
|
180
|
+
if (!args[1] && !flags.service) {
|
|
181
181
|
console.error(chalk.red('Error: Service name required'));
|
|
182
182
|
console.log('Usage: launchframe service:add <service-name>');
|
|
183
183
|
process.exit(1);
|
|
184
184
|
}
|
|
185
|
-
await serviceAdd(args[1]);
|
|
185
|
+
await serviceAdd(args[1] || flags.service, flags);
|
|
186
186
|
break;
|
|
187
187
|
case 'service:list':
|
|
188
188
|
await serviceList();
|
|
@@ -196,18 +196,18 @@ async function main() {
|
|
|
196
196
|
await serviceRemove(args[1]);
|
|
197
197
|
break;
|
|
198
198
|
case 'module:add':
|
|
199
|
-
if (!args[1]) {
|
|
199
|
+
if (!args[1] && !flags.name) {
|
|
200
200
|
console.error(chalk.red('Error: Module name required'));
|
|
201
201
|
console.log('Usage: launchframe module:add <module-name>');
|
|
202
202
|
process.exit(1);
|
|
203
203
|
}
|
|
204
|
-
await moduleAdd(args[1]);
|
|
204
|
+
await moduleAdd(args[1] || flags.name, flags);
|
|
205
205
|
break;
|
|
206
206
|
case 'module:list':
|
|
207
207
|
await moduleList();
|
|
208
208
|
break;
|
|
209
209
|
case 'cache:clear':
|
|
210
|
-
await cacheClear();
|
|
210
|
+
await cacheClear(flags);
|
|
211
211
|
break;
|
|
212
212
|
case 'cache:info':
|
|
213
213
|
await cacheInfo();
|
|
@@ -222,7 +222,7 @@ async function main() {
|
|
|
222
222
|
await devQueue();
|
|
223
223
|
break;
|
|
224
224
|
case 'dev:logo':
|
|
225
|
-
await devLogo();
|
|
225
|
+
await devLogo(args[1] || flags.svg);
|
|
226
226
|
break;
|
|
227
227
|
case 'dev:npm-install':
|
|
228
228
|
if (!args[1]) {
|