ai-flow-dev 1.0.1

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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +408 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +791 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/fs-utils.d.ts +2 -0
  8. package/dist/fs-utils.d.ts.map +1 -0
  9. package/dist/fs-utils.js +46 -0
  10. package/dist/fs-utils.js.map +1 -0
  11. package/package.json +71 -0
  12. package/prompts/backend/flow-dev-feature.md +1318 -0
  13. package/prompts/backend/flow-dev-fix.md +903 -0
  14. package/prompts/backend/flow-dev-refactor.md +715 -0
  15. package/prompts/backend/flow-dev-review.md +401 -0
  16. package/prompts/backend/flow-dev-work.md +1129 -0
  17. package/prompts/backend/flow-docs-gen-phase-0.md +1840 -0
  18. package/prompts/backend/flow-docs-gen-phase-1.md +435 -0
  19. package/prompts/backend/flow-docs-gen-phase-2.md +460 -0
  20. package/prompts/backend/flow-docs-gen-phase-3.md +684 -0
  21. package/prompts/backend/flow-docs-gen-phase-4.md +516 -0
  22. package/prompts/backend/flow-docs-gen-phase-5.md +637 -0
  23. package/prompts/backend/flow-docs-gen-phase-6.md +465 -0
  24. package/prompts/backend/flow-docs-gen-phase-7.md +1207 -0
  25. package/prompts/backend/flow-docs-gen.md +820 -0
  26. package/prompts/backend/flow-docs-sync.md +526 -0
  27. package/prompts/backend/flow-project-init.md +248 -0
  28. package/prompts/backend/flow-project-roadmap.md +1159 -0
  29. package/prompts/frontend/flow-docs-gen-phase-0.md +494 -0
  30. package/prompts/frontend/flow-docs-gen-phase-1.md +449 -0
  31. package/prompts/frontend/flow-docs-gen-phase-2.md +983 -0
  32. package/prompts/frontend/flow-docs-gen-phase-3.md +685 -0
  33. package/prompts/frontend/flow-docs-gen-phase-4.md +480 -0
  34. package/prompts/frontend/flow-docs-gen-phase-5.md +483 -0
  35. package/prompts/frontend/flow-docs-gen-phase-6.md +570 -0
  36. package/prompts/frontend/flow-docs-gen-phase-7.md +582 -0
  37. package/prompts/frontend/flow-docs-gen.md +413 -0
  38. package/prompts/frontend/flow-docs-sync.md +561 -0
  39. package/prompts/mobile/flow-docs-gen-phase-0.md +387 -0
  40. package/prompts/mobile/flow-docs-gen-phase-1.md +530 -0
  41. package/prompts/mobile/flow-docs-gen-phase-2.md +584 -0
  42. package/prompts/mobile/flow-docs-gen-phase-3.md +659 -0
  43. package/prompts/mobile/flow-docs-gen-phase-4.md +363 -0
  44. package/prompts/mobile/flow-docs-gen-phase-5.md +369 -0
  45. package/prompts/mobile/flow-docs-gen-phase-6.md +490 -0
  46. package/prompts/mobile/flow-docs-gen-phase-7.md +407 -0
  47. package/prompts/mobile/flow-docs-gen.md +430 -0
  48. package/prompts/mobile/flow-docs-sync.md +634 -0
  49. package/templates/backend/.clauderules.template +111 -0
  50. package/templates/backend/.cursorrules.template +102 -0
  51. package/templates/backend/.env.example.template +122 -0
  52. package/templates/backend/README.template.md +200 -0
  53. package/templates/backend/ai-instructions.template.md +354 -0
  54. package/templates/backend/copilot-instructions.template.md +160 -0
  55. package/templates/backend/docs/api.template.md +251 -0
  56. package/templates/backend/docs/architecture.template.md +612 -0
  57. package/templates/backend/docs/business-flows.template.md +109 -0
  58. package/templates/backend/docs/code-standards.template.md +828 -0
  59. package/templates/backend/docs/contributing.template.md +163 -0
  60. package/templates/backend/docs/data-model.template.md +416 -0
  61. package/templates/backend/docs/operations.template.md +591 -0
  62. package/templates/backend/docs/testing.template.md +762 -0
  63. package/templates/backend/project-brief.template.md +176 -0
  64. package/templates/backend/specs/configuration.template.md +133 -0
  65. package/templates/backend/specs/security.template.md +422 -0
  66. package/templates/frontend/README.template.md +121 -0
  67. package/templates/frontend/ai-instructions.template.md +368 -0
  68. package/templates/frontend/docs/api-integration.template.md +390 -0
  69. package/templates/frontend/docs/components.template.md +567 -0
  70. package/templates/frontend/docs/error-handling.template.md +385 -0
  71. package/templates/frontend/docs/operations.template.md +123 -0
  72. package/templates/frontend/docs/performance.template.md +140 -0
  73. package/templates/frontend/docs/pwa.template.md +135 -0
  74. package/templates/frontend/docs/state-management.template.md +394 -0
  75. package/templates/frontend/docs/styling.template.md +779 -0
  76. package/templates/frontend/docs/testing.template.md +736 -0
  77. package/templates/frontend/project-brief.template.md +55 -0
  78. package/templates/frontend/specs/accessibility.template.md +111 -0
  79. package/templates/frontend/specs/configuration.template.md +520 -0
  80. package/templates/frontend/specs/security.template.md +197 -0
  81. package/templates/fullstack/README.template.md +282 -0
  82. package/templates/fullstack/ai-instructions.template.md +487 -0
  83. package/templates/fullstack/project-brief.template.md +197 -0
  84. package/templates/fullstack/specs/configuration.template.md +380 -0
  85. package/templates/mobile/AGENT.template.md +251 -0
  86. package/templates/mobile/README.template.md +195 -0
  87. package/templates/mobile/ai-instructions.template.md +221 -0
  88. package/templates/mobile/docs/app-store.template.md +163 -0
  89. package/templates/mobile/docs/architecture.template.md +100 -0
  90. package/templates/mobile/docs/native-features.template.md +137 -0
  91. package/templates/mobile/docs/navigation.template.md +81 -0
  92. package/templates/mobile/docs/offline-strategy.template.md +90 -0
  93. package/templates/mobile/docs/permissions.template.md +70 -0
  94. package/templates/mobile/docs/state-management.template.md +116 -0
  95. package/templates/mobile/docs/testing.template.md +146 -0
  96. package/templates/mobile/project-brief.template.md +97 -0
  97. package/templates/mobile/specs/build-configuration.template.md +116 -0
  98. package/templates/mobile/specs/deployment.template.md +114 -0
  99. package/templates/shared/AGENT.template.md +252 -0
package/dist/cli.js ADDED
@@ -0,0 +1,791 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const commander_1 = require("commander");
41
+ const inquirer_1 = __importDefault(require("inquirer"));
42
+ const chalk_1 = __importDefault(require("chalk"));
43
+ const ora_1 = __importDefault(require("ora"));
44
+ const fs = __importStar(require("fs-extra"));
45
+ const path = __importStar(require("path"));
46
+ const ejs_1 = __importDefault(require("ejs"));
47
+ const fs_utils_1 = require("./fs-utils");
48
+ const ROOT_DIR = path.resolve(__dirname, '..');
49
+ const program = new commander_1.Command();
50
+ const AI_TOOLS = [
51
+ {
52
+ name: 'GitHub Copilot',
53
+ value: 'copilot',
54
+ description: '',
55
+ },
56
+ {
57
+ name: 'Claude Code',
58
+ value: 'claude',
59
+ description: '',
60
+ },
61
+ {
62
+ name: 'Cursor',
63
+ value: 'cursor',
64
+ description: '',
65
+ },
66
+ {
67
+ name: 'Gemini',
68
+ value: 'gemini',
69
+ description: '',
70
+ },
71
+ {
72
+ name: 'All AI Tools',
73
+ value: 'all',
74
+ description: '',
75
+ },
76
+ ];
77
+ const PKG_VERSION = fs.readJSONSync(path.join(__dirname, '..', 'package.json')).version;
78
+ const EXIT = {
79
+ OK: 0,
80
+ INVALID_ARGS: 2,
81
+ FS_ERROR: 3,
82
+ };
83
+ function logVerbose(message, verbose) {
84
+ if (verbose)
85
+ console.log(chalk_1.default.gray(message));
86
+ }
87
+ function isValidName(value) {
88
+ const v = value.trim();
89
+ if (v.length < 2 || v.length > 100)
90
+ return false;
91
+ return /^[A-Za-z0-9 _\-\.]+$/.test(v);
92
+ }
93
+ function isValidDescription(value) {
94
+ const v = value.trim();
95
+ if (v.length < 2 || v.length > 500)
96
+ return false;
97
+ return /^[\p{L}\p{N} \-_,.!?:()]+$/u.test(v);
98
+ }
99
+ function fsErrorMessage(e) {
100
+ const anyErr = e;
101
+ const code = anyErr && anyErr.code ? String(anyErr.code) : 'UNKNOWN';
102
+ const msg = anyErr && anyErr.message ? String(anyErr.message) : String(e);
103
+ return `${code}: ${msg}`;
104
+ }
105
+ async function selectAITool(providedTool) {
106
+ if (providedTool) {
107
+ const tool = AI_TOOLS.find((t) => t.value === providedTool);
108
+ if (!tool) {
109
+ console.error(chalk_1.default.red(`āŒ Invalid AI tool: ${providedTool}`));
110
+ console.log(chalk_1.default.yellow('Available options: claude, cursor, copilot, gemini, all'));
111
+ process.exit(EXIT.INVALID_ARGS);
112
+ }
113
+ return providedTool === 'all'
114
+ ? ['claude', 'cursor', 'copilot', 'gemini']
115
+ : [providedTool];
116
+ }
117
+ // Display banner
118
+ console.log('\n');
119
+ console.log(chalk_1.default.cyan(' ╔═══════════════════════════════════════════════════════════════════╗'));
120
+ console.log(chalk_1.default.cyan(' ā•‘') +
121
+ ' ' +
122
+ chalk_1.default.cyan('ā•‘'));
123
+ console.log(chalk_1.default.cyan(' ā•‘') +
124
+ chalk_1.default.bold.cyan(' ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•— ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•— ā–ˆā–ˆā•—') +
125
+ ' ' +
126
+ chalk_1.default.cyan('ā•‘'));
127
+ console.log(chalk_1.default.cyan(' ā•‘') +
128
+ chalk_1.default.bold.cyan(' ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā•ā•ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā•ā–ˆā–ˆā•—ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘') +
129
+ ' ' +
130
+ chalk_1.default.cyan('ā•‘'));
131
+ console.log(chalk_1.default.cyan(' ā•‘') +
132
+ chalk_1.default.bold.cyan(' ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā•— ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā•— ā–ˆā–ˆā•‘') +
133
+ ' ' +
134
+ chalk_1.default.cyan('ā•‘'));
135
+ console.log(chalk_1.default.cyan(' ā•‘') +
136
+ chalk_1.default.bold.cyan(' ā–ˆā–ˆā•”ā•ā•ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•”ā•ā•ā• ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ā–ˆā–ˆā–ˆā•—ā–ˆā–ˆā•‘') +
137
+ ' ' +
138
+ chalk_1.default.cyan('ā•‘'));
139
+ console.log(chalk_1.default.cyan(' ā•‘') +
140
+ chalk_1.default.bold.cyan(' ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ā–ˆā–ˆā•‘ ā–ˆā–ˆā•‘ ā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•—ā•šā–ˆā–ˆā–ˆā–ˆā–ˆā–ˆā•”ā•ā•šā–ˆā–ˆā–ˆā•”ā–ˆā–ˆā–ˆā•”ā•') +
141
+ ' ' +
142
+ chalk_1.default.cyan('ā•‘'));
143
+ console.log(chalk_1.default.cyan(' ā•‘') +
144
+ chalk_1.default.cyan(' ā•šā•ā• ā•šā•ā•ā•šā•ā• ā•šā•ā• ā•šā•ā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•ā•ā• ā•šā•ā•ā•ā•šā•ā•ā•') +
145
+ ' ' +
146
+ chalk_1.default.cyan('ā•‘'));
147
+ console.log(chalk_1.default.cyan(' ā•‘') +
148
+ ' ' +
149
+ chalk_1.default.cyan('ā•‘'));
150
+ console.log(chalk_1.default.cyan(' ā•‘') +
151
+ ' ' +
152
+ chalk_1.default.white('✨ From Idea to Production with AI Guidance') +
153
+ ' ' +
154
+ chalk_1.default.cyan('ā•‘'));
155
+ console.log(chalk_1.default.cyan(' ā•‘') +
156
+ ' ' +
157
+ chalk_1.default.cyan('ā•‘'));
158
+ console.log(chalk_1.default.cyan(' ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•'));
159
+ console.log('\n');
160
+ console.log(chalk_1.default.white(' šŸ“‚ Project Setup'));
161
+ console.log(chalk_1.default.gray(' ────────────────────────────────────────────────────────────────────'));
162
+ console.log(chalk_1.default.gray(` Working Directory: ${process.cwd()}`));
163
+ console.log(chalk_1.default.gray(` Version: ${PKG_VERSION}`));
164
+ console.log('\n');
165
+ console.log(chalk_1.default.white(' šŸ¤– Select your AI development tool:'));
166
+ console.log(chalk_1.default.gray(' ────────────────────────────────────────────────────────────────────'));
167
+ const { selectedTool } = await inquirer_1.default.prompt([
168
+ {
169
+ type: 'list',
170
+ name: 'selectedTool',
171
+ message: '\u200B', // invisible char para ocultar el ?
172
+ choices: AI_TOOLS.map((tool) => ({
173
+ name: ' ' + tool.name, // 4 espacios para alinear
174
+ value: tool.value,
175
+ })),
176
+ pageSize: 10,
177
+ },
178
+ ]);
179
+ return selectedTool === 'all'
180
+ ? ['claude', 'cursor', 'copilot', 'gemini']
181
+ : [selectedTool];
182
+ }
183
+ async function selectProjectType(providedType) {
184
+ // v1.4.0: Backend, Frontend, Fullstack, and Mobile supported
185
+ if (providedType) {
186
+ const valid = ['backend', 'frontend', 'fullstack', 'mobile'];
187
+ if (!valid.includes(providedType)) {
188
+ console.error(chalk_1.default.red(`āŒ Invalid project type: ${providedType}`));
189
+ console.log(chalk_1.default.yellow('Available options: backend, frontend, fullstack, mobile'));
190
+ process.exit(EXIT.INVALID_ARGS);
191
+ }
192
+ return providedType;
193
+ }
194
+ // If no TTY available (non-interactive mode, e.g., in tests), default to backend
195
+ // This maintains backward compatibility with existing tests and scripts
196
+ if (!process.stdin.isTTY) {
197
+ return 'backend';
198
+ }
199
+ // v1.4.0: Interactive selection for backend/frontend/fullstack/mobile
200
+ const answer = await inquirer_1.default.prompt([
201
+ {
202
+ type: 'list',
203
+ name: 'projectType',
204
+ message: 'What type of project are you bootstrapping?',
205
+ choices: [
206
+ { name: 'šŸ”§ Backend API/Service', value: 'backend' },
207
+ { name: 'šŸŽØ Frontend Application', value: 'frontend' },
208
+ { name: 'šŸš€ Full Stack Application', value: 'fullstack' },
209
+ { name: 'šŸ“± Mobile Application', value: 'mobile' },
210
+ ],
211
+ },
212
+ ]);
213
+ return answer.projectType;
214
+ }
215
+ async function checkIfInitialized(targetPath) {
216
+ const bootstrapPath = path.join(targetPath, '.ai-flow');
217
+ return await fs.pathExists(bootstrapPath);
218
+ }
219
+ async function createBootstrapStructure(targetPath, aiTools, projectType = 'backend', dryRun, verbose) {
220
+ const spinner = (0, ora_1.default)('Creating .ai-flow structure...').start();
221
+ try {
222
+ const bootstrapPath = path.join(targetPath, '.ai-flow');
223
+ // Create core directories
224
+ if (dryRun) {
225
+ spinner.succeed('Created .ai-flow structure (dry-run)');
226
+ return;
227
+ }
228
+ await (0, fs_utils_1.assertDirWritable)(targetPath);
229
+ await fs.ensureDir(path.join(bootstrapPath, 'core'));
230
+ await fs.ensureDir(path.join(bootstrapPath, 'prompts'));
231
+ await fs.ensureDir(path.join(bootstrapPath, 'templates', 'docs'));
232
+ await fs.ensureDir(path.join(bootstrapPath, 'templates', 'specs'));
233
+ await fs.ensureDir(path.join(bootstrapPath, 'scripts'));
234
+ // Create config file with new projectType field
235
+ const config = {
236
+ version: PKG_VERSION,
237
+ aiTools: aiTools,
238
+ createdAt: new Date().toISOString(),
239
+ projectType: projectType,
240
+ // Deprecated fields for backward compatibility
241
+ backend: projectType === 'backend' || projectType === 'fullstack',
242
+ frontend: projectType === 'frontend' || projectType === 'fullstack',
243
+ mobile: projectType === 'mobile',
244
+ };
245
+ await fs.writeJSON(path.join(bootstrapPath, 'core', 'config.json'), config, { spaces: 2 });
246
+ logVerbose(`Wrote ${path.join(bootstrapPath, 'core', 'config.json')}`, verbose);
247
+ spinner.succeed('Created .ai-flow structure');
248
+ }
249
+ catch (error) {
250
+ spinner.fail(fsErrorMessage(error));
251
+ throw error;
252
+ }
253
+ }
254
+ async function renderTemplates(targetPath, projectData, projectType = 'backend', aiTools = [], dryRun, verbose) {
255
+ const spinner = (0, ora_1.default)('Generating documentation from templates...').start();
256
+ try {
257
+ const templatesTarget = path.join(targetPath, '.ai-flow', 'templates');
258
+ if (dryRun) {
259
+ spinner.succeed('Documentation generated from templates (dry-run)');
260
+ return;
261
+ }
262
+ await (0, fs_utils_1.assertDirWritable)(templatesTarget);
263
+ await fs.ensureDir(templatesTarget);
264
+ // Find all .template.md and .template files in a directory and subfolders
265
+ const walk = async (dir) => {
266
+ let files = [];
267
+ for (const entry of await fs.readdir(dir)) {
268
+ const fullPath = path.join(dir, entry);
269
+ const stat = await fs.stat(fullPath);
270
+ if (stat.isDirectory()) {
271
+ files = files.concat(await walk(fullPath));
272
+ }
273
+ else if (entry.endsWith('.template.md') ||
274
+ entry.endsWith('.template')) {
275
+ files.push(fullPath);
276
+ }
277
+ }
278
+ return files;
279
+ };
280
+ // Collect template files from shared and project-type-specific directories
281
+ const templateSources = [];
282
+ // Always include shared templates (e.g., AGENT.md)
283
+ const sharedSource = path.join(ROOT_DIR, 'templates', 'shared');
284
+ templateSources.push({ source: sharedSource, base: sharedSource });
285
+ // Include project-type-specific templates
286
+ if (projectType === 'backend') {
287
+ const backendSource = path.join(ROOT_DIR, 'templates', 'backend');
288
+ templateSources.push({ source: backendSource, base: backendSource });
289
+ }
290
+ else if (projectType === 'frontend') {
291
+ const frontendSource = path.join(ROOT_DIR, 'templates', 'frontend');
292
+ templateSources.push({ source: frontendSource, base: frontendSource });
293
+ }
294
+ else if (projectType === 'fullstack') {
295
+ // v1.3.0: Copy both backend and frontend templates
296
+ // Priority: fullstack-specific templates > backend templates > frontend templates
297
+ const fullstackSource = path.join(ROOT_DIR, 'templates', 'fullstack');
298
+ const backendSource = path.join(ROOT_DIR, 'templates', 'backend');
299
+ const frontendSource = path.join(ROOT_DIR, 'templates', 'frontend');
300
+ // Check if fullstack templates directory exists
301
+ const fullstackExists = await fs.pathExists(fullstackSource);
302
+ if (fullstackExists) {
303
+ templateSources.push({
304
+ source: fullstackSource,
305
+ base: fullstackSource,
306
+ });
307
+ }
308
+ // Backend templates (used as base for conflicts)
309
+ templateSources.push({ source: backendSource, base: backendSource });
310
+ // Frontend templates (will overwrite only if not in fullstack and not conflicting with backend)
311
+ templateSources.push({ source: frontendSource, base: frontendSource });
312
+ }
313
+ else if (projectType === 'mobile') {
314
+ // v1.4.0: Copy mobile templates
315
+ const mobileSource = path.join(ROOT_DIR, 'templates', 'mobile');
316
+ templateSources.push({ source: mobileSource, base: mobileSource });
317
+ }
318
+ // Walk all source directories and collect template files
319
+ // For fullstack, use a Map to track processed files (priority: fullstack > backend > frontend)
320
+ const processedFiles = new Map();
321
+ for (const { source, base } of templateSources) {
322
+ const files = await walk(source);
323
+ for (const file of files) {
324
+ const relPath = path
325
+ .relative(base, file)
326
+ .replace('.template.md', '.md')
327
+ .replace('.template', '');
328
+ // Only add if not already processed (first occurrence wins)
329
+ if (!processedFiles.has(relPath)) {
330
+ processedFiles.set(relPath, { file, base });
331
+ }
332
+ }
333
+ }
334
+ // Render each template
335
+ for (const [relPath, { file: templateFile }] of processedFiles) {
336
+ // Skip AI tool-specific config files if the tool is not selected
337
+ const fileName = path.basename(relPath);
338
+ if (fileName === '.clauderules' &&
339
+ !aiTools.includes('claude') &&
340
+ !aiTools.includes('all')) {
341
+ logVerbose(`Skipping ${relPath} (Claude not selected)`, verbose);
342
+ continue;
343
+ }
344
+ if (fileName === '.cursorrules' &&
345
+ !aiTools.includes('cursor') &&
346
+ !aiTools.includes('all')) {
347
+ logVerbose(`Skipping ${relPath} (Cursor not selected)`, verbose);
348
+ continue;
349
+ }
350
+ const destPath = path.join(templatesTarget, relPath);
351
+ await fs.ensureDir(path.dirname(destPath));
352
+ const templateContent = await fs.readFile(templateFile, 'utf8');
353
+ // Render with EJS, leaving {{PLACEHOLDER}} for everything except name/description
354
+ const rendered = ejs_1.default.render(templateContent, {
355
+ PROJECT_NAME: projectData.name,
356
+ PROJECT_DESCRIPTION: projectData.description,
357
+ PROJECT_TYPE: projectType,
358
+ GENERATION_DATE: new Date().toISOString().split('T')[0],
359
+ PLACEHOLDER: '{{PLACEHOLDER}}',
360
+ }, { delimiter: '?' });
361
+ await fs.writeFile(destPath, rendered, 'utf8');
362
+ logVerbose(`Rendered ${destPath}`, verbose);
363
+ }
364
+ spinner.succeed('Documentation generated from templates');
365
+ }
366
+ catch (error) {
367
+ spinner.fail(fsErrorMessage(error));
368
+ throw error;
369
+ }
370
+ }
371
+ async function copyPrompts(targetPath, dryRun, verbose) {
372
+ const spinner = (0, ora_1.default)('Copying master prompts...').start();
373
+ try {
374
+ const promptsSource = path.join(ROOT_DIR, 'prompts');
375
+ const promptsTarget = path.join(targetPath, '.ai-flow', 'prompts');
376
+ if (dryRun) {
377
+ spinner.succeed('Master prompts copied (dry-run)');
378
+ return;
379
+ }
380
+ await (0, fs_utils_1.assertDirWritable)(promptsTarget);
381
+ await fs.copy(promptsSource, promptsTarget);
382
+ logVerbose(`Copied prompts to ${promptsTarget}`, verbose);
383
+ spinner.succeed('Master prompts copied');
384
+ }
385
+ catch (error) {
386
+ spinner.fail(fsErrorMessage(error));
387
+ throw error;
388
+ }
389
+ }
390
+ async function setupSlashCommands(targetPath, aiTools, projectType = 'backend', dryRun, verbose) {
391
+ const spinner = (0, ora_1.default)('Setting up slash commands...').start();
392
+ try {
393
+ // Determine which prompt directories to copy from
394
+ const promptSources = [];
395
+ if (projectType === 'backend') {
396
+ promptSources.push({ dir: 'backend' });
397
+ }
398
+ else if (projectType === 'frontend') {
399
+ promptSources.push({ dir: 'frontend' });
400
+ }
401
+ else if (projectType === 'fullstack') {
402
+ // For fullstack, copy both with prefixes
403
+ promptSources.push({ dir: 'backend', prefix: 'backend-' });
404
+ promptSources.push({ dir: 'frontend', prefix: 'frontend-' });
405
+ }
406
+ else if (projectType === 'mobile') {
407
+ promptSources.push({ dir: 'mobile' });
408
+ }
409
+ for (const { dir, prefix } of promptSources) {
410
+ const promptsSource = path.join(ROOT_DIR, 'prompts', dir);
411
+ const allFiles = await fs.readdir(promptsSource);
412
+ // Filter all markdown files (all prompts are valid slash commands)
413
+ const files = allFiles.filter((file) => file.endsWith('.md'));
414
+ for (const tool of aiTools) {
415
+ if (tool === 'copilot') {
416
+ // Copilot: prompts in .github/prompts with .prompt.md suffix
417
+ const promptsTarget = path.join(targetPath, '.github', 'prompts');
418
+ if (!dryRun) {
419
+ await (0, fs_utils_1.assertDirWritable)(promptsTarget);
420
+ await fs.ensureDir(promptsTarget);
421
+ }
422
+ for (const file of files) {
423
+ const srcFile = path.join(promptsSource, file);
424
+ const base = file.replace(/\.md$/, '');
425
+ const destName = prefix
426
+ ? `${prefix}${base}.prompt.md`
427
+ : `${base}.prompt.md`;
428
+ const destFile = path.join(promptsTarget, destName);
429
+ if (!dryRun)
430
+ await fs.copyFile(srcFile, destFile);
431
+ logVerbose(`Installed ${destFile}`, verbose);
432
+ }
433
+ }
434
+ else if (tool === 'claude') {
435
+ const commandsTarget = path.join(targetPath, '.claude', 'commands');
436
+ if (!dryRun) {
437
+ await (0, fs_utils_1.assertDirWritable)(commandsTarget);
438
+ await fs.ensureDir(commandsTarget);
439
+ }
440
+ for (const file of files) {
441
+ const srcFile = path.join(promptsSource, file);
442
+ const destName = prefix ? `${prefix}${file}` : file;
443
+ const destFile = path.join(commandsTarget, destName);
444
+ if (!dryRun)
445
+ await fs.copyFile(srcFile, destFile);
446
+ logVerbose(`Installed ${destFile}`, verbose);
447
+ }
448
+ }
449
+ else if (tool === 'cursor') {
450
+ const commandsTarget = path.join(targetPath, '.cursor', 'commands');
451
+ if (!dryRun) {
452
+ await (0, fs_utils_1.assertDirWritable)(commandsTarget);
453
+ await fs.ensureDir(commandsTarget);
454
+ }
455
+ for (const file of files) {
456
+ const srcFile = path.join(promptsSource, file);
457
+ const destName = prefix ? `${prefix}${file}` : file;
458
+ const destFile = path.join(commandsTarget, destName);
459
+ if (!dryRun)
460
+ await fs.copyFile(srcFile, destFile);
461
+ logVerbose(`Installed ${destFile}`, verbose);
462
+ }
463
+ }
464
+ else if (tool === 'gemini') {
465
+ const commandsTarget = path.join(targetPath, '.gemini', 'commands');
466
+ if (!dryRun) {
467
+ await (0, fs_utils_1.assertDirWritable)(commandsTarget);
468
+ await fs.ensureDir(commandsTarget);
469
+ }
470
+ for (const file of files) {
471
+ const srcFile = path.join(promptsSource, file);
472
+ const destName = prefix ? `${prefix}${file}` : file;
473
+ const destFile = path.join(commandsTarget, destName);
474
+ if (!dryRun)
475
+ await fs.copyFile(srcFile, destFile);
476
+ logVerbose(`Installed ${destFile}`, verbose);
477
+ }
478
+ }
479
+ }
480
+ }
481
+ spinner.succeed(`Slash commands set up for: ${aiTools.join(', ')}`);
482
+ }
483
+ catch (error) {
484
+ spinner.fail(fsErrorMessage(error));
485
+ throw error;
486
+ }
487
+ }
488
+ async function initializeProject(targetPath, aiTool, projectType, projectName, projectDescription, flags) {
489
+ try {
490
+ // Check if already initialized
491
+ const isInitialized = await checkIfInitialized(targetPath);
492
+ if (isInitialized) {
493
+ console.log(chalk_1.default.yellow('\nāš ļø Project already initialized with AI Flow'));
494
+ const { reinitialize } = await inquirer_1.default.prompt([
495
+ {
496
+ type: 'confirm',
497
+ name: 'reinitialize',
498
+ message: 'Do you want to reinitialize?',
499
+ default: false,
500
+ },
501
+ ]);
502
+ if (!reinitialize) {
503
+ console.log(chalk_1.default.blue('Initialization cancelled'));
504
+ return;
505
+ }
506
+ }
507
+ // Select AI tools
508
+ const aiTools = await selectAITool(aiTool);
509
+ // Select project type (v1.2.0: backend or frontend)
510
+ const selectedProjectType = await selectProjectType(projectType);
511
+ // Infer project name from directory
512
+ const inferredName = path
513
+ .basename(targetPath)
514
+ .split('-')
515
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
516
+ .join(' ');
517
+ // Request minimal project data only if not provided
518
+ if (projectName && !isValidName(projectName)) {
519
+ console.error(chalk_1.default.red('Invalid project name'));
520
+ process.exit(EXIT.INVALID_ARGS);
521
+ }
522
+ if (projectDescription && !isValidDescription(projectDescription)) {
523
+ console.error(chalk_1.default.red('Invalid project description'));
524
+ process.exit(EXIT.INVALID_ARGS);
525
+ }
526
+ let finalProjectName = projectName;
527
+ let finalProjectDescription = projectDescription || 'TBD - Run /flow-docs-gen to define';
528
+ if (!finalProjectName) {
529
+ const answers = await inquirer_1.default.prompt([
530
+ {
531
+ type: 'input',
532
+ name: 'projectName',
533
+ message: 'Project name (you can refine it in /bootstrap):',
534
+ default: inferredName,
535
+ validate: (input) => isValidName(input) ||
536
+ 'Enter 2-100 chars: letters, numbers, space, - _ .',
537
+ },
538
+ ]);
539
+ finalProjectName = answers.projectName;
540
+ }
541
+ console.log(chalk_1.default.cyan('\nšŸ“¦ Initializing AI Flow...\n'));
542
+ // Create structure
543
+ await createBootstrapStructure(targetPath, aiTools, selectedProjectType, flags?.dryRun, flags?.verbose);
544
+ await renderTemplates(targetPath, { name: finalProjectName, description: finalProjectDescription }, selectedProjectType, aiTools, flags?.dryRun, flags?.verbose);
545
+ await copyPrompts(targetPath, flags?.dryRun, flags?.verbose);
546
+ await setupSlashCommands(targetPath, aiTools, selectedProjectType, flags?.dryRun, flags?.verbose);
547
+ const modeText = flags?.dryRun ? 'DRY-RUN' : 'WRITE';
548
+ console.log(chalk_1.default.green('\nāœ… AI Flow initialized successfully!'));
549
+ console.log(chalk_1.default.white('\nSummary:'));
550
+ console.log(chalk_1.default.gray(` Project: ${finalProjectName}`));
551
+ console.log(chalk_1.default.gray(` Version: ${PKG_VERSION}`));
552
+ console.log(chalk_1.default.gray(` Directory: ${targetPath}`));
553
+ console.log(chalk_1.default.gray(` Tools: ${aiTools.join(', ')}`));
554
+ console.log(chalk_1.default.gray(` Mode: ${modeText}`));
555
+ console.log(chalk_1.default.white('\nNext steps:\n'));
556
+ const toolsText = aiTools.length === 1
557
+ ? aiTools[0]
558
+ : `${aiTools.slice(0, -1).join(', ')} and ${aiTools[aiTools.length - 1]}`;
559
+ if (selectedProjectType === 'fullstack') {
560
+ if (aiTools.includes('claude')) {
561
+ console.log(chalk_1.default.cyan(' 1. Open Claude Code'));
562
+ console.log(chalk_1.default.cyan(' 2. Run: /backend-flow-docs-gen (for backend documentation)'));
563
+ console.log(chalk_1.default.cyan(' 3. Run: /frontend-flow-docs-gen (for frontend documentation)'));
564
+ console.log(chalk_1.default.gray(' Each will guide you through 7 phases\n'));
565
+ }
566
+ else if (aiTools.includes('cursor')) {
567
+ console.log(chalk_1.default.cyan(' 1. Open Cursor'));
568
+ console.log(chalk_1.default.cyan(' 2. Run: /backend-flow-docs-gen (for backend documentation)'));
569
+ console.log(chalk_1.default.cyan(' 3. Run: /frontend-flow-docs-gen (for frontend documentation)'));
570
+ console.log(chalk_1.default.gray(' Each will guide you through 7 phases\n'));
571
+ }
572
+ else {
573
+ console.log(chalk_1.default.cyan(` 1. Open your AI tool (${toolsText})`));
574
+ console.log(chalk_1.default.cyan(' 2. Run: /backend-flow-docs-gen (for backend documentation)'));
575
+ console.log(chalk_1.default.cyan(' 3. Run: /frontend-flow-docs-gen (for frontend documentation)'));
576
+ console.log(chalk_1.default.gray(' Each will guide you through 7 phases\n'));
577
+ }
578
+ console.log(chalk_1.default.white('Available slash commands:'));
579
+ console.log(chalk_1.default.gray(' Backend commands:'));
580
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen - Backend 7-phase documentation generation'));
581
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen-phase-0-context - Backend context discovery'));
582
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen-phase-1-business - Backend discovery & business'));
583
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen-phase-2-data - Backend data architecture'));
584
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen-phase-3-architecture - Backend system architecture'));
585
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen-phase-4-security - Backend security & auth'));
586
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen-phase-5-standards - Backend code standards'));
587
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen-phase-6-testing - Backend testing'));
588
+ console.log(chalk_1.default.gray(' /backend-flow-docs-gen-phase-7-operations - Backend operations + tools'));
589
+ console.log(chalk_1.default.gray(' /backend-flow-docs-sync - Update backend documentation\n'));
590
+ console.log(chalk_1.default.gray(' Frontend commands:'));
591
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen - Frontend 7-phase documentation generation'));
592
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen-phase-0-context - Frontend context discovery'));
593
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen-phase-1-discovery - Frontend discovery & UX'));
594
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen-phase-2-components - Frontend components & framework'));
595
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen-phase-3-state - Frontend state management'));
596
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen-phase-4-styling - Frontend styling & design'));
597
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen-phase-5-standards - Frontend code standards'));
598
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen-phase-6-testing - Frontend testing'));
599
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-gen-phase-7-deployment - Frontend deployment'));
600
+ console.log(chalk_1.default.gray(' /frontend-flow-docs-sync - Update frontend documentation\n'));
601
+ }
602
+ else if (selectedProjectType === 'mobile') {
603
+ if (aiTools.includes('claude')) {
604
+ console.log(chalk_1.default.cyan(' 1. Open Claude Code'));
605
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
606
+ console.log(chalk_1.default.gray(' This will start the 7-phase interactive setup\n'));
607
+ }
608
+ else if (aiTools.includes('cursor')) {
609
+ console.log(chalk_1.default.cyan(' 1. Open Cursor'));
610
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
611
+ console.log(chalk_1.default.gray(' This will start the 7-phase interactive setup\n'));
612
+ }
613
+ else {
614
+ console.log(chalk_1.default.cyan(` 1. Open your AI tool (${toolsText})`));
615
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
616
+ console.log(chalk_1.default.gray(' This will start the 7-phase interactive setup\n'));
617
+ }
618
+ console.log(chalk_1.default.white('Available slash commands:'));
619
+ console.log(chalk_1.default.gray(' /flow-docs-gen - Full 7-phase documentation generation'));
620
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-0-context - Context Discovery (existing projects)'));
621
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-1-platform - Platform & Framework Selection'));
622
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-2-navigation - Navigation & Architecture'));
623
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-3-state - State & Data Management'));
624
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-4-permissions - Permissions & Native Features'));
625
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-5-standards - Code Standards'));
626
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-6-testing - Testing Strategy'));
627
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-7-deployment - Store Deployment'));
628
+ console.log(chalk_1.default.gray(' /flow-docs-sync - Update documentation when code changes\n'));
629
+ }
630
+ else {
631
+ if (aiTools.includes('claude')) {
632
+ console.log(chalk_1.default.cyan(' 1. Open Claude Code'));
633
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
634
+ console.log(chalk_1.default.gray(' This will start the 7-phase interactive setup\n'));
635
+ }
636
+ else if (aiTools.includes('cursor')) {
637
+ console.log(chalk_1.default.cyan(' 1. Open Cursor'));
638
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
639
+ console.log(chalk_1.default.gray(' This will start the 7-phase interactive setup\n'));
640
+ }
641
+ else {
642
+ console.log(chalk_1.default.cyan(` 1. Open your AI tool (${toolsText})`));
643
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
644
+ console.log(chalk_1.default.gray(' This will start the 7-phase interactive setup\n'));
645
+ }
646
+ console.log(chalk_1.default.white('Available slash commands:'));
647
+ console.log(chalk_1.default.gray(' /flow-docs-gen - Full 7-phase documentation generation'));
648
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-0-context - Context Discovery (existing projects)'));
649
+ if (selectedProjectType === 'backend') {
650
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-1-business - Discovery & Business'));
651
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-2-data - Data Architecture'));
652
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-3-architecture - System Architecture'));
653
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-4-security - Security & Auth'));
654
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-5-standards - Code Standards'));
655
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-6-testing - Testing'));
656
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-7-operations - Operations + Tools'));
657
+ }
658
+ else {
659
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-1-discovery - Discovery & UX'));
660
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-2-components - Components & Framework'));
661
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-3-state - State Management'));
662
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-4-styling - Styling & Design'));
663
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-5-standards - Code Standards'));
664
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-6-testing - Testing'));
665
+ console.log(chalk_1.default.gray(' /flow-docs-gen-phase-7-deployment - Deployment'));
666
+ }
667
+ console.log(chalk_1.default.gray(' /flow-docs-sync - Update documentation when code changes\n'));
668
+ }
669
+ if (flags?.dryRun) {
670
+ console.log(chalk_1.default.yellow('āš ļø Dry-run: no files were written. Run again without --dry-run to apply changes.\n'));
671
+ }
672
+ console.log(chalk_1.default.yellow('šŸ’” Tip: You can run individual phases if you want to work step-by-step\n'));
673
+ }
674
+ catch (error) {
675
+ console.error(chalk_1.default.red('\nāŒ Initialization failed:'), fsErrorMessage(error));
676
+ process.exit(EXIT.FS_ERROR);
677
+ }
678
+ }
679
+ // CLI Commands
680
+ program
681
+ .name('ai-flow')
682
+ .description('AI-powered development workflow from idea to production. Generate specs, plan features, and build with AI assistance.')
683
+ .version('1.0.1');
684
+ program
685
+ .command('init')
686
+ .description('Initialize AI Flow in current directory')
687
+ .argument('[path]', 'Target directory (defaults to current directory)', '.')
688
+ .option('--ai <tool>', 'AI tool to use (claude, cursor, copilot, gemini, all)')
689
+ .option('--type <type>', 'Project type (backend, frontend, fullstack, mobile)')
690
+ .option('--name <name>', 'Project name (skip interactive prompt)')
691
+ .option('--description <desc>', 'Project description (skip interactive prompt)')
692
+ .option('--verbose', 'Enable verbose logging')
693
+ .option('--dry-run', 'Simulate without writing files')
694
+ .action(async (targetPath, options) => {
695
+ const absolutePath = path.resolve(targetPath);
696
+ const flags = {
697
+ dryRun: options.dryRun === true,
698
+ verbose: options.verbose === true,
699
+ };
700
+ await initializeProject(absolutePath, options.ai, options.type, options.name, options.description, flags);
701
+ });
702
+ program
703
+ .command('check')
704
+ .description('Check if current directory is initialized')
705
+ .action(async () => {
706
+ const isInitialized = await checkIfInitialized(process.cwd());
707
+ if (isInitialized) {
708
+ console.log(chalk_1.default.green('āœ… Project is initialized with AI Flow'));
709
+ const configPath = path.join(process.cwd(), '.ai-flow', 'core', 'config.json');
710
+ const config = await fs.readJSON(configPath);
711
+ // Detect project type (support both old and new config format)
712
+ const projectType = config.projectType ||
713
+ (config.backend && !config.frontend
714
+ ? 'backend'
715
+ : config.frontend && !config.backend
716
+ ? 'frontend'
717
+ : config.mobile
718
+ ? 'mobile'
719
+ : 'backend');
720
+ const projectTypeDisplay = projectType === 'backend'
721
+ ? 'šŸ”§ Backend'
722
+ : projectType === 'frontend'
723
+ ? 'šŸŽØ Frontend'
724
+ : projectType === 'fullstack'
725
+ ? 'šŸš€ Full Stack'
726
+ : projectType === 'mobile'
727
+ ? 'šŸ“± Mobile'
728
+ : 'šŸ”§ Backend';
729
+ console.log(chalk_1.default.white('\nConfiguration:'));
730
+ console.log(chalk_1.default.gray(` Version: ${config.version}`));
731
+ console.log(chalk_1.default.gray(` Project Type: ${projectTypeDisplay}`));
732
+ console.log(chalk_1.default.gray(` AI Tools: ${config.aiTools.join(', ')}`));
733
+ console.log(chalk_1.default.gray(` Created: ${new Date(config.createdAt).toLocaleString()}`));
734
+ console.log(chalk_1.default.gray(` Working Dir: ${process.cwd()}`));
735
+ // Show correct prompts path based on project type
736
+ if (projectType === 'fullstack') {
737
+ const backendPromptsPath = path.join(process.cwd(), '.ai-flow', 'prompts', 'backend', 'bootstrap.md');
738
+ const frontendPromptsPath = path.join(process.cwd(), '.ai-flow', 'prompts', 'frontend', 'bootstrap.md');
739
+ console.log(chalk_1.default.gray(` Backend Prompts: ${backendPromptsPath}`));
740
+ console.log(chalk_1.default.gray(` Frontend Prompts: ${frontendPromptsPath}`));
741
+ }
742
+ else {
743
+ const promptsPath = path.join(process.cwd(), '.ai-flow', 'prompts', projectType, 'bootstrap.md');
744
+ console.log(chalk_1.default.gray(` Prompts: ${promptsPath}`));
745
+ }
746
+ console.log(chalk_1.default.white('\nNext steps:'));
747
+ if (projectType === 'fullstack') {
748
+ if (config.aiTools.includes('claude')) {
749
+ console.log(chalk_1.default.cyan(' 1. Open Claude Code'));
750
+ console.log(chalk_1.default.cyan(' 2. Run: /backend-flow-docs-gen (for backend documentation)'));
751
+ console.log(chalk_1.default.cyan(' 3. Run: /frontend-flow-docs-gen (for frontend documentation)'));
752
+ }
753
+ else if (config.aiTools.includes('cursor')) {
754
+ console.log(chalk_1.default.cyan(' 1. Open Cursor'));
755
+ console.log(chalk_1.default.cyan(' 2. Run: /backend-flow-docs-gen (for backend documentation)'));
756
+ console.log(chalk_1.default.cyan(' 3. Run: /frontend-flow-docs-gen (for frontend documentation)'));
757
+ }
758
+ else {
759
+ const toolsText = config.aiTools.length === 1
760
+ ? config.aiTools[0]
761
+ : `${config.aiTools.slice(0, -1).join(', ')} and ${config.aiTools[config.aiTools.length - 1]}`;
762
+ console.log(chalk_1.default.cyan(` 1. Open your AI tool (${toolsText})`));
763
+ console.log(chalk_1.default.cyan(' 2. Run: /backend-flow-docs-gen (for backend documentation)'));
764
+ console.log(chalk_1.default.cyan(' 3. Run: /frontend-flow-docs-gen (for frontend documentation)'));
765
+ }
766
+ }
767
+ else {
768
+ if (config.aiTools.includes('claude')) {
769
+ console.log(chalk_1.default.cyan(' 1. Open Claude Code'));
770
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
771
+ }
772
+ else if (config.aiTools.includes('cursor')) {
773
+ console.log(chalk_1.default.cyan(' 1. Open Cursor'));
774
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
775
+ }
776
+ else {
777
+ const toolsText = config.aiTools.length === 1
778
+ ? config.aiTools[0]
779
+ : `${config.aiTools.slice(0, -1).join(', ')} and ${config.aiTools[config.aiTools.length - 1]}`;
780
+ console.log(chalk_1.default.cyan(` 1. Open your AI tool (${toolsText})`));
781
+ console.log(chalk_1.default.cyan(' 2. Run: /bootstrap'));
782
+ }
783
+ }
784
+ }
785
+ else {
786
+ console.log(chalk_1.default.yellow('āš ļø Project is not initialized'));
787
+ console.log(chalk_1.default.white('Run: ai-flow init .'));
788
+ }
789
+ });
790
+ program.parse();
791
+ //# sourceMappingURL=cli.js.map