@magicappdev/cli 0.0.10 → 0.0.13

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/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2CpC,6BAA6B;AAC7B,wBAAgB,aAAa,IAAI,OAAO,CA2BvC;AAED,kBAAkB;AAClB,wBAAsB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBxD"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2CpC,6BAA6B;AAC7B,wBAAgB,aAAa,IAAI,OAAO,CAwCvC;AAED,kBAAkB;AAClB,wBAAsB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBxD"}
package/dist/cli.js CHANGED
@@ -7,6 +7,7 @@ import { doctorCommand } from "./commands/doctor.js";
7
7
  import { initCommand } from "./commands/init.js";
8
8
  import { chatCommand } from "./commands/chat.js";
9
9
  import { authCommand } from "./commands/auth.js";
10
+ import { cloneCommand } from "./commands/clone.js";
10
11
  import { createRequire } from "module";
11
12
  import { Command } from "commander";
12
13
  const require = createRequire(import.meta.url);
@@ -51,6 +52,15 @@ export function createProgram() {
51
52
  .description("CLI for creating and managing MagicAppDev apps")
52
53
  .version(VERSION, "-V, --version", "Display version number")
53
54
  .option("-d, --debug", "Enable debug mode for verbose logging")
55
+ .option("--no-update-check", "Skip checking for updates")
56
+ .addHelpText("after", `
57
+ Examples:
58
+ $ magicappdev init my-app
59
+ $ magicappdev chat
60
+ $ magicappdev auth login
61
+ $ magicappdev clone --list
62
+ $ magicappdev doctor
63
+ `)
54
64
  .hook("preAction", thisCommand => {
55
65
  const opts = thisCommand.opts();
56
66
  if (opts.debug) {
@@ -64,6 +74,7 @@ export function createProgram() {
64
74
  program.addCommand(initCommand);
65
75
  program.addCommand(authCommand);
66
76
  program.addCommand(chatCommand);
77
+ program.addCommand(cloneCommand);
67
78
  program.addCommand(generateCommand);
68
79
  program.addCommand(doctorCommand);
69
80
  program.addCommand(completionsCommand);
@@ -79,10 +90,14 @@ export async function run(argv) {
79
90
  process.on("SIGTERM", () => {
80
91
  process.exit(0);
81
92
  });
93
+ const args = argv || process.argv;
94
+ const noUpdateCheck = args.includes("--no-update-check");
82
95
  // Check for updates (non-blocking)
83
- checkForUpdates();
96
+ if (!noUpdateCheck) {
97
+ checkForUpdates();
98
+ }
84
99
  const program = createProgram();
85
- await program.parseAsync(argv || process.argv);
100
+ await program.parseAsync(args);
86
101
  }
87
102
  // Run if executed directly
88
103
  if (import.meta.url.endsWith(process.argv[1].replace(/\\/g, "/"))) {
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,WAAW,SAEvB,CAAC"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,WAAW,SASrB,CAAC"}
@@ -7,7 +7,13 @@ import { api } from "../lib/api.js";
7
7
  import { Command } from "commander";
8
8
  import open from "open";
9
9
  import http from "http";
10
- export const authCommand = new Command("auth").description("Authentication commands");
10
+ export const authCommand = new Command("auth")
11
+ .description("Authentication commands")
12
+ .addHelpText("after", `
13
+ Examples:
14
+ $ magicappdev auth login
15
+ $ magicappdev auth whoami
16
+ `);
11
17
  authCommand
12
18
  .command("login")
13
19
  .description("Login to MagicAppDev using GitHub")
@@ -16,6 +22,7 @@ authCommand
16
22
  header("Authentication");
17
23
  info("Opening GitHub login in your browser...");
18
24
  // Setup local callback server
25
+ const authState = crypto.randomUUID();
19
26
  const server = http.createServer(async (req, res) => {
20
27
  const url = new URL(req.url, `http://${req.headers.host}`);
21
28
  // Ignore favicon and other non-callback requests
@@ -26,12 +33,20 @@ authCommand
26
33
  }
27
34
  const accessToken = url.searchParams.get("accessToken");
28
35
  const refreshToken = url.searchParams.get("refreshToken");
36
+ const returnedState = url.searchParams.get("state");
29
37
  // If no tokens yet, this is just the initial browser request - wait for callback
30
- if (!accessToken && !refreshToken) {
38
+ if (!accessToken || !refreshToken) {
31
39
  res.writeHead(200, { "Content-Type": "text/html" });
32
40
  res.end("<h1>Authenticating...</h1><p>Please complete the GitHub login in the popup.</p>");
33
41
  return;
34
42
  }
43
+ // Verify state to prevent CSRF/bypass
44
+ if (returnedState !== authState) {
45
+ error("Login failed: Security state mismatch");
46
+ res.writeHead(403, { "Content-Type": "text/html" });
47
+ res.end("<h1>Login Failed</h1><p>Security state mismatch. Please try again.</p>");
48
+ return;
49
+ }
35
50
  // Validate accessToken is JWT format (basic check)
36
51
  const isValidJwt = (token) => typeof token === "string" &&
37
52
  token.split(".").length === 3 &&
@@ -41,17 +56,26 @@ authCommand
41
56
  const isValidUuid = (token) => typeof token === "string" &&
42
57
  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(token);
43
58
  if (isValidJwt(accessToken) && isValidUuid(refreshToken)) {
44
- // Store tokens
45
- await saveConfig({
46
- accessToken: accessToken,
47
- refreshToken: refreshToken,
48
- });
49
- api.setToken(accessToken);
50
- info(`Access Token received and saved`);
51
- res.writeHead(200, { "Content-Type": "text/html" });
52
- res.end("<h1>Login Successful!</h1><p>You can close this window now.</p>");
53
- success("Successfully logged in!");
54
- process.exit(0);
59
+ try {
60
+ // Verify token with API before saving (fixes user-controlled bypass)
61
+ api.setToken(accessToken);
62
+ await api.getCurrentUser();
63
+ // Store tokens
64
+ await saveConfig({
65
+ accessToken,
66
+ refreshToken,
67
+ });
68
+ info(`Access Token verified and saved`);
69
+ res.writeHead(200, { "Content-Type": "text/html" });
70
+ res.end("<h1>Login Successful!</h1><p>You can close this window now.</p>");
71
+ success("Successfully logged in!");
72
+ process.exit(0);
73
+ }
74
+ catch (err) {
75
+ error(`Verification failed: ${err instanceof Error ? err.message : "Invalid token"}`);
76
+ res.writeHead(401, { "Content-Type": "text/html" });
77
+ res.end("<h1>Login Failed</h1><p>Token verification failed. Please try again.</p>");
78
+ }
55
79
  }
56
80
  else {
57
81
  error("Login failed: Invalid token format received");
@@ -64,7 +88,8 @@ authCommand
64
88
  const port = address.port;
65
89
  const redirectUri = `http://localhost:${port}`;
66
90
  const loginUrl = api.getGitHubLoginUrl("mobile") +
67
- `&redirect_uri=${encodeURIComponent(redirectUri)}`;
91
+ `&redirect_uri=${encodeURIComponent(redirectUri)}` +
92
+ `&state=${authState}`;
68
93
  await open(loginUrl);
69
94
  info(`If the browser didn't open, visit: ${loginUrl}`);
70
95
  });
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBpC,eAAO,MAAM,WAAW,SAoEpB,CAAC"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/commands/chat.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BpC,eAAO,MAAM,WAAW,SA4EpB,CAAC"}
@@ -9,6 +9,10 @@ import prompts from "prompts";
9
9
  import WebSocket from "ws";
10
10
  import chalk from "chalk";
11
11
  import ora from "ora";
12
+ /** Sanitize user-controlled strings for logging to prevent log injection */
13
+ function sanitize(str) {
14
+ return str.replace(/[\r\n]/g, " ");
15
+ }
12
16
  // Handle Ctrl+C in prompts
13
17
  const onCancel = () => {
14
18
  console.log(chalk.dim("\nGoodbye!"));
@@ -17,6 +21,11 @@ const onCancel = () => {
17
21
  export const chatCommand = new Command("chat")
18
22
  .description("Chat with the Magic AI App Builder")
19
23
  .option("-d, --debug", "Enable debug logging")
24
+ .addHelpText("after", `
25
+ Examples:
26
+ $ magicappdev chat
27
+ $ magicappdev chat --debug
28
+ `)
20
29
  .action(async (options) => {
21
30
  const debug = options.debug || process.env.DEBUG === "true";
22
31
  logo();
@@ -53,7 +62,7 @@ export const chatCommand = new Command("chat")
53
62
  });
54
63
  ws.on("close", (code, reason) => {
55
64
  clearTimeout(connectionTimeout);
56
- const reasonStr = reason?.toString() || "Connection closed";
65
+ const reasonStr = sanitize(reason?.toString() || "Connection closed");
57
66
  if (debug) {
58
67
  console.log(chalk.dim(`\n[DEBUG] WebSocket closed: ${code} - ${reasonStr}`));
59
68
  }
@@ -65,9 +74,9 @@ export const chatCommand = new Command("chat")
65
74
  });
66
75
  ws.on("error", (err) => {
67
76
  clearTimeout(connectionTimeout);
68
- spinner.fail(`Connection error: ${err.message}`);
77
+ spinner.fail(`Connection error: ${sanitize(err.message)}`);
69
78
  if (debug) {
70
- console.error(chalk.red(`\n[DEBUG] WebSocket error:`), err);
79
+ console.error(chalk.red(`\n[DEBUG] WebSocket error:`), sanitize(err.toString()));
71
80
  }
72
81
  process.exit(1);
73
82
  });
@@ -85,14 +94,14 @@ async function startChatLoop(ws, debug) {
85
94
  const raw = data.toString();
86
95
  const message = JSON.parse(raw);
87
96
  if (debug) {
88
- console.log(chalk.dim(`\n[DEBUG] Received: ${message.type || "unknown"}`));
89
- console.log(chalk.dim(`[DEBUG] Raw: ${raw.substring(0, 200)}...`));
97
+ console.log(chalk.dim(`\n[DEBUG] Received: ${sanitize(message.type || "unknown")}`));
98
+ console.log(chalk.dim(`[DEBUG] Raw: ${sanitize(raw.substring(0, 200))}...`));
90
99
  }
91
100
  // Handle different message types
92
101
  switch (message.type) {
93
102
  case "chat_start":
94
103
  if (debug) {
95
- console.log(chalk.dim(`[DEBUG] Using model: ${message.model}`));
104
+ console.log(chalk.dim(`[DEBUG] Using model: ${sanitize(message.model || "unknown")}`));
96
105
  }
97
106
  break;
98
107
  case "chat_chunk":
@@ -101,7 +110,10 @@ async function startChatLoop(ws, debug) {
101
110
  if (responseSpinner) {
102
111
  // Show last line of response in spinner
103
112
  const lastLine = currentResponse.split("\n").pop() || "...";
104
- responseSpinner.text = chalk.gray(lastLine.length > 60 ? lastLine.slice(-60) + "..." : lastLine);
113
+ const sanitizedLine = sanitize(lastLine);
114
+ responseSpinner.text = chalk.gray(sanitizedLine.length > 60
115
+ ? sanitizedLine.slice(-60) + "..."
116
+ : sanitizedLine);
105
117
  }
106
118
  }
107
119
  break;
@@ -110,14 +122,14 @@ async function startChatLoop(ws, debug) {
110
122
  responseSpinner.stop();
111
123
  }
112
124
  if (currentResponse) {
113
- console.log(chalk.green("\nMagic AI:"), currentResponse);
125
+ console.log(chalk.green("\nMagic AI:"), sanitize(currentResponse));
114
126
  }
115
127
  else {
116
128
  console.log(chalk.yellow("\nMagic AI: (No response received)"));
117
129
  }
118
130
  if (message.suggestedTemplate) {
119
- console.log(chalk.yellow("\nSuggested Template:"), chalk.bold(message.suggestedTemplate));
120
- console.log(chalk.dim(`Run 'magicappdev init --template ${message.suggestedTemplate}' to use it.`));
131
+ console.log(chalk.yellow("\nSuggested Template:"), chalk.bold(sanitize(message.suggestedTemplate)));
132
+ console.log(chalk.dim(`Run 'magicappdev init --template ${sanitize(message.suggestedTemplate)}' to use it.`));
121
133
  }
122
134
  console.log(""); // Spacing
123
135
  // Reset state and resolve promise
@@ -130,7 +142,8 @@ async function startChatLoop(ws, debug) {
130
142
  break;
131
143
  case "error":
132
144
  if (responseSpinner) {
133
- responseSpinner.fail(`Error: ${message.error || message.message || "Unknown error"}`);
145
+ const errorMsg = sanitize(message.error || message.message || "Unknown error");
146
+ responseSpinner.fail(`Error: ${errorMsg}`);
134
147
  }
135
148
  currentResponse = "";
136
149
  waitingForResponse = false;
@@ -145,13 +158,13 @@ async function startChatLoop(ws, debug) {
145
158
  break;
146
159
  default:
147
160
  if (debug) {
148
- console.log(chalk.dim(`[DEBUG] Ignored message type: ${message.type}`));
161
+ console.log(chalk.dim(`[DEBUG] Ignored message type: ${sanitize(message.type)}`));
149
162
  }
150
163
  }
151
164
  }
152
165
  catch (err) {
153
166
  if (debug) {
154
- console.error(chalk.red("[DEBUG] Parse error:"), err);
167
+ console.error(chalk.red("[DEBUG] Parse error:"), sanitize(err?.toString() || "Unknown"));
155
168
  }
156
169
  }
157
170
  });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Clone command - Clone a project from the database to local filesystem
3
+ */
4
+ import { Command } from "commander";
5
+ export declare const cloneCommand: Command;
6
+ //# sourceMappingURL=clone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clone.d.ts","sourceRoot":"","sources":["../../src/commands/clone.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsDpC,eAAO,MAAM,YAAY,SAgMrB,CAAC"}
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Clone command - Clone a project from the database to local filesystem
3
+ */
4
+ import { header, logo, success, error, info, keyValue, command, newline, divider, } from "../lib/ui.js";
5
+ import { api } from "../lib/api.js";
6
+ import { withSpinner } from "../lib/spinner.js";
7
+ import { spawn } from "child_process";
8
+ import * as fs from "fs";
9
+ import * as path from "path";
10
+ import { Command } from "commander";
11
+ /** Ensure directory exists, create if not */
12
+ function ensureDir(dir) {
13
+ if (!fs.existsSync(dir)) {
14
+ fs.mkdirSync(dir, { recursive: true });
15
+ }
16
+ }
17
+ /** Write file to filesystem */
18
+ function writeFile(filePath, content) {
19
+ ensureDir(path.dirname(filePath));
20
+ fs.writeFileSync(filePath, content, "utf-8");
21
+ }
22
+ /** Install dependencies for the project */
23
+ async function installDependencies(projectDir) {
24
+ return new Promise(resolve => {
25
+ // Detect package manager
26
+ let pm = "npm";
27
+ if (fs.existsSync(path.join(projectDir, "pnpm-lock.yaml"))) {
28
+ pm = "pnpm";
29
+ }
30
+ else if (fs.existsSync(path.join(projectDir, "yarn.lock"))) {
31
+ pm = "yarn";
32
+ }
33
+ else if (fs.existsSync(path.join(projectDir, "bun.lockb"))) {
34
+ pm = "bun";
35
+ }
36
+ const child = spawn(pm, ["install"], {
37
+ cwd: projectDir,
38
+ stdio: "inherit",
39
+ shell: true,
40
+ });
41
+ child.on("close", code => {
42
+ if (code === 0) {
43
+ resolve({ success: true });
44
+ }
45
+ else {
46
+ resolve({ success: false, error: `Exit code ${code}` });
47
+ }
48
+ });
49
+ child.on("error", err => {
50
+ resolve({ success: false, error: err.message });
51
+ });
52
+ });
53
+ }
54
+ export const cloneCommand = new Command("clone")
55
+ .description("Clone a project from the database to local filesystem")
56
+ .argument("[project-id]", "Project ID to clone")
57
+ .option("-o, --output <dir>", "Output directory")
58
+ .option("--list", "List available projects")
59
+ .option("--no-install", "Skip installing dependencies")
60
+ .addHelpText("after", `
61
+ Examples:
62
+ $ magicappdev clone --list
63
+ $ magicappdev clone abc-123-def
64
+ $ magicappdev clone abc-123-def -o my-app
65
+ `)
66
+ .action(async (projectId, options) => {
67
+ logo();
68
+ header("Clone Project");
69
+ try {
70
+ // List projects mode
71
+ if (options.list) {
72
+ divider();
73
+ info("Fetching available projects...");
74
+ const projects = await withSpinner("Loading projects...", async () => {
75
+ return await api.listExportableProjects();
76
+ }, { successText: "Projects loaded" });
77
+ newline();
78
+ if (projects.length === 0) {
79
+ info("No projects available to clone.");
80
+ return;
81
+ }
82
+ info(`Found ${projects.length} project(s):`);
83
+ newline();
84
+ for (const p of projects) {
85
+ divider();
86
+ keyValue("Name", p.name);
87
+ keyValue("ID", p.id);
88
+ keyValue("Framework", p.framework);
89
+ keyValue("Files", String(p.fileCount));
90
+ keyValue("Status", p.status);
91
+ keyValue("Updated", new Date(p.updatedAt).toLocaleDateString());
92
+ }
93
+ newline();
94
+ info("To clone a project, run:");
95
+ command(`magicappdev clone <project-id>`);
96
+ newline();
97
+ return;
98
+ }
99
+ // Validate project ID
100
+ if (!projectId) {
101
+ error("Project ID is required. Use --list to see available projects.");
102
+ newline();
103
+ info("Usage:");
104
+ command("magicappdev clone <project-id>");
105
+ command("magicappdev clone --list");
106
+ newline();
107
+ process.exit(1);
108
+ }
109
+ divider();
110
+ info(`Cloning project: ${projectId}`);
111
+ newline();
112
+ // Export project from database
113
+ const exportData = await withSpinner("Exporting project from database...", async () => {
114
+ return await api.exportProject(projectId);
115
+ }, { successText: "Project exported" });
116
+ newline();
117
+ info("Project details:");
118
+ keyValue("Name", exportData.project.name);
119
+ keyValue("Framework", exportData.project.framework);
120
+ keyValue("Files", String(exportData.metadata.fileCount));
121
+ keyValue("Size", `${(exportData.metadata.totalSize / 1024).toFixed(1)} KB`);
122
+ divider();
123
+ newline();
124
+ // Determine output directory
125
+ const outputDir = options.output || exportData.project.name;
126
+ const projectPath = path.resolve(process.cwd(), outputDir);
127
+ // Check if directory exists
128
+ if (fs.existsSync(projectPath)) {
129
+ error(`Directory already exists: ${outputDir}`);
130
+ newline();
131
+ info("Please choose a different output directory or remove the existing one.");
132
+ command(`rm -rf "${outputDir}"`);
133
+ process.exit(1);
134
+ }
135
+ // Create project directory
136
+ await withSpinner("Creating project directory...", async () => {
137
+ ensureDir(projectPath);
138
+ await new Promise(resolve => setTimeout(resolve, 100)); // Small delay
139
+ }, { successText: "Directory created" });
140
+ newline();
141
+ // Write files
142
+ const writeFiles = async () => {
143
+ for (const file of exportData.files) {
144
+ const filePath = path.join(projectPath, file.path);
145
+ writeFile(filePath, file.content);
146
+ }
147
+ };
148
+ await withSpinner(`Writing ${exportData.metadata.fileCount} files...`, writeFiles, { successText: `${exportData.metadata.fileCount} files written` });
149
+ newline();
150
+ success(`Project cloned successfully to: ${outputDir}`);
151
+ newline();
152
+ // Write export metadata
153
+ const metadataPath = path.join(projectPath, ".magicappdev.json");
154
+ writeFile(metadataPath, JSON.stringify({
155
+ version: exportData.version,
156
+ exportedAt: exportData.exportedAt,
157
+ project: exportData.project,
158
+ metadata: exportData.metadata,
159
+ }, null, 2));
160
+ // Install dependencies if requested
161
+ const shouldInstall = options.install !== false;
162
+ if (shouldInstall) {
163
+ // Check if package.json exists
164
+ const packageJsonPath = path.join(projectPath, "package.json");
165
+ if (fs.existsSync(packageJsonPath)) {
166
+ newline();
167
+ const installResult = await withSpinner("Installing dependencies...", async () => installDependencies(projectPath), { successText: "Dependencies installed" });
168
+ if (!installResult.success) {
169
+ newline();
170
+ error(`Failed to install dependencies: ${installResult.error || "Unknown error"}`);
171
+ info("You can install them manually:");
172
+ command(`cd ${outputDir}`);
173
+ command("npm install"); // or pnpm install, yarn install, etc.
174
+ }
175
+ }
176
+ }
177
+ newline();
178
+ info("Next steps:");
179
+ command(`cd ${outputDir}`);
180
+ // Suggest start command based on framework
181
+ if (exportData.project.framework === "expo" || exportData.project.framework === "react-native") {
182
+ command("npm start # or expo start");
183
+ }
184
+ else if (exportData.project.framework === "next") {
185
+ command("npm run dev");
186
+ }
187
+ else {
188
+ command("npm start");
189
+ }
190
+ newline();
191
+ success("Happy coding!");
192
+ }
193
+ catch (err) {
194
+ error(err instanceof Error ? err.message : "Failed to clone project");
195
+ newline();
196
+ info("Troubleshooting:");
197
+ command("magicappdev clone --list # Check available projects");
198
+ command("magicappdev auth login # Verify authentication");
199
+ newline();
200
+ process.exit(1);
201
+ }
202
+ });
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,eAAO,MAAM,aAAa,SA0KtB,CAAC"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,eAAO,MAAM,aAAa,SAkLtB,CAAC"}
@@ -10,6 +10,11 @@ import { execa } from "execa";
10
10
  export const doctorCommand = new Command("doctor")
11
11
  .description("Diagnose project issues and check environment")
12
12
  .option("--fix", "Attempt to fix issues automatically")
13
+ .addHelpText("after", `
14
+ Examples:
15
+ $ magicappdev doctor
16
+ $ magicappdev doctor --fix
17
+ `)
13
18
  .action(async () => {
14
19
  header("Project Diagnostics");
15
20
  const checks = [];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/generate/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,eAAe,SAoIzB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/generate/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,eAAe,SA4IzB,CAAC"}
@@ -9,6 +9,11 @@ import { Command } from "commander";
9
9
  export const generateCommand = new Command("generate")
10
10
  .alias("g")
11
11
  .description("Generate code from templates")
12
+ .addHelpText("after", `
13
+ Examples:
14
+ $ magicappdev generate component MyButton
15
+ $ magicappdev generate screen SettingsScreen --path ./app/settings
16
+ `)
12
17
  .addCommand(new Command("component")
13
18
  .alias("c")
14
19
  .description("Generate a new component")
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8CpC,eAAO,MAAM,WAAW,SA2JpB,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyBH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8CpC,eAAO,MAAM,WAAW,SAoKpB,CAAC"}
@@ -49,6 +49,12 @@ export const initCommand = new Command("init")
49
49
  .option("--typescript", "Use TypeScript", true)
50
50
  .option("-y, --yes", "Skip prompts and use defaults")
51
51
  .option("--no-install", "Skip installing dependencies")
52
+ .addHelpText("after", `
53
+ Examples:
54
+ $ magicappdev init my-app
55
+ $ magicappdev init my-app --template tabs --framework expo
56
+ $ magicappdev init my-app -y
57
+ `)
52
58
  .action(async (name, options) => {
53
59
  logo();
54
60
  header("Create a new project");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magicappdev/cli",
3
- "version": "0.0.10",
3
+ "version": "0.0.13",
4
4
  "description": "CLI tool for creating and managing MagicAppDev apps",
5
5
  "keywords": [
6
6
  "cli",
@@ -31,7 +31,6 @@
31
31
  "dependencies": {
32
32
  "@magicappdev/shared": "workspace:*",
33
33
  "@magicappdev/templates": "workspace:*",
34
- "agents": "^0.3.6",
35
34
  "chalk": "^5.4.0",
36
35
  "commander": "^14.0.2",
37
36
  "execa": "^9.5.0",