mycontext-cli 3.0.1 → 3.0.3

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.
@@ -44,9 +44,7 @@ const gradient_string_1 = __importDefault(require("gradient-string"));
44
44
  const spinner_1 = require("../utils/spinner");
45
45
  const fileSystem_1 = require("../utils/fileSystem");
46
46
  const child_process_1 = require("child_process");
47
- const fs = __importStar(require("fs-extra"));
48
47
  const path = __importStar(require("path"));
49
- const envExampleGenerator_1 = require("../utils/envExampleGenerator");
50
48
  class InitCommand {
51
49
  constructor() {
52
50
  this.fs = new fileSystem_1.FileSystemManager();
@@ -56,51 +54,10 @@ class InitCommand {
56
54
  try {
57
55
  // Display ASCII art branding
58
56
  this.displayBranding();
59
- // Handle current directory initialization with "."
57
+ // Handle project name
60
58
  let finalProjectName = projectName;
61
- let useCurrentDir = false;
62
- if (projectName === ".") {
63
- const currentDir = path.basename(process.cwd());
64
- finalProjectName = currentDir;
65
- useCurrentDir = true;
66
- console.log(chalk_1.default.cyan(`šŸ“ Initializing in current directory: ${currentDir}`));
67
- }
68
- else {
69
- // Validate project name for new directories
70
- if (!this.isValidProjectName(projectName)) {
71
- throw new Error("Project name must be alphanumeric with hyphens or underscores only");
72
- }
73
- }
74
- // Check if this is an existing project and analyze it
75
- if (useCurrentDir || options.existing) {
76
- const isExistingProject = await this.isExistingProject(process.cwd());
77
- if (isExistingProject) {
78
- console.log(chalk_1.default.yellow("šŸ” Existing project detected!"));
79
- if (options.analyze) {
80
- // Run analysis on existing project
81
- await this.analyzeExistingProject(process.cwd(), options);
82
- return;
83
- }
84
- else {
85
- // Ask user if they want to analyze
86
- const shouldAnalyze = await this.askToAnalyze();
87
- if (shouldAnalyze) {
88
- await this.analyzeExistingProject(process.cwd(), options);
89
- return;
90
- }
91
- }
92
- }
93
- }
94
- const workingDir = process.cwd();
95
- // Interactive prompts if not using --yes flag
96
- let finalDescription = options.description;
97
- let finalFramework = options.framework;
98
- // Set framework based on explicit flags
99
- if (options.next || options.scaffoldNext) {
100
- finalFramework = "nextjs";
101
- }
102
- // Minimal prompts - only ask for project name if not provided
103
- if (!options.yes && !finalProjectName) {
59
+ let useCurrentDir = projectName === ".";
60
+ if (!finalProjectName && !options.yes) {
104
61
  const responses = await (0, prompts_1.default)([
105
62
  {
106
63
  type: "text",
@@ -111,129 +68,175 @@ class InitCommand {
111
68
  },
112
69
  ]);
113
70
  finalProjectName = responses.name || "my-app";
71
+ useCurrentDir = finalProjectName === ".";
114
72
  }
115
- // Smart defaults - no prompts needed
116
- finalDescription = finalDescription || `${finalProjectName} - AI-powered app`;
117
- finalFramework = finalFramework || "instantdb"; // Auto-select InstantDB
118
- // Validate required fields
119
- if (!finalDescription) {
120
- throw new Error("Project description is required");
73
+ if (!finalProjectName) {
74
+ finalProjectName = "my-app";
121
75
  }
76
+ const workingDir = process.cwd();
77
+ const projectPath = useCurrentDir
78
+ ? workingDir
79
+ : path.resolve(workingDir, finalProjectName);
122
80
  spinner.start();
123
- // Setup framework-specific project with correct order
124
- if (finalFramework === "instantdb") {
125
- // 1. Setup Next.js first (if needed)
126
- const projectPath = useCurrentDir
127
- ? workingDir
128
- : path.join(workingDir, finalProjectName);
129
- const packageJsonPath = path.join(projectPath, "package.json");
130
- if (!(await fs.pathExists(packageJsonPath))) {
131
- spinner.updateText("Setting up Next.js project...");
132
- await this.setupNextJSProject(finalProjectName, workingDir, useCurrentDir);
133
- }
134
- // 2. Setup shadcn/ui FIRST (before InstantDB)
135
- const shouldInitShadcn = options.skipShadcn !== true;
136
- if (shouldInitShadcn) {
137
- spinner.updateText("Initializing shadcn/ui...");
138
- await this.setupShadcn(finalProjectName, workingDir, useCurrentDir);
139
- }
140
- // 3. Setup InstantDB (MyContext branded flow)
141
- spinner.stop(); // Stop spinner for InstantDB setup output
142
- await this.setupInstantDBProject(finalProjectName, workingDir, useCurrentDir);
143
- spinner.start(); // Restart spinner for remaining setup
81
+ // Determine framework (default to instantdb for backward compatibility)
82
+ const framework = options.framework || "instantdb";
83
+ if (framework === "instantdb") {
84
+ // InstantDB workflow
85
+ await this.initInstantDBProject(spinner, workingDir, projectPath, finalProjectName, options, useCurrentDir);
144
86
  }
145
- else if (finalFramework === "nextjs") {
146
- // Next.js only setup
147
- spinner.updateText("Setting up Next.js project...");
148
- await this.setupNextJSProject(finalProjectName, workingDir, useCurrentDir);
149
- // Setup shadcn/ui for Next.js projects
150
- const shouldInitShadcn = options.skipShadcn !== true;
151
- if (shouldInitShadcn) {
152
- const projectPath = useCurrentDir
153
- ? workingDir
154
- : path.join(workingDir, finalProjectName);
155
- const packageJsonPath = path.join(projectPath, "package.json");
156
- if (await fs.pathExists(packageJsonPath)) {
157
- spinner.updateText("Initializing shadcn/ui...");
158
- await this.setupShadcn(finalProjectName, workingDir, useCurrentDir);
159
- }
160
- else {
161
- console.log(chalk_1.default.yellow(" āš ļø shadcn/ui init skipped (no package.json found). Run it inside an existing Next.js project."));
162
- console.log(chalk_1.default.gray(" pnpm dlx shadcn@latest init -y"));
163
- }
164
- }
87
+ else if (framework === "nextjs" || framework === "next") {
88
+ // Next.js workflow (shadcn + MyContext only)
89
+ await this.initNextJSProject(spinner, workingDir, projectPath, finalProjectName, options, useCurrentDir);
165
90
  }
166
- // Initialize MyContext directory structure and context after framework setup
167
- spinner.updateText("Initializing MyContext project files...");
168
- const config = await this.fs.initializeProject(finalProjectName, finalDescription, workingDir, useCurrentDir);
169
- // Write .mycontext/.env.example with guidance
170
- try {
171
- const projectPath = useCurrentDir
172
- ? workingDir
173
- : path.join(workingDir, finalProjectName);
174
- const envDir = path.join(projectPath, ".mycontext");
175
- await fs.ensureDir(envDir);
176
- const envExamplePath = path.join(envDir, ".env.example");
177
- const envExample = await envExampleGenerator_1.EnvExampleGenerator.generateForProject(projectPath);
178
- await fs.writeFile(envExamplePath, envExample);
91
+ else {
92
+ // Default: MyContext only
93
+ await this.initBasicProject(spinner, projectPath, finalProjectName, options, useCurrentDir);
179
94
  }
180
- catch { }
181
- // Setup Studio (if bundled)
182
- const projectPath = useCurrentDir
183
- ? workingDir
184
- : path.join(workingDir, finalProjectName);
185
- await this.setupStudio(projectPath);
186
- spinner.success({
187
- text: `Project "${finalProjectName}" initialized successfully!`,
188
- });
189
- // PRD Review Workflow - Encourage users to review and update PRD
190
- await this.handlePRDReviewWorkflow(finalProjectName, workingDir, useCurrentDir);
191
- // Show next steps with framework-specific guidance
192
- this.showNextSteps(config, finalFramework, useCurrentDir);
193
95
  }
194
96
  catch (error) {
195
97
  spinner.error({ text: "Failed to initialize project" });
196
- // Don't re-throw - let the CLI handle it
98
+ console.error(chalk_1.default.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
99
+ throw error;
100
+ }
101
+ }
102
+ /**
103
+ * Initialize an InstantDB project with full setup
104
+ */
105
+ async initInstantDBProject(spinner, workingDir, projectPath, projectName, options, useCurrentDir) {
106
+ // 1. Run shadcn init
107
+ spinner.updateText("Running shadcn init...");
108
+ (0, child_process_1.execSync)("pnpm dlx shadcn@latest init", {
109
+ cwd: workingDir,
110
+ stdio: "inherit",
111
+ });
112
+ // 2. Prompt user for instant-cli init
113
+ spinner.stop();
114
+ const { runInstantInit } = await (0, prompts_1.default)({
115
+ type: "confirm",
116
+ name: "runInstantInit",
117
+ message: "Run 'npx instant-cli init' to initialize InstantDB?",
118
+ initial: true,
119
+ });
120
+ if (runInstantInit) {
121
+ spinner.start();
122
+ spinner.updateText("Running instant-cli init...");
123
+ (0, child_process_1.execSync)("npx instant-cli init", {
124
+ cwd: projectPath,
125
+ stdio: "inherit",
126
+ });
127
+ // Prompt user to push schemas
128
+ spinner.stop();
129
+ const { pushSchemas } = await (0, prompts_1.default)({
130
+ type: "confirm",
131
+ name: "pushSchemas",
132
+ message: "Push schemas to InstantDB dashboard? (Make sure you've configured your app)",
133
+ initial: false,
134
+ });
135
+ if (pushSchemas) {
136
+ spinner.start();
137
+ spinner.updateText("Pushing schemas to InstantDB...");
138
+ (0, child_process_1.execSync)("npx instant-cli push", {
139
+ cwd: projectPath,
140
+ stdio: "inherit",
141
+ });
142
+ }
197
143
  }
144
+ // 3. Install @instantdb/react and @instantdb/admin
145
+ spinner.start();
146
+ spinner.updateText("Installing InstantDB packages...");
147
+ (0, child_process_1.execSync)("pnpm add @instantdb/react @instantdb/admin", {
148
+ cwd: projectPath,
149
+ stdio: "inherit",
150
+ });
151
+ // Install bcrypt for auth utilities
152
+ spinner.updateText("Installing auth dependencies...");
153
+ (0, child_process_1.execSync)("pnpm add bcryptjs nanoid && pnpm add -D @types/bcryptjs", {
154
+ cwd: projectPath,
155
+ stdio: "inherit",
156
+ });
157
+ // 4. Copy InstantDB templates to lib folder
158
+ spinner.updateText("Copying InstantDB template files...");
159
+ await this.fs.copyInstantDBTemplates(projectPath);
160
+ // 5. Initialize MyContext directory structure and context
161
+ spinner.updateText("Initializing MyContext project files...");
162
+ const config = await this.fs.initializeProject(projectName, options.description || `${projectName} - AI-powered app`, workingDir, useCurrentDir);
163
+ spinner.success({
164
+ text: `Project "${projectName}" initialized successfully with InstantDB!`,
165
+ });
166
+ // Show next steps
167
+ this.showNextSteps(config, "instantdb", useCurrentDir);
168
+ }
169
+ /**
170
+ * Initialize a Next.js project (shadcn + MyContext only)
171
+ */
172
+ async initNextJSProject(spinner, workingDir, projectPath, projectName, options, useCurrentDir) {
173
+ // 1. Run shadcn init
174
+ spinner.updateText("Running shadcn init...");
175
+ (0, child_process_1.execSync)("pnpm dlx shadcn@latest init", {
176
+ cwd: workingDir,
177
+ stdio: "inherit",
178
+ });
179
+ // 2. Initialize MyContext directory structure and context
180
+ spinner.updateText("Initializing MyContext project files...");
181
+ const config = await this.fs.initializeProject(projectName, options.description || `${projectName} - Next.js app`, workingDir, useCurrentDir);
182
+ spinner.success({
183
+ text: `Project "${projectName}" initialized successfully with Next.js!`,
184
+ });
185
+ // Show next steps
186
+ this.showNextSteps(config, "nextjs", useCurrentDir);
187
+ }
188
+ /**
189
+ * Initialize a basic MyContext project (no framework)
190
+ */
191
+ async initBasicProject(spinner, projectPath, projectName, options, useCurrentDir) {
192
+ spinner.updateText("Initializing MyContext project files...");
193
+ const config = await this.fs.initializeProject(projectName, options.description || `${projectName} - AI-powered app`, process.cwd(), useCurrentDir);
194
+ spinner.success({
195
+ text: `Project "${projectName}" initialized successfully!`,
196
+ });
197
+ // Show next steps
198
+ this.showNextSteps(config, undefined, useCurrentDir);
198
199
  }
199
- async handlePRDReviewWorkflow(projectName, workingDir, useCurrentDir) {
200
- console.log(chalk_1.default.blue("\nšŸ“‹ PRD Review Workflow"));
201
- console.log(chalk_1.default.yellow("ā— IMPORTANT: Please review and update your PRD before proceeding with context generation."));
202
- console.log(chalk_1.default.gray(" The PRD is the foundation of your project - make sure it accurately describes your requirements."));
203
- const projectPath = useCurrentDir
204
- ? workingDir
205
- : path.join(workingDir, projectName);
206
- const prdPath = path.join(projectPath, ".mycontext", "01-prd.md");
207
- console.log(chalk_1.default.cyan("\nšŸ“„ Your PRD has been initialized at:"));
208
- console.log(chalk_1.default.gray(` ${prdPath}`));
209
- console.log(chalk_1.default.cyan("\nšŸ” Next steps:"));
210
- console.log(chalk_1.default.gray(" 1. Open and review the PRD file"));
211
- console.log(chalk_1.default.gray(" 2. Update it with your specific requirements"));
212
- console.log(chalk_1.default.gray(" 3. Add user stories, acceptance criteria, and technical details"));
213
- console.log(chalk_1.default.gray(" 4. Run 'mycontext generate context' when ready"));
214
- console.log(chalk_1.default.yellow("\nāš ļø Reminder: Context generation requires a reviewed PRD!"));
215
- console.log(chalk_1.default.gray(" The AI will use your PRD to generate accurate types and brand guidelines."));
200
+ isValidProjectName(name) {
201
+ // Allow alphanumeric, hyphens, and underscores
202
+ return /^[a-zA-Z0-9._-]+$/.test(name);
216
203
  }
217
204
  showNextSteps(config, framework, useCurrentDir) {
218
- const projectPath = useCurrentDir ? process.cwd() : config.name;
205
+ const projectPath = useCurrentDir ? "." : config.name;
219
206
  console.log(chalk_1.default.blue("\nšŸŽÆ Quick Start:\n"));
220
- console.log(chalk_1.default.yellow("1. Navigate to your project:"));
221
- console.log(chalk_1.default.gray(` cd ${projectPath}\n`));
222
- console.log(chalk_1.default.yellow("2. ļæ½ļø Analyze a screenshot (Gemini 2.0 Flash):"));
207
+ if (!useCurrentDir) {
208
+ console.log(chalk_1.default.yellow("1. Navigate to your project:"));
209
+ console.log(chalk_1.default.gray(` cd ${projectPath}\n`));
210
+ }
211
+ if (framework === "instantdb") {
212
+ console.log(chalk_1.default.yellow("2. Configure InstantDB:"));
213
+ console.log(chalk_1.default.gray(" • Add your InstantDB App ID to .env.local:"));
214
+ console.log(chalk_1.default.cyan(" NEXT_PUBLIC_INSTANT_APP_ID=your-app-id"));
215
+ console.log(chalk_1.default.gray(" • Template files copied to lib/ (or src/lib/):"));
216
+ console.log(chalk_1.default.gray(" - instant-client.ts (Client SDK)"));
217
+ console.log(chalk_1.default.gray(" - instant-admin.ts (Admin SDK)"));
218
+ console.log(chalk_1.default.gray(" - auth.ts (Auth helpers)"));
219
+ console.log(chalk_1.default.gray(" - instantdb-storage.ts (File storage)\n"));
220
+ }
221
+ console.log(chalk_1.default.yellow("3. ļø Analyze a screenshot (Gemini 2.0 Flash):"));
223
222
  console.log(chalk_1.default.cyan(" mycontext analyze /path/to/screenshot.png"));
224
223
  console.log(chalk_1.default.gray(" # Reverse-engineer any UI into a comprehensive spec!\n"));
225
- console.log(chalk_1.default.yellow("3. Configure AI provider:"));
226
- console.log(chalk_1.default.gray(" šŸ“Œ Gemini (Free - Recommended for screenshots):"));
224
+ console.log(chalk_1.default.yellow("4. Configure AI provider:"));
225
+ console.log(chalk_1.default.gray(" šŸ”„ Gemini (Free - Recommended for screenshots):"));
227
226
  console.log(chalk_1.default.gray(" Get API key: https://aistudio.google.com/apikey"));
228
227
  console.log(chalk_1.default.cyan(" echo 'GEMINI_API_KEY=your-key' >> .mycontext/.env\n"));
229
228
  console.log(chalk_1.default.gray(" šŸ“Œ Claude (Best for text generation):"));
230
229
  console.log(chalk_1.default.gray(" https://console.anthropic.com/\n"));
231
- console.log(chalk_1.default.yellow("4. Generate full context:"));
230
+ console.log(chalk_1.default.yellow("5. Generate full context:"));
232
231
  console.log(chalk_1.default.gray(" mycontext generate context --full\n"));
233
- console.log(chalk_1.default.yellow("5. Start development:"));
232
+ console.log(chalk_1.default.yellow("6. Start development:"));
234
233
  console.log(chalk_1.default.gray(" pnpm dev\n"));
235
234
  console.log(chalk_1.default.green("✨ Tips:"));
236
235
  console.log(chalk_1.default.gray("• Check .mycontext/ for all generated files"));
236
+ if (framework === "instantdb") {
237
+ console.log(chalk_1.default.gray("• InstantDB templates are ready to use in your lib/ folder"));
238
+ console.log(chalk_1.default.gray("• Update instant.schema.ts with your data model"));
239
+ }
237
240
  console.log(chalk_1.default.gray("• Use --yes flag to skip prompts"));
238
241
  console.log(chalk_1.default.gray("• Run 'mycontext status' to check project progress\n"));
239
242
  // Exit the process gracefully after displaying all information
@@ -255,346 +258,6 @@ class InitCommand {
255
258
  console.log(chalk_1.default.blue.bold("\nšŸš€ MyContext - Screenshot to Spec\n"));
256
259
  }
257
260
  }
258
- async detectPackageManager() {
259
- const pnpmLock = path.join(process.cwd(), "pnpm-lock.yaml");
260
- const yarnLock = path.join(process.cwd(), "yarn.lock");
261
- const packageLock = path.join(process.cwd(), "package-lock.json");
262
- if (await fs.pathExists(pnpmLock))
263
- return "pnpm";
264
- if (await fs.pathExists(yarnLock))
265
- return "yarn";
266
- if (await fs.pathExists(packageLock))
267
- return "npm";
268
- return "pnpm"; // Default to pnpm
269
- }
270
- async installInstantDBDeps(projectPath) {
271
- try {
272
- const packageManager = await this.detectPackageManager();
273
- const installCmd = packageManager === "pnpm"
274
- ? "pnpm add"
275
- : packageManager === "yarn"
276
- ? "yarn add"
277
- : "npm install";
278
- console.log(chalk_1.default.gray(" Installing InstantDB dependencies..."));
279
- (0, child_process_1.execSync)(`${installCmd} @instantdb/react @instantdb/admin @tanstack/react-query`, {
280
- cwd: projectPath,
281
- stdio: "inherit",
282
- timeout: 180000,
283
- });
284
- console.log(chalk_1.default.green(" āœ… Dependencies installed"));
285
- }
286
- catch (error) {
287
- console.log(chalk_1.default.yellow(" āš ļø Failed to install dependencies automatically"));
288
- console.log(chalk_1.default.gray(" Run manually:"));
289
- console.log(chalk_1.default.gray(" pnpm add @instantdb/react @instantdb/admin @tanstack/react-query"));
290
- }
291
- }
292
- async generateInstantDBSchema(projectPath) {
293
- try {
294
- const schemaTemplatePath = path.join(__dirname, "../templates/instantdb/schema.template.ts");
295
- const schemaContent = await fs.readFile(schemaTemplatePath, "utf-8");
296
- const schemaPath = path.join(projectPath, "instant.schema.ts");
297
- await fs.writeFile(schemaPath, schemaContent);
298
- console.log(chalk_1.default.green(" āœ… instant.schema.ts created"));
299
- }
300
- catch (error) {
301
- console.log(chalk_1.default.yellow(" āš ļø Failed to create schema file"));
302
- }
303
- }
304
- async generateInstantDBPerms(projectPath) {
305
- try {
306
- const permsTemplatePath = path.join(__dirname, "../templates/instantdb/perms.template.ts");
307
- const permsContent = await fs.readFile(permsTemplatePath, "utf-8");
308
- const permsPath = path.join(projectPath, "instant.perms.ts");
309
- await fs.writeFile(permsPath, permsContent);
310
- console.log(chalk_1.default.green(" āœ… instant.perms.ts created"));
311
- }
312
- catch (error) {
313
- console.log(chalk_1.default.yellow(" āš ļø Failed to create permissions file"));
314
- }
315
- }
316
- async generateDBClient(projectPath) {
317
- try {
318
- const dbTemplatePath = path.join(__dirname, "../templates/instantdb/db.template.ts");
319
- const dbContent = await fs.readFile(dbTemplatePath, "utf-8");
320
- const libDir = path.join(projectPath, "lib");
321
- await fs.ensureDir(libDir);
322
- const dbPath = path.join(libDir, "db.ts");
323
- await fs.writeFile(dbPath, dbContent);
324
- console.log(chalk_1.default.green(" āœ… lib/db.ts created"));
325
- }
326
- catch (error) {
327
- console.log(chalk_1.default.yellow(" āš ļø Failed to create database client"));
328
- }
329
- }
330
- async createInstantDBEnv(projectPath, appId) {
331
- try {
332
- const envPath = path.join(projectPath, ".env");
333
- const envContent = `# InstantDB Configuration
334
- NEXT_PUBLIC_INSTANT_APP_ID=${appId || "__YOUR_APP_ID_HERE__"}
335
-
336
- # Get your app ID from: https://instantdb.com/dash
337
- # Create a new app or use an existing one
338
- `;
339
- // Check if .env exists
340
- if (await fs.pathExists(envPath)) {
341
- const existingEnv = await fs.readFile(envPath, "utf-8");
342
- if (!existingEnv.includes("NEXT_PUBLIC_INSTANT_APP_ID")) {
343
- await fs.appendFile(envPath, "\n" + envContent);
344
- console.log(chalk_1.default.green(" āœ… .env updated with InstantDB config"));
345
- }
346
- else {
347
- console.log(chalk_1.default.gray(" āœ… .env already has InstantDB config"));
348
- }
349
- }
350
- else {
351
- await fs.writeFile(envPath, envContent);
352
- console.log(chalk_1.default.green(" āœ… .env created"));
353
- }
354
- }
355
- catch (error) {
356
- console.log(chalk_1.default.yellow(" āš ļø Failed to create .env file"));
357
- }
358
- }
359
- async generateSampleComponents(projectPath) {
360
- try {
361
- // Generate home-client.tsx
362
- const homeClientTemplatePath = path.join(__dirname, "../templates/instantdb/home-client.template.tsx");
363
- const homeClientContent = await fs.readFile(homeClientTemplatePath, "utf-8");
364
- const appDir = path.join(projectPath, "app");
365
- await fs.ensureDir(appDir);
366
- const homeClientPath = path.join(appDir, "home-client.tsx");
367
- await fs.writeFile(homeClientPath, homeClientContent);
368
- console.log(chalk_1.default.green(" āœ… app/home-client.tsx created"));
369
- // Generate/update page.tsx
370
- const pageTemplatePath = path.join(__dirname, "../templates/instantdb/page.template.tsx");
371
- const pageContent = await fs.readFile(pageTemplatePath, "utf-8");
372
- const pagePath = path.join(appDir, "page.tsx");
373
- await fs.writeFile(pagePath, pageContent);
374
- console.log(chalk_1.default.green(" āœ… app/page.tsx updated"));
375
- }
376
- catch (error) {
377
- console.log(chalk_1.default.yellow(" āš ļø Failed to create sample components"));
378
- }
379
- }
380
- async pushInstantDBSchema(projectPath) {
381
- try {
382
- console.log(chalk_1.default.gray(" Pushing schema to InstantDB..."));
383
- (0, child_process_1.execSync)("npx instant-cli@latest push -y", {
384
- cwd: projectPath,
385
- stdio: "inherit",
386
- timeout: 60000,
387
- });
388
- console.log(chalk_1.default.green(" āœ… Schema pushed to InstantDB"));
389
- }
390
- catch (error) {
391
- console.log(chalk_1.default.yellow(" āš ļø Schema push failed (you can push it manually later)"));
392
- console.log(chalk_1.default.gray(" Run: npx instant-cli@latest push"));
393
- }
394
- }
395
- isValidProjectName(name) {
396
- // Allow alphanumeric, hyphens, and underscores
397
- return /^[a-zA-Z0-9_-]+$/.test(name);
398
- }
399
- async setupInstantDBProject(projectName, workingDir, useCurrentDir) {
400
- try {
401
- const projectPath = useCurrentDir
402
- ? workingDir
403
- : path.join(workingDir, projectName);
404
- // Check if InstantDB project already exists
405
- const instantSchemaPath = path.join(projectPath, "instant.schema.ts");
406
- const packageJsonPath = path.join(projectPath, "package.json");
407
- if ((await fs.pathExists(instantSchemaPath)) &&
408
- (await fs.pathExists(packageJsonPath))) {
409
- console.log(chalk_1.default.gray(" āœ… InstantDB project structure detected"));
410
- return;
411
- }
412
- console.log(chalk_1.default.blue("\nšŸ—„ļø Setting up InstantDB...\n"));
413
- // Step 1: Install dependencies
414
- await this.installInstantDBDeps(projectPath);
415
- // Step 2: Generate schema
416
- await this.generateInstantDBSchema(projectPath);
417
- // Step 3: Generate permissions
418
- await this.generateInstantDBPerms(projectPath);
419
- // Step 4: Create database client
420
- await this.generateDBClient(projectPath);
421
- // Step 5: Create environment file
422
- await this.createInstantDBEnv(projectPath);
423
- // Step 6: Generate sample components
424
- await this.generateSampleComponents(projectPath);
425
- // Step 7: Push schema to InstantDB
426
- await this.pushInstantDBSchema(projectPath);
427
- console.log(chalk_1.default.green("\nāœ… InstantDB setup complete!\n"));
428
- console.log(chalk_1.default.yellow("šŸ“ Next steps:"));
429
- console.log(chalk_1.default.gray(" 1. Get your App ID from: https://instantdb.com/dash"));
430
- console.log(chalk_1.default.gray(" 2. Update NEXT_PUBLIC_INSTANT_APP_ID in .env"));
431
- console.log(chalk_1.default.gray(" 3. Run: pnpm dev"));
432
- console.log(chalk_1.default.gray(" 4. Open http://localhost:3000 to see your todo app\n"));
433
- }
434
- catch (error) {
435
- console.log(chalk_1.default.yellow(`\nāš ļø InstantDB setup encountered an issue: ${error instanceof Error ? error.message : "Unknown error"}`));
436
- console.log(chalk_1.default.gray(" You can complete the setup manually if needed"));
437
- console.log(chalk_1.default.blue("šŸ”„ MyContext will continue with project setup...\n"));
438
- }
439
- }
440
- async setupNextJSProject(projectName, workingDir, useCurrentDir) {
441
- try {
442
- const projectPath = path.join(workingDir, projectName);
443
- // Check if Next.js project already exists
444
- const packageJsonPath = path.join(projectPath, "package.json");
445
- if (await fs.pathExists(packageJsonPath)) {
446
- console.log(chalk_1.default.gray(" āœ… Next.js project structure detected"));
447
- return;
448
- }
449
- // Create Next.js project
450
- console.log(chalk_1.default.gray(" Creating Next.js project..."));
451
- try {
452
- (0, child_process_1.execSync)(`npx create-next-app@latest ${projectName} --typescript --tailwind --eslint --app --import-alias "@/*" --yes`, {
453
- cwd: workingDir,
454
- stdio: "inherit",
455
- timeout: 300000, // 5 minutes
456
- });
457
- console.log(chalk_1.default.green(" āœ… Next.js project created"));
458
- }
459
- catch (error) {
460
- console.log(chalk_1.default.yellow(` āš ļø Failed to create Next.js project automatically`));
461
- console.log(chalk_1.default.gray(` Please create it manually:`));
462
- console.log(chalk_1.default.gray(` npx create-next-app@latest ${projectName} --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"`));
463
- }
464
- }
465
- catch (error) {
466
- console.log(chalk_1.default.yellow(` āš ļø Next.js setup encountered an issue: ${error instanceof Error ? error.message : "Unknown error"}`));
467
- console.log(chalk_1.default.gray(" You can create the Next.js project manually if needed"));
468
- }
469
- }
470
- async setupShadcn(projectName, workingDir, useCurrentDir) {
471
- const projectPath = path.join(workingDir, projectName);
472
- try {
473
- console.log(chalk_1.default.gray(" Running shadcn/ui init (pnpm first)..."));
474
- try {
475
- (0, child_process_1.execSync)(`pnpm dlx shadcn@latest init -y`, {
476
- cwd: projectPath,
477
- stdio: "inherit",
478
- timeout: 180000,
479
- });
480
- console.log(chalk_1.default.green(" āœ… shadcn/ui initialized (pnpm)"));
481
- return;
482
- }
483
- catch (e) {
484
- console.log(chalk_1.default.gray(" pnpm not available or failed, trying npx..."));
485
- }
486
- (0, child_process_1.execSync)(`npx shadcn@latest init -y`, {
487
- cwd: projectPath,
488
- stdio: "inherit",
489
- timeout: 180000,
490
- });
491
- console.log(chalk_1.default.green(" āœ… shadcn/ui initialized (npx)"));
492
- }
493
- catch (error) {
494
- console.log(chalk_1.default.yellow(" āš ļø shadcn/ui init failed. You can run it manually inside the project:"));
495
- console.log(chalk_1.default.gray(" pnpm dlx shadcn@latest init -y"));
496
- console.log(chalk_1.default.gray(" # or"));
497
- console.log(chalk_1.default.gray(" npx shadcn@latest init -y"));
498
- }
499
- }
500
- async isExistingProject(projectPath) {
501
- const packageJsonPath = path.join(projectPath, "package.json");
502
- const instantSchemaPath = path.join(projectPath, "instant.schema.ts");
503
- const nextConfigPath = path.join(projectPath, "next.config.js");
504
- const nextConfigTsPath = path.join(projectPath, "next.config.ts");
505
- const hasPackageJson = await fs.pathExists(packageJsonPath);
506
- const hasInstantSchema = await fs.pathExists(instantSchemaPath);
507
- const hasNextConfig = (await fs.pathExists(nextConfigPath)) ||
508
- (await fs.pathExists(nextConfigTsPath));
509
- if (!hasPackageJson)
510
- return false;
511
- try {
512
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
513
- // Check for InstantDB project
514
- const hasInstantDependency = packageJson.dependencies?.["@instantdb/react"] ||
515
- packageJson.dependencies?.["@instantdb/core"];
516
- // Check for Next.js project
517
- const hasNextDependency = packageJson.dependencies?.next || packageJson.devDependencies?.next;
518
- return ((hasInstantDependency && hasInstantSchema) ||
519
- (hasNextDependency && hasNextConfig));
520
- }
521
- catch {
522
- return false;
523
- }
524
- }
525
- async askToAnalyze() {
526
- const response = await (0, prompts_1.default)({
527
- type: "confirm",
528
- name: "analyze",
529
- message: "Would you like to analyze this existing project and generate context files?",
530
- initial: true,
531
- });
532
- return response.analyze;
533
- }
534
- async analyzeExistingProject(projectPath, options) {
535
- console.log(chalk_1.default.blue.bold("šŸ” Analyzing Existing Project\n"));
536
- try {
537
- // Import and use AnalyzeCommand
538
- const { AnalyzeCommand } = await Promise.resolve().then(() => __importStar(require("./analyze")));
539
- const analyzeCommand = new AnalyzeCommand();
540
- await analyzeCommand.execute(projectPath, {
541
- output: ".mycontext",
542
- generateContext: true,
543
- includeBrand: true,
544
- includeTypes: true,
545
- includeComponents: true,
546
- verbose: options.verbose || false,
547
- });
548
- console.log(chalk_1.default.green.bold("\nāœ… Existing project analysis completed!"));
549
- console.log(chalk_1.default.yellow("\nšŸ“‹ Next Steps:"));
550
- console.log(chalk_1.default.gray("1. Review the generated context files in .mycontext/"));
551
- console.log(chalk_1.default.gray("2. Run 'mycontext generate context --full' to enhance context"));
552
- console.log(chalk_1.default.gray("3. Run 'mycontext generate components-list' to plan new components"));
553
- console.log(chalk_1.default.gray("4. Run 'mycontext generate-components' to create new components"));
554
- }
555
- catch (error) {
556
- console.error(chalk_1.default.red("āŒ Analysis failed:"), error);
557
- // Don't re-throw - let the CLI handle it
558
- }
559
- }
560
- async setupStudio(projectPath) {
561
- try {
562
- const studioPath = path.join(projectPath, "studio");
563
- // Check if Studio is bundled (exists in CLI directory)
564
- const bundledStudioPath = path.join(__dirname, "../../studio");
565
- if (!(await this.fs.exists(bundledStudioPath))) {
566
- console.log(chalk_1.default.yellow("šŸ“± Studio not bundled - skipping setup"));
567
- return;
568
- }
569
- console.log(chalk_1.default.blue("šŸ“± Setting up MyContext Studio preview..."));
570
- // Copy Studio to project
571
- await fs.copy(bundledStudioPath, studioPath);
572
- // Install Studio dependencies
573
- console.log(chalk_1.default.blue("šŸ“¦ Installing Studio dependencies..."));
574
- try {
575
- (0, child_process_1.execSync)("pnpm install", {
576
- cwd: studioPath,
577
- stdio: "inherit",
578
- timeout: 120000, // 2 minutes timeout
579
- });
580
- }
581
- catch (error) {
582
- console.log(chalk_1.default.yellow("āš ļø Failed to install Studio dependencies. You can run 'cd studio && pnpm install' manually."));
583
- }
584
- // Create .env.local for Studio
585
- const envLocalPath = path.join(studioPath, ".env.local");
586
- const envContent = `# MyContext Studio Configuration
587
- NEXT_PUBLIC_CLI_COMPONENTS_PATH=../components/generated
588
- NEXT_PUBLIC_STUDIO_VERSION=0.1.0
589
- `;
590
- await fs.writeFile(envLocalPath, envContent);
591
- console.log(chalk_1.default.green("āœ… Studio setup complete!"));
592
- console.log(chalk_1.default.gray(" Run 'pnpm studio:dev' to start the preview server"));
593
- }
594
- catch (error) {
595
- console.log(chalk_1.default.yellow("āš ļø Studio setup failed - you can set it up manually later"));
596
- }
597
- }
598
261
  }
599
262
  exports.InitCommand = InitCommand;
600
263
  //# sourceMappingURL=init.js.map