create-supyagent-app 0.1.36 → 0.1.38
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/index.js +179 -185
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/api-route/compact/route.ts.tmpl +30 -0
- package/templates/api-route/route.skills.ts.tmpl +54 -2
- package/templates/api-route/route.tools.ts.tmpl +54 -2
- package/templates/base/src/app/layout.tsx +12 -2
- package/templates/base/src/components/chat-input.tsx +58 -2
- package/templates/base/src/components/chat-message.tsx +10 -0
- package/templates/base/src/components/chat.tsx +164 -23
- package/templates/base/src/components/header.tsx +15 -1
- package/templates/base/src/components/slash-menu.tsx +127 -0
- package/templates/base/src/components/theme-provider.tsx +58 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
4
|
+
import * as p3 from "@clack/prompts";
|
|
5
|
+
import pc3 from "picocolors";
|
|
6
6
|
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
7
7
|
import { resolve as resolve2, dirname as dirname2 } from "path";
|
|
8
8
|
|
|
@@ -210,6 +210,11 @@ function scaffoldProject(config) {
|
|
|
210
210
|
"src/app/api/chat/route.ts",
|
|
211
211
|
applyTemplate(readTemplate(routeTemplate), vars)
|
|
212
212
|
);
|
|
213
|
+
writeProject(
|
|
214
|
+
projectPath,
|
|
215
|
+
"src/app/api/chat/compact/route.ts",
|
|
216
|
+
applyTemplate(readTemplate("api-route/compact/route.ts.tmpl"), vars)
|
|
217
|
+
);
|
|
213
218
|
writeProject(projectPath, "src/app/api/chats/route.ts", readTemplate("base/src/app/api/chats/route.ts"));
|
|
214
219
|
writeProject(projectPath, "src/app/api/chats/[id]/route.ts", readTemplate("base/src/app/api/chats/[id]/route.ts"));
|
|
215
220
|
writeProject(projectPath, "src/app/api/jobs/[id]/route.ts", readTemplate("base/src/app/api/jobs/[id]/route.ts"));
|
|
@@ -221,6 +226,8 @@ function scaffoldProject(config) {
|
|
|
221
226
|
writeProject(projectPath, "src/components/chat-input.tsx", readTemplate("base/src/components/chat-input.tsx"));
|
|
222
227
|
writeProject(projectPath, "src/components/header.tsx", readTemplate("base/src/components/header.tsx"));
|
|
223
228
|
writeProject(projectPath, "src/components/user-button.tsx", readTemplate("base/src/components/user-button.tsx"));
|
|
229
|
+
writeProject(projectPath, "src/components/theme-provider.tsx", readTemplate("base/src/components/theme-provider.tsx"));
|
|
230
|
+
writeProject(projectPath, "src/components/slash-menu.tsx", readTemplate("base/src/components/slash-menu.tsx"));
|
|
224
231
|
writeProject(projectPath, "src/components/ui/badge.tsx", readTemplate("base/src/components/ui/badge.tsx"));
|
|
225
232
|
writeProject(projectPath, "src/components/ui/collapsible.tsx", readTemplate("base/src/components/ui/collapsible.tsx"));
|
|
226
233
|
writeProject(projectPath, "src/components/ai-elements/tool.tsx", readTemplate("base/src/components/ai-elements/tool.tsx"));
|
|
@@ -303,8 +310,9 @@ import { join as join2 } from "path";
|
|
|
303
310
|
import { execSync, spawn as nodeSpawn } from "child_process";
|
|
304
311
|
import { detectPackageManager as detectPackageManager2 } from "nypm";
|
|
305
312
|
function writeEnvLocal(config) {
|
|
306
|
-
const { projectPath, aiProvider, apiKeys } = config;
|
|
313
|
+
const { projectPath, aiProvider, apiKeys, database, databaseUrl } = config;
|
|
307
314
|
const ai = AI_PROVIDERS[aiProvider];
|
|
315
|
+
const dbUrl = databaseUrl ?? DB_CONFIGS[database].url;
|
|
308
316
|
const lines = [
|
|
309
317
|
"# Supyagent \u2014 Get your API key at https://app.supyagent.com",
|
|
310
318
|
`SUPYAGENT_API_KEY=${apiKeys?.supyagent ?? ""}`,
|
|
@@ -313,18 +321,18 @@ function writeEnvLocal(config) {
|
|
|
313
321
|
`${ai.envKey}=${apiKeys?.provider ?? ""}`,
|
|
314
322
|
"",
|
|
315
323
|
"# Database",
|
|
316
|
-
`DATABASE_URL="
|
|
324
|
+
`DATABASE_URL="${dbUrl}"`,
|
|
317
325
|
""
|
|
318
326
|
];
|
|
319
327
|
writeFileSync2(join2(projectPath, ".env.local"), lines.join("\n"), "utf-8");
|
|
320
328
|
}
|
|
321
|
-
async function runDbSetup(projectPath) {
|
|
329
|
+
async function runDbSetup(projectPath, databaseUrl) {
|
|
322
330
|
const pm = await detectPackageManager2(projectPath);
|
|
323
331
|
const cmd = pm?.name ?? "pnpm";
|
|
324
332
|
execSync(`${cmd} run db:setup`, {
|
|
325
333
|
cwd: projectPath,
|
|
326
334
|
stdio: "inherit",
|
|
327
|
-
env: { ...process.env, DATABASE_URL: "file:./dev.db" }
|
|
335
|
+
env: { ...process.env, DATABASE_URL: databaseUrl ?? "file:./dev.db" }
|
|
328
336
|
});
|
|
329
337
|
}
|
|
330
338
|
async function runDevServer(projectPath) {
|
|
@@ -349,6 +357,69 @@ async function runDevServer(projectPath) {
|
|
|
349
357
|
});
|
|
350
358
|
}
|
|
351
359
|
|
|
360
|
+
// src/device-auth.ts
|
|
361
|
+
import * as p2 from "@clack/prompts";
|
|
362
|
+
import pc2 from "picocolors";
|
|
363
|
+
import { exec } from "child_process";
|
|
364
|
+
import { platform } from "os";
|
|
365
|
+
var SUPYAGENT_API_URL = "https://app.supyagent.com";
|
|
366
|
+
function openBrowser(url) {
|
|
367
|
+
const cmd = platform() === "darwin" ? "open" : platform() === "win32" ? "start" : "xdg-open";
|
|
368
|
+
exec(`${cmd} ${JSON.stringify(url)}`);
|
|
369
|
+
}
|
|
370
|
+
async function loginViaBrowser() {
|
|
371
|
+
const s = p2.spinner();
|
|
372
|
+
let deviceCode;
|
|
373
|
+
try {
|
|
374
|
+
const res = await fetch(`${SUPYAGENT_API_URL}/api/v1/auth/device/code`, {
|
|
375
|
+
method: "POST",
|
|
376
|
+
headers: { "Content-Type": "application/json" }
|
|
377
|
+
});
|
|
378
|
+
if (!res.ok) {
|
|
379
|
+
p2.log.error("Failed to start browser login. Please enter your API key manually.");
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
deviceCode = await res.json();
|
|
383
|
+
} catch {
|
|
384
|
+
p2.log.error("Could not reach Supyagent. Please enter your API key manually.");
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
p2.log.step(
|
|
388
|
+
`Opening browser to ${pc2.cyan(deviceCode.verification_uri)}
|
|
389
|
+
Enter code: ${pc2.bold(pc2.cyan(deviceCode.user_code))}`
|
|
390
|
+
);
|
|
391
|
+
openBrowser(deviceCode.verification_uri);
|
|
392
|
+
s.start("Waiting for approval in your browser...");
|
|
393
|
+
const interval = (deviceCode.interval || 5) * 1e3;
|
|
394
|
+
const deadline = Date.now() + deviceCode.expires_in * 1e3;
|
|
395
|
+
while (Date.now() < deadline) {
|
|
396
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
397
|
+
try {
|
|
398
|
+
const res = await fetch(`${SUPYAGENT_API_URL}/api/v1/auth/device/token`, {
|
|
399
|
+
method: "POST",
|
|
400
|
+
headers: { "Content-Type": "application/json" },
|
|
401
|
+
body: JSON.stringify({ device_code: deviceCode.device_code })
|
|
402
|
+
});
|
|
403
|
+
if (res.ok) {
|
|
404
|
+
const data = await res.json();
|
|
405
|
+
s.stop(pc2.green("Logged in successfully!"));
|
|
406
|
+
return data.api_key;
|
|
407
|
+
}
|
|
408
|
+
if (res.status === 403) {
|
|
409
|
+
s.stop(pc2.red("Authorization denied."));
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
if (res.status === 410) {
|
|
413
|
+
s.stop(pc2.red("Code expired. Please try again."));
|
|
414
|
+
return null;
|
|
415
|
+
}
|
|
416
|
+
} catch {
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
s.stop(pc2.red("Timed out waiting for approval."));
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
|
|
352
423
|
// src/index.ts
|
|
353
424
|
function parseArgs() {
|
|
354
425
|
const args = process.argv.slice(2);
|
|
@@ -366,10 +437,6 @@ function parseArgs() {
|
|
|
366
437
|
result.agentMode = args[++i];
|
|
367
438
|
} else if (arg === "--model" && hasValue) {
|
|
368
439
|
result.model = args[++i];
|
|
369
|
-
} else if (arg === "--quickstart") {
|
|
370
|
-
result.quickstart = true;
|
|
371
|
-
} else if (arg === "--skip-install") {
|
|
372
|
-
result.skipInstall = true;
|
|
373
440
|
} else if (arg === "--supyagent-api-key" && hasValue) {
|
|
374
441
|
result.supyagentApiKey = args[++i];
|
|
375
442
|
} else if (arg === "--anthropic-api-key" && hasValue) {
|
|
@@ -432,206 +499,133 @@ function loadEnvFiles() {
|
|
|
432
499
|
return merged;
|
|
433
500
|
}
|
|
434
501
|
async function promptForKey(name) {
|
|
435
|
-
const value = await
|
|
436
|
-
if (
|
|
437
|
-
|
|
502
|
+
const value = await p3.password({ message: `Enter your ${name}` });
|
|
503
|
+
if (p3.isCancel(value)) {
|
|
504
|
+
p3.cancel("Cancelled.");
|
|
438
505
|
process.exit(1);
|
|
439
506
|
}
|
|
440
507
|
return value;
|
|
441
508
|
}
|
|
509
|
+
async function resolveSupyagentKey(parsed) {
|
|
510
|
+
const dotenvVars = loadEnvFiles();
|
|
511
|
+
const existing = parsed.supyagentApiKey ?? process.env.SUPYAGENT_API_KEY ?? dotenvVars.SUPYAGENT_API_KEY;
|
|
512
|
+
if (existing) {
|
|
513
|
+
if (!parsed.supyagentApiKey) {
|
|
514
|
+
p3.log.info(`Using ${pc3.cyan("SUPYAGENT_API_KEY")} from ${process.env.SUPYAGENT_API_KEY ? "environment" : ".env file"}`);
|
|
515
|
+
}
|
|
516
|
+
return existing;
|
|
517
|
+
}
|
|
518
|
+
const method = await p3.select({
|
|
519
|
+
message: "How would you like to authenticate with Supyagent?",
|
|
520
|
+
options: [
|
|
521
|
+
{
|
|
522
|
+
value: "browser",
|
|
523
|
+
label: "Login via browser",
|
|
524
|
+
hint: "recommended \u2014 opens app.supyagent.com"
|
|
525
|
+
},
|
|
526
|
+
{
|
|
527
|
+
value: "manual",
|
|
528
|
+
label: "Paste API key",
|
|
529
|
+
hint: "enter an existing key manually"
|
|
530
|
+
}
|
|
531
|
+
]
|
|
532
|
+
});
|
|
533
|
+
if (p3.isCancel(method)) {
|
|
534
|
+
p3.cancel("Cancelled.");
|
|
535
|
+
process.exit(1);
|
|
536
|
+
}
|
|
537
|
+
if (method === "browser") {
|
|
538
|
+
const key = await loginViaBrowser();
|
|
539
|
+
if (key) return key;
|
|
540
|
+
p3.log.warn("Browser login failed. Please enter your API key manually.");
|
|
541
|
+
}
|
|
542
|
+
return promptForKey("SUPYAGENT_API_KEY");
|
|
543
|
+
}
|
|
442
544
|
async function resolveApiKeys(provider, parsed) {
|
|
443
545
|
const envKey = ENV_KEY_MAP[provider];
|
|
444
546
|
const cliFlag = CLI_KEY_MAP[provider];
|
|
445
547
|
const dotenvVars = loadEnvFiles();
|
|
446
|
-
const supyagent =
|
|
447
|
-
if (!parsed.supyagentApiKey && (process.env.SUPYAGENT_API_KEY || dotenvVars.SUPYAGENT_API_KEY)) {
|
|
448
|
-
p2.log.info(`Using ${pc2.cyan("SUPYAGENT_API_KEY")} from ${process.env.SUPYAGENT_API_KEY ? "environment" : ".env file"}`);
|
|
449
|
-
}
|
|
548
|
+
const supyagent = await resolveSupyagentKey(parsed);
|
|
450
549
|
const providerKey = parsed[cliFlag] ?? process.env[envKey] ?? dotenvVars[envKey] ?? await promptForKey(envKey);
|
|
451
550
|
if (!parsed[cliFlag] && (process.env[envKey] || dotenvVars[envKey])) {
|
|
452
|
-
|
|
551
|
+
p3.log.info(`Using ${pc3.cyan(envKey)} from ${process.env[envKey] ? "environment" : ".env file"}`);
|
|
453
552
|
}
|
|
454
553
|
return { supyagent, provider: providerKey };
|
|
455
554
|
}
|
|
456
555
|
async function main() {
|
|
457
556
|
const parsed = parseArgs();
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
pc2.yellow("--quickstart requires SQLite \u2014 ignoring --db postgres")
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
if (parsed.skipInstall) {
|
|
465
|
-
p2.log.warn(
|
|
466
|
-
pc2.yellow(
|
|
467
|
-
"--quickstart needs dependencies installed \u2014 ignoring --skip-install"
|
|
468
|
-
)
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
|
-
p2.intro(pc2.bgCyan(pc2.black(" Create Supyagent App \u2014 Quickstart ")));
|
|
472
|
-
let projectName = parsed.projectName;
|
|
473
|
-
if (!projectName) {
|
|
474
|
-
const name = await p2.text({
|
|
475
|
-
message: "Project name",
|
|
476
|
-
placeholder: "my-supyagent-app",
|
|
477
|
-
defaultValue: "my-supyagent-app",
|
|
478
|
-
validate(value) {
|
|
479
|
-
if (!value) return "Project name is required";
|
|
480
|
-
if (!/^[a-z0-9][a-z0-9._-]*$/.test(value)) {
|
|
481
|
-
return "Invalid project name (lowercase, alphanumeric, hyphens, dots)";
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
});
|
|
485
|
-
if (p2.isCancel(name)) {
|
|
486
|
-
p2.cancel("Cancelled.");
|
|
487
|
-
process.exit(1);
|
|
488
|
-
}
|
|
489
|
-
projectName = name;
|
|
490
|
-
}
|
|
491
|
-
const projectPath = resolveProjectPath(projectName);
|
|
557
|
+
let config;
|
|
558
|
+
if (parsed.projectName && parsed.aiProvider && parsed.database) {
|
|
559
|
+
const projectPath = resolveProjectPath(parsed.projectName);
|
|
492
560
|
if (projectExists(projectPath)) {
|
|
493
|
-
|
|
561
|
+
p3.cancel(`Directory "${parsed.projectName}" already exists.`);
|
|
494
562
|
process.exit(1);
|
|
495
563
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
const selected = await p2.select({
|
|
499
|
-
message: "AI provider",
|
|
500
|
-
options: [
|
|
501
|
-
{ value: "anthropic", label: AI_PROVIDERS.anthropic.label },
|
|
502
|
-
{ value: "openai", label: AI_PROVIDERS.openai.label },
|
|
503
|
-
{ value: "openrouter", label: AI_PROVIDERS.openrouter.label }
|
|
504
|
-
]
|
|
505
|
-
});
|
|
506
|
-
if (p2.isCancel(selected)) {
|
|
507
|
-
p2.cancel("Cancelled.");
|
|
508
|
-
process.exit(1);
|
|
509
|
-
}
|
|
510
|
-
aiProvider = selected;
|
|
511
|
-
}
|
|
512
|
-
let agentMode = parsed.agentMode;
|
|
513
|
-
if (!agentMode) {
|
|
514
|
-
const selected = await p2.select({
|
|
515
|
-
message: "Agent mode",
|
|
516
|
-
options: [
|
|
517
|
-
{ value: "skills", label: "Skills (token-efficient)", hint: "recommended" },
|
|
518
|
-
{ value: "tools", label: "Tools (rich tool definitions)" }
|
|
519
|
-
]
|
|
520
|
-
});
|
|
521
|
-
if (p2.isCancel(selected)) {
|
|
522
|
-
p2.cancel("Cancelled.");
|
|
523
|
-
process.exit(1);
|
|
524
|
-
}
|
|
525
|
-
agentMode = selected;
|
|
526
|
-
}
|
|
527
|
-
const apiKeys = await resolveApiKeys(aiProvider, parsed);
|
|
528
|
-
const config = {
|
|
529
|
-
projectName,
|
|
564
|
+
config = {
|
|
565
|
+
projectName: parsed.projectName,
|
|
530
566
|
projectPath,
|
|
531
|
-
aiProvider,
|
|
532
|
-
agentMode,
|
|
533
|
-
database:
|
|
534
|
-
model: parsed.model
|
|
535
|
-
quickstart: true,
|
|
536
|
-
apiKeys
|
|
567
|
+
aiProvider: parsed.aiProvider,
|
|
568
|
+
agentMode: parsed.agentMode ?? "skills",
|
|
569
|
+
database: parsed.database,
|
|
570
|
+
model: parsed.model
|
|
537
571
|
};
|
|
538
|
-
const s = p2.spinner();
|
|
539
|
-
s.start("Scaffolding project...");
|
|
540
|
-
scaffoldProject(config);
|
|
541
|
-
writeEnvLocal(config);
|
|
542
|
-
s.stop("Scaffolded project");
|
|
543
|
-
s.start("Installing dependencies...");
|
|
544
|
-
try {
|
|
545
|
-
await installDeps(config.projectPath);
|
|
546
|
-
s.stop("Installed dependencies");
|
|
547
|
-
} catch {
|
|
548
|
-
s.stop("Failed to install dependencies \u2014 run install manually");
|
|
549
|
-
process.exit(1);
|
|
550
|
-
}
|
|
551
|
-
s.start("Setting up database...");
|
|
552
|
-
try {
|
|
553
|
-
await runDbSetup(config.projectPath);
|
|
554
|
-
s.stop("Database ready");
|
|
555
|
-
} catch (err) {
|
|
556
|
-
s.stop("Database setup failed");
|
|
557
|
-
p2.log.warn(
|
|
558
|
-
`Run ${pc2.cyan(`cd ${projectName} && pnpm db:setup`)} manually`
|
|
559
|
-
);
|
|
560
|
-
}
|
|
561
|
-
p2.log.info(pc2.green("Starting dev server..."));
|
|
562
|
-
await runDevServer(config.projectPath);
|
|
563
572
|
} else {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
agentMode: parsed.agentMode ?? "skills",
|
|
572
|
-
database: parsed.database,
|
|
573
|
-
model: parsed.model
|
|
574
|
-
};
|
|
575
|
-
console.log(`Creating ${config.projectName}...`);
|
|
576
|
-
} else {
|
|
577
|
-
config = await runPrompts(parsed.projectName, {
|
|
578
|
-
aiProvider: parsed.aiProvider,
|
|
579
|
-
agentMode: parsed.agentMode,
|
|
580
|
-
database: parsed.database
|
|
581
|
-
});
|
|
582
|
-
if (config && parsed.model) {
|
|
583
|
-
config.model = parsed.model;
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
if (!config) {
|
|
587
|
-
process.exit(1);
|
|
573
|
+
config = await runPrompts(parsed.projectName, {
|
|
574
|
+
aiProvider: parsed.aiProvider,
|
|
575
|
+
agentMode: parsed.agentMode,
|
|
576
|
+
database: parsed.database
|
|
577
|
+
});
|
|
578
|
+
if (config && parsed.model) {
|
|
579
|
+
config.model = parsed.model;
|
|
588
580
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
console.log(
|
|
604
|
-
`
|
|
605
|
-
Next steps:
|
|
606
|
-
cd ${config.projectName}
|
|
607
|
-
cp .env.example .env.local
|
|
608
|
-
pnpm db:setup
|
|
609
|
-
pnpm dev`
|
|
610
|
-
);
|
|
611
|
-
} else {
|
|
612
|
-
const s = p2.spinner();
|
|
613
|
-
s.start("Scaffolding project...");
|
|
614
|
-
scaffoldProject(config);
|
|
615
|
-
s.stop("Scaffolded project");
|
|
616
|
-
s.start("Installing dependencies...");
|
|
617
|
-
try {
|
|
618
|
-
await installDeps(config.projectPath);
|
|
619
|
-
s.stop("Installed dependencies");
|
|
620
|
-
} catch {
|
|
621
|
-
s.stop("Failed to install dependencies \u2014 run install manually");
|
|
581
|
+
}
|
|
582
|
+
if (!config) {
|
|
583
|
+
process.exit(1);
|
|
584
|
+
}
|
|
585
|
+
p3.intro(pc3.bgCyan(pc3.black(" Create Supyagent App ")));
|
|
586
|
+
if (config.database === "postgres") {
|
|
587
|
+
const dbUrl = await p3.text({
|
|
588
|
+
message: "PostgreSQL connection URL",
|
|
589
|
+
placeholder: DB_CONFIGS.postgres.url,
|
|
590
|
+
validate(value) {
|
|
591
|
+
if (!value) return "Connection URL is required";
|
|
622
592
|
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
`pnpm db:setup ${pc2.dim("# Initialize database")}`,
|
|
628
|
-
`pnpm dev ${pc2.dim("# Start development server")}`
|
|
629
|
-
].join("\n"),
|
|
630
|
-
"Next steps"
|
|
631
|
-
);
|
|
632
|
-
p2.outro(pc2.green("Done!"));
|
|
593
|
+
});
|
|
594
|
+
if (p3.isCancel(dbUrl)) {
|
|
595
|
+
p3.cancel("Cancelled.");
|
|
596
|
+
process.exit(1);
|
|
633
597
|
}
|
|
598
|
+
config.databaseUrl = dbUrl;
|
|
599
|
+
} else {
|
|
600
|
+
config.databaseUrl = DB_CONFIGS.sqlite.url;
|
|
601
|
+
}
|
|
602
|
+
const apiKeys = await resolveApiKeys(config.aiProvider, parsed);
|
|
603
|
+
config.apiKeys = apiKeys;
|
|
604
|
+
const s = p3.spinner();
|
|
605
|
+
s.start("Scaffolding project...");
|
|
606
|
+
scaffoldProject(config);
|
|
607
|
+
writeEnvLocal(config);
|
|
608
|
+
s.stop("Scaffolded project");
|
|
609
|
+
s.start("Installing dependencies...");
|
|
610
|
+
try {
|
|
611
|
+
await installDeps(config.projectPath);
|
|
612
|
+
s.stop("Installed dependencies");
|
|
613
|
+
} catch {
|
|
614
|
+
s.stop("Failed to install dependencies \u2014 run install manually");
|
|
615
|
+
process.exit(1);
|
|
616
|
+
}
|
|
617
|
+
s.start("Setting up database...");
|
|
618
|
+
try {
|
|
619
|
+
await runDbSetup(config.projectPath, config.databaseUrl);
|
|
620
|
+
s.stop("Database ready");
|
|
621
|
+
} catch {
|
|
622
|
+
s.stop("Database setup failed");
|
|
623
|
+
p3.log.warn(
|
|
624
|
+
`Run ${pc3.cyan(`cd ${config.projectName} && pnpm db:setup`)} manually`
|
|
625
|
+
);
|
|
634
626
|
}
|
|
627
|
+
p3.log.info(pc3.green("Starting dev server..."));
|
|
628
|
+
await runDevServer(config.projectPath);
|
|
635
629
|
}
|
|
636
630
|
main().catch(console.error);
|
|
637
631
|
//# sourceMappingURL=index.js.map
|