@jetstart/cli 1.2.0 → 1.4.0

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.
Files changed (68) hide show
  1. package/dist/cli.js +18 -1
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/android-emulator.d.ts +8 -0
  4. package/dist/commands/android-emulator.d.ts.map +1 -0
  5. package/dist/commands/android-emulator.js +280 -0
  6. package/dist/commands/android-emulator.js.map +1 -0
  7. package/dist/commands/create.d.ts +1 -6
  8. package/dist/commands/create.d.ts.map +1 -1
  9. package/dist/commands/create.js +119 -0
  10. package/dist/commands/create.js.map +1 -1
  11. package/dist/commands/dev.d.ts +1 -7
  12. package/dist/commands/dev.d.ts.map +1 -1
  13. package/dist/commands/dev.js +69 -10
  14. package/dist/commands/dev.js.map +1 -1
  15. package/dist/commands/index.d.ts +2 -0
  16. package/dist/commands/index.d.ts.map +1 -1
  17. package/dist/commands/index.js +5 -1
  18. package/dist/commands/index.js.map +1 -1
  19. package/dist/commands/install-audit.d.ts +9 -0
  20. package/dist/commands/install-audit.d.ts.map +1 -0
  21. package/dist/commands/install-audit.js +185 -0
  22. package/dist/commands/install-audit.js.map +1 -0
  23. package/dist/types/index.d.ts +22 -0
  24. package/dist/types/index.d.ts.map +1 -1
  25. package/dist/types/index.js +8 -0
  26. package/dist/types/index.js.map +1 -1
  27. package/dist/utils/android-sdk.d.ts +81 -0
  28. package/dist/utils/android-sdk.d.ts.map +1 -0
  29. package/dist/utils/android-sdk.js +432 -0
  30. package/dist/utils/android-sdk.js.map +1 -0
  31. package/dist/utils/downloader.d.ts +35 -0
  32. package/dist/utils/downloader.d.ts.map +1 -0
  33. package/dist/utils/downloader.js +214 -0
  34. package/dist/utils/downloader.js.map +1 -0
  35. package/dist/utils/emulator-deployer.d.ts +29 -0
  36. package/dist/utils/emulator-deployer.d.ts.map +1 -0
  37. package/dist/utils/emulator-deployer.js +224 -0
  38. package/dist/utils/emulator-deployer.js.map +1 -0
  39. package/dist/utils/emulator.d.ts +101 -0
  40. package/dist/utils/emulator.d.ts.map +1 -0
  41. package/dist/utils/emulator.js +410 -0
  42. package/dist/utils/emulator.js.map +1 -0
  43. package/dist/utils/java.d.ts +25 -0
  44. package/dist/utils/java.d.ts.map +1 -0
  45. package/dist/utils/java.js +363 -0
  46. package/dist/utils/java.js.map +1 -0
  47. package/dist/utils/system-tools.d.ts +93 -0
  48. package/dist/utils/system-tools.d.ts.map +1 -0
  49. package/dist/utils/system-tools.js +599 -0
  50. package/dist/utils/system-tools.js.map +1 -0
  51. package/dist/utils/template.d.ts.map +1 -1
  52. package/dist/utils/template.js +777 -748
  53. package/dist/utils/template.js.map +1 -1
  54. package/package.json +7 -3
  55. package/src/cli.ts +20 -2
  56. package/src/commands/android-emulator.ts +304 -0
  57. package/src/commands/create.ts +128 -5
  58. package/src/commands/dev.ts +71 -18
  59. package/src/commands/index.ts +3 -1
  60. package/src/commands/install-audit.ts +227 -0
  61. package/src/types/index.ts +30 -0
  62. package/src/utils/android-sdk.ts +478 -0
  63. package/src/utils/downloader.ts +201 -0
  64. package/src/utils/emulator-deployer.ts +210 -0
  65. package/src/utils/emulator.ts +463 -0
  66. package/src/utils/java.ts +369 -0
  67. package/src/utils/system-tools.ts +648 -0
  68. package/src/utils/template.ts +875 -867
@@ -5,18 +5,14 @@
5
5
 
6
6
  import * as path from 'path';
7
7
  import * as os from 'os';
8
+ import * as fs from 'fs-extra';
8
9
  import chalk from 'chalk';
9
10
  import qrcode from 'qrcode-terminal';
10
- import { log, success, error, info } from '../utils/logger';
11
+ import { log, success, error, info, warning } from '../utils/logger';
11
12
  import { JetStartServer } from '@jetstart/core';
12
13
  import { DEFAULT_CORE_PORT, DEFAULT_WS_PORT } from '@jetstart/shared';
13
-
14
- interface DevOptions {
15
- port?: string;
16
- host?: string;
17
- qr?: boolean;
18
- open?: boolean;
19
- }
14
+ import { DevOptions } from '../types';
15
+ import { EmulatorDeployer } from '../utils/emulator-deployer';
20
16
 
21
17
  export async function devCommand(options: DevOptions) {
22
18
  try {
@@ -32,6 +28,40 @@ export async function devCommand(options: DevOptions) {
32
28
  const projectPath = process.cwd();
33
29
  const projectName = path.basename(projectPath);
34
30
 
31
+ // Setup emulator deployment if requested
32
+ let deployer: EmulatorDeployer | null = null;
33
+ let packageName: string | null = null;
34
+
35
+ if (options.emulator) {
36
+ try {
37
+ deployer = await EmulatorDeployer.findOrSelectEmulator(options.avd);
38
+
39
+ // Try to read package name from build.gradle (modern Android)
40
+ const buildGradlePath = path.join(projectPath, 'app/build.gradle');
41
+ info(`Looking for build.gradle at: ${buildGradlePath}`);
42
+ if (await fs.pathExists(buildGradlePath)) {
43
+ const buildGradleContent = await fs.readFile(buildGradlePath, 'utf8');
44
+ // Match both applicationId "..." and applicationId '...'
45
+ const packageMatch = buildGradleContent.match(/applicationId\s+["']([^"']+)["']/);
46
+ packageName = packageMatch ? packageMatch[1] : null;
47
+ info(`Package name: ${packageName || 'NOT FOUND'}`);
48
+ } else {
49
+ warning('build.gradle not found - emulator deployment requires package name');
50
+ }
51
+
52
+ if (packageName) {
53
+ success('Emulator deployment enabled');
54
+ } else {
55
+ warning('Emulator deployment disabled: package name not found');
56
+ }
57
+ console.log();
58
+ } catch (err: any) {
59
+ error(`Emulator setup failed: ${err.message}`);
60
+ info('Continuing without emulator deployment...');
61
+ console.log();
62
+ }
63
+ }
64
+
35
65
  // Create and start Core server
36
66
  // Bind to 0.0.0.0 to accept connections on all interfaces,
37
67
  // but pass the detected IP for display and client connections
@@ -46,9 +76,37 @@ export async function devCommand(options: DevOptions) {
46
76
 
47
77
  const session = await server.start();
48
78
 
79
+ // Listen for build completion and deploy to emulator
80
+ if (deployer && packageName) {
81
+ info(`Setting up build:complete listener for package: ${packageName}`);
82
+ let hasDeployed = false; // Track if we've already deployed to prevent reinstall loops
83
+
84
+ server.on('build:complete', async (result: any) => {
85
+ info(`Build complete event received! APK: ${result.apkPath || 'NO APK PATH'}`);
86
+
87
+ // Only deploy if this is the first time OR if it's a file-change build (not initial client connection)
88
+ if (!hasDeployed && result.apkPath && deployer) {
89
+ try {
90
+ info('Deploying to emulator (initial deployment)...');
91
+ await deployer.installAPK(result.apkPath, packageName!);
92
+ await deployer.launchApp(packageName!);
93
+ hasDeployed = true; // Mark as deployed to prevent reinstall loop
94
+ success('Initial deployment complete. Future builds will be sent via hot reload.');
95
+ } catch (err: any) {
96
+ warning(`Emulator deployment failed: ${err.message}`);
97
+ }
98
+ } else if (hasDeployed) {
99
+ info('Skipping deployment (app already installed, using hot reload)');
100
+ } else {
101
+ warning(`Skipping deployment: apkPath=${result.apkPath}, deployer=${!!deployer}`);
102
+ }
103
+ });
104
+ } else {
105
+ info(`Emulator deployment not configured: deployer=${!!deployer}, packageName=${packageName}`);
106
+ }
107
+
49
108
  // Get URLs
50
109
  const serverUrl = `http://${host}:${port}`;
51
- const wsUrl = `ws://${host}:${wsPort}`;
52
110
  const localUrl = `http://localhost:${port}`;
53
111
 
54
112
  console.log();
@@ -61,17 +119,12 @@ export async function devCommand(options: DevOptions) {
61
119
 
62
120
  // Generate QR code for mobile connection
63
121
  if (showQR) {
64
- const qrData = {
65
- serverUrl,
66
- wsUrl,
67
- sessionId: session.id,
68
- token: session.token,
69
- projectName,
70
- version: '0.1.0',
71
- };
122
+ // Ultra-compact format: host|port|wsPort|sessionId|token|projectName
123
+ // Using short alphanumeric IDs for minimal QR code size
124
+ const qrData = `${host}|${port}|${wsPort}|${session.id}|${session.token}|${projectName}`;
72
125
 
73
126
  console.log(chalk.bold('Scan QR or connect manually:'));
74
- qrcode.generate(JSON.stringify(qrData), { small: true });
127
+ qrcode.generate(qrData, { small: true });
75
128
  console.log();
76
129
  info(`IP: ${chalk.cyan(host)}`);
77
130
  info(`Session: ${chalk.dim(session.id)}`);
@@ -5,4 +5,6 @@
5
5
  export { createCommand } from './create';
6
6
  export { devCommand } from './dev';
7
7
  export { buildCommand } from './build';
8
- export { logsCommand } from './logs';
8
+ export { logsCommand } from './logs';
9
+ export { installAuditCommand } from './install-audit';
10
+ export { androidEmulatorCommand } from './android-emulator';
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Installation audit command - checks all required tools and dependencies
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import { AuditOptions } from '../types';
7
+ import {
8
+ detectNode,
9
+ detectNpm,
10
+ detectJava,
11
+ detectGradle,
12
+ detectAndroidSDK,
13
+ detectAndroidCmdlineTools,
14
+ detectAndroidBuildTools,
15
+ detectAndroidPlatformTools,
16
+ detectAndroidEmulator,
17
+ detectAndroidPlatform,
18
+ checkJavaHome,
19
+ checkAndroidHome,
20
+ ToolInfo,
21
+ } from '../utils/system-tools';
22
+ import { warning } from '../utils/logger';
23
+
24
+ /**
25
+ * Print tool status in table format
26
+ */
27
+ function printToolStatus(tool: ToolInfo): void {
28
+ const icon =
29
+ tool.status === 'ok'
30
+ ? chalk.green('✓')
31
+ : tool.status === 'warning'
32
+ ? chalk.yellow('⚠')
33
+ : chalk.red('✗');
34
+
35
+ const name = tool.name.padEnd(25);
36
+ const version = (tool.version || (tool.installed ? 'Unknown' : 'Not installed')).padEnd(15);
37
+
38
+ let statusText = '';
39
+ if (tool.status === 'ok') {
40
+ statusText = chalk.green('OK');
41
+ } else if (tool.status === 'warning') {
42
+ statusText = chalk.yellow(tool.message || 'Warning');
43
+ } else {
44
+ statusText = chalk.red(tool.message || 'ERROR');
45
+ }
46
+
47
+ console.log(` ${icon} ${name} ${version} ${statusText}`);
48
+ }
49
+
50
+ /**
51
+ * Print section header
52
+ */
53
+ function printSection(title: string): void {
54
+ console.log();
55
+ console.log(chalk.bold(title + ':'));
56
+ console.log('━'.repeat(70));
57
+ }
58
+
59
+ /**
60
+ * Run audit in table format
61
+ */
62
+ async function runAuditTable(): Promise<void> {
63
+ console.log();
64
+ console.log(chalk.cyan.bold(' JetStart Installation Audit'));
65
+ console.log();
66
+
67
+ const allTools: ToolInfo[] = [];
68
+
69
+ // Development Tools
70
+ printSection('Development Tools');
71
+
72
+ const node = await detectNode();
73
+ printToolStatus(node);
74
+ allTools.push(node);
75
+
76
+ const npm = await detectNpm();
77
+ printToolStatus(npm);
78
+ allTools.push(npm);
79
+
80
+ const java = await detectJava();
81
+ printToolStatus(java);
82
+ allTools.push(java);
83
+
84
+ const gradle = await detectGradle();
85
+ printToolStatus(gradle);
86
+ allTools.push(gradle);
87
+
88
+ // Android SDK
89
+ printSection('Android SDK');
90
+
91
+ const sdk = await detectAndroidSDK();
92
+ printToolStatus(sdk);
93
+ allTools.push(sdk);
94
+
95
+ const cmdlineTools = await detectAndroidCmdlineTools();
96
+ printToolStatus(cmdlineTools);
97
+ allTools.push(cmdlineTools);
98
+
99
+ const buildTools = await detectAndroidBuildTools();
100
+ printToolStatus(buildTools);
101
+ allTools.push(buildTools);
102
+
103
+ const platformTools = await detectAndroidPlatformTools();
104
+ printToolStatus(platformTools);
105
+ allTools.push(platformTools);
106
+
107
+ const emulator = await detectAndroidEmulator();
108
+ printToolStatus(emulator);
109
+ allTools.push(emulator);
110
+
111
+ // Android Platforms
112
+ printSection('Android Platforms');
113
+
114
+ const api34 = await detectAndroidPlatform(34);
115
+ printToolStatus({ ...api34, name: 'API 34 (Target)' });
116
+ allTools.push(api34);
117
+
118
+ const api24 = await detectAndroidPlatform(24);
119
+ printToolStatus({ ...api24, name: 'API 24 (Minimum)' });
120
+ allTools.push(api24);
121
+
122
+ // Environment Variables
123
+ printSection('Environment Variables');
124
+
125
+ const javaHome = await checkJavaHome();
126
+ printToolStatus(javaHome);
127
+ allTools.push(javaHome);
128
+
129
+ const androidHome = await checkAndroidHome();
130
+ printToolStatus(androidHome);
131
+ allTools.push(androidHome);
132
+
133
+ // Summary
134
+ const summary = {
135
+ ok: allTools.filter((t) => t.status === 'ok').length,
136
+ warning: allTools.filter((t) => t.status === 'warning').length,
137
+ error: allTools.filter((t) => t.status === 'error').length,
138
+ };
139
+
140
+ printSection('Summary');
141
+ console.log(` ${chalk.green('✓')} ${summary.ok} components OK`);
142
+ if (summary.warning > 0) {
143
+ console.log(` ${chalk.yellow('⚠')} ${summary.warning} warning${summary.warning > 1 ? 's' : ''}`);
144
+ }
145
+ if (summary.error > 0) {
146
+ console.log(` ${chalk.red('✗')} ${summary.error} error${summary.error > 1 ? 's' : ''}`);
147
+ }
148
+
149
+ // Recommendations
150
+ if (summary.error > 0) {
151
+ console.log();
152
+ warning('Recommendation:');
153
+ console.log(' Run "jetstart create <project-name> --full-install" to install missing dependencies');
154
+ }
155
+
156
+ console.log();
157
+ }
158
+
159
+ /**
160
+ * Run audit in JSON format
161
+ */
162
+ async function runAuditJSON(): Promise<void> {
163
+ const tools = {
164
+ node: await detectNode(),
165
+ npm: await detectNpm(),
166
+ java: await detectJava(),
167
+ gradle: await detectGradle(),
168
+ };
169
+
170
+ const androidComponents = {
171
+ sdk: await detectAndroidSDK(),
172
+ cmdlineTools: await detectAndroidCmdlineTools(),
173
+ buildTools: await detectAndroidBuildTools(),
174
+ platformTools: await detectAndroidPlatformTools(),
175
+ emulator: await detectAndroidEmulator(),
176
+ platforms: {
177
+ api34: await detectAndroidPlatform(34),
178
+ api24: await detectAndroidPlatform(24),
179
+ },
180
+ };
181
+
182
+ const environment = {
183
+ javaHome: await checkJavaHome(),
184
+ androidHome: await checkAndroidHome(),
185
+ };
186
+
187
+ const allTools = [
188
+ ...Object.values(tools),
189
+ ...Object.values(androidComponents).filter((v) => typeof v === 'object' && 'status' in v),
190
+ androidComponents.platforms.api34,
191
+ androidComponents.platforms.api24,
192
+ ...Object.values(environment),
193
+ ] as ToolInfo[];
194
+
195
+ const summary = {
196
+ ok: allTools.filter((t) => t.status === 'ok').length,
197
+ warning: allTools.filter((t) => t.status === 'warning').length,
198
+ error: allTools.filter((t) => t.status === 'error').length,
199
+ };
200
+
201
+ const result = {
202
+ timestamp: new Date().toISOString(),
203
+ platform: process.platform,
204
+ tools,
205
+ androidComponents,
206
+ environment,
207
+ summary,
208
+ };
209
+
210
+ console.log(JSON.stringify(result, null, 2));
211
+ }
212
+
213
+ /**
214
+ * Install audit command handler
215
+ */
216
+ export async function installAuditCommand(options: AuditOptions): Promise<void> {
217
+ try {
218
+ if (options.json) {
219
+ await runAuditJSON();
220
+ } else {
221
+ await runAuditTable();
222
+ }
223
+ } catch (err: any) {
224
+ console.error(chalk.red(`\nAudit failed: ${err.message}`));
225
+ process.exit(1);
226
+ }
227
+ }
@@ -19,4 +19,34 @@ export interface TemplateOptions {
19
19
  export interface CommandContext {
20
20
  cwd: string;
21
21
  config?: ProjectConfig;
22
+ }
23
+
24
+ // Create command options
25
+ export interface CreateOptions {
26
+ package?: string;
27
+ template?: string;
28
+ skipInstall?: boolean;
29
+ fullInstall?: boolean;
30
+ }
31
+
32
+ // Install audit command options
33
+ export interface AuditOptions {
34
+ json?: boolean;
35
+ }
36
+
37
+ // Dev command options
38
+ export interface DevOptions {
39
+ port?: string;
40
+ host?: string;
41
+ qr?: boolean;
42
+ open?: boolean;
43
+ emulator?: boolean;
44
+ avd?: string;
45
+ }
46
+
47
+ // Install action enum
48
+ export enum InstallAction {
49
+ SKIP = 'skip',
50
+ UPDATE = 'update',
51
+ REPLACE = 'replace',
22
52
  }