openprompt-lang 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +483 -32
  2. package/bin/cli.js +232 -41
  3. package/bin/create.js +135 -0
  4. package/bin/lint.js +20 -21
  5. package/docs/COMMANDS.md +200 -127
  6. package/docs/COMMITS/INDEX.md +1 -0
  7. package/docs/PROMPT_AI_CONTEXT.md +99 -0
  8. package/docs/langs/dotnet.md +36 -0
  9. package/docs/langs/java-spring.md +45 -0
  10. package/docs/langs/python-fastapi.md +35 -0
  11. package/docs/langs/unity.md +30 -0
  12. package/docs/langs/vue-nuxt.md +36 -0
  13. package/package.json +31 -3
  14. package/scaffolds/.cursorrules +6 -0
  15. package/scaffolds/AGENTS.md +27 -0
  16. package/scaffolds/Dockerfile +11 -0
  17. package/scaffolds/capacitor.config.ts +17 -0
  18. package/scaffolds/netlify.toml +8 -0
  19. package/scaffolds/prompt-lang.json +15 -0
  20. package/scaffolds/railway.json +12 -0
  21. package/scaffolds/tailwind.config.js +8 -0
  22. package/scaffolds/tauri.conf.json +26 -0
  23. package/schemas/language-module.json +116 -0
  24. package/schemas/prompt-lang.json +38 -3
  25. package/schemas/structures.json +145 -0
  26. package/src/ai/prompt-builder.js +184 -0
  27. package/src/ai/providers.js +247 -0
  28. package/src/annotations/registry.js +39 -0
  29. package/src/annotations/tags.json +24 -0
  30. package/src/commands/ai-gen.js +161 -0
  31. package/src/commands/component.js +242 -212
  32. package/src/commands/context.js +184 -109
  33. package/src/commands/extract.js +242 -0
  34. package/src/commands/figma.js +15 -15
  35. package/src/commands/init.js +197 -93
  36. package/src/commands/integrate.js +406 -0
  37. package/src/commands/lang.js +148 -0
  38. package/src/commands/qa-gen.js +139 -0
  39. package/src/commands/scaffold.js +127 -0
  40. package/src/commands/suggest.js +24 -14
  41. package/src/commands/teach.js +110 -0
  42. package/src/commands/validate.js +143 -83
  43. package/src/commands/wizard.js +456 -0
  44. package/src/generators/figma-prompt.js +20 -12
  45. package/src/language-service/plugin.cjs +94 -0
  46. package/src/language-service/plugin.d.ts +6 -0
  47. package/src/mcp-server.js +605 -0
  48. package/src/templates/langs/react/INDEX.json +262 -0
  49. package/src/templates/langs/react/MODULE.json +166 -0
  50. package/src/templates/langs/react/templates/hooks/useAuth.template.ts +134 -0
  51. package/src/templates/langs/react/templates/hooks/useDebounce.template.ts +45 -0
  52. package/src/templates/langs/react/templates/hooks/useForm.template.ts +146 -0
  53. package/src/templates/langs/react/templates/hooks/usePagination.template.ts +108 -0
  54. package/src/templates/langs/react/templates/services/apiService.template.ts +123 -0
  55. package/src/templates/langs/react/templates/ui/Button.template.tsx +87 -0
  56. package/src/templates/langs/react/templates/ui/Card.template.tsx +85 -0
  57. package/src/templates/langs/react/templates/ui/DataTable.template.tsx +163 -0
  58. package/src/templates/langs/react/templates/ui/Input.template.tsx +96 -0
  59. package/src/templates/langs/react/templates/ui/Modal.template.tsx +133 -0
  60. package/src/templates/langs/react/templates/ui/Select.template.tsx +99 -0
  61. package/src/templates/langs/vue/INDEX.json +246 -0
  62. package/src/templates/langs/vue/MODULE.json +105 -0
  63. package/src/templates/langs/vue/templates/composables/useAuth.template.ts +106 -0
  64. package/src/templates/langs/vue/templates/composables/useDebounce.template.ts +47 -0
  65. package/src/templates/langs/vue/templates/composables/useFetch.template.ts +54 -0
  66. package/src/templates/langs/vue/templates/composables/useForm.template.ts +127 -0
  67. package/src/templates/langs/vue/templates/composables/usePagination.template.ts +98 -0
  68. package/src/templates/langs/vue/templates/services/apiService.template.ts +116 -0
  69. package/src/templates/langs/vue/templates/ui/Button.template.vue +79 -0
  70. package/src/templates/langs/vue/templates/ui/Card.template.vue +73 -0
  71. package/src/templates/langs/vue/templates/ui/DataTable.template.vue +115 -0
  72. package/src/templates/langs/vue/templates/ui/Input.template.vue +70 -0
  73. package/src/templates/langs/vue/templates/ui/Modal.template.vue +112 -0
  74. package/src/templates/langs/vue/templates/ui/Select.template.vue +77 -0
  75. package/src/templates/scripts/log-actividad.sh +32 -0
  76. package/src/templates/scripts/log-commit.sh +35 -0
  77. package/src/templates/scripts/log-error.sh +45 -0
  78. package/src/templates/scripts/validate.sh +23 -0
  79. package/src/ts-transformer/index.cjs +86 -0
  80. package/src/utils/ai.js +35 -53
  81. package/src/utils/annotations.js +260 -214
  82. package/src/utils/config.js +61 -13
  83. package/src/utils/error-learner.js +203 -0
  84. package/src/utils/file-utils.js +119 -0
  85. package/src/utils/language-loader.js +167 -0
  86. package/src/utils/template-utils.js +45 -0
  87. package/src/vite-plugin/index.js +54 -0
  88. package/vscode-extension/package.json +23 -2
  89. package/vscode-extension/snippets/promptlang.json +1 -3
  90. package/vscode-extension/syntaxes/annotations-code.tmGrammar.json +15 -0
package/bin/cli.js CHANGED
@@ -1,22 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { Command } from "commander";
4
- import chalk from "chalk";
5
- import { readFileSync, existsSync } from "fs";
6
- import { join, dirname } from "path";
7
- import { fileURLToPath } from "url";
8
- import { createRequire } from "module";
3
+ import { Command } from "commander"
4
+ import chalk from "chalk"
5
+ import { readFileSync, existsSync } from "fs"
6
+ import { join, dirname } from "path"
7
+ import { fileURLToPath } from "url"
9
8
 
10
- const __dirname = dirname(fileURLToPath(import.meta.url));
11
- const require = createRequire(import.meta.url);
12
- const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
9
+ const __dirname = dirname(fileURLToPath(import.meta.url))
10
+ const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"))
13
11
 
14
- const program = new Command();
12
+ const program = new Command()
15
13
 
16
14
  program
17
15
  .name("openPrompt-Lang")
18
16
  .description(chalk.cyan("Framework de anotaciones para desarrollo asistido por IA"))
19
- .version(pkg.version);
17
+ .version(pkg.version)
20
18
 
21
19
  program
22
20
  .command("init")
@@ -25,17 +23,17 @@ program
25
23
  .option("--describe <text>", "Descripción del proyecto para sugerencia IA")
26
24
  .option("--existing", "Configurar en proyecto existente (solo archivos de configuración)")
27
25
  .action(async (options) => {
28
- const { init } = await import("../src/commands/init.js");
29
- await init(options);
30
- });
26
+ const { init } = await import("../src/commands/init.js")
27
+ await init(options)
28
+ })
31
29
 
32
30
  program
33
31
  .command("figma")
34
32
  .description("Generar prompt para diseño en Figma con convenciones React + Tailwind")
35
33
  .action(async () => {
36
- const { figma } = await import("../src/commands/figma.js");
37
- await figma();
38
- });
34
+ const { figma } = await import("../src/commands/figma.js")
35
+ await figma()
36
+ })
39
37
 
40
38
  program
41
39
  .command("context")
@@ -44,49 +42,54 @@ program
44
42
  .option("--scope <module>", "Filtrar por módulo (@scope)")
45
43
  .option("--no-ai", "No incluir anotaciones PromptLang en el output")
46
44
  .action(async (options) => {
47
- const { context } = await import("../src/commands/context.js");
48
- await context(options);
49
- });
45
+ const { context } = await import("../src/commands/context.js")
46
+ await context(options)
47
+ })
50
48
 
51
49
  program
52
50
  .command("validate")
53
51
  .description("Ejecutar pipeline de validación y verificar anotaciones")
54
52
  .option("--fix", "Auto-corregir errores cuando sea posible")
55
53
  .action(async (options) => {
56
- const { validate } = await import("../src/commands/validate.js");
57
- await validate(options);
58
- });
54
+ const { validate } = await import("../src/commands/validate.js")
55
+ await validate(options)
56
+ })
59
57
 
60
58
  program
61
59
  .command("suggest")
62
60
  .description("IA sugiere estructura/stack según descripción del proyecto")
63
61
  .argument("<description>", "Descripción del proyecto")
64
62
  .action(async (description) => {
65
- const { suggest } = await import("../src/commands/suggest.js");
66
- await suggest(description);
67
- });
63
+ const { suggest } = await import("../src/commands/suggest.js")
64
+ await suggest(description)
65
+ })
68
66
 
69
67
  const component = program
70
68
  .command("component")
71
- .description("Gestionar biblioteca de componentes reutilizables");
69
+ .description("Gestionar biblioteca de componentes reutilizables")
72
70
 
73
71
  component
74
72
  .command("list")
75
73
  .description("Listar componentes disponibles")
76
74
  .option("--library <path>", "Ruta a la biblioteca de componentes")
77
75
  .action(async (options) => {
78
- const { componentList } = await import("../src/commands/component.js");
79
- await componentList(options);
80
- });
76
+ const { componentList } = await import("../src/commands/component.js")
77
+ await componentList(options)
78
+ })
81
79
 
82
80
  component
83
81
  .command("add <name>")
84
- .description("Agregar componente de la biblioteca al proyecto")
82
+ .description("Agregar componente desde biblioteca o template del módulo de lenguaje")
85
83
  .option("--library <path>", "Ruta a la biblioteca de componentes")
84
+ .option("--template", "Usar template del módulo de lenguaje (INDEX.json)")
85
+ .option("--lang <lang>", "Lenguaje del template (default: de prompt-lang.json)")
86
+ .option("--variants <list>", "Variantes a incluir (separadas por coma)")
87
+ .option("--output <name>", "Nombre del archivo de salida (sin extensión)")
88
+ .option("--force", "Sobrescribir archivo existente")
86
89
  .action(async (name, options) => {
87
- const { componentAdd } = await import("../src/commands/component.js");
88
- await componentAdd(name, options);
89
- });
90
+ const { componentAdd } = await import("../src/commands/component.js")
91
+ await componentAdd(name, options)
92
+ })
90
93
 
91
94
  component
92
95
  .command("init")
@@ -94,17 +97,205 @@ component
94
97
  .option("--library <path>", "Ruta donde crear la biblioteca")
95
98
  .option("--name <name>", "Nombre de la biblioteca")
96
99
  .action(async (options) => {
97
- const { componentInit } = await import("../src/commands/component.js");
98
- await componentInit(options);
99
- });
100
+ const { componentInit } = await import("../src/commands/component.js")
101
+ await componentInit(options)
102
+ })
100
103
 
101
104
  component
102
105
  .command("manifest")
103
106
  .description("Mostrar el manifiesto de la biblioteca de componentes")
104
107
  .option("--library <path>", "Ruta a la biblioteca de componentes")
105
108
  .action(async (options) => {
106
- const { componentManifest } = await import("../src/commands/component.js");
107
- await componentManifest(options);
108
- });
109
+ const { componentManifest } = await import("../src/commands/component.js")
110
+ await componentManifest(options)
111
+ })
109
112
 
110
- program.parse(process.argv);
113
+ // ─── Wizard command ──────────────────────────────────────────────────────────
114
+
115
+ program
116
+ .command("wizard")
117
+ .description("Asistente interactivo para configurar proyecto openPrompt-Lang")
118
+ .action(async () => {
119
+ const { wizard } = await import("../src/commands/wizard.js")
120
+ await wizard()
121
+ })
122
+
123
+ // ─── Teach command ───────────────────────────────────────────────────────────
124
+
125
+ program
126
+ .command("teach <templateId>")
127
+ .description("Enseñanza estructurada desde template con @teachMe")
128
+ .option("--lang <lang>", "Lenguaje del template (default: react)")
129
+ .option("--code", "Mostrar código completo del template")
130
+ .option("--force", "Mostrar template aunque no tenga @teachMe")
131
+ .action(async (templateId, options) => {
132
+ const { teach } = await import("../src/commands/teach.js")
133
+ await teach(templateId, options)
134
+ })
135
+
136
+ // ─── QA commands ─────────────────────────────────────────────────────────────
137
+
138
+ program
139
+ .command("qa-gen")
140
+ .description("Generate tests from learned errors (@learn-error)")
141
+ .option("--lang <lang>", "Language module (default: from INDEX.json)")
142
+ .option("--source <dir>", "Source directory to scan for @learn-error")
143
+ .option("--output <dir>", "Output directory for generated tests (default: src/__tests__)")
144
+ .option("--template <id>", "Generate tests only for a specific template")
145
+ .option("--dry-run", "Preview without writing files")
146
+ .option("--no-scan", "Skip scanning source for new @learn-error annotations")
147
+ .action(async (options) => {
148
+ const { qaGen } = await import("../src/commands/qa-gen.js")
149
+ await qaGen(options)
150
+ })
151
+
152
+ program
153
+ .command("qa-learn")
154
+ .description("Parse @learn-error from a file and persist to language module")
155
+ .option("--file <path>", "Source file to scan for @learn-error annotations")
156
+ .option("--lang <lang>", "Language module (default: react)")
157
+ .action(async (options) => {
158
+ const { qaLearn } = await import("../src/commands/qa-gen.js")
159
+ await qaLearn(options)
160
+ })
161
+
162
+ // ─── Lang command ────────────────────────────────────────────────────────────
163
+
164
+ const lang = program.command("lang").description("Gestionar módulos de lenguaje plugables")
165
+
166
+ lang
167
+ .command("list")
168
+ .description("Listar lenguajes disponibles")
169
+ .action(async () => {
170
+ const { langList } = await import("../src/commands/lang.js")
171
+ await langList()
172
+ })
173
+
174
+ lang
175
+ .command("index <langId>")
176
+ .description("Mostrar índice de templates de un lenguaje")
177
+ .option("--category <category>", "Filtrar por categoría")
178
+ .action(async (langId, options) => {
179
+ const { langIndex } = await import("../src/commands/lang.js")
180
+ await langIndex(langId, options)
181
+ })
182
+
183
+ lang
184
+ .command("search <query>")
185
+ .description("Buscar templates en todos los lenguajes")
186
+ .option("--lang <lang>", "Filtrar por lenguaje")
187
+ .action(async (query, options) => {
188
+ const { langSearch } = await import("../src/commands/lang.js")
189
+ await langSearch(query, options)
190
+ })
191
+
192
+ lang
193
+ .command("errors [langId]")
194
+ .description("Mostrar errores aprendidos")
195
+ .option("--template <id>", "Filtrar por template ID")
196
+ .action(async (langId, options) => {
197
+ const { langErrors } = await import("../src/commands/lang.js")
198
+ await langErrors(langId || "react", options)
199
+ })
200
+
201
+ // ─── Extract command ─────────────────────────────────────────────────────────
202
+
203
+ program
204
+ .command("extract [sourceDir]")
205
+ .description("Analyze project and extract reusable components as templates")
206
+ .option("--lang <lang>", "Language module to extract into (default: from prompt-lang.json)")
207
+ .option("--min-reuse <n>", "Minimum imports to qualify (default: 2)")
208
+ .option("--dry-run", "Analyze only, don't write files")
209
+ .action(async (sourceDir, options) => {
210
+ const { extractTemplates } = await import("../src/commands/extract.js")
211
+ await extractTemplates(sourceDir || "src", options)
212
+ })
213
+
214
+ program
215
+ .command("analyze [sourceDir]")
216
+ .description("Analyze project structure, deps, and code health")
217
+ .action(async (sourceDir) => {
218
+ const { extractAnalyze } = await import("../src/commands/extract.js")
219
+ await extractAnalyze(sourceDir || "src", {})
220
+ })
221
+
222
+ // ─── Integrate command ────────────────────────────────────────────────────────
223
+
224
+ program
225
+ .command("integrate")
226
+ .description("Configure Opencode, Cursor, and VS Code for the project")
227
+ .option("--all", "Setup all integrations without prompting")
228
+ .option("--lang <lang>", "Language (auto-detects from prompt-lang.json)")
229
+ .option("--no-ask", "Skip interactive prompts")
230
+ .action(async (options) => {
231
+ const { integrate } = await import("../src/commands/integrate.js")
232
+ await integrate(options)
233
+ })
234
+
235
+ // ─── AI commands ─────────────────────────────────────────────────────────────
236
+
237
+ program
238
+ .command("ai-gen")
239
+ .description("Generate components from natural language descriptions")
240
+ .option("--description <text>", "Description of what to generate")
241
+ .option("--name <name>", "Component name (auto-suggested if omitted)")
242
+ .option("--lang <lang>", "Language module (default: react)")
243
+ .option("--profile <profile>", "senior | mid | junior (default: mid)")
244
+ .option(
245
+ "--provider <provider>",
246
+ "AI provider: openai | anthropic | ollama | mock (default: auto-detect)"
247
+ )
248
+ .option("--output <dir>", "Output directory (default: src/components)")
249
+ .option("--force", "Overwrite existing files without asking")
250
+ .option("--validate", "Run annotation validation after generation")
251
+ .option("--verbose", "Show prompt and extended output")
252
+ .option("--temperature <num>", "Temperature for generation (default: 0.3)")
253
+ .option("--max-tokens <num>", "Max tokens for generation (default: 4096)")
254
+ .action(async (options) => {
255
+ const { aiGen } = await import("../src/commands/ai-gen.js")
256
+ await aiGen(options)
257
+ })
258
+
259
+ program
260
+ .command("ai-providers")
261
+ .description("List available AI providers and their status")
262
+ .action(async () => {
263
+ const { aiProviders } = await import("../src/commands/ai-gen.js")
264
+ await aiProviders()
265
+ })
266
+
267
+ // ─── Scaffold command ────────────────────────────────────────────────────────
268
+
269
+ const scaffold = program
270
+ .command("scaffold")
271
+ .description("Gestionar scafffolding de proyectos por framework")
272
+
273
+ scaffold
274
+ .command("folders <framework>")
275
+ .description("Crear estructura de carpetas según framework")
276
+ .option("--name <name>", "Nombre del proyecto (directorio)")
277
+ .option("--force", "Sobrescribir archivos existentes")
278
+ .action(async (framework, options) => {
279
+ const { scaffoldFolders } = await import("../src/commands/scaffold.js")
280
+ await scaffoldFolders(framework, options)
281
+ })
282
+
283
+ scaffold
284
+ .command("list")
285
+ .description("Listar frameworks disponibles en el catálogo")
286
+ .action(async () => {
287
+ const { scaffoldList } = await import("../src/commands/scaffold.js")
288
+ await scaffoldList()
289
+ })
290
+
291
+ // ─── MCP server command ───────────────────────────────────────────────────────
292
+
293
+ program
294
+ .command("mcp")
295
+ .description("Start MCP server for opencode integration via stdio")
296
+ .action(async () => {
297
+ const { startServer } = await import("../src/mcp-server.js")
298
+ await startServer()
299
+ })
300
+
301
+ program.parse(process.argv)
package/bin/create.js ADDED
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execSync } from "child_process"
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync, rmSync } from "fs"
5
+ import { join, dirname } from "path"
6
+ import { fileURLToPath } from "url"
7
+ import chalk from "chalk"
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url))
10
+
11
+ async function main() {
12
+ const args = process.argv.slice(2)
13
+ const projectName = args[0] || "mi-app"
14
+ const depsIndex = args.indexOf("--deps")
15
+ const deps = depsIndex !== -1 ? args[depsIndex + 1]?.split(",") || [] : []
16
+ const deployIndex = args.indexOf("--deploy")
17
+ const deploy = deployIndex !== -1 ? args[deployIndex + 1] : null
18
+ const hasIonic = args.includes("--ionic")
19
+ const hasTauri = args.includes("--tauri")
20
+ const force = args.includes("--force")
21
+
22
+ const projectDir = join(process.cwd(), projectName)
23
+
24
+ console.log(chalk.cyan(`\n🚀 Creando proyecto: ${projectName}\n`))
25
+
26
+ // 1. Crear con Vite
27
+ try {
28
+ console.log(chalk.blue(" [1/5] Creando base Vite + React + TS..."))
29
+ execSync(
30
+ `npx create-vite@latest ${projectName} --template react-ts ${force ? "--force" : ""}`,
31
+ {
32
+ stdio: "pipe",
33
+ cwd: process.cwd(),
34
+ }
35
+ )
36
+ console.log(chalk.green(" ✅ Base Vite creada"))
37
+ } catch {
38
+ console.log(chalk.yellow(" ⚠️ Vite base ya existe o falló. Continuando..."))
39
+ }
40
+
41
+ // 2. Limpiar boilerplate predecible
42
+ console.log(chalk.blue(" [2/5] Limpiando boilerplate innecesario..."))
43
+ const toDelete = ["src/App.css", "src/assets", "public/vite.svg"]
44
+ for (const file of toDelete) {
45
+ const fullPath = join(projectDir, file)
46
+ if (existsSync(fullPath)) {
47
+ rmSync(fullPath, { recursive: true, force: true })
48
+ }
49
+ }
50
+ // Reescribir App.tsx minimal
51
+ const appContent = `function App() {
52
+ return <div className="min-h-screen bg-gray-50" />
53
+ }
54
+
55
+ export default App
56
+ `
57
+ writeFileSync(join(projectDir, "src/App.tsx"), appContent, "utf-8")
58
+
59
+ // 3. Instalar dependencias adicionales
60
+ if (deps.length > 0) {
61
+ console.log(chalk.blue(` [3/5] Instalando dependencias: ${deps.join(", ")}...`))
62
+ try {
63
+ execSync(`npm install ${deps.join(" ")}`, { stdio: "pipe", cwd: projectDir })
64
+ console.log(chalk.green(" ✅ Dependencias instaladas"))
65
+ } catch {
66
+ console.log(
67
+ chalk.yellow(" ⚠️ Error instalando dependencias. Continúa con npm install manual.")
68
+ )
69
+ }
70
+ }
71
+
72
+ // 4. Copiar scaffolds
73
+ console.log(chalk.blue(" [4/5] Copiando archivos de configuración..."))
74
+ const scaffoldsDir = join(__dirname, "..", "scaffolds")
75
+
76
+ const scaffoldFiles = [
77
+ ["tailwind.config.js", "tailwind.config.js"],
78
+ ["prompt-lang.json", "prompt-lang.json"],
79
+ ]
80
+
81
+ if (deploy === "railway") scaffoldFiles.push(["railway.json", "railway.json"])
82
+ if (deploy === "netlify") scaffoldFiles.push(["netlify.toml", "netlify.toml"])
83
+ if (hasIonic) scaffoldFiles.push(["capacitor.config.ts", "capacitor.config.ts"])
84
+ if (hasTauri) scaffoldFiles.push(["tauri.conf.json", "tauri.conf.json"])
85
+
86
+ for (const [src, dest] of scaffoldFiles) {
87
+ const srcPath = join(scaffoldsDir, src)
88
+ const destPath = join(projectDir, dest)
89
+ if (existsSync(srcPath) && (!existsSync(destPath) || force)) {
90
+ copyFileSync(srcPath, destPath)
91
+ console.log(` ✅ ${dest}`)
92
+ }
93
+ }
94
+
95
+ // 5. Configurar package.json con scripts descriptivos
96
+ console.log(chalk.blue(" [5/5] Agregando scripts descriptivos..."))
97
+ const pkgPath = join(projectDir, "package.json")
98
+ if (existsSync(pkgPath)) {
99
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"))
100
+ const descriptiveScripts = {
101
+ "dev:start": "vite",
102
+ "dev:preview": "vite preview",
103
+ "build:prod": "vite build",
104
+ "build:analyze": "vite build --analyze",
105
+ "lint:check": "eslint src --ext .ts,.tsx",
106
+ "lint:fix": "eslint src --ext .ts,.tsx --fix",
107
+ "type:check": "tsc --noEmit",
108
+ "test:unit": "vitest run",
109
+ "test:watch": "vitest",
110
+ "test:coverage": "vitest run --coverage",
111
+ "validate:all": "npm run lint:check && npm run type:check && npm run test:unit",
112
+ }
113
+ pkg.scripts = { ...descriptiveScripts, ...pkg.scripts }
114
+ writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8")
115
+ console.log(chalk.green(" ✅ Scripts descriptivos agregados"))
116
+ }
117
+
118
+ // Ionic plug
119
+ if (hasIonic) {
120
+ console.log(chalk.blue(" 🔌 Integrando Ionic..."))
121
+ try {
122
+ execSync("npx cap init App com.app.app --web-dir=dist", { stdio: "pipe", cwd: projectDir })
123
+ execSync("npx cap add android", { stdio: "pipe", cwd: projectDir })
124
+ console.log(chalk.green(" ✅ Ionic/Capacitor configurado"))
125
+ } catch {
126
+ console.log(chalk.yellow(" ⚠️ Error en setup Ionic. Configura manualmente."))
127
+ }
128
+ }
129
+
130
+ console.log(chalk.cyan(`\n✅ ${projectName} listo!`))
131
+ console.log(chalk.cyan(` cd ${projectName}`))
132
+ console.log(chalk.cyan(` npm run dev:start\n`))
133
+ }
134
+
135
+ main().catch(console.error)
package/bin/lint.js CHANGED
@@ -1,50 +1,49 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { readFileSync, existsSync } from "fs";
4
- import { join } from "path";
5
- import { loadConfig } from "../src/utils/config.js";
6
- import { lintFile } from "../src/utils/annotations.js";
7
- import chalk from "chalk";
3
+ import { readFileSync, existsSync } from "fs"
4
+ import { join } from "path"
5
+ import { lintFile } from "../src/utils/annotations.js"
6
+ import chalk from "chalk"
8
7
 
9
- const targetFile = join(process.cwd(), process.argv[2] || "");
8
+ const targetFile = join(process.cwd(), process.argv[2] || "")
10
9
 
11
10
  if (!targetFile || !existsSync(targetFile)) {
12
- console.log(chalk.red("❌ Archivo no encontrado"));
13
- console.log("Uso: node bin/lint.js <archivo>");
14
- process.exit(1);
11
+ console.log(chalk.red("❌ Archivo no encontrado"))
12
+ console.log("Uso: node bin/lint.js <archivo>")
13
+ process.exit(1)
15
14
  }
16
15
 
17
- const content = readFileSync(targetFile, "utf-8");
18
- const { annotations, errors, warnings } = lintFile(content);
16
+ const content = readFileSync(targetFile, "utf-8")
17
+ const { annotations, errors, warnings } = lintFile(content)
19
18
 
20
19
  if (annotations.length === 0) {
21
- console.log(chalk.cyan("📭 Sin anotaciones PromptLang en este archivo"));
22
- process.exit(0);
20
+ console.log(chalk.cyan("📭 Sin anotaciones PromptLang en este archivo"))
21
+ process.exit(0)
23
22
  }
24
23
 
25
- console.log(chalk.cyan(`\n🔍 Anotaciones encontradas: ${annotations.length}\n`));
24
+ console.log(chalk.cyan(`\n🔍 Anotaciones encontradas: ${annotations.length}\n`))
26
25
 
27
26
  for (const ann of annotations) {
28
27
  const argsStr = ann.args.length
29
28
  ? ann.args.map((a) => (a.key ? `${a.key}: ${a.value}` : a.value)).join(", ")
30
- : "";
31
- console.log(` @${ann.name}${argsStr ? `(${argsStr})` : ""}`);
29
+ : ""
30
+ console.log(` @${ann.name}${argsStr ? `(${argsStr})` : ""}`)
32
31
  }
33
32
 
34
33
  if (errors.length > 0) {
35
- console.log(chalk.red(`\n❌ Errores (${errors.length}):\n`));
34
+ console.log(chalk.red(`\n❌ Errores (${errors.length}):\n`))
36
35
  for (const err of errors) {
37
- console.log(chalk.red(` • ${err}`));
36
+ console.log(chalk.red(` • ${err}`))
38
37
  }
39
38
  }
40
39
 
41
40
  if (warnings.length > 0) {
42
- console.log(chalk.yellow(`\n⚠️ Advertencias (${warnings.length}):\n`));
41
+ console.log(chalk.yellow(`\n⚠️ Advertencias (${warnings.length}):\n`))
43
42
  for (const warn of warnings) {
44
- console.log(chalk.yellow(` • ${warn}`));
43
+ console.log(chalk.yellow(` • ${warn}`))
45
44
  }
46
45
  }
47
46
 
48
47
  if (errors.length === 0 && warnings.length === 0) {
49
- console.log(chalk.green("\n✅ Todas las anotaciones válidas\n"));
48
+ console.log(chalk.green("\n✅ Todas las anotaciones válidas\n"))
50
49
  }