openprompt-lang 0.3.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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +663 -0
  3. package/bin/cli.js +110 -0
  4. package/bin/lint.js +50 -0
  5. package/docs/COMMANDS.md +229 -0
  6. package/docs/COMMITS/INDEX.md +11 -0
  7. package/docs/COMMITS/v0.1.0-existing.md +31 -0
  8. package/docs/COMMITS/v0.1.0-inicial.md +50 -0
  9. package/docs/COMMITS/v0.1.0-readme.md +24 -0
  10. package/docs/COMMITS/v0.2.0-strict-db-templates.md +50 -0
  11. package/docs/COMMITS/v0.3.0-parser-fixes-vscode.md +67 -0
  12. package/docs/COMMITS/v0.3.0-versioning-component.md +44 -0
  13. package/docs/DEPENDENCIES.md +45 -0
  14. package/docs/FRAMEWORK.md +1741 -0
  15. package/docs/SYNTAX.md +359 -0
  16. package/docs/VERSIONING.md +150 -0
  17. package/docs/referencia-metodologia/Anexos Finales Documentos de Respaldo y Estandarizaci/303/263n.md" +90 -0
  18. package/docs/referencia-metodologia/Cotizaciones.md +84 -0
  19. package/docs/referencia-metodologia/Example.md +1 -0
  20. package/docs/referencia-metodologia/ExtractorInformacion.py +78 -0
  21. package/docs/referencia-metodologia/Fase - 1 .- Desarrollo de la Metodolog/303/255a.md" +67 -0
  22. package/docs/referencia-metodologia/Fase - 2 .- Levantamiento de requisitos generales y traduccion a la IA.md +64 -0
  23. package/docs/referencia-metodologia/Fase - 3 .- Prototipado visual con IA (Figma Maker o equivalentes).md +64 -0
  24. package/docs/referencia-metodologia/Fase - 4 .- Especificacion de requisitos e iteracion con el cliente.md +58 -0
  25. package/docs/referencia-metodologia/Fase - 5 .- Estructuracion y maquetado de funciones (Scaffolding).md +118 -0
  26. package/docs/referencia-metodologia/Fase - 6 .- Estructuracion del backlog y division de tareas.md +48 -0
  27. package/docs/referencia-metodologia/Fase - 7 .- Desarrollo activo, pruebas y control de versiones.md +98 -0
  28. package/docs/referencia-metodologia/Fase - 8 .- Entrega, capacitaci/303/263n y mantenimiento.md" +55 -0
  29. package/docs/referencia-metodologia/Figma prompt template.md +130 -0
  30. package/docs/referencia-metodologia/Framework de Desarrollo Asistido por IA.md +1741 -0
  31. package/docs/referencia-metodologia/Indice General.md +83 -0
  32. package/docs/referencia-metodologia/Prompt refactorizar o creacion desde cero.md +50 -0
  33. package/docs/referencia-metodologia/docs/CONVENCIONES_DB.md +410 -0
  34. package/docs/referencia-metodologia/docs/CONVENCIONES_DOCUMENTACION.md +209 -0
  35. package/docs/referencia-metodologia/docs/PROMPTS/INDEX.md +73 -0
  36. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/01-hook-supabase.md +79 -0
  37. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/02-componente-ui.md +82 -0
  38. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/03-pagina-feature.md +70 -0
  39. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/04-comando-tauri.md +56 -0
  40. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/05-store-zustand.md +74 -0
  41. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/06-servicio-supabase.md +74 -0
  42. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/07-formulario-validacion.md +63 -0
  43. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/08-hook-capacitor.md +65 -0
  44. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/09-refactor-division.md +51 -0
  45. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/10-scaffolding-inicial.md +79 -0
  46. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/11-supabase-crud-service.md +114 -0
  47. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/12-supabase-hook-usetable.md +143 -0
  48. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/13-tauri-command-rust.md +84 -0
  49. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/14-tauri-wrapper-typescript.md +92 -0
  50. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/15-documentar-tabla-db.md +50 -0
  51. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/16-diagrama-arquitectura.md +60 -0
  52. package/docs/referencia-metodologia/docs/PROMPTS/PLANTILLAS/17-documentar-api-rpc.md +56 -0
  53. package/docs/referencia-metodologia/docs/PROMPTS/STACK/ionic-capacitor.md +52 -0
  54. package/docs/referencia-metodologia/docs/PROMPTS/STACK/react-web-puro.md +46 -0
  55. package/docs/referencia-metodologia/docs/PROMPTS/STACK/tauri-desktop.md +53 -0
  56. package/package.json +56 -0
  57. package/schemas/prompt-lang.json +98 -0
  58. package/src/commands/component.js +326 -0
  59. package/src/commands/context.js +206 -0
  60. package/src/commands/figma.js +63 -0
  61. package/src/commands/init.js +373 -0
  62. package/src/commands/suggest.js +31 -0
  63. package/src/commands/validate.js +183 -0
  64. package/src/generators/figma-prompt.js +56 -0
  65. package/src/utils/ai.js +143 -0
  66. package/src/utils/annotations.js +510 -0
  67. package/src/utils/config.js +60 -0
  68. package/vscode-extension/README.md +31 -0
  69. package/vscode-extension/language-configuration.json +7 -0
  70. package/vscode-extension/package.json +62 -0
  71. package/vscode-extension/snippets/promptlang.json +105 -0
  72. package/vscode-extension/syntaxes/annotations.tmGrammar.json +39 -0
  73. package/vscode-extension/syntaxes/promptlang.tmGrammar.json +14 -0
@@ -0,0 +1,373 @@
1
+ import { writeFileSync, readFileSync, existsSync, mkdirSync } from "fs";
2
+ import { join } from "path";
3
+ import chalk from "chalk";
4
+ import { detectStack } from "../utils/config.js";
5
+
6
+ const BASE_STRUCTURE = {
7
+ "src/components/ui": { desc: "Componentes atómicos reutilizables" },
8
+ "src/components/layout": { desc: "Componentes de layout (Navbar, Sidebar)" },
9
+ "src/components/shared": { desc: "Componentes compartidos del dominio" },
10
+ "src/features": { desc: "Módulos de features (auth, dashboard, etc.)" },
11
+ "src/hooks": { desc: "Custom hooks globales" },
12
+ "src/services": { desc: "APIs, clientes externos" },
13
+ "src/store": { desc: "Estado global (Zustand)" },
14
+ "src/types": { desc: "Interfaces globales" },
15
+ "src/utils": { desc: "Funciones utilitarias" },
16
+ "docs/COMMITS": { desc: "Logs de commits" },
17
+ "docs/LOGS/ERRORES": { desc: "Logs de errores por tipo" },
18
+ "docs/LOGS/ACTIVIDAD": { desc: "Logs de actividad diaria" },
19
+ "docs/BACKLOG": { desc: "Backlog por fases" },
20
+ "docs/PROMPTS/PLANTILLAS": { desc: "Prompts reutilizables" },
21
+ "docs/PROMPTS/STACK": { desc: "Contextos por tecnología" },
22
+ "scripts": { desc: "Scripts de automatización" },
23
+ };
24
+
25
+ const DESCRIPTIVE_SCRIPTS = {
26
+ "dev:start": "vite",
27
+ "dev:preview": "vite preview",
28
+ "build:prod": "vite build",
29
+ "build:analyze": "vite build --analyze",
30
+ "lint:check": "eslint src --ext .ts,.tsx",
31
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
32
+ "type:check": "tsc --noEmit",
33
+ "quality:doctor": "npx react-doctor check ./src",
34
+ "test:unit": "vitest run",
35
+ "test:watch": "vitest",
36
+ "test:coverage": "vitest run --coverage",
37
+ "validate:all": "npm run lint:check && npm run type:check && npm run quality:doctor && npm run test:unit",
38
+ };
39
+
40
+ export async function init(options) {
41
+ if (options.existing) {
42
+ return initExisting();
43
+ }
44
+
45
+ const projectName = options.name || "mi-proyecto";
46
+ const baseDir = join(process.cwd(), projectName);
47
+
48
+ console.log(chalk.cyan(`\n🚀 Inicializando proyecto: ${projectName}\n`));
49
+
50
+ // Crear directorios
51
+ for (const [dir, meta] of Object.entries(BASE_STRUCTURE)) {
52
+ const fullPath = join(baseDir, dir);
53
+ mkdirSync(fullPath, { recursive: true });
54
+ console.log(` 📁 ${dir}/`);
55
+ }
56
+
57
+ // Crear prompt-lang.json
58
+ const config = {
59
+ name: projectName,
60
+ version: "0.1.0",
61
+ stack: {
62
+ base: ["react", "typescript", "vite", "tailwind"],
63
+ extensions: options.stack ? [options.stack] : [],
64
+ },
65
+ profile: options.profile || "senior",
66
+ pipeline: {
67
+ "pre-commit": ["lint", "typecheck", "doctor", "test"],
68
+ scripts: {
69
+ "lint:check": "eslint src --ext .ts,.tsx",
70
+ "type:check": "tsc --noEmit",
71
+ "quality:doctor": "npx react-doctor check ./src",
72
+ "test:unit": "vitest run",
73
+ },
74
+ },
75
+ annotations: { enabled: true, strict: true },
76
+ components: {
77
+ source: "src/components/ui",
78
+ library: "",
79
+ },
80
+ docs: { commits: true, logs: true, backlog: true },
81
+ extractor: { ignore: [".env", "*.local", "dist"], output: "contexto.md" },
82
+ };
83
+
84
+ writeFileSync(join(baseDir, "prompt-lang.json"), JSON.stringify(config, null, 2), "utf-8");
85
+ console.log(chalk.green(" ✅ prompt-lang.json"));
86
+
87
+ // Crear AGENTS.md
88
+ const agentsContent = `# AGENTS.md — Contexto para IA
89
+
90
+ ## Stack
91
+ - React 18 + TypeScript + Vite
92
+ - Tailwind CSS 3.4
93
+ ${config.stack.extensions.includes("ionic") ? "- Ionic 8 + Capacitor 6 (mobile)" : ""}
94
+ ${config.stack.extensions.includes("tauri") ? "- Tauri v2 (desktop)" : ""}
95
+ ${config.stack.extensions.includes("supabase") ? "- Supabase (backend)" : ""}
96
+ - Zustand (estado global)
97
+
98
+ ## Convenciones
99
+ - Un componente por archivo, máximo 120 líneas
100
+ - Un hook por archivo, máximo 80 líneas
101
+ - 100% Tailwind utility classes (sin CSS personalizado)
102
+ - Barrel exports en cada carpeta (index.ts)
103
+ - Commits: conventional commits + log en docs/COMMITS/
104
+ - Prompt library: docs/PROMPTS/INDEX.md
105
+ - Framework: openPrompt-Lang (anotaciones @kind, @contract, @limit, etc.)
106
+
107
+ ## Perfil del desarrollador
108
+ ${config.profile}
109
+
110
+ ## Reglas críticas
111
+ - NO usar any
112
+ - NO superar límites de líneas sin refactorizar
113
+ - Ejecutar \`npm run validate:all\` antes de cada commit
114
+ - Las anotaciones PromptLang deben declarar @use() al inicio del archivo
115
+
116
+ ## Referencias
117
+ - Framework: docs/FRAMEWORK.md
118
+ - Prompt library: docs/PROMPTS/INDEX.md
119
+ `;
120
+
121
+ writeFileSync(join(baseDir, "AGENTS.md"), agentsContent, "utf-8");
122
+ console.log(chalk.green(" ✅ AGENTS.md"));
123
+
124
+ // Crear .gitignore
125
+ const gitignore = `node_modules/
126
+ dist/
127
+ build/
128
+ .env
129
+ .env.local
130
+ *.log
131
+ .DS_Store
132
+ coverage/
133
+ contexto.md
134
+ `;
135
+
136
+ writeFileSync(join(baseDir, ".gitignore"), gitignore, "utf-8");
137
+ console.log(chalk.green(" ✅ .gitignore"));
138
+
139
+ // Crear package.json con scripts descriptivos
140
+ const packageJson = {
141
+ name: projectName,
142
+ version: "0.1.0",
143
+ private: true,
144
+ type: "module",
145
+ scripts: { ...DESCRIPTIVE_SCRIPTS },
146
+ };
147
+
148
+ writeFileSync(join(baseDir, "package.json"), JSON.stringify(packageJson, null, 2), "utf-8");
149
+ console.log(chalk.green(" ✅ package.json (scripts descriptivos)"));
150
+
151
+ // Crear scripts de validación
152
+ const validateScript = `#!/bin/bash
153
+ set -e
154
+
155
+ echo "=== Pipeline de Validación (openPrompt-Lang) ==="
156
+
157
+ echo "[1/4] Linting..."
158
+ npm run lint:check || { echo "❌ Lint falló"; exit 1; }
159
+
160
+ echo "[2/4] TypeScript check..."
161
+ npm run type:check || { echo "❌ TypeScript falló"; exit 1; }
162
+
163
+ echo "[3/4] react-doctor..."
164
+ npm run quality:doctor || { echo "❌ react-doctor encontró problemas"; exit 1; }
165
+
166
+ echo "[4/4] Tests..."
167
+ npm run test:unit || { echo "❌ Tests fallaron"; exit 1; }
168
+
169
+ echo "=== ✅ Pipeline completo — Código válido ==="
170
+ `;
171
+
172
+ writeFileSync(join(baseDir, "scripts/validate.sh"), validateScript, "utf-8");
173
+ console.log(chalk.green(" ✅ scripts/validate.sh"));
174
+
175
+ // Crear docs/BACKLOG/PHASE-1-core.md
176
+ const backlogPhase1 = `# PHASE-1 Core — MVP Funcional
177
+
178
+ > Prioridad: P0 (Crítico) | 50% del proyecto
179
+
180
+ ## Tareas
181
+
182
+ ### TASK-001: Setup inicial del proyecto
183
+ **Módulo:** infraestructura
184
+ **Estimación:** 2h
185
+ **Criterios de aceptación:**
186
+ - [ ] Proyecto Vite + React + TypeScript creado
187
+ - [ ] Tailwind configurado
188
+ - [ ] Estructura de carpetas según estándar
189
+ - [ ] Pipeline de validación funcional
190
+
191
+ ### TASK-002: Sistema de autenticación
192
+ **Módulo:** auth
193
+ **Estimación:** 6h
194
+ **Dependencias:** TASK-001
195
+ **Criterios de aceptación:**
196
+ - [ ] Login con email/contraseña
197
+ - [ ] Registro de usuarios
198
+ - [ ] Protección de rutas
199
+ - [ ] Manejo de sesión con Zustand
200
+ `;
201
+
202
+ writeFileSync(join(baseDir, "docs/BACKLOG/PHASE-1-core.md"), backlogPhase1, "utf-8");
203
+ console.log(chalk.green(" ✅ docs/BACKLOG/PHASE-1-core.md"));
204
+
205
+ // Crear docs/COMMITS/INDEX.md
206
+ writeFileSync(
207
+ join(baseDir, "docs/COMMITS/INDEX.md"),
208
+ "# Índice de Commits\n\n| Fecha | Versión | Descripción |\n|---|---|---|\n",
209
+ "utf-8"
210
+ );
211
+ console.log(chalk.green(" ✅ docs/COMMITS/INDEX.md"));
212
+
213
+ console.log(chalk.cyan("\n📦 Estructura inicial creada exitosamente."));
214
+ console.log(chalk.cyan(`👉 cd ${projectName}`));
215
+ console.log(chalk.cyan(`👉 npx openPrompt-Lang context`));
216
+ console.log(chalk.cyan(`👉 npm run dev:start # Iniciar servidor de desarrollo`));
217
+ console.log(chalk.cyan(`👉 npm run validate:all # Pipeline completo de validación`));
218
+ console.log(chalk.cyan(`👉 Revisa docs/FRAMEWORK.md para las convenciones\n`));
219
+
220
+ return baseDir;
221
+ }
222
+
223
+ async function initExisting() {
224
+ const cwd = process.cwd();
225
+ const projectName = existsSync(join(cwd, "package.json"))
226
+ ? JSON.parse(readFileSync(join(cwd, "package.json"), "utf-8")).name || "mi-proyecto"
227
+ : "mi-proyecto";
228
+
229
+ console.log(chalk.cyan(`\n🔧 Configurando openPrompt-Lang en proyecto existente: ${projectName}\n`));
230
+
231
+ // Detectar stack
232
+ const stack = detectStack(cwd);
233
+ const detected = Object.entries(stack).filter(([, v]) => v).map(([k]) => k);
234
+ console.log(chalk.blue("🔍 Stack detectado:") + (detected.length ? detected.join(", ") : "ninguno detectado"));
235
+
236
+ const baseExtensions = [];
237
+ if (stack.ionic) baseExtensions.push("ionic");
238
+ if (stack.tauri) baseExtensions.push("tauri");
239
+ if (stack.supabase) baseExtensions.push("supabase");
240
+
241
+ // Crear prompt-lang.json
242
+ const config = {
243
+ name: projectName,
244
+ version: "0.1.0",
245
+ stack: {
246
+ base: detected.filter(t => ["react", "typescript", "vite", "tailwind"].includes(t)),
247
+ extensions: baseExtensions,
248
+ },
249
+ profile: "senior",
250
+ pipeline: {
251
+ "pre-commit": ["lint", "typecheck"],
252
+ scripts: {},
253
+ },
254
+ annotations: { enabled: true, strict: true },
255
+ components: {
256
+ source: "src/components/ui",
257
+ library: "",
258
+ },
259
+ docs: { commits: false, logs: false, backlog: false },
260
+ extractor: { ignore: [".env", "*.local", "dist", "node_modules"], output: "contexto.md" },
261
+ };
262
+
263
+ if (existsSync(join(cwd, "prompt-lang.json"))) {
264
+ console.log(chalk.yellow(" ⚠️ prompt-lang.json ya existe. Saltando."));
265
+ } else {
266
+ writeFileSync(join(cwd, "prompt-lang.json"), JSON.stringify(config, null, 2), "utf-8");
267
+ console.log(chalk.green(" ✅ prompt-lang.json"));
268
+ }
269
+
270
+ // Crear AGENTS.md
271
+ const agentsLines = [
272
+ "# AGENTS.md — Contexto para IA",
273
+ "",
274
+ "## Stack",
275
+ ...(stack.react ? ["- React 18+"] : []),
276
+ ...(stack.typescript ? ["- TypeScript"] : []),
277
+ ...(stack.vite ? ["- Vite"] : []),
278
+ ...(stack.tailwind ? ["- Tailwind CSS"] : []),
279
+ ...(stack.ionic ? ["- Ionic + Capacitor (mobile)"] : []),
280
+ ...(stack.tauri ? ["- Tauri (desktop)"] : []),
281
+ ...(stack.supabase ? ["- Supabase (backend)"] : []),
282
+ "",
283
+ "## Convenciones",
284
+ "- Anotaciones PromptLang con @kind, @contract, @limit",
285
+ "- Framework: openPrompt-Lang",
286
+ "",
287
+ "## Perfil del desarrollador",
288
+ "senior",
289
+ "",
290
+ "## Reglas críticas",
291
+ "- NO usar any",
292
+ "- NO superar límites de líneas sin refactorizar",
293
+ "- Las anotaciones PromptLang deben declarar @use() al inicio del archivo",
294
+ "",
295
+ "## Referencias",
296
+ "- Framework: openPrompt-Lang",
297
+ "- Prompt library: docs/PROMPTS/INDEX.md (si aplica)",
298
+ "",
299
+ ];
300
+
301
+ if (existsSync(join(cwd, "AGENTS.md"))) {
302
+ console.log(chalk.yellow(" ⚠️ AGENTS.md ya existe. Saltando."));
303
+ } else {
304
+ writeFileSync(join(cwd, "AGENTS.md"), agentsLines.join("\n"), "utf-8");
305
+ console.log(chalk.green(" ✅ AGENTS.md"));
306
+ }
307
+
308
+ // Preguntar: agregar scripts descriptivos al package.json
309
+ if (existsSync(join(cwd, "package.json"))) {
310
+ const { addScripts } = await import("inquirer").then(m =>
311
+ m.default.prompt([{
312
+ type: "confirm",
313
+ name: "addScripts",
314
+ message: "¿Agregar scripts descriptivos (dev:start, lint:check, validate:all...) al package.json?",
315
+ default: false,
316
+ }])
317
+ );
318
+
319
+ if (addScripts) {
320
+ const pkgPath = join(cwd, "package.json");
321
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
322
+ pkg.scripts = pkg.scripts || {};
323
+ let added = 0;
324
+ for (const [name, cmd] of Object.entries(DESCRIPTIVE_SCRIPTS)) {
325
+ if (!pkg.scripts[name]) {
326
+ pkg.scripts[name] = cmd;
327
+ added++;
328
+ }
329
+ }
330
+ if (added > 0) {
331
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
332
+ console.log(chalk.green(` ✅ ${added} scripts agregados al package.json`));
333
+ } else {
334
+ console.log(chalk.yellow(" ⚠️ Todos los scripts descriptivos ya existen. Sin cambios."));
335
+ }
336
+ }
337
+ }
338
+
339
+ // Preguntar: crear docs/
340
+ const { createDocs } = await import("inquirer").then(m =>
341
+ m.default.prompt([{
342
+ type: "confirm",
343
+ name: "createDocs",
344
+ message: "¿Crear docs/BACKLOG, docs/COMMITS y docs/LOGS?",
345
+ default: false,
346
+ }])
347
+ );
348
+
349
+ if (createDocs) {
350
+ const docDirs = ["docs/BACKLOG", "docs/COMMITS", "docs/LOGS/ERRORES", "docs/LOGS/ACTIVIDAD", "docs/PROMPTS/PLANTILLAS", "docs/PROMPTS/STACK"];
351
+ for (const dir of docDirs) {
352
+ const fullPath = join(cwd, dir);
353
+ mkdirSync(fullPath, { recursive: true });
354
+ console.log(` 📁 ${dir}/`);
355
+ }
356
+
357
+ const backlogIndex = join(cwd, "docs/BACKLOG/PHASE-1-core.md");
358
+ if (!existsSync(backlogIndex)) {
359
+ writeFileSync(backlogIndex, `# PHASE-1 Core — MVP Funcional\n\n> Prioridad: P0 (Crítico) | 50% del proyecto\n\n## Tareas\n\n### TASK-001: Primera tarea\n**Módulo:** \n**Estimación:** \n**Criterios de aceptación:**\n- [ ] \n`, "utf-8");
360
+ console.log(chalk.green(" ✅ docs/BACKLOG/PHASE-1-core.md"));
361
+ }
362
+
363
+ const commitsIndex = join(cwd, "docs/COMMITS/INDEX.md");
364
+ if (!existsSync(commitsIndex)) {
365
+ writeFileSync(commitsIndex, "# Índice de Commits\n\n| Fecha | Versión | Descripción |\n|---|---|---|\n", "utf-8");
366
+ console.log(chalk.green(" ✅ docs/COMMITS/INDEX.md"));
367
+ }
368
+ }
369
+
370
+ console.log(chalk.cyan("\n✅ openPrompt-Lang configurado en proyecto existente."));
371
+ console.log(chalk.cyan(`👉 openPrompt-Lang context --output contexto.md`));
372
+ console.log(chalk.cyan(`👉 Empieza a anotar tu código con @kind, @contract, @limit...\n`));
373
+ }
@@ -0,0 +1,31 @@
1
+ import chalk from "chalk";
2
+ import { suggestStack } from "../utils/ai.js";
3
+
4
+ export async function suggest(description) {
5
+ console.log(chalk.cyan(`\n🤖 Analizando: "${description}"\n`));
6
+
7
+ const result = await suggestStack(description);
8
+
9
+ if (result.source === "fallback" || !result.stack) {
10
+ console.log(result.plan);
11
+ console.log(chalk.yellow("\n📌 No se pudo conectar con IA. Usa el plan anterior con cualquier IA externa.\n"));
12
+ return;
13
+ }
14
+
15
+ console.log(chalk.green("✅ Stack sugerido:"));
16
+ console.log(` ${result.stack.join(", ") || "React + TypeScript + Vite + Tailwind"}`);
17
+
18
+ if (result.modules) {
19
+ console.log(chalk.green("\n📦 Módulos sugeridos:"));
20
+ for (const mod of result.modules) {
21
+ console.log(` • ${mod}`);
22
+ }
23
+ }
24
+
25
+ if (result.priorities) {
26
+ console.log(chalk.green("\n🎯 Prioridades:"));
27
+ for (const p of result.priorities) {
28
+ console.log(` ${p}`);
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,183 @@
1
+ import { readFileSync, existsSync, readdirSync, statSync } from "fs";
2
+ import { join, extname } from "path";
3
+ import { execSync } from "child_process";
4
+ import chalk from "chalk";
5
+ import { loadConfig, detectStack } from "../utils/config.js";
6
+ import { lintFile } from "../utils/annotations.js";
7
+
8
+ const CODE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx"]);
9
+
10
+ export async function validate(options) {
11
+ const baseDir = process.cwd();
12
+ const config = loadConfig(baseDir);
13
+ let hasErrors = false;
14
+
15
+ console.log(chalk.cyan("\n🔍 openPrompt-Lang: Validación\n"));
16
+
17
+ // 1. Validar estructura
18
+ console.log(chalk.yellow("[1/5] Verificando estructura..."));
19
+ const requiredDirs = ["src", "docs"];
20
+ for (const dir of requiredDirs) {
21
+ if (!existsSync(join(baseDir, dir))) {
22
+ console.log(chalk.red(` ❌ Falta carpeta: ${dir}/`));
23
+ hasErrors = true;
24
+ } else {
25
+ console.log(chalk.green(` ✅ ${dir}/`));
26
+ }
27
+ }
28
+
29
+ // 2. Validar config
30
+ console.log(chalk.yellow("\n[2/5] Verificando configuración..."));
31
+ if (existsSync(join(baseDir, "prompt-lang.json"))) {
32
+ console.log(chalk.green(" ✅ prompt-lang.json"));
33
+ } else {
34
+ console.log(chalk.yellow(" ⚠️ No hay prompt-lang.json (usando defaults)"));
35
+ }
36
+
37
+ if (existsSync(join(baseDir, "AGENTS.md"))) {
38
+ console.log(chalk.green(" ✅ AGENTS.md"));
39
+ } else {
40
+ console.log(chalk.yellow(" ⚠️ No hay AGENTS.md (recomendado)"));
41
+ }
42
+
43
+ // 2b. Validar coherencia stack
44
+ console.log(chalk.yellow("\n[2b/5] Validando coherencia stack..."));
45
+ const stack = config.stack || {};
46
+ const base = (stack.base || []).map(s => s.toLowerCase());
47
+ const extensions = (stack.extensions || []).map(s => s.toLowerCase());
48
+
49
+ if (base.includes("tauri") && !extensions.includes("tauri")) {
50
+ console.log(chalk.red(" ❌ stack.base incluye 'tauri' pero stack.extensions no lo declara"));
51
+ hasErrors = true;
52
+ } else {
53
+ console.log(chalk.green(" ✅ stack.base / extensions coherente"));
54
+ }
55
+
56
+ // 3. Validar anotaciones PromptLang en archivos
57
+ console.log(chalk.yellow("\n[3/5] Analizando anotaciones PromptLang..."));
58
+ let annotatedFiles = 0;
59
+ let annotationErrors = 0;
60
+ let annotationWarnings = 0;
61
+ let platformUsages = new Set();
62
+
63
+ const walkDir = (dirPath) => {
64
+ let entries;
65
+ try {
66
+ entries = readdirSync(dirPath);
67
+ } catch {
68
+ return;
69
+ }
70
+ for (const entry of entries) {
71
+ const fullPath = join(dirPath, entry);
72
+ try {
73
+ const stat = statSync(fullPath);
74
+ if (stat.isDirectory()) {
75
+ if (!entry.startsWith(".") && entry !== "node_modules" && entry !== "dist") {
76
+ walkDir(fullPath);
77
+ }
78
+ continue;
79
+ }
80
+ } catch {
81
+ continue;
82
+ }
83
+
84
+ const ext = extname(entry).toLowerCase();
85
+ if (!CODE_EXTENSIONS.has(ext)) continue;
86
+
87
+ try {
88
+ const content = readFileSync(fullPath, "utf-8");
89
+ if (!content.includes("@use") && !content.includes("@kind")) continue;
90
+
91
+ annotatedFiles++;
92
+ const { annotations, errors, warnings } = lintFile(content, config.annotations.strict);
93
+
94
+ // Colectar @platform usages para validación de stack
95
+ for (const ann of annotations) {
96
+ if (ann.tag === "platform" && ann.args) {
97
+ ann.args.split(",").forEach(p => platformUsages.add(p.trim()));
98
+ }
99
+ }
100
+
101
+ if (errors.length > 0 || warnings.length > 0) {
102
+ const relPath = entry;
103
+ for (const err of errors) {
104
+ annotationErrors++;
105
+ console.log(chalk.red(` ❌ ${relPath}: ${err}`));
106
+ }
107
+ for (const warn of warnings) {
108
+ annotationWarnings++;
109
+ console.log(chalk.yellow(` ⚠️ ${relPath}: ${warn}`));
110
+ }
111
+ }
112
+ } catch {
113
+ // skip
114
+ }
115
+ }
116
+ };
117
+
118
+ walkDir(join(baseDir, "src"));
119
+
120
+ if (annotatedFiles === 0) {
121
+ console.log(chalk.cyan(" 📭 No se encontraron archivos con anotaciones PromptLang"));
122
+ } else {
123
+ console.log(chalk.green(` 📄 ${annotatedFiles} archivos con anotaciones`));
124
+ if (annotationErrors > 0) {
125
+ hasErrors = true;
126
+ console.log(chalk.red(` ❌ ${annotationErrors} errores`));
127
+ }
128
+ if (annotationWarnings > 0) {
129
+ console.log(chalk.yellow(` ⚠️ ${annotationWarnings} advertencias`));
130
+ }
131
+ if (annotationErrors === 0 && annotationWarnings === 0) {
132
+ console.log(chalk.green(` ✅ Todas las anotaciones válidas`));
133
+ }
134
+ }
135
+
136
+ // Validación cruzada: @platform vs stack
137
+ if (platformUsages.size > 0) {
138
+ for (const plat of platformUsages) {
139
+ if (plat === "mobile" && !extensions.some(e => ["ionic", "capacitor"].includes(e))) {
140
+ console.log(chalk.yellow(` ⚠️ @platform(mobile) usado pero stack no incluye ionic/capacitor`));
141
+ }
142
+ if (plat === "desktop" && !extensions.includes("tauri")) {
143
+ console.log(chalk.yellow(` ⚠️ @platform(desktop) usado pero stack no incluye tauri`));
144
+ }
145
+ }
146
+ }
147
+
148
+ // 4. Ejecutar pipeline configurado
149
+ console.log(chalk.yellow("\n[4/5] Ejecutando pipeline..."));
150
+ const scripts = config.pipeline?.scripts || {};
151
+ const pipelineSteps = config.pipeline?.["pre-commit"] || [];
152
+
153
+ if (pipelineSteps.length === 0) {
154
+ console.log(chalk.cyan(" 📭 No hay pipeline configurado"));
155
+ } else {
156
+ for (const step of pipelineSteps) {
157
+ const scriptCmd = scripts[step];
158
+ if (!scriptCmd) {
159
+ console.log(chalk.yellow(` ⚠️ Paso "${step}" sin script configurado`));
160
+ continue;
161
+ }
162
+ try {
163
+ process.stdout.write(` ▶️ ${step}... `);
164
+ execSync(scriptCmd, { cwd: baseDir, stdio: "pipe" });
165
+ console.log(chalk.green("✅"));
166
+ } catch (err) {
167
+ console.log(chalk.red("❌"));
168
+ hasErrors = true;
169
+ console.log(chalk.red(` ${err.stderr?.toString().split("\n")[0] || "Error"}`));
170
+ }
171
+ }
172
+ }
173
+
174
+ // 5. Resumen
175
+ console.log(chalk.yellow("\n[5/5] Resumen\n"));
176
+
177
+ if (hasErrors) {
178
+ console.log(chalk.red("❌ Validación falló — revisa los errores arriba\n"));
179
+ process.exit(1);
180
+ } else {
181
+ console.log(chalk.green("✅ Validación completa — todo correcto\n"));
182
+ }
183
+ }
@@ -0,0 +1,56 @@
1
+ export function generateFigmaPrompt(answers) {
2
+ const { projectType, screens, mobileFirst, style, includeAntiPatterns } = answers;
3
+ const screenList = screens.split(",").map((s) => s.trim());
4
+
5
+ const styleMap = {
6
+ "Minimalista corporativo": "minimalista, profesional, colores neutros con acento azul oscuro, tipografía sans-serif limpia, espaciado generoso",
7
+ "Moderno vibrante": "moderno, atrevido, gradientes sutiles, colores vibrantes (púrpura/cian), micro-interacciones, glassmorphism ligero",
8
+ "Oscuro (dark mode)": "dark mode first, fondo gris oscuro (#0f0f0f), acentos en verde/azul neón, contrastes altos, sombras sutiles",
9
+ "Claro y limpio": "claro, fondos blancos/gris claro, mucho espacio negativo, bordes suaves, iconos lineales, tipografía elegante",
10
+ "Personalizado": style,
11
+ };
12
+
13
+ const prompt = `> [!example] Prompt generado por openPrompt-Lang
14
+ > \`\`\`markdown
15
+ > Eres un experto en diseño UI/UX y desarrollo Frontend con React y Tailwind CSS.
16
+ >
17
+ > ## Contexto
18
+ > - **Tipo de proyecto:** ${projectType}
19
+ > - **Pantallas a diseñar:** ${screenList.join(", ")}
20
+ > - **Enfoque:** ${mobileFirst ? "Mobile-first" : "Desktop-first"}
21
+ > - **Estilo visual:** ${styleMap[style] || style}
22
+ >
23
+ > ## Reglas de Diseño
24
+ > 1. **Modularidad React:** Cada elemento visual debe ser un componente independiente.
25
+ > - \`/components/ui/Button.tsx\`, \`/components/ui/Card.tsx\`, etc.
26
+ > - \`/components/layout/Navbar.tsx\`, \`/components/layout/Sidebar.tsx\`
27
+ > 2. **Tailwind 100%:** Sin CSS personalizado. Todo con clases de utilidad.
28
+ > 3. **Componentes atómicos:** Usar \`class-variance-authority\` para variantes.
29
+ > 4. **Composición:** Las páginas deben componer componentes, no ser monolíticas.
30
+ >
31
+ > ## Restricciones Técnicas
32
+ > - Navegación: ${mobileFirst ? "Bottom tabs en mobile, sidebar en desktop" : "Sidebar fija con header superior"}
33
+ > - Breakpoints: sm (640px), md (768px), lg (1024px), xl (1280px)
34
+ > - Zonas táctiles: mínimo \`h-10 w-10\` en mobile
35
+ > - Estados: loading, empty, error, success para cada vista
36
+ >
37
+ > ${includeAntiPatterns ? `## Anti-patrones (Prohibido)
38
+ > - ❌ Tamaños absolutos (h-[500px], w-[300px])
39
+ > - ❌ Posicionamiento absoluto para layout (usar flex/grid)
40
+ > - ❌ CSS personalizado o modules
41
+ > - ❌ Componentes de más de 120 líneas
42
+ > - ❌ Mezclar lógica de negocio en componentes de presentación` : ""}
43
+ >
44
+ > ## Lista de Pantallas
45
+ > ${screenList.map((s, i) => `${i + 1}. **${s}:** Describir componentes principales y flujo`).join("\n")}
46
+ >
47
+ > ## Entregables
48
+ > - Árbol de componentes con nombres y props principales
49
+ > - Layout de cada pantalla con estructura de grid/flex
50
+ > - Estados visuales (loading, empty, error) para cada componente crítico
51
+ > - Sugerencia de estructura de carpetas
52
+ > \`\`\`
53
+ `;
54
+
55
+ return prompt;
56
+ }