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.
- package/README.md +483 -32
- package/bin/cli.js +232 -41
- package/bin/create.js +135 -0
- package/bin/lint.js +20 -21
- package/docs/COMMANDS.md +200 -127
- package/docs/COMMITS/INDEX.md +1 -0
- package/docs/PROMPT_AI_CONTEXT.md +99 -0
- package/docs/langs/dotnet.md +36 -0
- package/docs/langs/java-spring.md +45 -0
- package/docs/langs/python-fastapi.md +35 -0
- package/docs/langs/unity.md +30 -0
- package/docs/langs/vue-nuxt.md +36 -0
- package/package.json +31 -3
- package/scaffolds/.cursorrules +6 -0
- package/scaffolds/AGENTS.md +27 -0
- package/scaffolds/Dockerfile +11 -0
- package/scaffolds/capacitor.config.ts +17 -0
- package/scaffolds/netlify.toml +8 -0
- package/scaffolds/prompt-lang.json +15 -0
- package/scaffolds/railway.json +12 -0
- package/scaffolds/tailwind.config.js +8 -0
- package/scaffolds/tauri.conf.json +26 -0
- package/schemas/language-module.json +116 -0
- package/schemas/prompt-lang.json +38 -3
- package/schemas/structures.json +145 -0
- package/src/ai/prompt-builder.js +184 -0
- package/src/ai/providers.js +247 -0
- package/src/annotations/registry.js +39 -0
- package/src/annotations/tags.json +24 -0
- package/src/commands/ai-gen.js +161 -0
- package/src/commands/component.js +242 -212
- package/src/commands/context.js +184 -109
- package/src/commands/extract.js +242 -0
- package/src/commands/figma.js +15 -15
- package/src/commands/init.js +197 -93
- package/src/commands/integrate.js +406 -0
- package/src/commands/lang.js +148 -0
- package/src/commands/qa-gen.js +139 -0
- package/src/commands/scaffold.js +127 -0
- package/src/commands/suggest.js +24 -14
- package/src/commands/teach.js +110 -0
- package/src/commands/validate.js +143 -83
- package/src/commands/wizard.js +456 -0
- package/src/generators/figma-prompt.js +20 -12
- package/src/language-service/plugin.cjs +94 -0
- package/src/language-service/plugin.d.ts +6 -0
- package/src/mcp-server.js +605 -0
- package/src/templates/langs/react/INDEX.json +262 -0
- package/src/templates/langs/react/MODULE.json +166 -0
- package/src/templates/langs/react/templates/hooks/useAuth.template.ts +134 -0
- package/src/templates/langs/react/templates/hooks/useDebounce.template.ts +45 -0
- package/src/templates/langs/react/templates/hooks/useForm.template.ts +146 -0
- package/src/templates/langs/react/templates/hooks/usePagination.template.ts +108 -0
- package/src/templates/langs/react/templates/services/apiService.template.ts +123 -0
- package/src/templates/langs/react/templates/ui/Button.template.tsx +87 -0
- package/src/templates/langs/react/templates/ui/Card.template.tsx +85 -0
- package/src/templates/langs/react/templates/ui/DataTable.template.tsx +163 -0
- package/src/templates/langs/react/templates/ui/Input.template.tsx +96 -0
- package/src/templates/langs/react/templates/ui/Modal.template.tsx +133 -0
- package/src/templates/langs/react/templates/ui/Select.template.tsx +99 -0
- package/src/templates/langs/vue/INDEX.json +246 -0
- package/src/templates/langs/vue/MODULE.json +105 -0
- package/src/templates/langs/vue/templates/composables/useAuth.template.ts +106 -0
- package/src/templates/langs/vue/templates/composables/useDebounce.template.ts +47 -0
- package/src/templates/langs/vue/templates/composables/useFetch.template.ts +54 -0
- package/src/templates/langs/vue/templates/composables/useForm.template.ts +127 -0
- package/src/templates/langs/vue/templates/composables/usePagination.template.ts +98 -0
- package/src/templates/langs/vue/templates/services/apiService.template.ts +116 -0
- package/src/templates/langs/vue/templates/ui/Button.template.vue +79 -0
- package/src/templates/langs/vue/templates/ui/Card.template.vue +73 -0
- package/src/templates/langs/vue/templates/ui/DataTable.template.vue +115 -0
- package/src/templates/langs/vue/templates/ui/Input.template.vue +70 -0
- package/src/templates/langs/vue/templates/ui/Modal.template.vue +112 -0
- package/src/templates/langs/vue/templates/ui/Select.template.vue +77 -0
- package/src/templates/scripts/log-actividad.sh +32 -0
- package/src/templates/scripts/log-commit.sh +35 -0
- package/src/templates/scripts/log-error.sh +45 -0
- package/src/templates/scripts/validate.sh +23 -0
- package/src/ts-transformer/index.cjs +86 -0
- package/src/utils/ai.js +35 -53
- package/src/utils/annotations.js +260 -214
- package/src/utils/config.js +61 -13
- package/src/utils/error-learner.js +203 -0
- package/src/utils/file-utils.js +119 -0
- package/src/utils/language-loader.js +167 -0
- package/src/utils/template-utils.js +45 -0
- package/src/vite-plugin/index.js +54 -0
- package/vscode-extension/package.json +23 -2
- package/vscode-extension/snippets/promptlang.json +1 -3
- 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
|
|
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
|
|
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
|
-
|
|
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 {
|
|
6
|
-
import
|
|
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
|
}
|