@revealui/cli 0.3.2 → 0.4.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.
package/dist/index.js CHANGED
@@ -1,22 +1,233 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { createLogger as createLogger11 } from "@revealui/setup/utils";
4
+ import { createLogger as createLogger12 } from "@revealui/setup/utils";
5
5
  import { Command } from "commander";
6
6
 
7
+ // src/commands/agent.ts
8
+ import { createInterface } from "readline";
9
+ import { createLogger } from "@revealui/setup/utils";
10
+ var logger = createLogger({ prefix: "agent" });
11
+ async function runAgentStatusCommand() {
12
+ const { available, provider, model, projectRoot } = await detectProvider();
13
+ logger.info(`Provider: ${provider}`);
14
+ logger.info(`Model: ${model}`);
15
+ logger.info(`Project root: ${projectRoot}`);
16
+ logger.info(`Available: ${available ? "yes" : "no"}`);
17
+ if (!available) {
18
+ logger.warn("No LLM provider detected. Start BitNet, Ollama, or set GROQ_API_KEY.");
19
+ }
20
+ }
21
+ async function runAgentHeadlessCommand(prompt) {
22
+ const deps = await loadProDeps();
23
+ if (!deps) return;
24
+ const { StreamingAgentRuntime, createLLMClientFromEnv, createCodingTools } = deps;
25
+ const projectRoot = process.cwd();
26
+ const tools = createCodingTools({ projectRoot });
27
+ const llmClient = createLLMClientFromEnv();
28
+ const agent = {
29
+ id: "revealui-coding-agent",
30
+ name: "RevealUI Coding Agent",
31
+ instructions: buildMinimalInstructions(),
32
+ tools,
33
+ config: {},
34
+ getContext: () => ({ projectRoot, workingDirectory: projectRoot })
35
+ };
36
+ const task = {
37
+ id: `task-${Date.now()}`,
38
+ type: "headless-prompt",
39
+ description: prompt
40
+ };
41
+ const runtime = new StreamingAgentRuntime({
42
+ maxIterations: 10,
43
+ timeout: 12e4
44
+ });
45
+ try {
46
+ for await (const chunk of runtime.streamTask(agent, task, llmClient)) {
47
+ switch (chunk.type) {
48
+ case "text":
49
+ if (chunk.content) process.stdout.write(chunk.content);
50
+ break;
51
+ case "tool_call_start":
52
+ if (chunk.toolCall) {
53
+ process.stderr.write(`
54
+ [tool] ${chunk.toolCall.name}
55
+ `);
56
+ }
57
+ break;
58
+ case "tool_call_result":
59
+ if (chunk.toolResult?.content) {
60
+ process.stderr.write(` \u2192 ${chunk.toolResult.content}
61
+ `);
62
+ }
63
+ break;
64
+ case "error":
65
+ process.stderr.write(`
66
+ [error] ${chunk.error}
67
+ `);
68
+ break;
69
+ case "done":
70
+ process.stdout.write("\n");
71
+ break;
72
+ }
73
+ }
74
+ } finally {
75
+ await runtime.cleanup();
76
+ }
77
+ }
78
+ async function runAgentReplCommand() {
79
+ const deps = await loadProDeps();
80
+ if (!deps) return;
81
+ const { StreamingAgentRuntime, createLLMClientFromEnv, createCodingTools } = deps;
82
+ const projectRoot = process.cwd();
83
+ const tools = createCodingTools({ projectRoot });
84
+ const llmClient = createLLMClientFromEnv();
85
+ const agent = {
86
+ id: "revealui-coding-agent",
87
+ name: "RevealUI Coding Agent",
88
+ instructions: buildMinimalInstructions(),
89
+ tools,
90
+ config: {},
91
+ getContext: () => ({ projectRoot, workingDirectory: projectRoot })
92
+ };
93
+ logger.info('RevealUI Agent (type "exit" or Ctrl+C to quit)');
94
+ const rl = createInterface({
95
+ input: process.stdin,
96
+ output: process.stdout,
97
+ prompt: "\n> "
98
+ });
99
+ rl.prompt();
100
+ rl.on("line", async (line) => {
101
+ const input = line.trim();
102
+ if (!input) {
103
+ rl.prompt();
104
+ return;
105
+ }
106
+ if (input === "exit" || input === "quit") {
107
+ rl.close();
108
+ return;
109
+ }
110
+ const task = {
111
+ id: `task-${Date.now()}`,
112
+ type: "repl-prompt",
113
+ description: input
114
+ };
115
+ const runtime = new StreamingAgentRuntime({
116
+ maxIterations: 10,
117
+ timeout: 12e4
118
+ });
119
+ try {
120
+ for await (const chunk of runtime.streamTask(agent, task, llmClient)) {
121
+ switch (chunk.type) {
122
+ case "text":
123
+ if (chunk.content) process.stdout.write(chunk.content);
124
+ break;
125
+ case "tool_call_start":
126
+ if (chunk.toolCall) {
127
+ process.stderr.write(`
128
+ [tool] ${chunk.toolCall.name}
129
+ `);
130
+ }
131
+ break;
132
+ case "tool_call_result":
133
+ if (chunk.toolResult?.content) {
134
+ process.stderr.write(` \u2192 ${chunk.toolResult.content}
135
+ `);
136
+ }
137
+ break;
138
+ case "error":
139
+ process.stderr.write(`
140
+ [error] ${chunk.error}
141
+ `);
142
+ break;
143
+ case "done":
144
+ break;
145
+ }
146
+ }
147
+ } catch (err) {
148
+ logger.error(err instanceof Error ? err.message : String(err));
149
+ } finally {
150
+ await runtime.cleanup();
151
+ }
152
+ rl.prompt();
153
+ });
154
+ rl.on("close", () => {
155
+ process.exit(0);
156
+ });
157
+ }
158
+ async function loadProDeps() {
159
+ const aiRuntimePath = "@revealui/ai/orchestration/streaming-runtime";
160
+ const aiClientPath = "@revealui/ai/llm/client";
161
+ const aiToolsPath = "@revealui/ai/tools/coding";
162
+ try {
163
+ const [runtimeMod, clientMod, toolsMod] = await Promise.all([
164
+ import(aiRuntimePath),
165
+ import(aiClientPath),
166
+ import(aiToolsPath)
167
+ ]);
168
+ return {
169
+ StreamingAgentRuntime: runtimeMod.StreamingAgentRuntime,
170
+ createLLMClientFromEnv: clientMod.createLLMClientFromEnv,
171
+ createCodingTools: toolsMod.createCodingTools
172
+ };
173
+ } catch {
174
+ logger.error(
175
+ "Pro packages not found. Install @revealui/ai to use the agent.\n npm install @revealui/ai"
176
+ );
177
+ return null;
178
+ }
179
+ }
180
+ async function detectProvider() {
181
+ const projectRoot = process.cwd();
182
+ if (process.env.BITNET_BASE_URL) {
183
+ try {
184
+ const res = await fetch(`${process.env.BITNET_BASE_URL}/v1/models`, {
185
+ signal: AbortSignal.timeout(2e3)
186
+ });
187
+ if (res.ok) {
188
+ return { available: true, provider: "bitnet", model: "bitnet-b1.58-2B-4T", projectRoot };
189
+ }
190
+ } catch {
191
+ }
192
+ }
193
+ const ollamaUrl = process.env.OLLAMA_BASE_URL ?? "http://localhost:11434";
194
+ try {
195
+ const res = await fetch(`${ollamaUrl}/api/tags`, {
196
+ signal: AbortSignal.timeout(2e3)
197
+ });
198
+ if (res.ok) {
199
+ return { available: true, provider: "ollama", model: "llama3.2:3b", projectRoot };
200
+ }
201
+ } catch {
202
+ }
203
+ if (process.env.GROQ_API_KEY) {
204
+ return { available: true, provider: "groq", model: "llama-3.3-70b-versatile", projectRoot };
205
+ }
206
+ return { available: false, provider: "none", model: "none", projectRoot };
207
+ }
208
+ function buildMinimalInstructions() {
209
+ return [
210
+ "You are the RevealUI coding agent. You help with software development tasks in this project.",
211
+ "Use the available tools to read, write, edit, search, and execute commands.",
212
+ "Always read files before modifying them. Prefer surgical edits over full rewrites.",
213
+ "Follow project conventions discovered via the project_context tool.",
214
+ "Be concise and direct. Show your work through tool usage, not verbose explanations."
215
+ ].join("\n");
216
+ }
217
+
7
218
  // src/commands/create-flow.ts
8
219
  import { readFileSync } from "fs";
9
220
  import { homedir } from "os";
10
221
  import { join } from "path";
11
- import { createLogger as createLogger6 } from "@revealui/setup/utils";
222
+ import { createLogger as createLogger7 } from "@revealui/setup/utils";
12
223
  import { importSPKI, jwtVerify } from "jose";
13
224
 
14
225
  // src/prompts/database.ts
15
226
  import inquirer from "inquirer";
16
227
 
17
228
  // src/validators/credentials.ts
18
- import { createLogger } from "@revealui/setup/utils";
19
- var logger = createLogger({ prefix: "Validator" });
229
+ import { createLogger as createLogger2 } from "@revealui/setup/utils";
230
+ var logger2 = createLogger2({ prefix: "Validator" });
20
231
  async function validateStripeKey(key) {
21
232
  if (!(key.startsWith("sk_test_") || key.startsWith("sk_live_"))) {
22
233
  return {
@@ -56,7 +267,7 @@ async function validateSupabaseUrl(url) {
56
267
  try {
57
268
  const parsed = new URL(url);
58
269
  if (!parsed.hostname.includes("supabase")) {
59
- logger.warn("URL does not appear to be a Supabase URL");
270
+ logger2.warn("URL does not appear to be a Supabase URL");
60
271
  }
61
272
  return { valid: true };
62
273
  } catch {
@@ -344,18 +555,18 @@ async function promptStorageConfig() {
344
555
  }
345
556
 
346
557
  // src/validators/node-version.ts
347
- import { createLogger as createLogger2 } from "@revealui/setup/utils";
348
- var logger2 = createLogger2({ prefix: "Setup" });
558
+ import { createLogger as createLogger3 } from "@revealui/setup/utils";
559
+ var logger3 = createLogger3({ prefix: "Setup" });
349
560
  var REQUIRED_NODE_VERSION = "24.13.0";
350
561
  function validateNodeVersion() {
351
562
  const currentVersion = process.version.slice(1);
352
563
  const [currentMajor, currentMinor] = currentVersion.split(".").map(Number);
353
564
  const [requiredMajor, requiredMinor] = REQUIRED_NODE_VERSION.split(".").map(Number);
354
565
  if (currentMajor < requiredMajor || currentMajor === requiredMajor && currentMinor < requiredMinor) {
355
- logger2.error(
566
+ logger3.error(
356
567
  `Node.js ${REQUIRED_NODE_VERSION} or higher is required. You have ${currentVersion}.`
357
568
  );
358
- logger2.info("Please upgrade Node.js: https://nodejs.org/");
569
+ logger3.info("Please upgrade Node.js: https://nodejs.org/");
359
570
  return false;
360
571
  }
361
572
  return true;
@@ -363,10 +574,11 @@ function validateNodeVersion() {
363
574
 
364
575
  // src/commands/create.ts
365
576
  import crypto from "crypto";
577
+ import { existsSync } from "fs";
366
578
  import fs5 from "fs/promises";
367
579
  import path5 from "path";
368
580
  import { fileURLToPath } from "url";
369
- import { createLogger as createLogger5 } from "@revealui/setup/utils";
581
+ import { createLogger as createLogger6 } from "@revealui/setup/utils";
370
582
  import ora2 from "ora";
371
583
 
372
584
  // src/generators/devbox.ts
@@ -564,70 +776,42 @@ Run the development server:
564
776
  pnpm dev
565
777
  \`\`\`
566
778
 
567
- Open [http://localhost:4000](http://localhost:4000) with your browser to access the CMS.
568
-
569
- The web application runs on [http://localhost:3000](http://localhost:3000).
779
+ Open [http://localhost:4000](http://localhost:4000) with your browser.
570
780
 
571
- ## Development Environments
781
+ ## Requirements
572
782
 
573
- ### Standard Setup
574
-
575
- Requirements:
576
783
  - Node.js 24.13.0 or higher
577
- - pnpm 10.28.2 or higher
578
- - PostgreSQL 16
579
-
580
- ### Dev Containers
581
-
582
- Open in VS Code and select "Reopen in Container", or use GitHub Codespaces.
583
-
584
- ### Devbox
585
-
586
- Install Devbox:
587
-
588
- \`\`\`bash
589
- curl -fsSL https://get.jetpack.io/devbox | bash
590
- \`\`\`
591
-
592
- Then start the Devbox shell:
593
-
594
- \`\`\`bash
595
- devbox shell
596
- pnpm dev
597
- \`\`\`
784
+ - pnpm 10 or higher
785
+ - PostgreSQL 16 (or use a hosted provider like [Neon](https://neon.tech))
598
786
 
599
787
  ## Project Structure
600
788
 
601
789
  \`\`\`
602
790
  ${projectConfig.projectName}/
603
- \u251C\u2500\u2500 apps/
604
- \u2502 \u251C\u2500\u2500 cms/ # CMS application
605
- \u2502 \u2514\u2500\u2500 web/ # Frontend application
606
- \u251C\u2500\u2500 packages/
607
- \u2502 \u251C\u2500\u2500 auth/ # Authentication
608
- \u2502 \u251C\u2500\u2500 db/ # Database
609
- \u2502 \u2514\u2500\u2500 ... # Other shared packages
610
- \u251C\u2500\u2500 .devcontainer/ # Dev Container configuration
611
- \u251C\u2500\u2500 devbox.json # Devbox configuration
612
- \u2514\u2500\u2500 .env.development.local # Environment variables
791
+ \u251C\u2500\u2500 src/
792
+ \u2502 \u251C\u2500\u2500 app/ # Next.js App Router pages
793
+ \u2502 \u251C\u2500\u2500 collections/ # RevealUI collection definitions
794
+ \u2502 \u2514\u2500\u2500 seed.ts # Database seed script
795
+ \u251C\u2500\u2500 revealui.config.ts # RevealUI configuration
796
+ \u251C\u2500\u2500 next.config.mjs # Next.js configuration
797
+ \u2514\u2500\u2500 .env.local # Environment variables (git-ignored)
613
798
  \`\`\`
614
799
 
615
800
  ## Available Scripts
616
801
 
617
- - \`pnpm dev\` - Start development servers
802
+ - \`pnpm dev\` - Start the development server
618
803
  - \`pnpm build\` - Build for production
619
804
  - \`pnpm test\` - Run tests
620
- - \`pnpm lint\` - Run linters
805
+ - \`pnpm lint\` - Lint with Biome
621
806
  - \`pnpm typecheck\` - Type check
622
- - \`pnpm db:init\` - Initialize database
807
+ - \`pnpm db:init\` - Initialize the database
623
808
  - \`pnpm db:migrate\` - Run migrations
624
- - \`pnpm db:seed\` - Seed database
809
+ - \`pnpm db:seed\` - Seed sample content
625
810
 
626
811
  ## Learn More
627
812
 
628
- - [RevealUI Documentation](https://github.com/your-org/RevealUI)
813
+ - [RevealUI Documentation](https://docs.revealui.com)
629
814
  - [Next.js Documentation](https://nextjs.org/docs)
630
- - [Hono Documentation](https://hono.dev)
631
815
 
632
816
  ## Template
633
817
 
@@ -641,10 +825,10 @@ MIT
641
825
  }
642
826
 
643
827
  // src/installers/dependencies.ts
644
- import { createLogger as createLogger3 } from "@revealui/setup/utils";
828
+ import { createLogger as createLogger4 } from "@revealui/setup/utils";
645
829
  import { execa } from "execa";
646
830
  import ora from "ora";
647
- var logger3 = createLogger3({ prefix: "Install" });
831
+ var logger4 = createLogger4({ prefix: "Install" });
648
832
  async function installDependencies(projectPath) {
649
833
  const spinner = ora("Installing dependencies with pnpm...").start();
650
834
  try {
@@ -655,7 +839,7 @@ async function installDependencies(projectPath) {
655
839
  spinner.succeed("Dependencies installed successfully");
656
840
  } catch (error) {
657
841
  spinner.fail("Failed to install dependencies");
658
- logger3.error('Please run "pnpm install" manually');
842
+ logger4.error('Please run "pnpm install" manually');
659
843
  throw error;
660
844
  }
661
845
  }
@@ -669,15 +853,15 @@ async function isPnpmInstalled() {
669
853
  }
670
854
 
671
855
  // src/utils/git.ts
672
- import { createLogger as createLogger4 } from "@revealui/setup/utils";
856
+ import { createLogger as createLogger5 } from "@revealui/setup/utils";
673
857
  import { execa as execa2 } from "execa";
674
- var logger4 = createLogger4({ prefix: "Git" });
858
+ var logger5 = createLogger5({ prefix: "Git" });
675
859
  async function initializeGitRepo(projectPath) {
676
860
  try {
677
861
  await execa2("git", ["init"], { cwd: projectPath });
678
- logger4.success("Initialized git repository");
862
+ logger5.success("Initialized git repository");
679
863
  } catch (error) {
680
- logger4.warn("Failed to initialize git repository");
864
+ logger5.warn("Failed to initialize git repository");
681
865
  throw error;
682
866
  }
683
867
  }
@@ -685,9 +869,9 @@ async function createInitialCommit(projectPath) {
685
869
  try {
686
870
  await execa2("git", ["add", "."], { cwd: projectPath });
687
871
  await execa2("git", ["commit", "-m", "Initial commit from @revealui/cli"], { cwd: projectPath });
688
- logger4.success("Created initial commit");
872
+ logger5.success("Created initial commit");
689
873
  } catch (error) {
690
- logger4.warn("Failed to create initial commit");
874
+ logger5.warn("Failed to create initial commit");
691
875
  throw error;
692
876
  }
693
877
  }
@@ -701,10 +885,10 @@ async function isGitInstalled() {
701
885
  }
702
886
 
703
887
  // src/commands/create.ts
704
- var logger5 = createLogger5({ prefix: "Create" });
888
+ var logger6 = createLogger6({ prefix: "Create" });
705
889
  var __filename2 = fileURLToPath(import.meta.url);
706
890
  var __dirname2 = path5.dirname(__filename2);
707
- var TEMPLATES_DIR = path5.resolve(__dirname2, "../templates");
891
+ var TEMPLATES_DIR = existsSync(path5.resolve(__dirname2, "../../templates")) ? path5.resolve(__dirname2, "../../templates") : path5.resolve(__dirname2, "../templates");
708
892
  function buildEnvLocal(cfg) {
709
893
  const lines = [
710
894
  "# Generated by @revealui/cli \u2014 fill in the remaining placeholders before running `pnpm dev`",
@@ -789,6 +973,47 @@ function resolveTemplateName(template) {
789
973
  };
790
974
  return map[template] ?? "starter";
791
975
  }
976
+ async function pullContentRules(projectPath) {
977
+ const baseUrl = process.env.REVEALUI_RULES_URL ?? "https://raw.githubusercontent.com/RevealUIStudio/editor-configs/main/harnesses";
978
+ const spinner = ora2("Pulling AI coding rules...").start();
979
+ try {
980
+ const manifestRes = await fetch(`${baseUrl}/manifest.json`, {
981
+ signal: AbortSignal.timeout(1e4)
982
+ });
983
+ if (!manifestRes.ok) {
984
+ spinner.info("AI rules not available \u2014 skipping");
985
+ return;
986
+ }
987
+ const manifest = await manifestRes.json();
988
+ const generatorId = "claude-code";
989
+ const ossDefs = manifest.definitions.filter((d) => d.tier === "oss");
990
+ let written = 0;
991
+ for (const def of ossDefs) {
992
+ const paths = def.generatorPaths[generatorId] ?? [];
993
+ for (const relPath of paths) {
994
+ try {
995
+ const fileRes = await fetch(`${baseUrl}/generators/${generatorId}/${relPath}`, {
996
+ signal: AbortSignal.timeout(5e3)
997
+ });
998
+ if (!fileRes.ok) continue;
999
+ const content = await fileRes.text();
1000
+ const absolutePath = path5.join(projectPath, relPath);
1001
+ await fs5.mkdir(path5.dirname(absolutePath), { recursive: true });
1002
+ await fs5.writeFile(absolutePath, content, "utf-8");
1003
+ written++;
1004
+ } catch {
1005
+ }
1006
+ }
1007
+ }
1008
+ if (written > 0) {
1009
+ spinner.succeed(`Pulled ${written} AI coding rules`);
1010
+ } else {
1011
+ spinner.info("No AI rules pulled");
1012
+ }
1013
+ } catch {
1014
+ spinner.info("AI rules not available \u2014 skipping");
1015
+ }
1016
+ }
792
1017
  async function createProject(cfg) {
793
1018
  const { project, skipGit = false, skipInstall = false } = cfg;
794
1019
  const { projectPath, projectName, template } = project;
@@ -815,42 +1040,43 @@ async function createProject(cfg) {
815
1040
  throw err;
816
1041
  }
817
1042
  await generateReadme(projectPath, project);
818
- logger5.success("README.md generated");
1043
+ logger6.success("README.md generated");
819
1044
  if (cfg.devenv.createDevContainer) {
820
1045
  await generateDevContainer(projectPath);
821
- logger5.success(".devcontainer/ generated");
1046
+ logger6.success(".devcontainer/ generated");
822
1047
  }
823
1048
  if (cfg.devenv.createDevbox) {
824
1049
  await generateDevbox(projectPath);
825
- logger5.success("devbox.json generated");
1050
+ logger6.success("devbox.json generated");
826
1051
  }
1052
+ await pullContentRules(projectPath);
827
1053
  if (!skipInstall) {
828
1054
  const pnpmOk = await isPnpmInstalled();
829
1055
  if (!pnpmOk) {
830
- logger5.warn(
1056
+ logger6.warn(
831
1057
  "pnpm not found \u2014 skipping dependency installation. Run `pnpm install` manually."
832
1058
  );
833
1059
  } else {
834
1060
  await installDependencies(projectPath);
835
1061
  }
836
1062
  } else {
837
- logger5.info("Skipping dependency installation (--skip-install)");
1063
+ logger6.info("Skipping dependency installation (--skip-install)");
838
1064
  }
839
1065
  if (!skipGit) {
840
1066
  const gitOk = await isGitInstalled();
841
1067
  if (!gitOk) {
842
- logger5.warn("git not found \u2014 skipping repository initialisation.");
1068
+ logger6.warn("git not found \u2014 skipping repository initialisation.");
843
1069
  } else {
844
1070
  await initializeGitRepo(projectPath);
845
1071
  await createInitialCommit(projectPath);
846
1072
  }
847
1073
  } else {
848
- logger5.info("Skipping git initialisation (--skip-git)");
1074
+ logger6.info("Skipping git initialisation (--skip-git)");
849
1075
  }
850
1076
  }
851
1077
 
852
1078
  // src/commands/create-flow.ts
853
- var logger6 = createLogger6({ prefix: "@revealui/cli" });
1079
+ var logger7 = createLogger7({ prefix: "@revealui/cli" });
854
1080
  var PRO_TEMPLATES = /* @__PURE__ */ new Set([]);
855
1081
  async function checkProLicense() {
856
1082
  let key = process.env.REVEALUI_LICENSE_KEY;
@@ -863,7 +1089,7 @@ async function checkProLicense() {
863
1089
  }
864
1090
  }
865
1091
  if (!key) return false;
866
- const publicKeyPem = process.env.REVEALUI_LICENSE_PUBLIC_KEY;
1092
+ const publicKeyPem = process.env.REVEALUI_LICENSE_PUBLIC_KEY?.replace(/\\n/g, "\n");
867
1093
  if (publicKeyPem) {
868
1094
  try {
869
1095
  const publicKey = await importSPKI(publicKeyPem, "RS256");
@@ -887,76 +1113,131 @@ async function checkProLicense() {
887
1113
  return false;
888
1114
  }
889
1115
  }
890
- async function runCreateFlow(projectName, options) {
891
- logger6.info("[1/8] Validating Node.js version...");
892
- if (!validateNodeVersion()) {
893
- process.exit(1);
894
- }
895
- logger6.success(`Node.js version: ${process.version}`);
896
- logger6.info("[2/8] Configure your project");
897
- const projectConfig = await promptProjectConfig(projectName, options.template, options.yes);
898
- logger6.success(`Project: ${projectConfig.projectName}`);
899
- logger6.success(`Template: ${projectConfig.template}`);
900
- if (PRO_TEMPLATES.has(projectConfig.template)) {
901
- if (!await checkProLicense()) {
902
- logger6.error(`The "${projectConfig.template}" template requires a RevealUI Pro license.`);
903
- logger6.info("Get Pro at https://revealui.com/pricing");
904
- logger6.info("Set your license key: export REVEALUI_LICENSE_KEY=<your-key>");
905
- process.exit(2);
906
- }
907
- logger6.success("Pro license verified");
908
- }
909
- const nonInteractive = options.yes === true;
910
- logger6.info("[3/8] Configure database");
911
- const databaseConfig = nonInteractive ? { provider: "skip" } : await promptDatabaseConfig();
912
- if (databaseConfig.provider !== "skip") {
913
- logger6.success(`Database: ${databaseConfig.provider}`);
1116
+ function printBanner() {
1117
+ logger7.divider();
1118
+ logger7.info(" RevealUI \u2014 B.O.S.S.");
1119
+ logger7.info(" Build your business, not your boilerplate.");
1120
+ logger7.divider();
1121
+ logger7.info("");
1122
+ }
1123
+ function printPostCreateSummary(projectName) {
1124
+ logger7.divider();
1125
+ logger7.success("Your RevealUI project is ready!");
1126
+ logger7.info("");
1127
+ logger7.info(" Quick start:");
1128
+ logger7.info(` cd ${projectName}`);
1129
+ logger7.info(" pnpm install");
1130
+ logger7.info(" pnpm dev");
1131
+ logger7.info("");
1132
+ logger7.info(" What was created:");
1133
+ logger7.info(` ./${projectName}/ \u2014 project root`);
1134
+ logger7.info(` ./${projectName}/.env.local \u2014 environment variables (edit before pnpm dev)`);
1135
+ logger7.info(` ./${projectName}/README.md \u2014 getting started guide`);
1136
+ logger7.info("");
1137
+ logger7.info(" Helpful links:");
1138
+ logger7.info(" Docs: https://docs.revealui.com");
1139
+ logger7.info(" GitHub: https://github.com/RevealUIStudio/revealui");
1140
+ logger7.info(" Support: support@revealui.com");
1141
+ logger7.divider();
1142
+ }
1143
+ function formatCreateError(err) {
1144
+ const message = err instanceof Error ? err.message : String(err);
1145
+ const code = err instanceof Error && "code" in err ? err.code : void 0;
1146
+ logger7.error("Project creation failed.");
1147
+ logger7.info("");
1148
+ if (code === "EACCES") {
1149
+ logger7.info(" Permission denied. Try:");
1150
+ logger7.info(" - Running from a directory you own");
1151
+ logger7.info(" - Checking folder permissions with `ls -la`");
1152
+ } else if (code === "ENOENT") {
1153
+ logger7.info(" A required file or directory was not found.");
1154
+ logger7.info(" - Check that you are in the correct directory");
1155
+ logger7.info(" - Try running `revealui doctor` to diagnose your environment");
1156
+ } else if (code === "ENOSPC") {
1157
+ logger7.info(" Disk full. Free up space and try again.");
1158
+ } else if (message.includes("fetch") || message.includes("ENOTFOUND") || message.includes("ETIMEDOUT")) {
1159
+ logger7.info(" Network error. Check your internet connection and try again.");
914
1160
  } else {
915
- logger6.info("Database configuration skipped");
1161
+ logger7.info(` ${message}`);
916
1162
  }
917
- logger6.info("[4/8] Configure storage");
918
- const storageConfig = nonInteractive ? { provider: "skip" } : await promptStorageConfig();
919
- if (storageConfig.provider !== "skip") {
920
- logger6.success(`Storage: ${storageConfig.provider}`);
921
- } else {
922
- logger6.info("Storage configuration skipped");
923
- }
924
- logger6.info("[5/8] Configure payments");
925
- const paymentConfig = nonInteractive ? { enabled: false } : await promptPaymentConfig();
926
- if (paymentConfig.enabled) {
927
- logger6.success("Stripe configured");
928
- } else {
929
- logger6.info("Payments disabled");
1163
+ logger7.info("");
1164
+ logger7.info(" Troubleshooting:");
1165
+ logger7.info(" revealui doctor \u2014 diagnose your environment");
1166
+ logger7.info(" https://docs.revealui.com/docs/TROUBLESHOOTING");
1167
+ logger7.info(" support@revealui.com \u2014 we are here to help");
1168
+ logger7.divider();
1169
+ }
1170
+ async function runCreateFlow(projectName, options) {
1171
+ printBanner();
1172
+ try {
1173
+ logger7.info("[1/8] Validating Node.js version...");
1174
+ if (!validateNodeVersion()) {
1175
+ process.exit(1);
1176
+ }
1177
+ logger7.success(`Node.js version: ${process.version}`);
1178
+ logger7.info("[2/8] Configure your project");
1179
+ const projectConfig = await promptProjectConfig(projectName, options.template, options.yes);
1180
+ logger7.success(`Project: ${projectConfig.projectName}`);
1181
+ logger7.success(`Template: ${projectConfig.template}`);
1182
+ if (PRO_TEMPLATES.has(projectConfig.template)) {
1183
+ if (!await checkProLicense()) {
1184
+ logger7.error(`The "${projectConfig.template}" template requires a RevealUI Pro license.`);
1185
+ logger7.info("Get Pro at https://revealui.com/pricing");
1186
+ logger7.info("Set your license key: export REVEALUI_LICENSE_KEY=<your-key>");
1187
+ process.exit(2);
1188
+ }
1189
+ logger7.success("Pro license verified");
1190
+ }
1191
+ const nonInteractive = options.yes === true;
1192
+ logger7.info("[3/8] Configure database");
1193
+ const databaseConfig = nonInteractive ? { provider: "skip" } : await promptDatabaseConfig();
1194
+ if (databaseConfig.provider !== "skip") {
1195
+ logger7.success(`Database: ${databaseConfig.provider}`);
1196
+ } else {
1197
+ logger7.info("Database configuration skipped");
1198
+ }
1199
+ logger7.info("[4/8] Configure storage");
1200
+ const storageConfig = nonInteractive ? { provider: "skip" } : await promptStorageConfig();
1201
+ if (storageConfig.provider !== "skip") {
1202
+ logger7.success(`Storage: ${storageConfig.provider}`);
1203
+ } else {
1204
+ logger7.info("Storage configuration skipped");
1205
+ }
1206
+ logger7.info("[5/8] Configure payments");
1207
+ const paymentConfig = nonInteractive ? { enabled: false } : await promptPaymentConfig();
1208
+ if (paymentConfig.enabled) {
1209
+ logger7.success("Stripe configured");
1210
+ } else {
1211
+ logger7.info("Payments disabled");
1212
+ }
1213
+ logger7.info("[6/8] Configure development environment");
1214
+ const devEnvConfig = nonInteractive ? { createDevContainer: false, createDevbox: false } : await promptDevEnvConfig();
1215
+ logger7.success(
1216
+ `Dev Container: ${devEnvConfig.createDevContainer ? "Yes" : "No"}, Devbox: ${devEnvConfig.createDevbox ? "Yes" : "No"}`
1217
+ );
1218
+ logger7.info("[7/8] Creating project...");
1219
+ await createProject({
1220
+ project: projectConfig,
1221
+ database: databaseConfig,
1222
+ storage: storageConfig,
1223
+ payment: paymentConfig,
1224
+ devenv: devEnvConfig,
1225
+ skipGit: options.skipGit,
1226
+ skipInstall: options.skipInstall
1227
+ });
1228
+ logger7.success("Project created successfully");
1229
+ logger7.info("[8/8] Done!");
1230
+ printPostCreateSummary(projectConfig.projectName);
1231
+ } catch (err) {
1232
+ formatCreateError(err);
1233
+ process.exit(1);
930
1234
  }
931
- logger6.info("[6/8] Configure development environment");
932
- const devEnvConfig = nonInteractive ? { createDevContainer: false, createDevbox: false } : await promptDevEnvConfig();
933
- logger6.success(
934
- `Dev Container: ${devEnvConfig.createDevContainer ? "Yes" : "No"}, Devbox: ${devEnvConfig.createDevbox ? "Yes" : "No"}`
935
- );
936
- logger6.info("[7/8] Creating project...");
937
- await createProject({
938
- project: projectConfig,
939
- database: databaseConfig,
940
- storage: storageConfig,
941
- payment: paymentConfig,
942
- devenv: devEnvConfig,
943
- skipGit: options.skipGit,
944
- skipInstall: options.skipInstall
945
- });
946
- logger6.success("Project created successfully");
947
- logger6.info("[8/8] Next steps");
948
- logger6.divider();
949
- logger6.info(`cd ${projectConfig.projectName}`);
950
- logger6.info("pnpm install");
951
- logger6.info("pnpm dev");
952
- logger6.divider();
953
- logger6.success(`Project ${projectConfig.projectName} created successfully`);
954
1235
  }
955
1236
 
956
1237
  // src/commands/db.ts
957
1238
  import fs8 from "fs/promises";
958
1239
  import path8 from "path";
959
- import { createLogger as createLogger7 } from "@revealui/setup/utils";
1240
+ import { createLogger as createLogger8 } from "@revealui/setup/utils";
960
1241
  import { execa as execa4 } from "execa";
961
1242
 
962
1243
  // src/utils/command.ts
@@ -1068,7 +1349,7 @@ function findWorkspaceRoot(startDir = process.cwd()) {
1068
1349
  }
1069
1350
 
1070
1351
  // src/commands/db.ts
1071
- var logger7 = createLogger7({ prefix: "DB" });
1352
+ var logger8 = createLogger8({ prefix: "DB" });
1072
1353
  function isPgCtlNotRunningError(error) {
1073
1354
  return typeof error === "object" && error !== null && "exitCode" in error && error.exitCode === 3;
1074
1355
  }
@@ -1129,7 +1410,7 @@ async function runDbInitCommand(options = {}) {
1129
1410
  }
1130
1411
  );
1131
1412
  await writeLocalDbConfigs(pgdata);
1132
- logger7.success(`PostgreSQL initialized at ${pgdata}`);
1413
+ logger8.success(`PostgreSQL initialized at ${pgdata}`);
1133
1414
  }
1134
1415
  async function runDbStartCommand() {
1135
1416
  const root = getWorkspaceRootOrThrow();
@@ -1168,7 +1449,7 @@ async function runDbStatusCommand() {
1168
1449
  });
1169
1450
  } catch (error) {
1170
1451
  if (isPgCtlNotRunningError(error)) {
1171
- logger7.warn(`PostgreSQL is not running (PGDATA: ${pgdata})`);
1452
+ logger8.warn(`PostgreSQL is not running (PGDATA: ${pgdata})`);
1172
1453
  return;
1173
1454
  }
1174
1455
  throw error;
@@ -1212,7 +1493,7 @@ async function runDbCleanupCommand(options = {}) {
1212
1493
  }
1213
1494
 
1214
1495
  // src/commands/dev.ts
1215
- import { createLogger as createLogger10 } from "@revealui/setup/utils";
1496
+ import { createLogger as createLogger11 } from "@revealui/setup/utils";
1216
1497
  import { execa as execa6 } from "execa";
1217
1498
 
1218
1499
  // src/runtime/doctor.ts
@@ -1348,8 +1629,8 @@ function writeDevConfig(config, startDir = process.cwd()) {
1348
1629
  }
1349
1630
 
1350
1631
  // src/commands/doctor.ts
1351
- import { createLogger as createLogger8 } from "@revealui/setup/utils";
1352
- var logger8 = createLogger8({ prefix: "Doctor" });
1632
+ import { createLogger as createLogger9 } from "@revealui/setup/utils";
1633
+ var logger9 = createLogger9({ prefix: "Doctor" });
1353
1634
  function getDoctorFixPlan(report) {
1354
1635
  const attempted = [];
1355
1636
  const skipped = [];
@@ -1407,7 +1688,7 @@ async function runDoctorCommand(options = {}) {
1407
1688
  `);
1408
1689
  if (options.fix) {
1409
1690
  if (fixPlan.attempted.length === 0) {
1410
- logger8.warn("No safe automatic fixes available");
1691
+ logger9.warn("No safe automatic fixes available");
1411
1692
  } else {
1412
1693
  await applyDoctorFixes(report);
1413
1694
  report = await gatherDoctorReport();
@@ -1416,7 +1697,7 @@ async function runDoctorCommand(options = {}) {
1416
1697
  }
1417
1698
  }
1418
1699
  if (report.checks.some((check) => !check.ok)) {
1419
- logger8.warn("Some checks failed");
1700
+ logger9.warn("Some checks failed");
1420
1701
  if (options.strict || options.json || process.env.CI) {
1421
1702
  process.exitCode = 1;
1422
1703
  }
@@ -1424,9 +1705,9 @@ async function runDoctorCommand(options = {}) {
1424
1705
  }
1425
1706
 
1426
1707
  // src/commands/shell.ts
1427
- import { createLogger as createLogger9 } from "@revealui/setup/utils";
1708
+ import { createLogger as createLogger10 } from "@revealui/setup/utils";
1428
1709
  import { execa as execa5 } from "execa";
1429
- var logger9 = createLogger9({ prefix: "Shell" });
1710
+ var logger10 = createLogger10({ prefix: "Shell" });
1430
1711
  async function runShellCommand(options = {}) {
1431
1712
  if (!(options.inside || process.env.IN_NIX_SHELL) && await commandExists("nix")) {
1432
1713
  const workspaceRoot = findWorkspaceRoot();
@@ -1471,12 +1752,12 @@ async function runShellCommand(options = {}) {
1471
1752
  }
1472
1753
  process.stdout.write(`${formatDoctorReport(freshReport)}
1473
1754
  `);
1474
- logger9.info("Use `revealui doctor --json` for machine-readable status.");
1755
+ logger10.info("Use `revealui doctor --json` for machine-readable status.");
1475
1756
  return false;
1476
1757
  }
1477
1758
 
1478
1759
  // src/commands/dev.ts
1479
- var logger10 = createLogger10({ prefix: "Dev" });
1760
+ var logger11 = createLogger11({ prefix: "Dev" });
1480
1761
  var DEV_PROFILES = {
1481
1762
  local: {},
1482
1763
  agent: {
@@ -1602,20 +1883,20 @@ async function runDevUpCommand(options = {}) {
1602
1883
  process.stdout.write(`${formatDevActions(plan)}
1603
1884
  `);
1604
1885
  if (plan.dryRun) {
1605
- logger10.info("Dry run only; no migrations or services were started.");
1886
+ logger11.info("Dry run only; no migrations or services were started.");
1606
1887
  return;
1607
1888
  }
1608
1889
  if (options.fix) {
1609
1890
  await runDoctorCommand({ fix: true });
1610
1891
  }
1611
1892
  await runDbMigrateCommand();
1612
- logger10.success("Database migration complete");
1893
+ logger11.success("Database migration complete");
1613
1894
  if (shouldIncludeMcp(resolved.include)) {
1614
1895
  const workspaceRoot = findWorkspaceRoot();
1615
1896
  if (!workspaceRoot) {
1616
1897
  throw new Error("RevealUI workspace root not found");
1617
1898
  }
1618
- logger10.info("Validating MCP setup");
1899
+ logger11.info("Validating MCP setup");
1619
1900
  await execa6("pnpm", ["setup:mcp"], {
1620
1901
  cwd: workspaceRoot,
1621
1902
  stdio: "inherit"
@@ -1626,7 +1907,7 @@ async function runDevUpCommand(options = {}) {
1626
1907
  if (!workspaceRoot) {
1627
1908
  throw new Error("RevealUI workspace root not found");
1628
1909
  }
1629
- logger10.info(`Starting dev script: ${resolved.script}`);
1910
+ logger11.info(`Starting dev script: ${resolved.script}`);
1630
1911
  await execa6("pnpm", [resolved.script], {
1631
1912
  cwd: workspaceRoot,
1632
1913
  stdio: "inherit"
@@ -1684,7 +1965,7 @@ async function runDevProfileSetCommand(profile) {
1684
1965
  );
1685
1966
  }
1686
1967
  const configPath = writeDevConfig({ defaultProfile: profile });
1687
- logger10.success(`Default dev profile set to "${profile}" in ${configPath}`);
1968
+ logger11.success(`Default dev profile set to "${profile}" in ${configPath}`);
1688
1969
  }
1689
1970
  async function runDevProfileShowCommand(options = {}) {
1690
1971
  const configuredProfile = getConfiguredProfile() ?? null;
@@ -1698,10 +1979,10 @@ async function runDevProfileShowCommand(options = {}) {
1698
1979
  }
1699
1980
 
1700
1981
  // src/cli.ts
1701
- var logger11 = createLogger11({ prefix: "CLI" });
1982
+ var logger12 = createLogger12({ prefix: "CLI" });
1702
1983
  function configureCreateCommand(command, legacyName) {
1703
1984
  command.description("Create a new RevealUI project").argument("[project-name]", "Name of the project").option("-t, --template <name>", "Template to use (basic-blog, e-commerce, portfolio)").option("--skip-git", "Skip git initialization", false).option("--skip-install", "Skip dependency installation", false).option("-y, --yes", "Skip all prompts and use defaults", false).action(async (projectName, options) => {
1704
- logger11.header(legacyName ? "Create RevealUI Project" : "RevealUI Create");
1985
+ logger12.header(legacyName ? "Create RevealUI Project" : "RevealUI Create");
1705
1986
  await runCreateFlow(projectName, options);
1706
1987
  });
1707
1988
  return command;
@@ -1713,6 +1994,17 @@ function createCli() {
1713
1994
  program.command("doctor").description("Check RevealUI workspace and developer environment health").option("--json", "Output machine-readable JSON", false).option("--fix", "Apply safe automatic fixes when possible", false).option("--strict", "Exit nonzero when checks fail", false).action(async (options) => {
1714
1995
  await runDoctorCommand(options);
1715
1996
  });
1997
+ const agent = program.command("agent").description("RevealUI coding agent (powered by local or cloud LLMs)");
1998
+ agent.option("-p, --prompt <text>", "Run a single prompt in headless mode").action(async (options) => {
1999
+ if (options.prompt) {
2000
+ await runAgentHeadlessCommand(options.prompt);
2001
+ } else {
2002
+ await runAgentReplCommand();
2003
+ }
2004
+ });
2005
+ agent.command("status").description("Show agent status: model, provider, project root").action(async () => {
2006
+ await runAgentStatusCommand();
2007
+ });
1716
2008
  const db = program.command("db").description("Manage the local RevealUI database");
1717
2009
  db.command("init").description("Initialize the local PostgreSQL data directory").option("--force", "Delete and recreate the local data directory", false).action(async (options) => {
1718
2010
  await runDbInitCommand(options);