create-alta-app 1.9.0 → 2.1.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 (2) hide show
  1. package/index.mjs +51 -101
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import { execSync } from 'node:child_process';
4
4
  import fs from 'node:fs';
5
- import os from 'node:os';
6
5
  import path from 'node:path';
7
6
  import prompts from 'prompts';
8
7
  import ora from 'ora';
@@ -149,17 +148,9 @@ export default function Root() {
149
148
 
150
149
  fs.writeFileSync(
151
150
  path.join(appDir, 'components', 'layout', 'header.tsx'),
152
- `import { Separator } from '@alta/design-system/components/ui/separator';
153
- import { Text } from '@alta/design-system/components/ui/text';
154
-
155
- export function Header() {
151
+ `export function Header() {
156
152
  return (
157
- <header className="flex h-14 items-center gap-2 border-b px-4">
158
- <Separator orientation="vertical" className="h-4" />
159
- <div className="ml-auto flex items-center gap-3">
160
- <Text variant="muted">Alta App</Text>
161
- </div>
162
- </header>
153
+ <header className="flex h-14 items-center justify-end border-b px-4" />
163
154
  );
164
155
  }
165
156
  `
@@ -167,49 +158,10 @@ export function Header() {
167
158
 
168
159
  fs.writeFileSync(
169
160
  path.join(appDir, 'routes', 'app', 'dashboard.tsx'),
170
- `import { Card, CardContent, CardHeader, CardTitle } from '@alta/design-system/components/ui/card';
171
- import { Text } from '@alta/design-system/components/ui/text';
172
- import { Badge } from '@alta/design-system/components/ui/badge';
173
- import { Separator } from '@alta/design-system/components/ui/separator';
174
-
175
- export default function DashboardRoute() {
161
+ `export default function DashboardRoute() {
176
162
  return (
177
163
  <div className="space-y-6">
178
- <div>
179
- <Text variant="heading3">Dashboard</Text>
180
- <Text variant="muted" className="mt-1">Welcome to your app</Text>
181
- </div>
182
- <Separator />
183
- <div className="grid gap-4 md:grid-cols-3">
184
- <Card>
185
- <CardHeader className="flex flex-row items-center justify-between pb-2">
186
- <CardTitle className="text-sm font-medium text-muted-foreground">Status</CardTitle>
187
- <Badge variant="default">Active</Badge>
188
- </CardHeader>
189
- <CardContent>
190
- <Text variant="heading3">All systems go</Text>
191
- <Text variant="small" className="mt-1 text-muted-foreground">Your app is running smoothly</Text>
192
- </CardContent>
193
- </Card>
194
- <Card>
195
- <CardHeader className="pb-2">
196
- <CardTitle className="text-sm font-medium text-muted-foreground">Environment</CardTitle>
197
- </CardHeader>
198
- <CardContent>
199
- <Text variant="heading3">Development</Text>
200
- <Text variant="small" className="mt-1 text-muted-foreground">Local dev server</Text>
201
- </CardContent>
202
- </Card>
203
- <Card>
204
- <CardHeader className="pb-2">
205
- <CardTitle className="text-sm font-medium text-muted-foreground">Framework</CardTitle>
206
- </CardHeader>
207
- <CardContent>
208
- <Text variant="heading3">Alta</Text>
209
- <Text variant="small" className="mt-1 text-muted-foreground">React + Supabase + Vercel</Text>
210
- </CardContent>
211
- </Card>
212
- </div>
164
+ <h1 className="text-2xl font-bold">Dashboard</h1>
213
165
  </div>
214
166
  );
215
167
  }
@@ -218,24 +170,10 @@ export default function DashboardRoute() {
218
170
 
219
171
  fs.writeFileSync(
220
172
  path.join(appDir, 'routes', 'app', 'settings.tsx'),
221
- `import { Card, CardContent, CardHeader, CardTitle } from '@alta/design-system/components/ui/card';
222
- import { Text } from '@alta/design-system/components/ui/text';
223
-
224
- export default function SettingsRoute() {
173
+ `export default function SettingsRoute() {
225
174
  return (
226
175
  <div className="space-y-6">
227
- <div>
228
- <Text variant="heading3">Settings</Text>
229
- <Text variant="muted" className="mt-1">Manage your app preferences</Text>
230
- </div>
231
- <Card>
232
- <CardHeader>
233
- <CardTitle>App Settings</CardTitle>
234
- </CardHeader>
235
- <CardContent>
236
- <Text variant="paragraph">Configure your app here.</Text>
237
- </CardContent>
238
- </Card>
176
+ <h1 className="text-2xl font-bold">Settings</h1>
239
177
  </div>
240
178
  );
241
179
  }
@@ -431,46 +369,17 @@ async function main() {
431
369
  credentials = null;
432
370
  }
433
371
 
434
- // ── Step 4: Setup shell credentials (needed for polling in next step) ──
435
- const shellRc = path.join(os.homedir(), '.zshrc');
436
- const tokensToSet = {
437
- SUPABASE_ACCESS_TOKEN: 'sbp_66e351be37d4e570fe4347ea7c78bbebc8988219',
438
- };
439
-
440
- try {
441
- let rcContent = fs.existsSync(shellRc) ? fs.readFileSync(shellRc, 'utf-8') : '';
442
-
443
- for (const [key, value] of Object.entries(tokensToSet)) {
444
- const regex = new RegExp(`^export ${key}=.*$`, 'm');
445
- const line = `export ${key}=${value}`;
446
-
447
- if (regex.test(rcContent)) {
448
- rcContent = rcContent.replace(regex, line);
449
- } else {
450
- rcContent += `\n# Alta\n${line}\n`;
451
- }
452
- process.env[key] = value;
453
- }
454
-
455
- const spinnerShell = ora({ text: 'Setting up shell credentials...', indent: 2 }).start();
456
- fs.writeFileSync(shellRc, rcContent);
457
- spinnerShell.succeed(pc.green('Shell credentials configured'));
458
- } catch {
459
- console.log(` ${pc.dim('Could not update ~/.zshrc — add SUPABASE_ACCESS_TOKEN manually')}`);
460
- }
461
-
462
- // ── Step 5: Wait for Supabase project to provision & get anon key ──
372
+ // ── Step 4: Wait for Supabase project to provision & get anon key ──
463
373
  let anonKey = '';
464
374
  if (credentials) {
465
375
  const spinnerKeys = ora({ text: 'Waiting for Supabase project to provision...', indent: 2 }).start();
466
- const token = process.env.SUPABASE_ACCESS_TOKEN;
467
376
  const ref = credentials.supabaseProjectRef;
468
377
 
469
378
  for (let i = 0; i < 24; i++) {
470
379
  await new Promise((r) => setTimeout(r, 5000));
471
380
  try {
472
381
  const res = await fetch(`https://api.supabase.com/v1/projects/${ref}/api-keys`, {
473
- headers: { Authorization: `Bearer ${token}` },
382
+ headers: { Authorization: `Bearer ${credentials.supabaseToken}` },
474
383
  });
475
384
  if (res.ok) {
476
385
  const keys = await res.json();
@@ -539,6 +448,47 @@ async function main() {
539
448
  }
540
449
 
541
450
 
451
+ // ── Step 6: Login & link Supabase + Vercel ──
452
+ if (credentials) {
453
+ const spinnerLink = ora({ text: 'Linking Supabase project...', indent: 2 }).start();
454
+ try {
455
+ run(`npx supabase login --token ${credentials.supabaseToken}`, targetDir);
456
+ run(`npx supabase link --project-ref ${credentials.supabaseProjectRef}`, targetDir);
457
+ spinnerLink.succeed(pc.green('Supabase project linked'));
458
+ } catch {
459
+ spinnerLink.warn(pc.yellow('Could not link Supabase project'));
460
+ console.log(` ${pc.dim(`Run manually: npx supabase login && npx supabase link --project-ref ${credentials.supabaseProjectRef}`)}`);
461
+ }
462
+
463
+ const spinnerVercel = ora({ text: 'Authenticating Vercel CLI...', indent: 2 }).start();
464
+ try {
465
+ // Persist Vercel auth globally so user doesn't need --token on every command
466
+ const vercelConfigDir = path.join(process.env.HOME, 'Library', 'Application Support', 'com.vercel.cli');
467
+ if (!fs.existsSync(vercelConfigDir)) fs.mkdirSync(vercelConfigDir, { recursive: true });
468
+
469
+ fs.writeFileSync(
470
+ path.join(vercelConfigDir, 'auth.json'),
471
+ JSON.stringify({ token: credentials.vercelToken }) + '\n'
472
+ );
473
+
474
+ // Set current team scope
475
+ const configPath = path.join(vercelConfigDir, 'config.json');
476
+ let vercelConfig = {};
477
+ if (fs.existsSync(configPath)) {
478
+ vercelConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
479
+ }
480
+ vercelConfig.currentTeam = credentials.vercelTeamId;
481
+ fs.writeFileSync(configPath, JSON.stringify(vercelConfig, null, 2) + '\n');
482
+
483
+ // Link the project to Vercel
484
+ run(`npx vercel link --project ${projectName} --yes`, targetDir);
485
+ spinnerVercel.succeed(pc.green('Vercel authenticated & project linked'));
486
+ } catch {
487
+ spinnerVercel.warn(pc.yellow('Could not link Vercel project'));
488
+ console.log(` ${pc.dim('Deploy manually: cd ' + projectName + ' && pnpm run deploy')}`);
489
+ }
490
+ }
491
+
542
492
  // ── Step 7: Write project-specific MCP config ──
543
493
  if (credentials) {
544
494
  const spinnerMcp = ora({ text: 'Configuring Claude MCP...', indent: 2 }).start();
@@ -551,7 +501,7 @@ async function main() {
551
501
  supabase: {
552
502
  url: `https://mcp.supabase.com/mcp`,
553
503
  headers: {
554
- 'x-supabase-access-token': '${SUPABASE_ACCESS_TOKEN}',
504
+ 'x-supabase-access-token': credentials.supabaseToken,
555
505
  'x-project-ref': credentials.supabaseProjectRef,
556
506
  },
557
507
  },
@@ -605,7 +555,7 @@ async function main() {
605
555
  spinnerDeploy.succeed(pc.green('Deployed to Vercel'));
606
556
  } catch {
607
557
  spinnerDeploy.warn(pc.yellow('Could not deploy to Vercel'));
608
- console.log(` ${pc.dim('Deploy manually: cd ' + projectName + ' && pnpm deploy')}`);
558
+ console.log(` ${pc.dim('Deploy manually: cd ' + projectName + ' && pnpm run deploy')}`);
609
559
  }
610
560
  }
611
561
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-alta-app",
3
- "version": "1.9.0",
3
+ "version": "2.1.0",
4
4
  "description": "Create a new Alta project",
5
5
  "bin": {
6
6
  "create-alta-app": "./index.mjs"