helix-lang 11.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +168 -0
  2. package/dist/architect.d.ts +14 -0
  3. package/dist/architect.d.ts.map +1 -0
  4. package/dist/architect.js +127 -0
  5. package/dist/architect.js.map +1 -0
  6. package/dist/bin/helix.d.ts +20 -0
  7. package/dist/bin/helix.d.ts.map +1 -0
  8. package/dist/bin/helix.js +921 -0
  9. package/dist/bin/helix.js.map +1 -0
  10. package/dist/commands/collaborate/index.d.ts +2 -0
  11. package/dist/commands/collaborate/index.d.ts.map +1 -0
  12. package/dist/commands/collaborate/index.js +129 -0
  13. package/dist/commands/collaborate/index.js.map +1 -0
  14. package/dist/commands/collaborate/server.d.ts +31 -0
  15. package/dist/commands/collaborate/server.d.ts.map +1 -0
  16. package/dist/commands/collaborate/server.js +159 -0
  17. package/dist/commands/collaborate/server.js.map +1 -0
  18. package/dist/commands/deploy/index.d.ts +25 -0
  19. package/dist/commands/deploy/index.d.ts.map +1 -0
  20. package/dist/commands/deploy/index.js +130 -0
  21. package/dist/commands/deploy/index.js.map +1 -0
  22. package/dist/commands/deploy/platforms/fly.d.ts +9 -0
  23. package/dist/commands/deploy/platforms/fly.d.ts.map +1 -0
  24. package/dist/commands/deploy/platforms/fly.js +68 -0
  25. package/dist/commands/deploy/platforms/fly.js.map +1 -0
  26. package/dist/commands/deploy/platforms/railway.d.ts +9 -0
  27. package/dist/commands/deploy/platforms/railway.d.ts.map +1 -0
  28. package/dist/commands/deploy/platforms/railway.js +115 -0
  29. package/dist/commands/deploy/platforms/railway.js.map +1 -0
  30. package/dist/commands/deploy/platforms/vercel.d.ts +10 -0
  31. package/dist/commands/deploy/platforms/vercel.d.ts.map +1 -0
  32. package/dist/commands/deploy/platforms/vercel.js +126 -0
  33. package/dist/commands/deploy/platforms/vercel.js.map +1 -0
  34. package/dist/commands/deploy.d.ts +6 -0
  35. package/dist/commands/deploy.d.ts.map +1 -0
  36. package/dist/commands/deploy.js +56 -0
  37. package/dist/commands/deploy.js.map +1 -0
  38. package/dist/commands/evolve/analyzers/performance.d.ts +13 -0
  39. package/dist/commands/evolve/analyzers/performance.d.ts.map +1 -0
  40. package/dist/commands/evolve/analyzers/performance.js +591 -0
  41. package/dist/commands/evolve/analyzers/performance.js.map +1 -0
  42. package/dist/commands/evolve/analyzers/security.d.ts +21 -0
  43. package/dist/commands/evolve/analyzers/security.d.ts.map +1 -0
  44. package/dist/commands/evolve/analyzers/security.js +280 -0
  45. package/dist/commands/evolve/analyzers/security.js.map +1 -0
  46. package/dist/commands/evolve/index.d.ts +2 -0
  47. package/dist/commands/evolve/index.d.ts.map +1 -0
  48. package/dist/commands/evolve/index.js +122 -0
  49. package/dist/commands/evolve/index.js.map +1 -0
  50. package/dist/commands/generate.d.ts +6 -0
  51. package/dist/commands/generate.d.ts.map +1 -0
  52. package/dist/commands/generate.js +277 -0
  53. package/dist/commands/generate.js.map +1 -0
  54. package/dist/commands/install.d.ts +2 -0
  55. package/dist/commands/install.d.ts.map +1 -0
  56. package/dist/commands/install.js +176 -0
  57. package/dist/commands/install.js.map +1 -0
  58. package/dist/commands/library/index.d.ts +27 -0
  59. package/dist/commands/library/index.d.ts.map +1 -0
  60. package/dist/commands/library/index.js +126 -0
  61. package/dist/commands/library/index.js.map +1 -0
  62. package/dist/commands/migrate.d.ts +5 -0
  63. package/dist/commands/migrate.d.ts.map +1 -0
  64. package/dist/commands/migrate.js +258 -0
  65. package/dist/commands/migrate.js.map +1 -0
  66. package/dist/commands/new.d.ts +6 -0
  67. package/dist/commands/new.d.ts.map +1 -0
  68. package/dist/commands/new.js +195 -0
  69. package/dist/commands/new.js.map +1 -0
  70. package/dist/commands/preflight.d.ts +20 -0
  71. package/dist/commands/preflight.d.ts.map +1 -0
  72. package/dist/commands/preflight.js +182 -0
  73. package/dist/commands/preflight.js.map +1 -0
  74. package/dist/commands/preview.d.ts +13 -0
  75. package/dist/commands/preview.d.ts.map +1 -0
  76. package/dist/commands/preview.js +260 -0
  77. package/dist/commands/preview.js.map +1 -0
  78. package/dist/commands/run.d.ts +6 -0
  79. package/dist/commands/run.d.ts.map +1 -0
  80. package/dist/commands/run.js +96 -0
  81. package/dist/commands/run.js.map +1 -0
  82. package/dist/commands/spawn.d.ts +11 -0
  83. package/dist/commands/spawn.d.ts.map +1 -0
  84. package/dist/commands/spawn.js +916 -0
  85. package/dist/commands/spawn.js.map +1 -0
  86. package/dist/compiler.d.ts +12 -0
  87. package/dist/compiler.d.ts.map +1 -0
  88. package/dist/compiler.js +92 -0
  89. package/dist/compiler.js.map +1 -0
  90. package/dist/core/file-writer.d.ts +36 -0
  91. package/dist/core/file-writer.d.ts.map +1 -0
  92. package/dist/core/file-writer.js +268 -0
  93. package/dist/core/file-writer.js.map +1 -0
  94. package/dist/core/registry.d.ts +57 -0
  95. package/dist/core/registry.d.ts.map +1 -0
  96. package/dist/core/registry.js +222 -0
  97. package/dist/core/registry.js.map +1 -0
  98. package/dist/core/self-healing.d.ts +47 -0
  99. package/dist/core/self-healing.d.ts.map +1 -0
  100. package/dist/core/self-healing.js +250 -0
  101. package/dist/core/self-healing.js.map +1 -0
  102. package/dist/core/types.d.ts +126 -0
  103. package/dist/core/types.d.ts.map +1 -0
  104. package/dist/core/types.js +7 -0
  105. package/dist/core/types.js.map +1 -0
  106. package/dist/generators/databases/mongodb.d.ts +10 -0
  107. package/dist/generators/databases/mongodb.d.ts.map +1 -0
  108. package/dist/generators/databases/mongodb.js +83 -0
  109. package/dist/generators/databases/mongodb.js.map +1 -0
  110. package/dist/generators/databases/redis.d.ts +2 -0
  111. package/dist/generators/databases/redis.d.ts.map +1 -0
  112. package/dist/generators/databases/redis.js +140 -0
  113. package/dist/generators/databases/redis.js.map +1 -0
  114. package/dist/generators/flutter.d.ts +32 -0
  115. package/dist/generators/flutter.d.ts.map +1 -0
  116. package/dist/generators/flutter.js +628 -0
  117. package/dist/generators/flutter.js.map +1 -0
  118. package/dist/openrouter.d.ts +68 -0
  119. package/dist/openrouter.d.ts.map +1 -0
  120. package/dist/openrouter.js +241 -0
  121. package/dist/openrouter.js.map +1 -0
  122. package/dist/page-generator.d.ts +22 -0
  123. package/dist/page-generator.d.ts.map +1 -0
  124. package/dist/page-generator.js +192 -0
  125. package/dist/page-generator.js.map +1 -0
  126. package/dist/parser.d.ts +76 -0
  127. package/dist/parser.d.ts.map +1 -0
  128. package/dist/parser.js +691 -0
  129. package/dist/parser.js.map +1 -0
  130. package/dist/prompts/master-architect.d.ts +9 -0
  131. package/dist/prompts/master-architect.d.ts.map +1 -0
  132. package/dist/prompts/master-architect.js +150 -0
  133. package/dist/prompts/master-architect.js.map +1 -0
  134. package/dist/researcher.d.ts +12 -0
  135. package/dist/researcher.d.ts.map +1 -0
  136. package/dist/researcher.js +85 -0
  137. package/dist/researcher.js.map +1 -0
  138. package/dist/self-heal.d.ts +29 -0
  139. package/dist/self-heal.d.ts.map +1 -0
  140. package/dist/self-heal.js +260 -0
  141. package/dist/self-heal.js.map +1 -0
  142. package/dist/services/SupabaseDeployer.d.ts +9 -0
  143. package/dist/services/SupabaseDeployer.d.ts.map +1 -0
  144. package/dist/services/SupabaseDeployer.js +50 -0
  145. package/dist/services/SupabaseDeployer.js.map +1 -0
  146. package/dist/test-generator.d.ts +18 -0
  147. package/dist/test-generator.d.ts.map +1 -0
  148. package/dist/test-generator.js +180 -0
  149. package/dist/test-generator.js.map +1 -0
  150. package/dist/themes/index.d.ts +52 -0
  151. package/dist/themes/index.d.ts.map +1 -0
  152. package/dist/themes/index.js +273 -0
  153. package/dist/themes/index.js.map +1 -0
  154. package/dist/types.d.ts +9 -0
  155. package/dist/types.d.ts.map +1 -0
  156. package/dist/types.js +81 -0
  157. package/dist/types.js.map +1 -0
  158. package/dist/utils/constitutional-validator.d.ts +73 -0
  159. package/dist/utils/constitutional-validator.d.ts.map +1 -0
  160. package/dist/utils/constitutional-validator.js +249 -0
  161. package/dist/utils/constitutional-validator.js.map +1 -0
  162. package/library/auth-flow/app/api/auth/[...nextauth]/route.ts +31 -0
  163. package/library/auth-flow/app/api/auth/login/route.ts +90 -0
  164. package/library/auth-flow/app/api/auth/register/route.ts +91 -0
  165. package/library/auth-flow/components/auth/AuthMiddleware.tsx +139 -0
  166. package/library/auth-flow/components/auth/LoginForm.tsx +125 -0
  167. package/library/auth-flow/components/auth/RegisterForm.tsx +168 -0
  168. package/library/auth-flow/components/auth/nextauth-config.ts +99 -0
  169. package/library/auth-flow/manifest.json +29 -0
  170. package/library/auth-flow/schema.prisma +45 -0
  171. package/library/dashboard-analytics/components/dashboard/ActivityFeed.tsx +109 -0
  172. package/library/dashboard-analytics/components/dashboard/LineChart.tsx +180 -0
  173. package/library/dashboard-analytics/components/dashboard/StatsCard.tsx +47 -0
  174. package/library/dashboard-analytics/components/dashboard/SummaryGrid.tsx +39 -0
  175. package/library/dashboard-analytics/manifest.json +19 -0
  176. package/library/data-table/components/table/BulkActions.tsx +59 -0
  177. package/library/data-table/components/table/ColumnToggle.tsx +65 -0
  178. package/library/data-table/components/table/DataTable.tsx +318 -0
  179. package/library/data-table/components/table/ExportCSV.tsx +52 -0
  180. package/library/data-table/components/table/SearchFilter.tsx +48 -0
  181. package/library/data-table/manifest.json +20 -0
  182. package/library/file-upload/app/api/upload/route.ts +107 -0
  183. package/library/file-upload/components/upload/DropZone.tsx +268 -0
  184. package/library/file-upload/components/upload/FilePreview.tsx +82 -0
  185. package/library/file-upload/components/upload/UploadProgress.tsx +92 -0
  186. package/library/file-upload/components/upload/fileStorage.ts +142 -0
  187. package/library/file-upload/manifest.json +21 -0
  188. package/library/notification-system/app/api/notifications/route.ts +121 -0
  189. package/library/notification-system/components/notifications/NotificationBell.tsx +154 -0
  190. package/library/notification-system/components/notifications/NotificationProvider.tsx +161 -0
  191. package/library/notification-system/components/notifications/Toast.tsx +112 -0
  192. package/library/notification-system/manifest.json +20 -0
  193. package/package.json +66 -0
@@ -0,0 +1,921 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Helix CLI v11.0 - Complete Development Platform
5
+ * AI-Native Programming Language with Full-Stack Generation
6
+ *
7
+ * Commands:
8
+ * spawn <prompt> - ONE-SHOT: Full app from natural language
9
+ * new <project> - Scaffold a new Helix project
10
+ * generate <blueprint> - Generate Prisma + API + UI from .helix
11
+ * run - Start the dev server
12
+ * preview - Hot-reload preview with file watching
13
+ * deploy - One-command deployment
14
+ * research <topic> - Generate domain research
15
+ * draft <idea> - Create a .helix blueprint
16
+ * build <file> - Compile .helix to React component
17
+ * plugins - List registered generator plugins
18
+ * models - List available AI models
19
+ */
20
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ var desc = Object.getOwnPropertyDescriptor(m, k);
23
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
24
+ desc = { enumerable: true, get: function() { return m[k]; } };
25
+ }
26
+ Object.defineProperty(o, k2, desc);
27
+ }) : (function(o, m, k, k2) {
28
+ if (k2 === undefined) k2 = k;
29
+ o[k2] = m[k];
30
+ }));
31
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
32
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
33
+ }) : function(o, v) {
34
+ o["default"] = v;
35
+ });
36
+ var __importStar = (this && this.__importStar) || (function () {
37
+ var ownKeys = function(o) {
38
+ ownKeys = Object.getOwnPropertyNames || function (o) {
39
+ var ar = [];
40
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
41
+ return ar;
42
+ };
43
+ return ownKeys(o);
44
+ };
45
+ return function (mod) {
46
+ if (mod && mod.__esModule) return mod;
47
+ var result = {};
48
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
49
+ __setModuleDefault(result, mod);
50
+ return result;
51
+ };
52
+ })();
53
+ var __importDefault = (this && this.__importDefault) || function (mod) {
54
+ return (mod && mod.__esModule) ? mod : { "default": mod };
55
+ };
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ const commander_1 = require("commander");
58
+ const chalk_1 = __importDefault(require("chalk"));
59
+ const dotenv = __importStar(require("dotenv"));
60
+ const fs = __importStar(require("fs"));
61
+ const path = __importStar(require("path"));
62
+ // Load environment variables
63
+ dotenv.config();
64
+ // Import core modules
65
+ const researcher_1 = require("../researcher");
66
+ const architect_1 = require("../architect");
67
+ const compiler_1 = require("../compiler");
68
+ const openrouter_1 = require("../openrouter");
69
+ // Import v11.0 command modules
70
+ const new_1 = require("../commands/new");
71
+ const generate_1 = require("../commands/generate");
72
+ const run_1 = require("../commands/run");
73
+ // Import v11.0 command modules (spawn & flutter)
74
+ const spawn_1 = require("../commands/spawn");
75
+ const flutter_1 = require("../generators/flutter");
76
+ // Import v11.0 command modules (deploy & platform)
77
+ const deploy_1 = require("../commands/deploy");
78
+ const preview_1 = require("../commands/preview");
79
+ const registry_1 = require("../core/registry");
80
+ const evolve_1 = require("../commands/evolve");
81
+ // ASCII Art Banner
82
+ const banner = `
83
+ ${chalk_1.default.cyan("╦ ╦╔═╗╦ ╦═╗ ╦")}
84
+ ${chalk_1.default.cyan("╠═╣║╣ ║ ║╔╩╦╝")}
85
+ ${chalk_1.default.cyan("╩ ╩╚═╝╩═╝╩╩ ╚═")} ${chalk_1.default.magenta("v11.0")}
86
+ ${chalk_1.default.gray("AI-Native Development Platform")}
87
+ ${chalk_1.default.gray("Generate • Preview • Deploy • Evolve")}
88
+ `;
89
+ const program = new commander_1.Command();
90
+ program
91
+ .name("helix")
92
+ .description("Helix - AI-Native Development Platform")
93
+ .version("11.0.0")
94
+ .addHelpText("before", banner);
95
+ // ============================================================================
96
+ // V4.0 COMMAND: One-Shot Spawn
97
+ // ============================================================================
98
+ program
99
+ .command("spawn <prompt>")
100
+ .description("One-shot generation: Full app from natural language")
101
+ .option("-t, --target <platform>", "Target: 'web' (Next.js) or 'flutter'", "web")
102
+ .option("-d, --db <database>", "Database: 'postgres', 'mongodb', 'redis', or comma-separated")
103
+ .option("--theme <theme>", "UI theme: glassmorphism, professional, minimal, vibrant", "glassmorphism")
104
+ .option("--ai-context", "Enable AI context layer with Redis")
105
+ .option("--cache", "Add Redis caching layer")
106
+ .option("--no-constitution", "Bypass constitutional validation")
107
+ .option("--components <ids>", "Helix Library component IDs (comma-separated)")
108
+ .option("--constitution <file>", "Path to constitution.md file")
109
+ .option("--ai <provider>", "AI provider (for Flutter): 'openrouter'")
110
+ .option("--dry-run", "Show what would be generated without creating files")
111
+ .action(async (prompt, options) => {
112
+ console.log(banner);
113
+ // Build spawn options
114
+ const spawnOptions = {
115
+ target: options.target,
116
+ db: options.db,
117
+ theme: options.theme,
118
+ aiContext: options.aiContext,
119
+ cache: options.cache,
120
+ noConstitution: options.noConstitution,
121
+ components: options.components ? options.components.split(',') : [],
122
+ dryRun: options.dryRun || false,
123
+ };
124
+ // Dry run mode - show what would happen
125
+ if (options.dryRun) {
126
+ console.log(chalk_1.default.yellow("🔍 DRY RUN MODE — No files will be created\n"));
127
+ console.log(chalk_1.default.white(" Configuration:"));
128
+ console.log(chalk_1.default.gray(` Target: ${options.target}`));
129
+ console.log(chalk_1.default.gray(` Theme: ${options.theme}`));
130
+ console.log(chalk_1.default.gray(` Database: ${options.db || 'sqlite (default)'}`));
131
+ console.log(chalk_1.default.gray(` Constitution: ${options.noConstitution ? 'disabled' : 'enabled'}`));
132
+ console.log(chalk_1.default.gray(` Components: ${spawnOptions.components.length > 0 ? spawnOptions.components.join(', ') : 'none'}`));
133
+ console.log(chalk_1.default.gray(` AI Context: ${options.aiContext ? 'yes' : 'no'}`));
134
+ console.log(chalk_1.default.gray(` Cache: ${options.cache ? 'yes' : 'no'}`));
135
+ console.log(chalk_1.default.white("\n Would generate:"));
136
+ console.log(chalk_1.default.gray(" • Next.js project scaffold"));
137
+ console.log(chalk_1.default.gray(" • AI-generated .helix blueprint from prompt"));
138
+ console.log(chalk_1.default.gray(" • Prisma schema + SQLite database"));
139
+ console.log(chalk_1.default.gray(" • API routes with validation, rate limiting, pagination"));
140
+ console.log(chalk_1.default.gray(" • React UI pages with theme applied"));
141
+ console.log(chalk_1.default.gray(" • globals.css with theme CSS"));
142
+ console.log(chalk_1.default.yellow("\n Run without --dry-run to generate the app."));
143
+ return;
144
+ }
145
+ // Load constitution if specified
146
+ let constitutionContent;
147
+ let constitutionSource = null;
148
+ if (options.constitution) {
149
+ // Priority 1: Explicit --constitution flag
150
+ const userConstitutionPath = path.isAbsolute(options.constitution)
151
+ ? options.constitution
152
+ : path.join(process.cwd(), options.constitution);
153
+ if (fs.existsSync(userConstitutionPath)) {
154
+ constitutionContent = fs.readFileSync(userConstitutionPath, "utf-8");
155
+ constitutionSource = path.basename(userConstitutionPath);
156
+ }
157
+ else {
158
+ console.error(chalk_1.default.red(`❌ Constitution file not found: ${options.constitution}`));
159
+ process.exit(1);
160
+ }
161
+ }
162
+ else {
163
+ // Priority 2: Auto-detect constitution.md in current directory
164
+ const defaultConstitution = path.join(process.cwd(), "constitution.md");
165
+ if (fs.existsSync(defaultConstitution)) {
166
+ constitutionContent = fs.readFileSync(defaultConstitution, "utf-8");
167
+ constitutionSource = "constitution.md";
168
+ }
169
+ }
170
+ // Log if constitution is loaded
171
+ if (constitutionSource) {
172
+ console.log(chalk_1.default.yellow(`⚖️ Constitution Loaded: ${constitutionSource}`));
173
+ }
174
+ // Check API key for ALL targets (web uses OpenRouter for blueprint generation)
175
+ if (!process.env.OPENROUTER_API_KEY) {
176
+ console.error(chalk_1.default.red("❌ OPENROUTER_API_KEY not found in environment"));
177
+ console.error(chalk_1.default.gray(" Set it in .env or export OPENROUTER_API_KEY=sk-or-v1-..."));
178
+ process.exit(1);
179
+ }
180
+ // Route to appropriate generator based on target
181
+ if (options.target === "flutter") {
182
+ console.log(chalk_1.default.magenta("📱 Target: Flutter Mobile App"));
183
+ if (options.db === "supabase") {
184
+ console.log(chalk_1.default.blue("☁️ Database: Supabase Cloud (Realtime)"));
185
+ }
186
+ else {
187
+ console.log(chalk_1.default.gray("💾 Database: Local (In-Memory)"));
188
+ }
189
+ if (options.ai === "openrouter") {
190
+ console.log(chalk_1.default.green("🤖 AI: OpenRouter (Cloud Intelligence)"));
191
+ }
192
+ await (0, flutter_1.generateFlutterApp)(prompt, constitutionContent, options.db, options.ai);
193
+ }
194
+ else {
195
+ console.log(chalk_1.default.cyan("🌐 Target: Next.js Web App"));
196
+ await (0, spawn_1.spawnApp)(prompt, spawnOptions, constitutionContent);
197
+ }
198
+ });
199
+ // ============================================================================
200
+ // V3.0 COMMANDS: Full-Stack Generation
201
+ // ============================================================================
202
+ program
203
+ .command("new <project-name>")
204
+ .description("Scaffold a new Helix project (Next.js + Prisma + Tailwind)")
205
+ .action(async (projectName) => {
206
+ console.log(banner);
207
+ await (0, new_1.createProject)(projectName);
208
+ });
209
+ program
210
+ .command("generate [blueprint]")
211
+ .alias("gen")
212
+ .description("Generate full stack from .helix blueprint or prompt")
213
+ .option("-t, --target <platform>", "Target platform: 'web' (Next.js) or 'flutter' (Mobile)", "web")
214
+ .option("-p, --prompt <text>", "Direct prompt for generation (Flutter only)")
215
+ .action(async (blueprint, options) => {
216
+ console.log(banner);
217
+ // Route to appropriate generator based on target
218
+ if (options.target === "flutter") {
219
+ console.log(chalk_1.default.magenta("📱 Target: Flutter Mobile App"));
220
+ let generationPrompt;
221
+ // Priority 1: Direct --prompt flag
222
+ if (options.prompt) {
223
+ generationPrompt = options.prompt;
224
+ console.log(chalk_1.default.yellow("📝 Using direct prompt"));
225
+ }
226
+ // Priority 2: Blueprint file
227
+ else if (blueprint) {
228
+ const blueprintPath = path.resolve(process.cwd(), blueprint);
229
+ if (!fs.existsSync(blueprintPath)) {
230
+ console.error(chalk_1.default.red(`❌ Blueprint file not found: ${blueprint}`));
231
+ process.exit(1);
232
+ }
233
+ const blueprintContent = fs.readFileSync(blueprintPath, "utf-8");
234
+ generationPrompt = `Generate from this .helix blueprint:\n\n${blueprintContent}`;
235
+ console.log(chalk_1.default.yellow(`📄 Using blueprint: ${blueprint}`));
236
+ }
237
+ // No input provided
238
+ else {
239
+ console.error(chalk_1.default.red("❌ Please provide a blueprint file or use --prompt"));
240
+ console.log(chalk_1.default.gray(" helix generate blueprint.helix --target flutter"));
241
+ console.log(chalk_1.default.gray(' helix generate --target flutter --prompt "A task app with..."'));
242
+ process.exit(1);
243
+ }
244
+ await (0, flutter_1.regenerateFlutterDart)(generationPrompt);
245
+ }
246
+ else {
247
+ // Web target requires a blueprint file
248
+ if (!blueprint) {
249
+ console.error(chalk_1.default.red("❌ Please provide a blueprint file for web generation"));
250
+ console.log(chalk_1.default.gray(" helix generate blueprint.helix"));
251
+ process.exit(1);
252
+ }
253
+ console.log(chalk_1.default.cyan("🌐 Target: Next.js Web App"));
254
+ await (0, generate_1.generateStack)(blueprint);
255
+ }
256
+ });
257
+ program
258
+ .command("run")
259
+ .description("Start the dev server and open browser")
260
+ .action(async () => {
261
+ console.log(banner);
262
+ await (0, run_1.runDevServer)();
263
+ });
264
+ // ============================================================================
265
+ // RESEARCH COMMAND
266
+ // ============================================================================
267
+ program
268
+ .command("research <topic>")
269
+ .description("Conduct deep domain research and generate context file")
270
+ .option("-m, --model <model>", "AI model to use")
271
+ .action(async (topic, options) => {
272
+ console.log(banner);
273
+ if (!process.env.OPENROUTER_API_KEY) {
274
+ console.error(chalk_1.default.red("❌ OPENROUTER_API_KEY not found in environment"));
275
+ process.exit(1);
276
+ }
277
+ const model = options.model || openrouter_1.RESEARCH_MODEL;
278
+ console.log(chalk_1.default.yellow(`💰 Using research-optimized model: ${model}`));
279
+ try {
280
+ await (0, researcher_1.conductResearch)(topic, model);
281
+ }
282
+ catch (error) {
283
+ process.exit(1);
284
+ }
285
+ });
286
+ // ============================================================================
287
+ // DRAFT COMMAND
288
+ // ============================================================================
289
+ program
290
+ .command("draft <idea>")
291
+ .description("Draft a .helix blueprint from a user idea")
292
+ .option("-c, --context <file>", "Path to context/research file")
293
+ .option("-m, --model <model>", "AI model to use")
294
+ .action(async (idea, options) => {
295
+ console.log(banner);
296
+ if (!process.env.OPENROUTER_API_KEY) {
297
+ console.error(chalk_1.default.red("❌ OPENROUTER_API_KEY not found in environment"));
298
+ process.exit(1);
299
+ }
300
+ const model = options.model || openrouter_1.DEFAULT_MODEL;
301
+ try {
302
+ let contextFile = options.context;
303
+ if (!contextFile) {
304
+ const defaultContext = path.join(process.cwd(), "research.md");
305
+ if (fs.existsSync(defaultContext)) {
306
+ contextFile = defaultContext;
307
+ console.log(chalk_1.default.yellow(`📎 Auto-using context: research.md`));
308
+ }
309
+ }
310
+ await (0, architect_1.draftBlueprint)(idea, contextFile, model);
311
+ }
312
+ catch (error) {
313
+ process.exit(1);
314
+ }
315
+ });
316
+ // ============================================================================
317
+ // BUILD COMMAND
318
+ // ============================================================================
319
+ program
320
+ .command("build <file>")
321
+ .description("Compile a .helix blueprint to React/Next.js component")
322
+ .option("-m, --model <model>", "AI model to use")
323
+ .action(async (file, options) => {
324
+ console.log(banner);
325
+ if (!process.env.OPENROUTER_API_KEY) {
326
+ console.error(chalk_1.default.red("❌ OPENROUTER_API_KEY not found in environment"));
327
+ process.exit(1);
328
+ }
329
+ const model = options.model || openrouter_1.DEFAULT_MODEL;
330
+ if (!file.endsWith(".helix")) {
331
+ console.error(chalk_1.default.red(`❌ Invalid file type. Expected .helix file`));
332
+ process.exit(1);
333
+ }
334
+ try {
335
+ await (0, compiler_1.compileToReact)(file, model);
336
+ }
337
+ catch (error) {
338
+ process.exit(1);
339
+ }
340
+ });
341
+ // ============================================================================
342
+ // PIPELINE COMMAND
343
+ // ============================================================================
344
+ program
345
+ .command("pipeline <topic> <idea>")
346
+ .description("Run full AI pipeline: research -> draft -> build")
347
+ .option("-m, --model <model>", "AI model for draft/build")
348
+ .action(async (topic, idea, options) => {
349
+ console.log(banner);
350
+ console.log(chalk_1.default.magenta("\n🚀 Starting Helix Pipeline...\n"));
351
+ if (!process.env.OPENROUTER_API_KEY) {
352
+ console.error(chalk_1.default.red("❌ OPENROUTER_API_KEY not found"));
353
+ process.exit(1);
354
+ }
355
+ const draftModel = options.model || openrouter_1.DEFAULT_MODEL;
356
+ try {
357
+ console.log(chalk_1.default.magenta("━━━ STEP 1: RESEARCH ━━━"));
358
+ await (0, researcher_1.conductResearch)(topic, openrouter_1.RESEARCH_MODEL);
359
+ console.log(chalk_1.default.magenta("\n━━━ STEP 2: DRAFT ━━━"));
360
+ const contextFile = path.join(process.cwd(), "research.md");
361
+ const helixFile = await (0, architect_1.draftBlueprint)(idea, contextFile, draftModel);
362
+ console.log(chalk_1.default.magenta("\n━━━ STEP 3: BUILD ━━━"));
363
+ await (0, compiler_1.compileToReact)(helixFile, draftModel);
364
+ console.log(chalk_1.default.green("\n🎉 Pipeline complete!"));
365
+ }
366
+ catch (error) {
367
+ console.error(chalk_1.default.red("\n❌ Pipeline failed"));
368
+ process.exit(1);
369
+ }
370
+ });
371
+ // ============================================================================
372
+ // MODELS COMMAND
373
+ // ============================================================================
374
+ program
375
+ .command("models")
376
+ .description("List available AI models and current defaults")
377
+ .action(() => {
378
+ console.log(banner);
379
+ console.log(chalk_1.default.cyan("\n⚙️ Current Configuration:\n"));
380
+ console.log(` ${chalk_1.default.gray("Default Model:")} ${chalk_1.default.green(openrouter_1.DEFAULT_MODEL)}`);
381
+ console.log(` ${chalk_1.default.gray("Research Model:")} ${chalk_1.default.green(openrouter_1.RESEARCH_MODEL)} ${chalk_1.default.yellow("(cost-optimized)")}`);
382
+ console.log(chalk_1.default.cyan("\n📋 Available Models:\n"));
383
+ openrouter_1.AVAILABLE_MODELS.forEach((model, index) => {
384
+ const isDefault = model === openrouter_1.DEFAULT_MODEL;
385
+ const isResearch = model === openrouter_1.RESEARCH_MODEL;
386
+ let suffix = "";
387
+ if (isDefault)
388
+ suffix = chalk_1.default.green(" ← default");
389
+ if (isResearch)
390
+ suffix = chalk_1.default.yellow(" ← research");
391
+ console.log(` ${chalk_1.default.gray(`${index + 1}.`)} ${chalk_1.default.white(model)}${suffix}`);
392
+ });
393
+ console.log(chalk_1.default.gray("\nUsage: helix <command> --model <model>\n"));
394
+ });
395
+ // ============================================================================
396
+ // V10.0 COMMANDS: Platform Features
397
+ // ============================================================================
398
+ program
399
+ .command("preview")
400
+ .description("Launch hot-reload preview server with .helix file watching")
401
+ .action(async () => {
402
+ console.log(banner);
403
+ await (0, preview_1.preview)();
404
+ });
405
+ program
406
+ .command("deploy")
407
+ .description("One-command deployment to cloud platforms")
408
+ .option("-p, --platform <platform>", "Deployment platform: vercel, firebase, netlify", "vercel")
409
+ .option("-t, --token <token>", "Auth token for the platform (optional)")
410
+ .action(async (options) => {
411
+ console.log(banner);
412
+ await (0, deploy_1.deploy)(options.platform, options.token);
413
+ });
414
+ program
415
+ .command("plugins")
416
+ .description("List registered generator plugins")
417
+ .action(async () => {
418
+ console.log(banner);
419
+ const registry = (0, registry_1.getRegistry)();
420
+ await registry.scanForPlugins();
421
+ registry.listPlugins();
422
+ });
423
+ // ============================================================================
424
+ // EVOLVE COMMAND: Codebase Evolution & Analysis
425
+ // ============================================================================
426
+ program
427
+ .command("evolve [action] [category]")
428
+ .description("Evolve codebase: scan, suggest, apply fixes, security-audit")
429
+ .option("-p, --path <path>", "Project path to analyze", process.cwd())
430
+ .action(async (action, category, options) => {
431
+ console.log(banner);
432
+ await (0, evolve_1.evolveCodebase)(action || 'scan', category, options.path);
433
+ });
434
+ // ============================================================================
435
+ // LIST COMMAND: Show all generated projects
436
+ // ============================================================================
437
+ program
438
+ .command("list")
439
+ .alias("ls")
440
+ .description("List all generated projects in builds/")
441
+ .action(async () => {
442
+ console.log(banner);
443
+ const buildsDir = path.resolve(__dirname, "..", "..", "builds");
444
+ if (!fs.existsSync(buildsDir)) {
445
+ console.log(chalk_1.default.yellow("No builds directory found. Run 'helix spawn' to generate your first app."));
446
+ return;
447
+ }
448
+ const projects = fs.readdirSync(buildsDir, { withFileTypes: true })
449
+ .filter((d) => d.isDirectory())
450
+ .map((d) => {
451
+ const configPath = path.join(buildsDir, d.name, "helix.config.json");
452
+ let config = {};
453
+ if (fs.existsSync(configPath)) {
454
+ try {
455
+ config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
456
+ }
457
+ catch { }
458
+ }
459
+ const stat = fs.statSync(path.join(buildsDir, d.name));
460
+ return { name: d.name, prompt: config.prompt || '(unknown)', date: config.generatedAt || stat.mtime.toISOString(), version: config.version || '?' };
461
+ });
462
+ if (projects.length === 0) {
463
+ console.log(chalk_1.default.yellow("No projects found. Run 'helix spawn' to generate your first app."));
464
+ return;
465
+ }
466
+ console.log(chalk_1.default.cyan(`\n📦 Generated Projects (${projects.length}):\n`));
467
+ projects.forEach((p, i) => {
468
+ console.log(` ${chalk_1.default.white(`${i + 1}.`)} ${chalk_1.default.green(p.name)}`);
469
+ console.log(` ${chalk_1.default.gray('Prompt:')} ${p.prompt.substring(0, 60)}`);
470
+ console.log(` ${chalk_1.default.gray('Date:')} ${new Date(p.date).toLocaleDateString()}`);
471
+ console.log(` ${chalk_1.default.gray('Run:')} cd builds/${p.name} && npm run dev\n`);
472
+ });
473
+ });
474
+ // ============================================================================
475
+ // COST COMMAND: Show session cost summary
476
+ // ============================================================================
477
+ program
478
+ .command("cost")
479
+ .description("Show AI model cost summary for the current session")
480
+ .action(async () => {
481
+ console.log(banner);
482
+ const { getCostSummary } = await Promise.resolve().then(() => __importStar(require("../openrouter")));
483
+ const summary = getCostSummary();
484
+ if (summary.callCount === 0) {
485
+ console.log(chalk_1.default.yellow("No API calls made in this session."));
486
+ return;
487
+ }
488
+ console.log(chalk_1.default.cyan(`\n💰 Session Cost Summary:\n`));
489
+ console.log(` Total Calls: ${chalk_1.default.white(String(summary.callCount))}`);
490
+ console.log(` Total Cost: ${chalk_1.default.green('$' + summary.totalCost.toFixed(6))}`);
491
+ console.log(`\n ${chalk_1.default.gray('Breakdown:')}`);
492
+ summary.entries.forEach(e => {
493
+ console.log(` ${chalk_1.default.gray(e.timestamp.toLocaleTimeString())} ${e.model} — $${e.cost.toFixed(6)} (${e.promptTokens}+${e.completionTokens} tokens)`);
494
+ });
495
+ });
496
+ // ============================================================================
497
+ // DOCTOR COMMAND: System Health Check
498
+ // ============================================================================
499
+ program
500
+ .command("doctor")
501
+ .description("Check system health: API keys, Node version, dependencies")
502
+ .action(async () => {
503
+ console.log(banner);
504
+ console.log(chalk_1.default.cyan("\n🩺 Helix Doctor — System Health Check\n"));
505
+ let issues = 0;
506
+ // Check Node.js version
507
+ const nodeVersion = process.version;
508
+ const major = parseInt(nodeVersion.slice(1).split('.')[0]);
509
+ if (major >= 18) {
510
+ console.log(chalk_1.default.green(` ✅ Node.js ${nodeVersion}`));
511
+ }
512
+ else {
513
+ console.log(chalk_1.default.red(` ❌ Node.js ${nodeVersion} — requires >= 18`));
514
+ issues++;
515
+ }
516
+ // Check API key
517
+ if (process.env.OPENROUTER_API_KEY) {
518
+ const key = process.env.OPENROUTER_API_KEY;
519
+ console.log(chalk_1.default.green(` ✅ OPENROUTER_API_KEY configured (${key.substring(0, 12)}...)`));
520
+ }
521
+ else {
522
+ console.log(chalk_1.default.red(" ❌ OPENROUTER_API_KEY not set"));
523
+ issues++;
524
+ }
525
+ // Check .env file
526
+ const envPath = path.resolve(__dirname, "..", "..", ".env");
527
+ if (fs.existsSync(envPath)) {
528
+ console.log(chalk_1.default.green(` ✅ .env file found`));
529
+ }
530
+ else {
531
+ console.log(chalk_1.default.yellow(" ⚠️ No .env file found (using environment variables)"));
532
+ }
533
+ // Check builds directory
534
+ const buildsDir = path.resolve(__dirname, "..", "..", "builds");
535
+ if (fs.existsSync(buildsDir)) {
536
+ const projects = fs.readdirSync(buildsDir, { withFileTypes: true })
537
+ .filter((d) => d.isDirectory());
538
+ console.log(chalk_1.default.green(` ✅ Builds directory: ${projects.length} project(s)`));
539
+ }
540
+ else {
541
+ console.log(chalk_1.default.gray(" ℹ️ No builds directory yet (run 'helix spawn' to create one)"));
542
+ }
543
+ // Check npm
544
+ try {
545
+ const { stdout } = await Promise.resolve().then(() => __importStar(require("execa"))).then(m => m.default("npm", ["--version"]));
546
+ console.log(chalk_1.default.green(` ✅ npm v${stdout.trim()}`));
547
+ }
548
+ catch {
549
+ console.log(chalk_1.default.red(" ❌ npm not found"));
550
+ issues++;
551
+ }
552
+ // Check npx (for prisma, create-next-app)
553
+ try {
554
+ const { stdout } = await Promise.resolve().then(() => __importStar(require("execa"))).then(m => m.default("npx", ["--version"]));
555
+ console.log(chalk_1.default.green(` ✅ npx v${stdout.trim()}`));
556
+ }
557
+ catch {
558
+ console.log(chalk_1.default.red(" ❌ npx not found"));
559
+ issues++;
560
+ }
561
+ // Check disk space (basic)
562
+ try {
563
+ const { stdout } = await Promise.resolve().then(() => __importStar(require("execa"))).then(m => m.default("df", ["-h", "."]));
564
+ const lines = stdout.split('\n');
565
+ if (lines.length > 1) {
566
+ const parts = lines[1].split(/\s+/);
567
+ const available = parts[3];
568
+ console.log(chalk_1.default.green(` ✅ Disk space available: ${available}`));
569
+ }
570
+ }
571
+ catch {
572
+ console.log(chalk_1.default.gray(" ℹ️ Could not check disk space"));
573
+ }
574
+ // Summary
575
+ console.log('');
576
+ if (issues === 0) {
577
+ console.log(chalk_1.default.green(" 🎉 All checks passed! Helix is ready to go."));
578
+ }
579
+ else {
580
+ console.log(chalk_1.default.red(` ⚠️ ${issues} issue(s) found. Fix them above and run 'helix doctor' again.`));
581
+ }
582
+ console.log('');
583
+ });
584
+ // ============================================================================
585
+ // DRIFT COMMAND: Detect manual changes vs original blueprint
586
+ // ============================================================================
587
+ program
588
+ .command("drift [project]")
589
+ .description("Detect manual changes made after generation")
590
+ .option("-p, --path <path>", "Path to project directory")
591
+ .action(async (project, options) => {
592
+ console.log(banner);
593
+ const buildsDir = path.resolve(__dirname, "..", "..", "builds");
594
+ let projectPath;
595
+ if (options.path) {
596
+ projectPath = path.resolve(options.path);
597
+ }
598
+ else if (project) {
599
+ projectPath = path.join(buildsDir, project);
600
+ }
601
+ else {
602
+ projectPath = process.cwd();
603
+ }
604
+ if (!fs.existsSync(projectPath)) {
605
+ console.error(chalk_1.default.red(`Project not found: ${projectPath}`));
606
+ process.exit(1);
607
+ }
608
+ const configPath = path.join(projectPath, "helix.config.json");
609
+ if (!fs.existsSync(configPath)) {
610
+ console.error(chalk_1.default.red("No helix.config.json found. Is this a Helix-generated project?"));
611
+ process.exit(1);
612
+ }
613
+ console.log(chalk_1.default.cyan(`\n🔍 Drift Detection: ${path.basename(projectPath)}\n`));
614
+ // Load the original generation manifest
615
+ let config = {};
616
+ try {
617
+ config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
618
+ }
619
+ catch { }
620
+ // Track files by category
621
+ const drifted = [];
622
+ const generated = [];
623
+ // Scan key generated directories
624
+ const scanDirs = ['app', 'prisma', 'components'];
625
+ for (const dir of scanDirs) {
626
+ const dirPath = path.join(projectPath, dir);
627
+ if (!fs.existsSync(dirPath))
628
+ continue;
629
+ const walkDir = (dirPath) => {
630
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
631
+ const files = [];
632
+ for (const entry of entries) {
633
+ const fullPath = path.join(dirPath, entry.name);
634
+ if (entry.isDirectory()) {
635
+ if (entry.name !== 'node_modules' && entry.name !== '.next') {
636
+ files.push(...walkDir(fullPath));
637
+ }
638
+ }
639
+ else {
640
+ files.push(fullPath);
641
+ }
642
+ }
643
+ return files;
644
+ };
645
+ const files = walkDir(dirPath);
646
+ for (const file of files) {
647
+ const relPath = path.relative(projectPath, file);
648
+ generated.push(relPath);
649
+ // Check git status for this file
650
+ try {
651
+ const { execSync } = require('child_process');
652
+ const gitStatus = execSync(`git -C "${projectPath}" diff --name-only HEAD -- "${relPath}" 2>/dev/null`, { encoding: 'utf-8' }).trim();
653
+ if (gitStatus) {
654
+ // Get the diff stats
655
+ const diffStat = execSync(`git -C "${projectPath}" diff --stat HEAD -- "${relPath}" 2>/dev/null`, { encoding: 'utf-8' }).trim();
656
+ drifted.push({
657
+ file: relPath,
658
+ type: 'modified',
659
+ detail: diffStat.split('\n').pop()?.trim() || 'modified'
660
+ });
661
+ }
662
+ }
663
+ catch {
664
+ // Not a git repo or file not tracked — check modification time vs config
665
+ const fileStat = fs.statSync(file);
666
+ const genTime = config.generatedAt ? new Date(config.generatedAt) : new Date(0);
667
+ if (fileStat.mtime > genTime) {
668
+ drifted.push({
669
+ file: relPath,
670
+ type: 'modified-after-gen',
671
+ detail: `modified ${fileStat.mtime.toLocaleDateString()}`
672
+ });
673
+ }
674
+ }
675
+ }
676
+ }
677
+ // Report
678
+ if (drifted.length === 0) {
679
+ console.log(chalk_1.default.green(" ✅ No drift detected — project matches original generation."));
680
+ }
681
+ else {
682
+ console.log(chalk_1.default.yellow(` ⚠️ ${drifted.length} file(s) have drifted from original generation:\n`));
683
+ drifted.forEach((d, i) => {
684
+ const icon = d.type === 'modified' ? '📝' : '🔧';
685
+ console.log(` ${icon} ${chalk_1.default.white(d.file)}`);
686
+ console.log(` ${chalk_1.default.gray(d.detail)}`);
687
+ });
688
+ console.log(chalk_1.default.gray(`\n Total generated files: ${generated.length}`));
689
+ console.log(chalk_1.default.gray(` Drifted files: ${drifted.length}`));
690
+ console.log(chalk_1.default.yellow(`\n 💡 Use 'helix spawn' with --preserve-drift to keep these changes during regeneration.`));
691
+ }
692
+ console.log('');
693
+ });
694
+ // ============================================================================
695
+ // SNAPSHOT COMMAND: Generate Docker configuration
696
+ // ============================================================================
697
+ program
698
+ .command("snapshot [project]")
699
+ .description("Bundle project with optimized Dockerfile for portable deployment")
700
+ .option("-p, --path <path>", "Path to project directory")
701
+ .option("--docker", "Generate Docker configuration (default)")
702
+ .option("--compose", "Also generate docker-compose.yml")
703
+ .action(async (project, options) => {
704
+ console.log(banner);
705
+ const buildsDir = path.resolve(__dirname, "..", "..", "builds");
706
+ let projectPath;
707
+ if (options.path) {
708
+ projectPath = path.resolve(options.path);
709
+ }
710
+ else if (project) {
711
+ projectPath = path.join(buildsDir, project);
712
+ }
713
+ else {
714
+ projectPath = process.cwd();
715
+ }
716
+ if (!fs.existsSync(projectPath)) {
717
+ console.error(chalk_1.default.red(`Project not found: ${projectPath}`));
718
+ process.exit(1);
719
+ }
720
+ const projectName = path.basename(projectPath);
721
+ console.log(chalk_1.default.cyan(`\n📦 Snapshot: ${projectName}\n`));
722
+ // Detect project type
723
+ const hasPrisma = fs.existsSync(path.join(projectPath, "prisma", "schema.prisma"));
724
+ const hasNextConfig = fs.existsSync(path.join(projectPath, "next.config.js")) || fs.existsSync(path.join(projectPath, "next.config.mjs")) || fs.existsSync(path.join(projectPath, "next.config.ts"));
725
+ const pkgPath = path.join(projectPath, "package.json");
726
+ let pkg = {};
727
+ if (fs.existsSync(pkgPath)) {
728
+ try {
729
+ pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
730
+ }
731
+ catch { }
732
+ }
733
+ // Generate optimized multi-stage Dockerfile
734
+ const dockerfile = `# Generated by Helix Snapshot
735
+ # Multi-stage build for optimized production image
736
+
737
+ # Stage 1: Dependencies
738
+ FROM node:20-alpine AS deps
739
+ RUN apk add --no-cache libc6-compat openssl
740
+ WORKDIR /app
741
+ COPY package.json package-lock.json* yarn.lock* pnpm-lock.yaml* ./
742
+ ${hasPrisma ? 'COPY prisma ./prisma/' : ''}
743
+ RUN \\
744
+ if [ -f yarn.lock ]; then yarn install --frozen-lockfile; \\
745
+ elif [ -f package-lock.json ]; then npm ci; \\
746
+ elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm install --frozen-lockfile; \\
747
+ else npm install; \\
748
+ fi
749
+ ${hasPrisma ? 'RUN npx prisma generate' : ''}
750
+
751
+ # Stage 2: Build
752
+ FROM node:20-alpine AS builder
753
+ WORKDIR /app
754
+ COPY --from=deps /app/node_modules ./node_modules
755
+ COPY . .
756
+ ENV NEXT_TELEMETRY_DISABLED=1
757
+ ENV NODE_ENV=production
758
+ RUN npm run build
759
+
760
+ # Stage 3: Production
761
+ FROM node:20-alpine AS runner
762
+ WORKDIR /app
763
+ ENV NODE_ENV=production
764
+ ENV NEXT_TELEMETRY_DISABLED=1
765
+
766
+ RUN addgroup --system --gid 1001 nodejs
767
+ RUN adduser --system --uid 1001 nextjs
768
+
769
+ COPY --from=builder /app/public ./public
770
+ COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
771
+ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
772
+ ${hasPrisma ? 'COPY --from=builder /app/prisma ./prisma\nCOPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma' : ''}
773
+
774
+ USER nextjs
775
+ EXPOSE 3000
776
+ ENV PORT=3000
777
+ ENV HOSTNAME="0.0.0.0"
778
+
779
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \\
780
+ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1
781
+
782
+ CMD ["node", "server.js"]
783
+ `;
784
+ const dockerignore = `node_modules
785
+ .next
786
+ .git
787
+ .env*
788
+ *.md
789
+ .DS_Store
790
+ builds/
791
+ `;
792
+ // Write Dockerfile
793
+ const dockerfilePath = path.join(projectPath, "Dockerfile");
794
+ fs.writeFileSync(dockerfilePath, dockerfile);
795
+ console.log(chalk_1.default.green(` ✅ Created: Dockerfile`));
796
+ // Write .dockerignore
797
+ const dockerignorePath = path.join(projectPath, ".dockerignore");
798
+ fs.writeFileSync(dockerignorePath, dockerignore);
799
+ console.log(chalk_1.default.green(` ✅ Created: .dockerignore`));
800
+ // Generate docker-compose.yml if requested or by default
801
+ const composeContent = `# Generated by Helix Snapshot
802
+ version: "3.8"
803
+
804
+ services:
805
+ ${projectName}:
806
+ build:
807
+ context: .
808
+ dockerfile: Dockerfile
809
+ ports:
810
+ - "3000:3000"
811
+ environment:
812
+ - NODE_ENV=production
813
+ - DATABASE_URL=file:./dev.db
814
+ restart: unless-stopped
815
+ healthcheck:
816
+ test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/"]
817
+ interval: 30s
818
+ timeout: 3s
819
+ retries: 3
820
+ start_period: 10s
821
+ `;
822
+ const composePath = path.join(projectPath, "docker-compose.yml");
823
+ fs.writeFileSync(composePath, composeContent);
824
+ console.log(chalk_1.default.green(` ✅ Created: docker-compose.yml`));
825
+ // Update next.config for standalone output if needed
826
+ if (hasNextConfig) {
827
+ const nextConfigPath = fs.existsSync(path.join(projectPath, "next.config.mjs"))
828
+ ? path.join(projectPath, "next.config.mjs")
829
+ : fs.existsSync(path.join(projectPath, "next.config.ts"))
830
+ ? path.join(projectPath, "next.config.ts")
831
+ : path.join(projectPath, "next.config.js");
832
+ const nextConfig = fs.readFileSync(nextConfigPath, "utf-8");
833
+ if (!nextConfig.includes("standalone")) {
834
+ console.log(chalk_1.default.yellow(` ⚠️ Add output: "standalone" to ${path.basename(nextConfigPath)} for optimized Docker builds`));
835
+ }
836
+ }
837
+ console.log(chalk_1.default.cyan(`\n 📋 Quick start:`));
838
+ console.log(chalk_1.default.gray(` cd ${projectPath}`));
839
+ console.log(chalk_1.default.gray(` docker compose up --build`));
840
+ console.log(chalk_1.default.gray(` # App available at http://localhost:3000\n`));
841
+ });
842
+ // ============================================================================
843
+ // PREFLIGHT COMMAND: Validate blueprint before generation
844
+ // ============================================================================
845
+ program
846
+ .command("preflight <file>")
847
+ .description("Validate a .helix blueprint before generation")
848
+ .action(async (file) => {
849
+ console.log(banner);
850
+ const filePath = path.isAbsolute(file) ? file : path.resolve(process.cwd(), file);
851
+ if (!fs.existsSync(filePath)) {
852
+ console.error(chalk_1.default.red(`File not found: ${file}`));
853
+ process.exit(1);
854
+ }
855
+ const content = fs.readFileSync(filePath, "utf-8");
856
+ try {
857
+ const { preflight, formatPreflightResult } = await Promise.resolve().then(() => __importStar(require("../commands/preflight")));
858
+ const result = preflight(content);
859
+ console.log('\n' + formatPreflightResult(result));
860
+ process.exit(result.passed ? 0 : 1);
861
+ }
862
+ catch (e) {
863
+ console.error(chalk_1.default.red(`Preflight error: ${e.message}`));
864
+ process.exit(1);
865
+ }
866
+ });
867
+ // ============================================================================
868
+ // INSTALL COMMAND: Component Marketplace
869
+ // ============================================================================
870
+ program
871
+ .command("install [component]")
872
+ .description("Install a component from the Helix library")
873
+ .option("-p, --path <path>", "Target project directory", process.cwd())
874
+ .action(async (component, options) => {
875
+ console.log(banner);
876
+ const { installComponent } = await Promise.resolve().then(() => __importStar(require("../commands/install")));
877
+ await installComponent(component || 'list', options.path);
878
+ });
879
+ // ============================================================================
880
+ // HELP ENHANCEMENTS
881
+ // ============================================================================
882
+ program.addHelpText("after", `
883
+ ${chalk_1.default.cyan("Examples:")}
884
+ ${chalk_1.default.gray("# ONE-SHOT: Complete app from natural language")}
885
+ $ helix spawn "Expense tracker for my small business"
886
+ $ helix spawn "Task app" --target flutter --db supabase --ai openrouter
887
+
888
+ ${chalk_1.default.gray("# Development workflow:")}
889
+ $ helix preview ${chalk_1.default.gray("# Hot-reload with file watching")}
890
+ $ helix deploy --platform vercel ${chalk_1.default.gray("# Ship to production")}
891
+
892
+ ${chalk_1.default.gray("# Manual workflow:")}
893
+ $ helix new my-app
894
+ $ helix generate app.helix
895
+ $ helix run
896
+
897
+ ${chalk_1.default.gray("# Project management:")}
898
+ $ helix list ${chalk_1.default.gray("# Show all generated projects")}
899
+ $ helix cost ${chalk_1.default.gray("# Show AI cost summary")}
900
+ $ helix doctor ${chalk_1.default.gray("# System health check")}
901
+ $ helix drift my-app ${chalk_1.default.gray("# Detect manual changes")}
902
+ $ helix snapshot my-app ${chalk_1.default.gray("# Generate Docker config")}
903
+ $ helix preflight app.helix ${chalk_1.default.gray("# Validate blueprint")}
904
+ $ helix evolve scan ${chalk_1.default.gray("# Analyze codebase health")}
905
+ $ helix evolve apply ${chalk_1.default.gray("# Auto-fix issues")}
906
+ $ helix spawn "..." --dry-run ${chalk_1.default.gray("# Preview without generating")}
907
+
908
+ ${chalk_1.default.gray("# Component library:")}
909
+ $ helix install ${chalk_1.default.gray("# List available components")}
910
+ $ helix install auth-flow ${chalk_1.default.gray("# Install a component package")}
911
+
912
+ ${chalk_1.default.gray("# Plugin system:")}
913
+ $ helix plugins ${chalk_1.default.gray("# List available generators")}
914
+ `);
915
+ // Parse command line arguments
916
+ program.parse(process.argv);
917
+ // Show help if no command provided
918
+ if (!process.argv.slice(2).length) {
919
+ program.outputHelp();
920
+ }
921
+ //# sourceMappingURL=helix.js.map