@recursiv/cli 0.1.5

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.
@@ -0,0 +1,527 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/bin/create-recursiv-app.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/commands/init.ts
7
+ import { existsSync as existsSync2 } from "fs";
8
+ import { mkdir, readFile as readFile3, unlink, writeFile as writeFile3 } from "fs/promises";
9
+ import { resolve } from "path";
10
+ import { execSync } from "child_process";
11
+ import prompts2 from "prompts";
12
+ import pc3 from "picocolors";
13
+ import ora2 from "ora";
14
+
15
+ // src/lib/logger.ts
16
+ import pc from "picocolors";
17
+ var log = {
18
+ info(msg) {
19
+ console.log(pc.cyan("info") + " " + msg);
20
+ },
21
+ success(msg) {
22
+ console.log(pc.green("ok") + " " + msg);
23
+ },
24
+ warn(msg) {
25
+ console.log(pc.yellow("warn") + " " + msg);
26
+ },
27
+ error(msg) {
28
+ console.error(pc.red("error") + " " + msg);
29
+ },
30
+ step(n, total, msg) {
31
+ console.log(pc.dim(`[${n}/${total}]`) + " " + msg);
32
+ },
33
+ blank() {
34
+ console.log();
35
+ }
36
+ };
37
+ function banner() {
38
+ console.log();
39
+ console.log(pc.bold("Recursiv") + pc.dim(" \u2014 build and ship apps with AI"));
40
+ console.log();
41
+ }
42
+
43
+ // src/lib/config.ts
44
+ import { readFile, writeFile } from "fs/promises";
45
+ import { join } from "path";
46
+ var CONFIG_FILE = ".recursiv.json";
47
+ function configPath(dir) {
48
+ return join(dir, CONFIG_FILE);
49
+ }
50
+ async function writeConfig(dir, config) {
51
+ await writeFile(configPath(dir), JSON.stringify(config, null, 2) + "\n", "utf-8");
52
+ }
53
+ function createConfig(opts) {
54
+ return {
55
+ version: 1,
56
+ project: {
57
+ name: opts.name,
58
+ template: opts.template,
59
+ framework: opts.framework
60
+ },
61
+ api: {
62
+ baseUrl: "https://api.recursiv.io/api/v1"
63
+ },
64
+ dev: {
65
+ port: opts.port ?? 3e3,
66
+ command: opts.devCommand ?? "npm run dev"
67
+ }
68
+ };
69
+ }
70
+
71
+ // src/lib/env.ts
72
+ import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
73
+ import { join as join2 } from "path";
74
+ async function writeEnvFile(dir, apiKey) {
75
+ const envPath = join2(dir, ".env");
76
+ const content = [
77
+ "# Recursiv API key",
78
+ `RECURSIV_API_KEY=${apiKey}`,
79
+ "",
80
+ "# Framework-specific public keys (uncomment as needed)",
81
+ `# NEXT_PUBLIC_RECURSIV_API_KEY=${apiKey}`,
82
+ `# VITE_RECURSIV_API_KEY=${apiKey}`,
83
+ ""
84
+ ].join("\n");
85
+ await writeFile2(envPath, content, "utf-8");
86
+ }
87
+
88
+ // src/lib/templates.ts
89
+ import degit from "degit";
90
+ import ora from "ora";
91
+ async function cloneTemplate(template, dest) {
92
+ const spinner = ora(`Cloning ${template.name} template...`).start();
93
+ try {
94
+ const emitter = degit(template.repo, {
95
+ cache: false,
96
+ force: true,
97
+ verbose: false
98
+ });
99
+ await emitter.clone(dest);
100
+ spinner.succeed(`Template cloned successfully`);
101
+ } catch (err) {
102
+ spinner.fail("Failed to clone template");
103
+ const message = err instanceof Error ? err.message : String(err);
104
+ throw new Error(
105
+ `Could not clone template from ${template.repo}.
106
+ Make sure you have internet access and the repo exists.
107
+ Details: ${message}`
108
+ );
109
+ }
110
+ }
111
+
112
+ // src/lib/auth-flow.ts
113
+ import prompts from "prompts";
114
+ import pc2 from "picocolors";
115
+ var API_KEY_PATTERN = /^sk_(live|test)_[a-zA-Z0-9]{20,}$/;
116
+ var DASHBOARD_URL = "https://recursiv.io/dashboard/api-keys";
117
+ var DEFAULT_SCOPES = [
118
+ "posts:read",
119
+ "posts:write",
120
+ "chat:read",
121
+ "chat:write",
122
+ "agents:read",
123
+ "agents:write",
124
+ "projects:read",
125
+ "projects:write",
126
+ "communities:read",
127
+ "communities:write",
128
+ "users:read"
129
+ ];
130
+ function isValidKeyFormat(key) {
131
+ return API_KEY_PATTERN.test(key);
132
+ }
133
+ async function validateApiKey(apiKey, baseUrl) {
134
+ try {
135
+ const res = await fetch(`${baseUrl}/users/me`, {
136
+ headers: {
137
+ Authorization: `Bearer ${apiKey}`,
138
+ Accept: "application/json"
139
+ }
140
+ });
141
+ return res.ok;
142
+ } catch {
143
+ return false;
144
+ }
145
+ }
146
+ async function terminalSignup(baseUrl) {
147
+ const rootUrl = baseUrl.replace(/\/api\/v1\/?$/, "");
148
+ console.log();
149
+ console.log(pc2.bold("Create a free Recursiv account"));
150
+ console.log(pc2.dim("Free tier: 1,000 API calls/day, 1 agent, 3 projects"));
151
+ console.log(pc2.dim("We'll send a 6-digit code to your email \u2014 no password needed."));
152
+ console.log();
153
+ const { email } = await prompts(
154
+ {
155
+ type: "text",
156
+ name: "email",
157
+ message: "Email",
158
+ validate: (v) => {
159
+ if (!v || !v.includes("@")) return "Valid email required";
160
+ return true;
161
+ }
162
+ },
163
+ { onCancel: () => process.exit(1) }
164
+ );
165
+ const origin = rootUrl || "https://api.recursiv.io";
166
+ const authHeaders = { "Content-Type": "application/json", Origin: origin };
167
+ try {
168
+ const sendRes = await fetch(`${rootUrl}/api/auth/email-otp/send-verification-otp`, {
169
+ method: "POST",
170
+ headers: authHeaders,
171
+ body: JSON.stringify({ email, type: "sign-in" })
172
+ });
173
+ if (!sendRes.ok) {
174
+ const errBody = await sendRes.text().catch(() => "");
175
+ log.error(`Failed to send code (${sendRes.status}): ${errBody || "Unknown error"}`);
176
+ return null;
177
+ }
178
+ } catch (err) {
179
+ log.error(
180
+ `Could not reach ${rootUrl} \u2014 ${err instanceof Error ? err.message : "network error"}`
181
+ );
182
+ log.info(`You can create an API key manually at ${pc2.underline(DASHBOARD_URL)}`);
183
+ return null;
184
+ }
185
+ log.success(`Verification code sent to ${email}`);
186
+ console.log();
187
+ const { code } = await prompts(
188
+ {
189
+ type: "text",
190
+ name: "code",
191
+ message: "Enter the 6-digit code",
192
+ validate: (v) => {
193
+ if (!v || !/^\d{6}$/.test(v.trim())) return "Enter the 6-digit code from your email";
194
+ return true;
195
+ }
196
+ },
197
+ { onCancel: () => process.exit(1) }
198
+ );
199
+ let sessionCookie = null;
200
+ try {
201
+ const verifyRes = await fetch(`${rootUrl}/api/auth/email-otp/verify-email`, {
202
+ method: "POST",
203
+ headers: authHeaders,
204
+ body: JSON.stringify({ email, otp: code.trim() }),
205
+ redirect: "manual"
206
+ });
207
+ if (verifyRes.ok || verifyRes.status === 302) {
208
+ sessionCookie = extractSessionCookie(verifyRes);
209
+ } else {
210
+ const errBody = await verifyRes.text().catch(() => "");
211
+ log.error(`Verification failed (${verifyRes.status}): ${errBody || "Invalid or expired code"}`);
212
+ return null;
213
+ }
214
+ } catch (err) {
215
+ log.error(
216
+ `Verification failed \u2014 ${err instanceof Error ? err.message : "network error"}`
217
+ );
218
+ return null;
219
+ }
220
+ if (!sessionCookie) {
221
+ log.error("No session returned from server");
222
+ log.info(`Create an API key manually at ${pc2.underline(DASHBOARD_URL)}`);
223
+ return null;
224
+ }
225
+ log.success("Authenticated");
226
+ try {
227
+ const keyRes = await fetch(`${baseUrl}/api-keys`, {
228
+ method: "POST",
229
+ headers: {
230
+ "Content-Type": "application/json",
231
+ Cookie: sessionCookie
232
+ },
233
+ body: JSON.stringify({
234
+ name: "CLI (auto-created)",
235
+ scopes: DEFAULT_SCOPES
236
+ })
237
+ });
238
+ if (!keyRes.ok) {
239
+ const errBody = await keyRes.text().catch(() => "");
240
+ log.error(`Failed to create API key (${keyRes.status}): ${errBody}`);
241
+ log.info(`Create one manually at ${pc2.underline(DASHBOARD_URL)}`);
242
+ return null;
243
+ }
244
+ const { data } = await keyRes.json();
245
+ log.success(`API key created (free tier: 1,000 calls/day)`);
246
+ return data.key;
247
+ } catch (err) {
248
+ log.error(
249
+ `Failed to create API key: ${err instanceof Error ? err.message : "unknown error"}`
250
+ );
251
+ log.info(`Create one manually at ${pc2.underline(DASHBOARD_URL)}`);
252
+ return null;
253
+ }
254
+ }
255
+ function extractSessionCookie(res) {
256
+ const setCookieHeaders = "getSetCookie" in res.headers ? res.headers.getSetCookie() : [];
257
+ if (setCookieHeaders.length === 0) {
258
+ const raw = res.headers.get("set-cookie");
259
+ if (raw) {
260
+ return raw.split(",").map((c) => c.split(";")[0].trim()).join("; ");
261
+ }
262
+ return null;
263
+ }
264
+ return setCookieHeaders.map((c) => c.split(";")[0].trim()).join("; ");
265
+ }
266
+ async function promptApiKey() {
267
+ console.log(
268
+ pc2.dim(
269
+ `Get your API key from ${pc2.underline(DASHBOARD_URL)}
270
+ Keys start with sk_live_ or sk_test_`
271
+ )
272
+ );
273
+ console.log();
274
+ const { apiKey } = await prompts(
275
+ {
276
+ type: "text",
277
+ name: "apiKey",
278
+ message: "API key (or press Enter to skip)",
279
+ validate: (value) => {
280
+ if (!value) return true;
281
+ if (!isValidKeyFormat(value)) {
282
+ return "Invalid key format. Keys start with sk_live_ or sk_test_";
283
+ }
284
+ return true;
285
+ }
286
+ },
287
+ { onCancel: () => process.exit(1) }
288
+ );
289
+ if (!apiKey) {
290
+ log.warn("No API key provided \u2014 you can add one later in .env");
291
+ return null;
292
+ }
293
+ return apiKey;
294
+ }
295
+ async function promptAndValidateApiKey(baseUrl) {
296
+ const apiKey = await promptApiKey();
297
+ if (!apiKey) return null;
298
+ const valid = await validateApiKey(apiKey, baseUrl);
299
+ if (!valid) {
300
+ log.warn("Could not validate API key (server unreachable or invalid key)");
301
+ log.info("Key saved to .env \u2014 you can update it later");
302
+ } else {
303
+ log.success("API key validated");
304
+ }
305
+ return apiKey;
306
+ }
307
+ async function getOrCreateApiKey(baseUrl) {
308
+ console.log();
309
+ const { method } = await prompts(
310
+ {
311
+ type: "select",
312
+ name: "method",
313
+ message: "How would you like to authenticate?",
314
+ choices: [
315
+ {
316
+ title: "Create a free account",
317
+ description: "Sign up with email (we'll send a 6-digit code)",
318
+ value: "signup"
319
+ },
320
+ {
321
+ title: "Enter an existing API key",
322
+ description: "Paste a key from your dashboard",
323
+ value: "paste"
324
+ },
325
+ {
326
+ title: "Skip for now",
327
+ description: "Add an API key later in .env",
328
+ value: "skip"
329
+ }
330
+ ]
331
+ },
332
+ { onCancel: () => process.exit(1) }
333
+ );
334
+ if (method === "signup") {
335
+ return terminalSignup(baseUrl);
336
+ }
337
+ if (method === "paste") {
338
+ return promptAndValidateApiKey(baseUrl);
339
+ }
340
+ log.warn("No API key \u2014 you can add one later in .env");
341
+ return null;
342
+ }
343
+
344
+ // src/lib/package-manager.ts
345
+ import { existsSync } from "fs";
346
+ import { join as join3 } from "path";
347
+ function detectFromUserAgent() {
348
+ const ua = process.env.npm_config_user_agent ?? "";
349
+ if (ua.startsWith("bun")) return "bun";
350
+ if (ua.startsWith("pnpm")) return "pnpm";
351
+ if (ua.startsWith("yarn")) return "yarn";
352
+ return "npm";
353
+ }
354
+ function installCommand(pm) {
355
+ return pm === "yarn" ? "yarn" : `${pm} install`;
356
+ }
357
+ function runCommand(pm, script) {
358
+ if (pm === "npm") return `npm run ${script}`;
359
+ return `${pm} ${script}`;
360
+ }
361
+
362
+ // src/templates/registry.ts
363
+ var templates = [
364
+ {
365
+ id: "nextjs",
366
+ name: "Next.js + Recursiv",
367
+ description: "Full-stack Next.js app with feeds, chat, and agents",
368
+ repo: "recursivlabs/template-nextjs",
369
+ framework: "nextjs",
370
+ devCommand: "next dev",
371
+ devPort: 3e3,
372
+ recommended: true
373
+ },
374
+ {
375
+ id: "node",
376
+ name: "Node.js + Express",
377
+ description: "Express API server with Recursiv SDK",
378
+ repo: "recursivlabs/template-node",
379
+ framework: "express",
380
+ devCommand: "node --watch src/index.js",
381
+ devPort: 4e3
382
+ },
383
+ {
384
+ id: "vite",
385
+ name: "Vite + React",
386
+ description: "React SPA with social feed components",
387
+ repo: "recursivlabs/template-vite",
388
+ framework: "vite",
389
+ devCommand: "vite",
390
+ devPort: 5173
391
+ }
392
+ ];
393
+
394
+ // src/commands/init.ts
395
+ async function initCommand(nameArg) {
396
+ banner();
397
+ const totalSteps = 7;
398
+ log.step(1, totalSteps, "Project setup");
399
+ let projectName;
400
+ if (nameArg) {
401
+ projectName = nameArg;
402
+ } else {
403
+ const { name } = await prompts2(
404
+ {
405
+ type: "text",
406
+ name: "name",
407
+ message: "Project name",
408
+ initial: "my-recursiv-app",
409
+ validate: (v) => v.trim() ? true : "Name is required"
410
+ },
411
+ { onCancel: () => process.exit(1) }
412
+ );
413
+ projectName = name;
414
+ }
415
+ const projectDir = resolve(process.cwd(), projectName);
416
+ if (existsSync2(projectDir)) {
417
+ log.error(`Directory ${pc3.bold(projectName)} already exists`);
418
+ process.exit(1);
419
+ }
420
+ log.step(2, totalSteps, "Choose a template");
421
+ const templateChoices = templates.map((t) => ({
422
+ title: t.recommended ? `${t.name} ${pc3.dim("(recommended)")}` : t.name,
423
+ description: t.description,
424
+ value: t.id
425
+ }));
426
+ const { templateId } = await prompts2(
427
+ {
428
+ type: "select",
429
+ name: "templateId",
430
+ message: "Template",
431
+ choices: templateChoices,
432
+ initial: 0
433
+ },
434
+ { onCancel: () => process.exit(1) }
435
+ );
436
+ const template = templates.find((t) => t.id === templateId);
437
+ log.step(3, totalSteps, "Authentication");
438
+ const apiKey = await getOrCreateApiKey("https://api.recursiv.io/api/v1");
439
+ log.step(4, totalSteps, "Creating project");
440
+ await mkdir(projectDir, { recursive: true });
441
+ await cloneTemplate(template, projectDir);
442
+ const nextConfigTs = resolve(projectDir, "next.config.ts");
443
+ const nextConfigMjs = resolve(projectDir, "next.config.mjs");
444
+ const cleanNextConfig = '/** @type {import("next").NextConfig} */\nconst nextConfig = {};\nexport default nextConfig;\n';
445
+ if (existsSync2(nextConfigTs)) {
446
+ await unlink(nextConfigTs);
447
+ if (existsSync2(nextConfigMjs)) await unlink(nextConfigMjs);
448
+ await writeFile3(nextConfigMjs, cleanNextConfig, "utf-8");
449
+ } else if (existsSync2(nextConfigMjs)) {
450
+ const content = await readFile3(nextConfigMjs, "utf-8");
451
+ if (content.includes("import type") || content.includes(": NextConfig")) {
452
+ await writeFile3(nextConfigMjs, cleanNextConfig, "utf-8");
453
+ }
454
+ }
455
+ log.step(5, totalSteps, "Writing config");
456
+ const pm = detectFromUserAgent();
457
+ const config = createConfig({
458
+ name: projectName,
459
+ template: template.id,
460
+ framework: template.framework,
461
+ port: template.devPort,
462
+ devCommand: runCommand(pm, "dev")
463
+ });
464
+ await writeConfig(projectDir, config);
465
+ if (apiKey) {
466
+ await writeEnvFile(projectDir, apiKey);
467
+ }
468
+ const gitignorePath = resolve(projectDir, ".gitignore");
469
+ if (!existsSync2(gitignorePath)) {
470
+ await writeFile3(
471
+ gitignorePath,
472
+ ["node_modules", "dist", ".env", ".env.local", ".next", ".turbo", ""].join("\n"),
473
+ "utf-8"
474
+ );
475
+ }
476
+ log.step(6, totalSteps, "Installing dependencies");
477
+ const installSpinner = ora2(`Running ${pc3.bold(installCommand(pm))}...`).start();
478
+ try {
479
+ execSync(installCommand(pm), {
480
+ cwd: projectDir,
481
+ stdio: "pipe",
482
+ timeout: 12e4
483
+ });
484
+ installSpinner.succeed("Dependencies installed");
485
+ } catch {
486
+ installSpinner.warn("Could not install dependencies \u2014 run install manually");
487
+ }
488
+ log.step(7, totalSteps, "Initializing git");
489
+ try {
490
+ execSync("git init", { cwd: projectDir, stdio: "pipe" });
491
+ execSync("git add -A", { cwd: projectDir, stdio: "pipe" });
492
+ execSync('git commit -m "Initial commit from create-recursiv-app"', {
493
+ cwd: projectDir,
494
+ stdio: "pipe"
495
+ });
496
+ log.success("Git repository initialized");
497
+ } catch {
498
+ log.warn("Could not initialize git repository");
499
+ }
500
+ log.blank();
501
+ console.log(pc3.bold(pc3.green("Your Recursiv app is ready!")));
502
+ log.blank();
503
+ console.log(" Next steps:");
504
+ console.log();
505
+ console.log(` ${pc3.dim("$")} cd ${projectName}`);
506
+ if (!apiKey) {
507
+ console.log(` ${pc3.dim("$")} ${pc3.dim("# Add your API key to .env")}`);
508
+ }
509
+ console.log(` ${pc3.dim("$")} ${runCommand(pm, "dev")}`);
510
+ log.blank();
511
+ console.log(pc3.dim("Docs: https://docs.recursiv.io"));
512
+ console.log(pc3.dim("Dashboard: https://recursiv.io/dashboard"));
513
+ log.blank();
514
+ }
515
+
516
+ // src/bin/create-recursiv-app.ts
517
+ var program = new Command();
518
+ program.name("create-recursiv-app").description("Create a new Recursiv application").version("0.1.0").argument("[name]", "project name").action(async (name) => {
519
+ try {
520
+ await initCommand(name);
521
+ } catch (err) {
522
+ console.error(err instanceof Error ? err.message : err);
523
+ process.exit(1);
524
+ }
525
+ });
526
+ program.parse();
527
+ //# sourceMappingURL=create-recursiv-app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/bin/create-recursiv-app.ts","../../src/commands/init.ts","../../src/lib/logger.ts","../../src/lib/config.ts","../../src/lib/env.ts","../../src/lib/templates.ts","../../src/lib/auth-flow.ts","../../src/lib/package-manager.ts","../../src/templates/registry.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { initCommand } from '../commands/init.js';\n\nconst program = new Command();\n\nprogram\n .name('create-recursiv-app')\n .description('Create a new Recursiv application')\n .version('0.1.0')\n .argument('[name]', 'project name')\n .action(async (name?: string) => {\n try {\n await initCommand(name);\n } catch (err) {\n console.error(err instanceof Error ? err.message : err);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import { existsSync } from 'node:fs';\nimport { mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { resolve, basename } from 'node:path';\nimport { execSync } from 'node:child_process';\nimport prompts from 'prompts';\nimport pc from 'picocolors';\nimport ora from 'ora';\nimport { log, banner } from '../lib/logger.js';\nimport { createConfig, writeConfig } from '../lib/config.js';\nimport { writeEnvFile } from '../lib/env.js';\nimport { cloneTemplate } from '../lib/templates.js';\nimport { getOrCreateApiKey } from '../lib/auth-flow.js';\nimport { detectFromUserAgent, installCommand, runCommand } from '../lib/package-manager.js';\nimport { templates, type Template } from '../templates/registry.js';\n\nexport async function initCommand(nameArg?: string): Promise<void> {\n banner();\n\n const totalSteps = 7;\n\n // 1. Project name\n log.step(1, totalSteps, 'Project setup');\n let projectName: string;\n if (nameArg) {\n projectName = nameArg;\n } else {\n const { name } = await prompts(\n {\n type: 'text',\n name: 'name',\n message: 'Project name',\n initial: 'my-recursiv-app',\n validate: (v: string) => (v.trim() ? true : 'Name is required'),\n },\n { onCancel: () => process.exit(1) }\n );\n projectName = name;\n }\n\n const projectDir = resolve(process.cwd(), projectName);\n\n if (existsSync(projectDir)) {\n log.error(`Directory ${pc.bold(projectName)} already exists`);\n process.exit(1);\n }\n\n // 2. Template selection\n log.step(2, totalSteps, 'Choose a template');\n const templateChoices = templates.map((t) => ({\n title: t.recommended ? `${t.name} ${pc.dim('(recommended)')}` : t.name,\n description: t.description,\n value: t.id,\n }));\n\n const { templateId } = await prompts(\n {\n type: 'select',\n name: 'templateId',\n message: 'Template',\n choices: templateChoices,\n initial: 0,\n },\n { onCancel: () => process.exit(1) }\n );\n\n const template = templates.find((t) => t.id === templateId) as Template;\n\n // 3. API key\n log.step(3, totalSteps, 'Authentication');\n const apiKey = await getOrCreateApiKey('https://api.recursiv.io/api/v1');\n\n // 4. Clone template\n log.step(4, totalSteps, 'Creating project');\n await mkdir(projectDir, { recursive: true });\n await cloneTemplate(template, projectDir);\n\n // Fix: ensure next.config is valid JS (templates may ship TypeScript syntax in .mjs/.ts)\n const nextConfigTs = resolve(projectDir, 'next.config.ts');\n const nextConfigMjs = resolve(projectDir, 'next.config.mjs');\n const cleanNextConfig = '/** @type {import(\"next\").NextConfig} */\\nconst nextConfig = {};\\nexport default nextConfig;\\n';\n\n if (existsSync(nextConfigTs)) {\n await unlink(nextConfigTs);\n // Remove stale .mjs if template shipped both\n if (existsSync(nextConfigMjs)) await unlink(nextConfigMjs);\n await writeFile(nextConfigMjs, cleanNextConfig, 'utf-8');\n } else if (existsSync(nextConfigMjs)) {\n // Template may have .mjs with TypeScript syntax (import type) — replace it\n const content = await readFile(nextConfigMjs, 'utf-8');\n if (content.includes('import type') || content.includes(': NextConfig')) {\n await writeFile(nextConfigMjs, cleanNextConfig, 'utf-8');\n }\n }\n\n // 5. Write config files\n log.step(5, totalSteps, 'Writing config');\n const pm = detectFromUserAgent();\n\n const config = createConfig({\n name: projectName,\n template: template.id,\n framework: template.framework,\n port: template.devPort,\n devCommand: runCommand(pm, 'dev'),\n });\n await writeConfig(projectDir, config);\n\n if (apiKey) {\n await writeEnvFile(projectDir, apiKey);\n }\n\n // Write .gitignore if it doesn't exist\n const gitignorePath = resolve(projectDir, '.gitignore');\n if (!existsSync(gitignorePath)) {\n await writeFile(\n gitignorePath,\n ['node_modules', 'dist', '.env', '.env.local', '.next', '.turbo', ''].join('\\n'),\n 'utf-8'\n );\n }\n\n // 6. Install dependencies\n log.step(6, totalSteps, 'Installing dependencies');\n const installSpinner = ora(`Running ${pc.bold(installCommand(pm))}...`).start();\n try {\n execSync(installCommand(pm), {\n cwd: projectDir,\n stdio: 'pipe',\n timeout: 120_000,\n });\n installSpinner.succeed('Dependencies installed');\n } catch {\n installSpinner.warn('Could not install dependencies — run install manually');\n }\n\n // 7. Init git\n log.step(7, totalSteps, 'Initializing git');\n try {\n execSync('git init', { cwd: projectDir, stdio: 'pipe' });\n execSync('git add -A', { cwd: projectDir, stdio: 'pipe' });\n execSync('git commit -m \"Initial commit from create-recursiv-app\"', {\n cwd: projectDir,\n stdio: 'pipe',\n });\n log.success('Git repository initialized');\n } catch {\n log.warn('Could not initialize git repository');\n }\n\n // Done!\n log.blank();\n console.log(pc.bold(pc.green('Your Recursiv app is ready!')));\n log.blank();\n console.log(' Next steps:');\n console.log();\n console.log(` ${pc.dim('$')} cd ${projectName}`);\n if (!apiKey) {\n console.log(` ${pc.dim('$')} ${pc.dim('# Add your API key to .env')}`);\n }\n console.log(` ${pc.dim('$')} ${runCommand(pm, 'dev')}`);\n log.blank();\n console.log(pc.dim('Docs: https://docs.recursiv.io'));\n console.log(pc.dim('Dashboard: https://recursiv.io/dashboard'));\n log.blank();\n}\n","import pc from 'picocolors';\n\nexport const log = {\n info(msg: string) {\n console.log(pc.cyan('info') + ' ' + msg);\n },\n success(msg: string) {\n console.log(pc.green('ok') + ' ' + msg);\n },\n warn(msg: string) {\n console.log(pc.yellow('warn') + ' ' + msg);\n },\n error(msg: string) {\n console.error(pc.red('error') + ' ' + msg);\n },\n step(n: number, total: number, msg: string) {\n console.log(pc.dim(`[${n}/${total}]`) + ' ' + msg);\n },\n blank() {\n console.log();\n },\n};\n\nexport function banner() {\n console.log();\n console.log(pc.bold('Recursiv') + pc.dim(' — build and ship apps with AI'));\n console.log();\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport interface RecursivConfig {\n version: number;\n project: {\n name: string;\n template: string;\n framework: string;\n };\n api: {\n baseUrl: string;\n };\n dev: {\n port: number;\n command: string;\n };\n}\n\nconst CONFIG_FILE = '.recursiv.json';\n\nexport function configPath(dir: string): string {\n return join(dir, CONFIG_FILE);\n}\n\nexport async function readConfig(dir: string): Promise<RecursivConfig | null> {\n try {\n const raw = await readFile(configPath(dir), 'utf-8');\n return JSON.parse(raw) as RecursivConfig;\n } catch {\n return null;\n }\n}\n\nexport async function writeConfig(dir: string, config: RecursivConfig): Promise<void> {\n await writeFile(configPath(dir), JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function createConfig(opts: {\n name: string;\n template: string;\n framework: string;\n port?: number;\n devCommand?: string;\n}): RecursivConfig {\n return {\n version: 1,\n project: {\n name: opts.name,\n template: opts.template,\n framework: opts.framework,\n },\n api: {\n baseUrl: 'https://api.recursiv.io/api/v1',\n },\n dev: {\n port: opts.port ?? 3000,\n command: opts.devCommand ?? 'npm run dev',\n },\n };\n}\n","import { readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nexport async function writeEnvFile(dir: string, apiKey: string): Promise<void> {\n const envPath = join(dir, '.env');\n const content = [\n '# Recursiv API key',\n `RECURSIV_API_KEY=${apiKey}`,\n '',\n '# Framework-specific public keys (uncomment as needed)',\n `# NEXT_PUBLIC_RECURSIV_API_KEY=${apiKey}`,\n `# VITE_RECURSIV_API_KEY=${apiKey}`,\n '',\n ].join('\\n');\n await writeFile(envPath, content, 'utf-8');\n}\n\nexport async function readApiKeyFromEnv(dir: string): Promise<string | null> {\n try {\n const raw = await readFile(join(dir, '.env'), 'utf-8');\n const match = raw.match(/^RECURSIV_API_KEY=(.+)$/m);\n return match?.[1]?.trim() ?? null;\n } catch {\n return null;\n }\n}\n\nexport async function updateApiKeyInEnv(dir: string, apiKey: string): Promise<void> {\n const envPath = join(dir, '.env');\n let content: string;\n try {\n content = await readFile(envPath, 'utf-8');\n if (content.includes('RECURSIV_API_KEY=')) {\n content = content.replace(/^RECURSIV_API_KEY=.+$/m, `RECURSIV_API_KEY=${apiKey}`);\n } else {\n content += `\\nRECURSIV_API_KEY=${apiKey}\\n`;\n }\n } catch {\n content = `RECURSIV_API_KEY=${apiKey}\\n`;\n }\n await writeFile(envPath, content, 'utf-8');\n}\n","import degit from 'degit';\nimport ora from 'ora';\nimport type { Template } from '../templates/registry.js';\n\nexport async function cloneTemplate(template: Template, dest: string): Promise<void> {\n const spinner = ora(`Cloning ${template.name} template...`).start();\n try {\n const emitter = degit(template.repo, {\n cache: false,\n force: true,\n verbose: false,\n });\n\n await emitter.clone(dest);\n spinner.succeed(`Template cloned successfully`);\n } catch (err) {\n spinner.fail('Failed to clone template');\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Could not clone template from ${template.repo}.\\n` +\n `Make sure you have internet access and the repo exists.\\n` +\n `Details: ${message}`\n );\n }\n}\n","import prompts from 'prompts';\nimport pc from 'picocolors';\nimport { log } from './logger.js';\n\nconst API_KEY_PATTERN = /^sk_(live|test)_[a-zA-Z0-9]{20,}$/;\nconst DASHBOARD_URL = 'https://recursiv.io/dashboard/api-keys';\n\nconst DEFAULT_SCOPES = [\n 'posts:read',\n 'posts:write',\n 'chat:read',\n 'chat:write',\n 'agents:read',\n 'agents:write',\n 'projects:read',\n 'projects:write',\n 'communities:read',\n 'communities:write',\n 'users:read',\n];\n\nexport function isValidKeyFormat(key: string): boolean {\n return API_KEY_PATTERN.test(key);\n}\n\nexport async function validateApiKey(apiKey: string, baseUrl: string): Promise<boolean> {\n try {\n const res = await fetch(`${baseUrl}/users/me`, {\n headers: {\n Authorization: `Bearer ${apiKey}`,\n Accept: 'application/json',\n },\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\n/**\n * Terminal signup flow — create a Recursiv account and API key without a browser.\n *\n * Flow (passwordless OTP):\n * 1. Prompt for email\n * 2. Send 6-digit OTP code via server\n * 3. Prompt user to enter the code\n * 4. Verify OTP → get session cookie\n * 5. Use session cookie to create an API key via REST endpoint\n * 6. Return the API key string\n */\nexport async function terminalSignup(baseUrl: string): Promise<string | null> {\n // baseUrl is like https://recursiv.io/api/v1 — we need the root for auth endpoints\n const rootUrl = baseUrl.replace(/\\/api\\/v1\\/?$/, '');\n\n console.log();\n console.log(pc.bold('Create a free Recursiv account'));\n console.log(pc.dim('Free tier: 1,000 API calls/day, 1 agent, 3 projects'));\n console.log(pc.dim('We\\'ll send a 6-digit code to your email — no password needed.'));\n console.log();\n\n const { email } = await prompts(\n {\n type: 'text',\n name: 'email',\n message: 'Email',\n validate: (v: string) => {\n if (!v || !v.includes('@')) return 'Valid email required';\n return true;\n },\n },\n { onCancel: () => process.exit(1) },\n );\n\n // Better Auth requires an Origin header for CSRF protection\n const origin = rootUrl || 'https://api.recursiv.io';\n const authHeaders = { 'Content-Type': 'application/json', Origin: origin };\n\n // Send OTP code\n try {\n const sendRes = await fetch(`${rootUrl}/api/auth/email-otp/send-verification-otp`, {\n method: 'POST',\n headers: authHeaders,\n body: JSON.stringify({ email, type: 'sign-in' }),\n });\n\n if (!sendRes.ok) {\n const errBody = await sendRes.text().catch(() => '');\n log.error(`Failed to send code (${sendRes.status}): ${errBody || 'Unknown error'}`);\n return null;\n }\n } catch (err) {\n log.error(\n `Could not reach ${rootUrl} — ${err instanceof Error ? err.message : 'network error'}`,\n );\n log.info(`You can create an API key manually at ${pc.underline(DASHBOARD_URL)}`);\n return null;\n }\n\n log.success(`Verification code sent to ${email}`);\n console.log();\n\n // Prompt for OTP code\n const { code } = await prompts(\n {\n type: 'text',\n name: 'code',\n message: 'Enter the 6-digit code',\n validate: (v: string) => {\n if (!v || !/^\\d{6}$/.test(v.trim())) return 'Enter the 6-digit code from your email';\n return true;\n },\n },\n { onCancel: () => process.exit(1) },\n );\n\n // Verify OTP\n let sessionCookie: string | null = null;\n\n try {\n const verifyRes = await fetch(`${rootUrl}/api/auth/email-otp/verify-email`, {\n method: 'POST',\n headers: authHeaders,\n body: JSON.stringify({ email, otp: code.trim() }),\n redirect: 'manual',\n });\n\n if (verifyRes.ok || verifyRes.status === 302) {\n sessionCookie = extractSessionCookie(verifyRes);\n } else {\n const errBody = await verifyRes.text().catch(() => '');\n log.error(`Verification failed (${verifyRes.status}): ${errBody || 'Invalid or expired code'}`);\n return null;\n }\n } catch (err) {\n log.error(\n `Verification failed — ${err instanceof Error ? err.message : 'network error'}`,\n );\n return null;\n }\n\n if (!sessionCookie) {\n log.error('No session returned from server');\n log.info(`Create an API key manually at ${pc.underline(DASHBOARD_URL)}`);\n return null;\n }\n\n log.success('Authenticated');\n\n // Create an API key using the session\n try {\n const keyRes = await fetch(`${baseUrl}/api-keys`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Cookie: sessionCookie,\n },\n body: JSON.stringify({\n name: 'CLI (auto-created)',\n scopes: DEFAULT_SCOPES,\n }),\n });\n\n if (!keyRes.ok) {\n const errBody = await keyRes.text().catch(() => '');\n log.error(`Failed to create API key (${keyRes.status}): ${errBody}`);\n log.info(`Create one manually at ${pc.underline(DASHBOARD_URL)}`);\n return null;\n }\n\n const { data } = (await keyRes.json()) as { data: { key: string } };\n log.success(`API key created (free tier: 1,000 calls/day)`);\n return data.key;\n } catch (err) {\n log.error(\n `Failed to create API key: ${err instanceof Error ? err.message : 'unknown error'}`,\n );\n log.info(`Create one manually at ${pc.underline(DASHBOARD_URL)}`);\n return null;\n }\n}\n\n/**\n * Extract session cookie from a Better Auth response.\n * Better Auth sets cookies via set-cookie header.\n */\nfunction extractSessionCookie(res: Response): string | null {\n // In Node.js, getSetCookie() returns individual cookie strings\n const setCookieHeaders =\n 'getSetCookie' in res.headers\n ? (res.headers as { getSetCookie(): string[] }).getSetCookie()\n : [];\n\n // Fall back to raw header if getSetCookie not available\n if (setCookieHeaders.length === 0) {\n const raw = res.headers.get('set-cookie');\n if (raw) {\n // Multiple cookies may be comma-separated (though non-standard)\n return raw\n .split(',')\n .map((c) => c.split(';')[0].trim())\n .join('; ');\n }\n return null;\n }\n\n // Extract cookie name=value pairs (strip attributes)\n return setCookieHeaders.map((c) => c.split(';')[0].trim()).join('; ');\n}\n\nexport async function promptApiKey(): Promise<string | null> {\n console.log(\n pc.dim(\n `Get your API key from ${pc.underline(DASHBOARD_URL)}\\n` +\n `Keys start with sk_live_ or sk_test_`,\n ),\n );\n console.log();\n\n const { apiKey } = await prompts(\n {\n type: 'text',\n name: 'apiKey',\n message: 'API key (or press Enter to skip)',\n validate: (value: string) => {\n if (!value) return true; // allow skip\n if (!isValidKeyFormat(value)) {\n return 'Invalid key format. Keys start with sk_live_ or sk_test_';\n }\n return true;\n },\n },\n { onCancel: () => process.exit(1) },\n );\n\n if (!apiKey) {\n log.warn('No API key provided — you can add one later in .env');\n return null;\n }\n\n return apiKey;\n}\n\nexport async function promptAndValidateApiKey(baseUrl: string): Promise<string | null> {\n const apiKey = await promptApiKey();\n if (!apiKey) return null;\n\n const valid = await validateApiKey(apiKey, baseUrl);\n if (!valid) {\n log.warn('Could not validate API key (server unreachable or invalid key)');\n log.info('Key saved to .env — you can update it later');\n } else {\n log.success('API key validated');\n }\n\n return apiKey;\n}\n\n/**\n * Get an API key — either from env, by prompting for an existing key,\n * or by creating a new account via terminal signup.\n */\nexport async function getOrCreateApiKey(baseUrl: string): Promise<string | null> {\n console.log();\n\n const { method } = await prompts(\n {\n type: 'select',\n name: 'method',\n message: 'How would you like to authenticate?',\n choices: [\n {\n title: 'Create a free account',\n description: 'Sign up with email (we\\'ll send a 6-digit code)',\n value: 'signup',\n },\n {\n title: 'Enter an existing API key',\n description: 'Paste a key from your dashboard',\n value: 'paste',\n },\n {\n title: 'Skip for now',\n description: 'Add an API key later in .env',\n value: 'skip',\n },\n ],\n },\n { onCancel: () => process.exit(1) },\n );\n\n if (method === 'signup') {\n return terminalSignup(baseUrl);\n }\n\n if (method === 'paste') {\n return promptAndValidateApiKey(baseUrl);\n }\n\n log.warn('No API key — you can add one later in .env');\n return null;\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';\n\nexport function detectPackageManager(dir: string): PackageManager {\n if (existsSync(join(dir, 'bun.lockb')) || existsSync(join(dir, 'bun.lock'))) return 'bun';\n if (existsSync(join(dir, 'pnpm-lock.yaml'))) return 'pnpm';\n if (existsSync(join(dir, 'yarn.lock'))) return 'yarn';\n return 'npm';\n}\n\nexport function detectFromUserAgent(): PackageManager {\n const ua = process.env.npm_config_user_agent ?? '';\n if (ua.startsWith('bun')) return 'bun';\n if (ua.startsWith('pnpm')) return 'pnpm';\n if (ua.startsWith('yarn')) return 'yarn';\n return 'npm';\n}\n\nexport function installCommand(pm: PackageManager): string {\n return pm === 'yarn' ? 'yarn' : `${pm} install`;\n}\n\nexport function runCommand(pm: PackageManager, script: string): string {\n if (pm === 'npm') return `npm run ${script}`;\n return `${pm} ${script}`;\n}\n","export interface Template {\n id: string;\n name: string;\n description: string;\n repo: string;\n framework: string;\n devCommand: string;\n devPort: number;\n recommended?: boolean;\n}\n\nexport const templates: Template[] = [\n {\n id: 'nextjs',\n name: 'Next.js + Recursiv',\n description: 'Full-stack Next.js app with feeds, chat, and agents',\n repo: 'recursivlabs/template-nextjs',\n framework: 'nextjs',\n devCommand: 'next dev',\n devPort: 3000,\n recommended: true,\n },\n {\n id: 'node',\n name: 'Node.js + Express',\n description: 'Express API server with Recursiv SDK',\n repo: 'recursivlabs/template-node',\n framework: 'express',\n devCommand: 'node --watch src/index.js',\n devPort: 4000,\n },\n {\n id: 'vite',\n name: 'Vite + React',\n description: 'React SPA with social feed components',\n repo: 'recursivlabs/template-vite',\n framework: 'vite',\n devCommand: 'vite',\n devPort: 5173,\n },\n];\n\nexport function getTemplate(id: string): Template | undefined {\n return templates.find((t) => t.id === id);\n}\n\nexport function getDefaultTemplate(): Template {\n return templates.find((t) => t.recommended) ?? templates[0]!;\n}\n"],"mappings":";;;AAAA,SAAS,eAAe;;;ACAxB,SAAS,cAAAA,mBAAkB;AAC3B,SAAS,OAAO,YAAAC,WAAU,QAAQ,aAAAC,kBAAiB;AACnD,SAAS,eAAyB;AAClC,SAAS,gBAAgB;AACzB,OAAOC,cAAa;AACpB,OAAOC,SAAQ;AACf,OAAOC,UAAS;;;ACNhB,OAAO,QAAQ;AAER,IAAM,MAAM;AAAA,EACjB,KAAK,KAAa;AAChB,YAAQ,IAAI,GAAG,KAAK,MAAM,IAAI,OAAO,GAAG;AAAA,EAC1C;AAAA,EACA,QAAQ,KAAa;AACnB,YAAQ,IAAI,GAAG,MAAM,IAAI,IAAI,SAAS,GAAG;AAAA,EAC3C;AAAA,EACA,KAAK,KAAa;AAChB,YAAQ,IAAI,GAAG,OAAO,MAAM,IAAI,OAAO,GAAG;AAAA,EAC5C;AAAA,EACA,MAAM,KAAa;AACjB,YAAQ,MAAM,GAAG,IAAI,OAAO,IAAI,MAAM,GAAG;AAAA,EAC3C;AAAA,EACA,KAAK,GAAW,OAAe,KAAa;AAC1C,YAAQ,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,IAAI,MAAM,GAAG;AAAA,EACnD;AAAA,EACA,QAAQ;AACN,YAAQ,IAAI;AAAA,EACd;AACF;AAEO,SAAS,SAAS;AACvB,UAAQ,IAAI;AACZ,UAAQ,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,IAAI,qCAAgC,CAAC;AAC1E,UAAQ,IAAI;AACd;;;AC3BA,SAAS,UAAU,iBAAiB;AACpC,SAAS,YAAY;AAkBrB,IAAM,cAAc;AAEb,SAAS,WAAW,KAAqB;AAC9C,SAAO,KAAK,KAAK,WAAW;AAC9B;AAWA,eAAsB,YAAY,KAAa,QAAuC;AACpF,QAAM,UAAU,WAAW,GAAG,GAAG,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,OAAO;AAClF;AAEO,SAAS,aAAa,MAMV;AACjB,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,MACP,MAAM,KAAK;AAAA,MACX,UAAU,KAAK;AAAA,MACf,WAAW,KAAK;AAAA,IAClB;AAAA,IACA,KAAK;AAAA,MACH,SAAS;AAAA,IACX;AAAA,IACA,KAAK;AAAA,MACH,MAAM,KAAK,QAAQ;AAAA,MACnB,SAAS,KAAK,cAAc;AAAA,IAC9B;AAAA,EACF;AACF;;;AC5DA,SAAS,YAAAC,WAAU,aAAAC,kBAAiB;AACpC,SAAS,QAAAC,aAAY;AAErB,eAAsB,aAAa,KAAa,QAA+B;AAC7E,QAAM,UAAUA,MAAK,KAAK,MAAM;AAChC,QAAM,UAAU;AAAA,IACd;AAAA,IACA,oBAAoB,MAAM;AAAA,IAC1B;AAAA,IACA;AAAA,IACA,kCAAkC,MAAM;AAAA,IACxC,2BAA2B,MAAM;AAAA,IACjC;AAAA,EACF,EAAE,KAAK,IAAI;AACX,QAAMD,WAAU,SAAS,SAAS,OAAO;AAC3C;;;ACfA,OAAO,WAAW;AAClB,OAAO,SAAS;AAGhB,eAAsB,cAAc,UAAoB,MAA6B;AACnF,QAAM,UAAU,IAAI,WAAW,SAAS,IAAI,cAAc,EAAE,MAAM;AAClE,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,MAAM;AAAA,MACnC,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,UAAM,QAAQ,MAAM,IAAI;AACxB,YAAQ,QAAQ,8BAA8B;AAAA,EAChD,SAAS,KAAK;AACZ,YAAQ,KAAK,0BAA0B;AACvC,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,UAAM,IAAI;AAAA,MACR,iCAAiC,SAAS,IAAI;AAAA;AAAA,WAEhC,OAAO;AAAA,IACvB;AAAA,EACF;AACF;;;ACxBA,OAAO,aAAa;AACpB,OAAOE,SAAQ;AAGf,IAAM,kBAAkB;AACxB,IAAM,gBAAgB;AAEtB,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,iBAAiB,KAAsB;AACrD,SAAO,gBAAgB,KAAK,GAAG;AACjC;AAEA,eAAsB,eAAe,QAAgB,SAAmC;AACtF,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,OAAO,aAAa;AAAA,MAC7C,SAAS;AAAA,QACP,eAAe,UAAU,MAAM;AAAA,QAC/B,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AACD,WAAO,IAAI;AAAA,EACb,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAaA,eAAsB,eAAe,SAAyC;AAE5E,QAAM,UAAU,QAAQ,QAAQ,iBAAiB,EAAE;AAEnD,UAAQ,IAAI;AACZ,UAAQ,IAAIC,IAAG,KAAK,gCAAgC,CAAC;AACrD,UAAQ,IAAIA,IAAG,IAAI,qDAAqD,CAAC;AACzE,UAAQ,IAAIA,IAAG,IAAI,oEAAgE,CAAC;AACpF,UAAQ,IAAI;AAEZ,QAAM,EAAE,MAAM,IAAI,MAAM;AAAA,IACtB;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,UAAU,CAAC,MAAc;AACvB,YAAI,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,EAAG,QAAO;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,EAAE,UAAU,MAAM,QAAQ,KAAK,CAAC,EAAE;AAAA,EACpC;AAGA,QAAM,SAAS,WAAW;AAC1B,QAAM,cAAc,EAAE,gBAAgB,oBAAoB,QAAQ,OAAO;AAGzE,MAAI;AACF,UAAM,UAAU,MAAM,MAAM,GAAG,OAAO,6CAA6C;AAAA,MACjF,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,MAAM,KAAK,UAAU,EAAE,OAAO,MAAM,UAAU,CAAC;AAAA,IACjD,CAAC;AAED,QAAI,CAAC,QAAQ,IAAI;AACf,YAAM,UAAU,MAAM,QAAQ,KAAK,EAAE,MAAM,MAAM,EAAE;AACnD,UAAI,MAAM,wBAAwB,QAAQ,MAAM,MAAM,WAAW,eAAe,EAAE;AAClF,aAAO;AAAA,IACT;AAAA,EACF,SAAS,KAAK;AACZ,QAAI;AAAA,MACF,mBAAmB,OAAO,WAAM,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,IACtF;AACA,QAAI,KAAK,yCAAyCA,IAAG,UAAU,aAAa,CAAC,EAAE;AAC/E,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,6BAA6B,KAAK,EAAE;AAChD,UAAQ,IAAI;AAGZ,QAAM,EAAE,KAAK,IAAI,MAAM;AAAA,IACrB;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,UAAU,CAAC,MAAc;AACvB,YAAI,CAAC,KAAK,CAAC,UAAU,KAAK,EAAE,KAAK,CAAC,EAAG,QAAO;AAC5C,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,EAAE,UAAU,MAAM,QAAQ,KAAK,CAAC,EAAE;AAAA,EACpC;AAGA,MAAI,gBAA+B;AAEnC,MAAI;AACF,UAAM,YAAY,MAAM,MAAM,GAAG,OAAO,oCAAoC;AAAA,MAC1E,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,MAAM,KAAK,UAAU,EAAE,OAAO,KAAK,KAAK,KAAK,EAAE,CAAC;AAAA,MAChD,UAAU;AAAA,IACZ,CAAC;AAED,QAAI,UAAU,MAAM,UAAU,WAAW,KAAK;AAC5C,sBAAgB,qBAAqB,SAAS;AAAA,IAChD,OAAO;AACL,YAAM,UAAU,MAAM,UAAU,KAAK,EAAE,MAAM,MAAM,EAAE;AACrD,UAAI,MAAM,wBAAwB,UAAU,MAAM,MAAM,WAAW,yBAAyB,EAAE;AAC9F,aAAO;AAAA,IACT;AAAA,EACF,SAAS,KAAK;AACZ,QAAI;AAAA,MACF,8BAAyB,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,IAC/E;AACA,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,eAAe;AAClB,QAAI,MAAM,iCAAiC;AAC3C,QAAI,KAAK,iCAAiCA,IAAG,UAAU,aAAa,CAAC,EAAE;AACvE,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,eAAe;AAG3B,MAAI;AACF,UAAM,SAAS,MAAM,MAAM,GAAG,OAAO,aAAa;AAAA,MAChD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,QAAQ;AAAA,MACV;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACnB,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,OAAO,IAAI;AACd,YAAM,UAAU,MAAM,OAAO,KAAK,EAAE,MAAM,MAAM,EAAE;AAClD,UAAI,MAAM,6BAA6B,OAAO,MAAM,MAAM,OAAO,EAAE;AACnE,UAAI,KAAK,0BAA0BA,IAAG,UAAU,aAAa,CAAC,EAAE;AAChE,aAAO;AAAA,IACT;AAEA,UAAM,EAAE,KAAK,IAAK,MAAM,OAAO,KAAK;AACpC,QAAI,QAAQ,8CAA8C;AAC1D,WAAO,KAAK;AAAA,EACd,SAAS,KAAK;AACZ,QAAI;AAAA,MACF,6BAA6B,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,IACnF;AACA,QAAI,KAAK,0BAA0BA,IAAG,UAAU,aAAa,CAAC,EAAE;AAChE,WAAO;AAAA,EACT;AACF;AAMA,SAAS,qBAAqB,KAA8B;AAE1D,QAAM,mBACJ,kBAAkB,IAAI,UACjB,IAAI,QAAyC,aAAa,IAC3D,CAAC;AAGP,MAAI,iBAAiB,WAAW,GAAG;AACjC,UAAM,MAAM,IAAI,QAAQ,IAAI,YAAY;AACxC,QAAI,KAAK;AAEP,aAAO,IACJ,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,EACjC,KAAK,IAAI;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAGA,SAAO,iBAAiB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,KAAK,IAAI;AACtE;AAEA,eAAsB,eAAuC;AAC3D,UAAQ;AAAA,IACNA,IAAG;AAAA,MACD,yBAAyBA,IAAG,UAAU,aAAa,CAAC;AAAA;AAAA,IAEtD;AAAA,EACF;AACA,UAAQ,IAAI;AAEZ,QAAM,EAAE,OAAO,IAAI,MAAM;AAAA,IACvB;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,UAAU,CAAC,UAAkB;AAC3B,YAAI,CAAC,MAAO,QAAO;AACnB,YAAI,CAAC,iBAAiB,KAAK,GAAG;AAC5B,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,EAAE,UAAU,MAAM,QAAQ,KAAK,CAAC,EAAE;AAAA,EACpC;AAEA,MAAI,CAAC,QAAQ;AACX,QAAI,KAAK,0DAAqD;AAC9D,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,eAAsB,wBAAwB,SAAyC;AACrF,QAAM,SAAS,MAAM,aAAa;AAClC,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,QAAQ,MAAM,eAAe,QAAQ,OAAO;AAClD,MAAI,CAAC,OAAO;AACV,QAAI,KAAK,gEAAgE;AACzE,QAAI,KAAK,kDAA6C;AAAA,EACxD,OAAO;AACL,QAAI,QAAQ,mBAAmB;AAAA,EACjC;AAEA,SAAO;AACT;AAMA,eAAsB,kBAAkB,SAAyC;AAC/E,UAAQ,IAAI;AAEZ,QAAM,EAAE,OAAO,IAAI,MAAM;AAAA,IACvB;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,QACP;AAAA,UACE,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,IACA,EAAE,UAAU,MAAM,QAAQ,KAAK,CAAC,EAAE;AAAA,EACpC;AAEA,MAAI,WAAW,UAAU;AACvB,WAAO,eAAe,OAAO;AAAA,EAC/B;AAEA,MAAI,WAAW,SAAS;AACtB,WAAO,wBAAwB,OAAO;AAAA,EACxC;AAEA,MAAI,KAAK,iDAA4C;AACrD,SAAO;AACT;;;AC5SA,SAAS,kBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAWd,SAAS,sBAAsC;AACpD,QAAM,KAAK,QAAQ,IAAI,yBAAyB;AAChD,MAAI,GAAG,WAAW,KAAK,EAAG,QAAO;AACjC,MAAI,GAAG,WAAW,MAAM,EAAG,QAAO;AAClC,MAAI,GAAG,WAAW,MAAM,EAAG,QAAO;AAClC,SAAO;AACT;AAEO,SAAS,eAAe,IAA4B;AACzD,SAAO,OAAO,SAAS,SAAS,GAAG,EAAE;AACvC;AAEO,SAAS,WAAW,IAAoB,QAAwB;AACrE,MAAI,OAAO,MAAO,QAAO,WAAW,MAAM;AAC1C,SAAO,GAAG,EAAE,IAAI,MAAM;AACxB;;;AChBO,IAAM,YAAwB;AAAA,EACnC;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,MAAM;AAAA,IACN,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AACF;;;APzBA,eAAsB,YAAY,SAAiC;AACjE,SAAO;AAEP,QAAM,aAAa;AAGnB,MAAI,KAAK,GAAG,YAAY,eAAe;AACvC,MAAI;AACJ,MAAI,SAAS;AACX,kBAAc;AAAA,EAChB,OAAO;AACL,UAAM,EAAE,KAAK,IAAI,MAAMC;AAAA,MACrB;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,QACT,UAAU,CAAC,MAAe,EAAE,KAAK,IAAI,OAAO;AAAA,MAC9C;AAAA,MACA,EAAE,UAAU,MAAM,QAAQ,KAAK,CAAC,EAAE;AAAA,IACpC;AACA,kBAAc;AAAA,EAChB;AAEA,QAAM,aAAa,QAAQ,QAAQ,IAAI,GAAG,WAAW;AAErD,MAAIC,YAAW,UAAU,GAAG;AAC1B,QAAI,MAAM,aAAaC,IAAG,KAAK,WAAW,CAAC,iBAAiB;AAC5D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI,KAAK,GAAG,YAAY,mBAAmB;AAC3C,QAAM,kBAAkB,UAAU,IAAI,CAAC,OAAO;AAAA,IAC5C,OAAO,EAAE,cAAc,GAAG,EAAE,IAAI,IAAIA,IAAG,IAAI,eAAe,CAAC,KAAK,EAAE;AAAA,IAClE,aAAa,EAAE;AAAA,IACf,OAAO,EAAE;AAAA,EACX,EAAE;AAEF,QAAM,EAAE,WAAW,IAAI,MAAMF;AAAA,IAC3B;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,IACA,EAAE,UAAU,MAAM,QAAQ,KAAK,CAAC,EAAE;AAAA,EACpC;AAEA,QAAM,WAAW,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,UAAU;AAG1D,MAAI,KAAK,GAAG,YAAY,gBAAgB;AACxC,QAAM,SAAS,MAAM,kBAAkB,gCAAgC;AAGvE,MAAI,KAAK,GAAG,YAAY,kBAAkB;AAC1C,QAAM,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAC3C,QAAM,cAAc,UAAU,UAAU;AAGxC,QAAM,eAAe,QAAQ,YAAY,gBAAgB;AACzD,QAAM,gBAAgB,QAAQ,YAAY,iBAAiB;AAC3D,QAAM,kBAAkB;AAExB,MAAIC,YAAW,YAAY,GAAG;AAC5B,UAAM,OAAO,YAAY;AAEzB,QAAIA,YAAW,aAAa,EAAG,OAAM,OAAO,aAAa;AACzD,UAAME,WAAU,eAAe,iBAAiB,OAAO;AAAA,EACzD,WAAWF,YAAW,aAAa,GAAG;AAEpC,UAAM,UAAU,MAAMG,UAAS,eAAe,OAAO;AACrD,QAAI,QAAQ,SAAS,aAAa,KAAK,QAAQ,SAAS,cAAc,GAAG;AACvE,YAAMD,WAAU,eAAe,iBAAiB,OAAO;AAAA,IACzD;AAAA,EACF;AAGA,MAAI,KAAK,GAAG,YAAY,gBAAgB;AACxC,QAAM,KAAK,oBAAoB;AAE/B,QAAM,SAAS,aAAa;AAAA,IAC1B,MAAM;AAAA,IACN,UAAU,SAAS;AAAA,IACnB,WAAW,SAAS;AAAA,IACpB,MAAM,SAAS;AAAA,IACf,YAAY,WAAW,IAAI,KAAK;AAAA,EAClC,CAAC;AACD,QAAM,YAAY,YAAY,MAAM;AAEpC,MAAI,QAAQ;AACV,UAAM,aAAa,YAAY,MAAM;AAAA,EACvC;AAGA,QAAM,gBAAgB,QAAQ,YAAY,YAAY;AACtD,MAAI,CAACF,YAAW,aAAa,GAAG;AAC9B,UAAME;AAAA,MACJ;AAAA,MACA,CAAC,gBAAgB,QAAQ,QAAQ,cAAc,SAAS,UAAU,EAAE,EAAE,KAAK,IAAI;AAAA,MAC/E;AAAA,IACF;AAAA,EACF;AAGA,MAAI,KAAK,GAAG,YAAY,yBAAyB;AACjD,QAAM,iBAAiBE,KAAI,WAAWH,IAAG,KAAK,eAAe,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM;AAC9E,MAAI;AACF,aAAS,eAAe,EAAE,GAAG;AAAA,MAC3B,KAAK;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AACD,mBAAe,QAAQ,wBAAwB;AAAA,EACjD,QAAQ;AACN,mBAAe,KAAK,4DAAuD;AAAA,EAC7E;AAGA,MAAI,KAAK,GAAG,YAAY,kBAAkB;AAC1C,MAAI;AACF,aAAS,YAAY,EAAE,KAAK,YAAY,OAAO,OAAO,CAAC;AACvD,aAAS,cAAc,EAAE,KAAK,YAAY,OAAO,OAAO,CAAC;AACzD,aAAS,2DAA2D;AAAA,MAClE,KAAK;AAAA,MACL,OAAO;AAAA,IACT,CAAC;AACD,QAAI,QAAQ,4BAA4B;AAAA,EAC1C,QAAQ;AACN,QAAI,KAAK,qCAAqC;AAAA,EAChD;AAGA,MAAI,MAAM;AACV,UAAQ,IAAIA,IAAG,KAAKA,IAAG,MAAM,6BAA6B,CAAC,CAAC;AAC5D,MAAI,MAAM;AACV,UAAQ,IAAI,eAAe;AAC3B,UAAQ,IAAI;AACZ,UAAQ,IAAI,KAAKA,IAAG,IAAI,GAAG,CAAC,OAAO,WAAW,EAAE;AAChD,MAAI,CAAC,QAAQ;AACX,YAAQ,IAAI,KAAKA,IAAG,IAAI,GAAG,CAAC,IAAIA,IAAG,IAAI,4BAA4B,CAAC,EAAE;AAAA,EACxE;AACA,UAAQ,IAAI,KAAKA,IAAG,IAAI,GAAG,CAAC,IAAI,WAAW,IAAI,KAAK,CAAC,EAAE;AACvD,MAAI,MAAM;AACV,UAAQ,IAAIA,IAAG,IAAI,gCAAgC,CAAC;AACpD,UAAQ,IAAIA,IAAG,IAAI,0CAA0C,CAAC;AAC9D,MAAI,MAAM;AACZ;;;ADjKA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,qBAAqB,EAC1B,YAAY,mCAAmC,EAC/C,QAAQ,OAAO,EACf,SAAS,UAAU,cAAc,EACjC,OAAO,OAAO,SAAkB;AAC/B,MAAI;AACF,UAAM,YAAY,IAAI;AAAA,EACxB,SAAS,KAAK;AACZ,YAAQ,MAAM,eAAe,QAAQ,IAAI,UAAU,GAAG;AACtD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QAAQ,MAAM;","names":["existsSync","readFile","writeFile","prompts","pc","ora","readFile","writeFile","join","pc","pc","join","prompts","existsSync","pc","writeFile","readFile","ora"]}