openprompt-lang 0.11.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +13 -2
- package/bin/opl.js +27 -0
- package/docs/FRAMEWORK.md +22 -74
- package/package.json +2 -1
- package/src/ai/providers.js +4 -1
- package/src/cli/commands-init.js +5 -4
- package/src/cli/commands-misc.js +11 -1
- package/src/cli/commands-opl.js +1 -1
- package/src/commands/component.js +1 -1
- package/src/commands/db-rules.js +1 -1
- package/src/commands/init-core.js +3 -3
- package/src/commands/init-existing.js +132 -40
- package/src/commands/init-helpers.js +1 -1
- package/src/commands/integrate.js +3 -0
- package/src/commands/learning.js +1 -1
- package/src/commands/opl-assess-detect.js +269 -0
- package/src/commands/opl-assess-display.js +217 -0
- package/src/commands/opl-assess-scoring.js +216 -0
- package/src/commands/opl-assess.js +37 -470
- package/src/commands/opl-context-index.js +1 -1
- package/src/commands/opl-read.js +1 -1
- package/src/commands/opl-session.js +1 -1
- package/src/commands/opl-upgrade.js +11 -6
- package/src/commands/validate.js +208 -216
- package/src/mcp-workflow.js +1 -1
- package/src/templates/langs/react/templates/hooks/use-reducer-form.ts +2 -2
- package/src/utils/annotations-parse.js +271 -0
- package/src/utils/annotations.js +49 -378
- package/src/utils/config.js +32 -1
- package/src/utils/errors.js +141 -0
- package/src/utils/file-utils.js +1 -1
- package/src/utils/generate-framework-md.js +57 -511
- package/src/utils/generate-framework-sections.js +553 -0
- package/src/utils/pipeline.js +181 -0
package/bin/cli.js
CHANGED
|
@@ -20,6 +20,11 @@ import { register as registerLearning } from "../src/cli/commands-learning.js"
|
|
|
20
20
|
import { register as registerOpl } from "../src/cli/commands-opl.js"
|
|
21
21
|
import { register as registerMisc } from "../src/cli/commands-misc.js"
|
|
22
22
|
|
|
23
|
+
import { handleUncaughtErrors, EXIT_CODES } from "../src/utils/errors.js"
|
|
24
|
+
|
|
25
|
+
// Global error handler for uncaught exceptions
|
|
26
|
+
handleUncaughtErrors()
|
|
27
|
+
|
|
23
28
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
24
29
|
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"))
|
|
25
30
|
|
|
@@ -62,6 +67,12 @@ registerMisc(program)
|
|
|
62
67
|
try {
|
|
63
68
|
await program.parseAsync(process.argv)
|
|
64
69
|
} catch (err) {
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
if (err.exitCode !== undefined) {
|
|
71
|
+
console.error('\n' + err.userMessage + '\n')
|
|
72
|
+
process.exitCode = err.exitCode
|
|
73
|
+
} else {
|
|
74
|
+
console.error(chalk.red(`\n✘ Error inesperado: ${err.message}\n`))
|
|
75
|
+
if (process.env.DEBUG) console.error(chalk.gray(err.stack))
|
|
76
|
+
process.exitCode = EXIT_CODES.GENERIC
|
|
77
|
+
}
|
|
67
78
|
}
|
package/bin/opl.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// @use(kind, contract, limit)
|
|
3
|
+
// @kind(util)
|
|
4
|
+
// @contract(in: argv -> out: exitCode, sideEffect: delega a cli.js con los mismos argumentos)
|
|
5
|
+
// @limit(lines: 30)
|
|
6
|
+
|
|
7
|
+
// Shortcut: 'opl' → 'openPrompt-Lang'
|
|
8
|
+
// Este archivo permite usar 'opl' como comando corto en vez de 'openPrompt-Lang'
|
|
9
|
+
// Ej: opl validate, opl assess, opl search react
|
|
10
|
+
|
|
11
|
+
import { fileURLToPath } from 'url'
|
|
12
|
+
import { dirname, join } from 'path'
|
|
13
|
+
import { execFileSync } from 'child_process'
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
16
|
+
const cliPath = join(__dirname, 'cli.js')
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const result = execFileSync(process.execPath, [cliPath, ...process.argv.slice(2)], {
|
|
20
|
+
cwd: process.cwd(),
|
|
21
|
+
stdio: 'inherit',
|
|
22
|
+
env: { ...process.env, OPL_ALIAS: '1' }
|
|
23
|
+
})
|
|
24
|
+
process.exitCode = result?.status ?? 0
|
|
25
|
+
} catch (err) {
|
|
26
|
+
process.exitCode = err.status ?? 1
|
|
27
|
+
}
|
package/docs/FRAMEWORK.md
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
## 1. Anotaciones Disponibles
|
|
10
11
|
|
|
11
12
|
| Tag | Categoría | Descripción |
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
| `@pattern()` | Arquitectura | Patrón de diseño (ver sección 5) |
|
|
25
26
|
| `@test()` | Calidad | Metadata de tests: `@test(coverage: 80)` |
|
|
26
27
|
| `@learn-error` | Calidad | Error aprendido: `@learn-error id=ID fix='...'` |
|
|
27
|
-
| `@scar` | Calidad | Cicatriz de Guerra
|
|
28
|
+
| `@scar` | Calidad | Cicatriz de Guerra |
|
|
28
29
|
| `@goodPractice()` | Documentación | Buena práctica |
|
|
29
30
|
| `@badPractice()` | Documentación | Anti-patrón |
|
|
30
31
|
| `@teachMe` | Documentación | Archivo es template de enseñanza |
|
|
@@ -95,21 +96,21 @@ Comandos disponibles desde `bin/cli.js` o `npm run opl` o `node bin/cli.js`:
|
|
|
95
96
|
opl # Pantalla de bienvenida "puerta de entrada"
|
|
96
97
|
opl help # Misma pantalla de bienvenida
|
|
97
98
|
opl tutorial # Recorrido guiado interactivo (7 min)
|
|
98
|
-
opl index [path] # Navegar conocimiento por niveles
|
|
99
|
+
opl index [path] # Navegar conocimiento por niveles
|
|
99
100
|
opl read <dominio>/<id> # Leer contenido específico (--chapter n --full)
|
|
100
|
-
opl search <query> # Búsqueda híbrida
|
|
101
|
-
opl system [name] # Explorar sistemas de conocimiento
|
|
102
|
-
opl graph [concept] # Grafo de relaciones
|
|
103
|
-
opl assess [path] # Evaluar
|
|
104
|
-
opl assess --verbose #
|
|
105
|
-
opl assess --save # Guardar reporte JSON
|
|
106
|
-
opl init --knowledge # Configurar biblioteca personal
|
|
107
|
-
opl session doc/close/diff # Gestión de sesiones
|
|
108
|
-
opl doc flow/framework # Generar documentación
|
|
109
|
-
opl upgrade # Migrar configuración
|
|
110
|
-
opl contract list # Listar contratos abstractos
|
|
101
|
+
opl search <query> # Búsqueda híbrida
|
|
102
|
+
opl system [name] # Explorar sistemas de conocimiento
|
|
103
|
+
opl graph [concept] # Grafo de relaciones
|
|
104
|
+
opl assess [path] # Evaluar PRA 0-100
|
|
105
|
+
opl assess --verbose # 7 dimensiones × 28 criterios
|
|
106
|
+
opl assess --save # Guardar reporte JSON
|
|
107
|
+
opl init --knowledge # Configurar biblioteca personal
|
|
108
|
+
opl session doc/close/diff # Gestión de sesiones
|
|
109
|
+
opl doc flow/framework # Generar documentación
|
|
110
|
+
opl upgrade # Migrar configuración
|
|
111
|
+
opl contract list # Listar contratos abstractos
|
|
111
112
|
opl contract show <id> # Mostrar detalle de contrato
|
|
112
|
-
opl contract search <query> # Buscar contratos
|
|
113
|
+
opl contract search <query> # Buscar contratos
|
|
113
114
|
```
|
|
114
115
|
|
|
115
116
|
## 8. Production Readiness Assessment (PRA)
|
|
@@ -243,8 +244,7 @@ npx openPrompt-Lang mcp
|
|
|
243
244
|
- **SIEMPRE** revisar @scar vinculados en contratos abstractos antes de implementar
|
|
244
245
|
- **SIEMPRE** declarar `@use()` al inicio de archivos anotados
|
|
245
246
|
- **SIEMPRE** ejecutar `npx openPrompt-Lang validate` antes de cada commit
|
|
246
|
-
- **
|
|
247
|
-
- **PRA zero-tolerance**: F5 (transacciones atómicas), S2 (deny-by-default), S4 (no hardcoded secrets)
|
|
247
|
+
- **PRA zero-tolerance**: F5, S2, S4
|
|
248
248
|
- **Sistemas de conocimiento**: usar `opl system` antes de implementar features complejas
|
|
249
249
|
- Preferir `export function Name() {}` sobre arrow functions para componentes
|
|
250
250
|
- Preferir Named Exports sobre Default Exports
|
|
@@ -255,7 +255,7 @@ npx openPrompt-Lang mcp
|
|
|
255
255
|
|
|
256
256
|
La IA dispone de **36 fuentes de conocimiento** organizadas en 13 dominios (incluyendo 2 proyectos reales extraídos).
|
|
257
257
|
|
|
258
|
-
El conocimiento se agrupa en **sistemas** — conjuntos de fuentes que se necesitan juntas para construir algo real
|
|
258
|
+
El conocimiento se agrupa en **sistemas** — conjuntos de fuentes que se necesitan juntas para construir algo real.
|
|
259
259
|
Explorar: `opl system list` para ver los 10 sistemas disponibles.
|
|
260
260
|
|
|
261
261
|
### Dominios
|
|
@@ -337,8 +337,6 @@ Explorar: `opl system list` para ver los 10 sistemas disponibles.
|
|
|
337
337
|
|
|
338
338
|
### Sistemas de Conocimiento
|
|
339
339
|
|
|
340
|
-
Sistemas agrupados por contexto de construcción (capas, patrones, errores comunes):
|
|
341
|
-
|
|
342
340
|
| Sistema | Capas | Fuentes |
|
|
343
341
|
|---------|-------|---------|
|
|
344
342
|
| react-fullstack-app | frontend, backend, auth, db, deploy | 7+ |
|
|
@@ -352,8 +350,6 @@ Sistemas agrupados por contexto de construcción (capas, patrones, errores comun
|
|
|
352
350
|
| microservicios-multi-lenguaje | gateway, java, node, python, monitor | 7+ |
|
|
353
351
|
| saas-pos-chileno | saas, multitenant, pos, billing, compliance | 7+ |
|
|
354
352
|
|
|
355
|
-
Explorar: `opl system [nombre]` — ver capas, patrones y errores documentados.
|
|
356
|
-
|
|
357
353
|
### Contratos Abstractos
|
|
358
354
|
|
|
359
355
|
IR de componentes que separa **Contrato (esencia)** de **Sintaxis (framework)**:
|
|
@@ -372,7 +368,7 @@ Los contratos se almacenan en `knowledge-repo/abstract-contracts/` con schema en
|
|
|
372
368
|
|
|
373
369
|
### Cicatrices de Guerra (@scar)
|
|
374
370
|
|
|
375
|
-
Anotación para **conocimiento negativo
|
|
371
|
+
Anotación para **conocimiento negativo**:
|
|
376
372
|
|
|
377
373
|
```typescript
|
|
378
374
|
// @scar(
|
|
@@ -387,8 +383,6 @@ Anotación para **conocimiento negativo** — registrar lo que salió mal para q
|
|
|
387
383
|
|
|
388
384
|
Campos: `id` (req), `symptom` (req), `cause` (req), `fix` (req), `detect` (opcional, regex), `severity` (opcional).
|
|
389
385
|
|
|
390
|
-
Integración PRA: @scar con severity=blocker penaliza el score de calidad. @scar no resueltos reducen F3.
|
|
391
|
-
|
|
392
386
|
### Pipeline Auto-curativo
|
|
393
387
|
|
|
394
388
|
El paso [4/5] de validate ejecuta un loop de auto-corrección:
|
|
@@ -438,55 +432,9 @@ knowledge_concept → { bookId, conceptSlug? }
|
|
|
438
432
|
## 14. Stack del Proyecto
|
|
439
433
|
|
|
440
434
|
- **Lenguaje:** node
|
|
441
|
-
- **Stack:** node, javascript, esm, commander
|
|
435
|
+
- **Stack base:** node, javascript, esm, commander
|
|
442
436
|
- **Extensiones:** vitest, eslint, inquirer, chalk, pdf-parse
|
|
443
437
|
- **Perfil:** senior
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
### Para desarrollo con MCP (ahorra tiempo)
|
|
448
|
-
|
|
449
|
-
```
|
|
450
|
-
analyze_project → context_unified → knowledge_search/recall → work_context_plan → work_context_start → implementar → validate → work_context_close
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
1. **analyze_project** — Auditoría inicial del proyecto (30s, ahorra ~15min)
|
|
454
|
-
2. **context_unified** — Búsqueda cruzada en 7 fuentes (10s, ahorra ~20min)
|
|
455
|
-
3. **knowledge_search** o **recall** — Buscar antes de crear (10s, ahorra ~30min)
|
|
456
|
-
4. **work_context_plan** — Planificar antes de implementar (1min, ahorra ~1hr)
|
|
457
|
-
5. **work_context_start** — Iniciar sesión con tracking
|
|
458
|
-
6. **implementar** — Escribir código siguiendo anotaciones
|
|
459
|
-
7. **validate** — Verificar anotaciones antes de commit
|
|
460
|
-
8. **work_context_close** — Cerrar sesión y registrar métricas
|
|
461
|
-
|
|
462
|
-
### Para evaluación de producción (PRA)
|
|
463
|
-
|
|
464
|
-
```
|
|
465
|
-
opl assess --verbose → opl assess --save → revisar PRA-ASSESSMENT.json
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
1. **opl assess --verbose** — Ver 7 dimensiones × 28 criterios
|
|
469
|
-
2. **opl assess --save** — Guardar reporte JSON en el proyecto
|
|
470
|
-
3. **Revisar zero-tolerance** — F5, S2, S4 deben estar en verde
|
|
471
|
-
4. **Priorizar mejoras** — Empezar por dimensiones con menor score
|
|
472
|
-
|
|
473
|
-
### Para QA completo (workflow integrado)
|
|
474
|
-
|
|
475
|
-
```
|
|
476
|
-
opl assess --save && npx openPrompt-Lang validate && recall "errores"
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
### Para validación de anotaciones
|
|
480
|
-
|
|
481
|
-
```
|
|
482
|
-
validate → lint_file → qa-gen → validate
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
1. **validate** — Verificar anotaciones antes de cambios
|
|
486
|
-
2. **lint_file** — Lint detallado del archivo modificado
|
|
487
|
-
3. **qa-gen** — Generar tests desde errores aprendidos
|
|
488
|
-
4. **validate** — Validación final antes de commit
|
|
489
|
-
|
|
490
|
-
---
|
|
491
|
-
|
|
492
|
-
*Generado automáticamente por openPrompt-Lang v0.10.1 — 2026-05-21*
|
|
438
|
+
- **Modo oscuro:** por defecto
|
|
439
|
+
- **Testing:** Vitest
|
|
440
|
+
- **Linting:** ESLint + Prettier
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openprompt-lang",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "PromptLang CLI — Context Engine de anotaciones para desarrollo asistido por IA",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./bin/cli.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"openPrompt-Lang": "./bin/cli.js",
|
|
9
9
|
"openprompt-lang": "./bin/cli.js",
|
|
10
|
+
"opl": "./bin/opl.js",
|
|
10
11
|
"openprompt-create": "./bin/create.js"
|
|
11
12
|
},
|
|
12
13
|
"files": [
|
package/src/ai/providers.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
// @use(
|
|
1
|
+
// @use(kind, contract, limit, generated)
|
|
2
|
+
// @kind(feature)
|
|
3
|
+
// @contract(in: provider name + prompt -> out: generated text, sideEffect: llama API externa)
|
|
4
|
+
// @limit(lines: 260)
|
|
2
5
|
// ─── AI Provider abstraction for openPrompt-Lang ────────────────────────────
|
|
3
6
|
// Each provider must implement: generate(prompt, options) => Promise<string>
|
|
4
7
|
|
package/src/cli/commands-init.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
// @use(commander, kind, contract, limit)
|
|
2
|
-
// @kind(
|
|
3
|
-
// @contract(in: program -> out: void, sideEffect: registra comandos init
|
|
4
|
-
// @limit(lines:
|
|
2
|
+
// @kind(feature)
|
|
3
|
+
// @contract(in: program -> out: void, sideEffect: registra comandos init)
|
|
4
|
+
// @limit(lines: 70)
|
|
5
5
|
|
|
6
6
|
export function register(program) {
|
|
7
|
-
program
|
|
7
|
+
const init = program
|
|
8
8
|
.command('init')
|
|
9
9
|
.description('Inicializar proyecto o biblioteca de conocimiento personal')
|
|
10
10
|
.option('--name <name>', 'Nombre del proyecto')
|
|
11
11
|
.option('--describe <text>', 'Descripción del proyecto para sugerencia IA')
|
|
12
12
|
.option('--existing', 'Configurar en proyecto existente (solo archivos de configuración)')
|
|
13
|
+
.option('--rebuild', 'Reconstruir integración OPL en proyecto existente (force-regenera archivos generados, aplica migraciones)')
|
|
13
14
|
.option('--knowledge', 'Configurar biblioteca de conocimiento personal (~/.opl/knowledge/)')
|
|
14
15
|
.option('--dry-run', 'Previsualizar sin crear archivos')
|
|
15
16
|
.option('--stack <items>', 'Stack base (separado por comas, ej: react,typescript,vite,tailwind)')
|
package/src/cli/commands-misc.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @use(commander, kind, contract, limit)
|
|
2
2
|
// @kind(util)
|
|
3
3
|
// @contract(in: program -> out: void, sideEffect: registra comandos misceláneos)
|
|
4
|
-
// @limit(lines:
|
|
4
|
+
// @limit(lines: 270)
|
|
5
5
|
|
|
6
6
|
export function register(program) {
|
|
7
7
|
const component = program
|
|
@@ -249,4 +249,14 @@ export function register(program) {
|
|
|
249
249
|
const { recall } = await import('../commands/recall.js')
|
|
250
250
|
await recall(query, options)
|
|
251
251
|
})
|
|
252
|
+
|
|
253
|
+
program
|
|
254
|
+
.command('rebuild')
|
|
255
|
+
.description('Reconstruir integración OPL en proyecto existente (force-regenera archivos, aplica migraciones)')
|
|
256
|
+
.option('--dir <path>', 'Directorio del proyecto (default: cwd)')
|
|
257
|
+
.option('--yes', 'Auto-aceptar migraciones y prompts')
|
|
258
|
+
.action(async (options) => {
|
|
259
|
+
const { initExisting } = await import('../commands/init-existing.js')
|
|
260
|
+
await initExisting({ rebuild: true, dir: options.dir || process.cwd() })
|
|
261
|
+
})
|
|
252
262
|
}
|
package/src/cli/commands-opl.js
CHANGED
package/src/commands/db-rules.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @use(kind, contract, limit)
|
|
2
2
|
// @kind(util)
|
|
3
3
|
// @contract(in: args -> out: void, sideEffect: muestra reglas de DB)
|
|
4
|
-
// @limit(lines:
|
|
4
|
+
// @limit(lines: 130)
|
|
5
5
|
import { readFileSync, existsSync } from 'fs'
|
|
6
6
|
import { join, dirname } from 'path'
|
|
7
7
|
import { fileURLToPath } from 'url'
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @use(kind, contract, limit)
|
|
2
2
|
// @kind(feature)
|
|
3
3
|
// @contract(in: options -> out: baseDir)
|
|
4
|
-
// @limit(lines:
|
|
4
|
+
// @limit(lines: 430)
|
|
5
5
|
|
|
6
6
|
import { writeFileSync, readFileSync, existsSync, mkdirSync, cpSync } from 'fs'
|
|
7
7
|
import { join, dirname } from 'path'
|
|
@@ -138,10 +138,10 @@ export async function init(options) {
|
|
|
138
138
|
]
|
|
139
139
|
}])
|
|
140
140
|
|
|
141
|
-
if (projectType === 'existing') return initExisting()
|
|
141
|
+
if (projectType === 'existing') return initExisting(options)
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
if (options.existing) return initExisting()
|
|
144
|
+
if (options.existing) return initExisting(options)
|
|
145
145
|
|
|
146
146
|
const baseDir = join(process.cwd(), (options.name || 'mi-proyecto'))
|
|
147
147
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @use(kind, contract, limit)
|
|
2
2
|
// @kind(feature)
|
|
3
3
|
// @contract(in: options -> out: cwd)
|
|
4
|
-
// @limit(lines:
|
|
4
|
+
// @limit(lines: 450)
|
|
5
5
|
|
|
6
6
|
import { writeFileSync, readFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'fs'
|
|
7
7
|
import { join } from 'path'
|
|
@@ -98,13 +98,18 @@ function auditProject(cwd) {
|
|
|
98
98
|
return results
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
export async function initExisting() {
|
|
102
|
-
const cwd = process.cwd()
|
|
101
|
+
export async function initExisting(options = {}) {
|
|
102
|
+
const cwd = options.dir || process.cwd()
|
|
103
|
+
const rebuild = options.rebuild || false
|
|
103
104
|
const projectName = existsSync(join(cwd, 'package.json'))
|
|
104
105
|
? JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf-8')).name || 'mi-proyecto'
|
|
105
106
|
: 'mi-proyecto'
|
|
106
107
|
|
|
107
|
-
|
|
108
|
+
if (rebuild) {
|
|
109
|
+
console.log(chalk.cyan(`\n🔧 Reconstruyendo integración OPL en: ${projectName}\n`))
|
|
110
|
+
} else {
|
|
111
|
+
console.log(chalk.cyan(`\n🔧 Configurando openPrompt-Lang en proyecto existente: ${projectName}\n`))
|
|
112
|
+
}
|
|
108
113
|
|
|
109
114
|
const stack = enhancedDetectStack(cwd)
|
|
110
115
|
const detected = Object.entries(stack)
|
|
@@ -148,16 +153,31 @@ export async function initExisting() {
|
|
|
148
153
|
extractor: { ignore: ['.env', '*.local', 'dist', 'node_modules'], output: 'contexto.md' }
|
|
149
154
|
}
|
|
150
155
|
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
// Add OPL version tracking
|
|
157
|
+
try {
|
|
158
|
+
const pkgPath = new URL('../../package.json', import.meta.url).pathname
|
|
159
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
|
160
|
+
config.oplVersion = pkg.version
|
|
161
|
+
} catch {}
|
|
162
|
+
|
|
163
|
+
const configPath = join(cwd, 'prompt-lang.json')
|
|
164
|
+
if (rebuild || !existsSync(configPath)) {
|
|
165
|
+
// Merge with existing config if rebuilding (preserve user fields)
|
|
166
|
+
if (rebuild && existsSync(configPath)) {
|
|
167
|
+
try {
|
|
168
|
+
const existing = JSON.parse(readFileSync(configPath, 'utf-8'))
|
|
169
|
+
// Preserve user customizations, merge new defaults
|
|
170
|
+
Object.assign(config, existing, { oplVersion: config.oplVersion })
|
|
171
|
+
} catch {}
|
|
172
|
+
}
|
|
173
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8')
|
|
174
|
+
console.log(chalk.green(` ✅ prompt-lang.json ${rebuild ? 'actualizado' : 'creado'}`))
|
|
153
175
|
} else {
|
|
154
|
-
|
|
155
|
-
console.log(chalk.green(' ✅ prompt-lang.json'))
|
|
176
|
+
console.log(chalk.yellow(' ⚠️ prompt-lang.json ya existe. Saltando.'))
|
|
156
177
|
}
|
|
157
178
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
} else {
|
|
179
|
+
const agentsPath = join(cwd, 'AGENTS.md')
|
|
180
|
+
if (rebuild || !existsSync(agentsPath)) {
|
|
161
181
|
const agentsLines = [
|
|
162
182
|
'# AGENTS.md — Contexto para IA',
|
|
163
183
|
'',
|
|
@@ -177,26 +197,24 @@ export async function initExisting() {
|
|
|
177
197
|
'- Framework: openPrompt-Lang',
|
|
178
198
|
'',
|
|
179
199
|
]
|
|
180
|
-
writeFileSync(
|
|
181
|
-
console.log(chalk.green(
|
|
200
|
+
writeFileSync(agentsPath, agentsLines.join('\n'), 'utf-8')
|
|
201
|
+
console.log(chalk.green(` ✅ AGENTS.md ${rebuild ? 'actualizado' : 'creado'}`))
|
|
202
|
+
} else {
|
|
203
|
+
console.log(chalk.yellow(' ⚠️ AGENTS.md ya existe. Saltando.'))
|
|
182
204
|
}
|
|
183
205
|
|
|
184
206
|
mkdirSync(join(cwd, '.openprompt'), { recursive: true })
|
|
185
207
|
const frameworkPath = join(cwd, '.openprompt', 'FRAMEWORK.md')
|
|
186
|
-
if (!existsSync(frameworkPath)) {
|
|
208
|
+
if (rebuild || !existsSync(frameworkPath)) {
|
|
187
209
|
writeFileSync(frameworkPath, generateFrameworkMd({ dir: cwd }), 'utf-8')
|
|
188
|
-
console.log(chalk.green(
|
|
210
|
+
console.log(chalk.green(` ✅ .openprompt/FRAMEWORK.md ${rebuild ? 'actualizado' : 'creado'}`))
|
|
211
|
+
} else {
|
|
212
|
+
console.log(chalk.yellow(' ⚠️ .openprompt/FRAMEWORK.md ya existe. Saltando.'))
|
|
189
213
|
}
|
|
190
214
|
|
|
191
215
|
if (existsSync(join(cwd, 'package.json'))) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
name: 'addScripts',
|
|
195
|
-
message: '¿Agregar scripts descriptivos al package.json?',
|
|
196
|
-
default: false
|
|
197
|
-
}])
|
|
198
|
-
|
|
199
|
-
if (addScripts) {
|
|
216
|
+
if (rebuild) {
|
|
217
|
+
// Always add scripts in rebuild mode
|
|
200
218
|
const pkgPath = join(cwd, 'package.json')
|
|
201
219
|
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
|
202
220
|
pkg.scripts = pkg.scripts || {}
|
|
@@ -206,32 +224,106 @@ export async function initExisting() {
|
|
|
206
224
|
}
|
|
207
225
|
if (added > 0) {
|
|
208
226
|
writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf-8')
|
|
209
|
-
console.log(chalk.green(` ✅ ${added} scripts agregados`))
|
|
227
|
+
console.log(chalk.green(` ✅ ${added} scripts descriptivos agregados`))
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
const { addScripts } = await inquirer.prompt([{
|
|
231
|
+
type: 'confirm',
|
|
232
|
+
name: 'addScripts',
|
|
233
|
+
message: '¿Agregar scripts descriptivos al package.json?',
|
|
234
|
+
default: false
|
|
235
|
+
}])
|
|
236
|
+
|
|
237
|
+
if (addScripts) {
|
|
238
|
+
const pkgPath = join(cwd, 'package.json')
|
|
239
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
|
|
240
|
+
pkg.scripts = pkg.scripts || {}
|
|
241
|
+
let added = 0
|
|
242
|
+
for (const [name, cmd] of Object.entries(DESCRIPTIVE_SCRIPTS)) {
|
|
243
|
+
if (!pkg.scripts[name]) { pkg.scripts[name] = cmd; added++ }
|
|
244
|
+
}
|
|
245
|
+
if (added > 0) {
|
|
246
|
+
writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, 'utf-8')
|
|
247
|
+
console.log(chalk.green(` ✅ ${added} scripts agregados`))
|
|
248
|
+
}
|
|
210
249
|
}
|
|
211
250
|
}
|
|
212
251
|
}
|
|
213
252
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
253
|
+
if (!rebuild) {
|
|
254
|
+
const { createDocs } = await inquirer.prompt([{
|
|
255
|
+
type: 'confirm',
|
|
256
|
+
name: 'createDocs',
|
|
257
|
+
message: '¿Crear estructura docs/ (BACKLOG, COMMITS, LOGS)?',
|
|
258
|
+
default: false
|
|
259
|
+
}])
|
|
260
|
+
|
|
261
|
+
if (createDocs) {
|
|
262
|
+
for (const dir of ['docs/BACKLOG', 'docs/PHASES', 'docs/COMMITS', 'docs/LOGS/ERRORES', 'docs/LOGS/ACTIVIDAD']) {
|
|
263
|
+
mkdirSync(join(cwd, dir), { recursive: true })
|
|
264
|
+
}
|
|
265
|
+
if (!existsSync(join(cwd, 'docs/BACKLOG/tasks.md'))) {
|
|
266
|
+
writeFileSync(join(cwd, 'docs/BACKLOG/tasks.md'), '# Backlog — Tareas\n\n## TASK-001\n- **Módulo:** \n- **Criterios:**\n - [ ] \n', 'utf-8')
|
|
267
|
+
}
|
|
268
|
+
if (!existsSync(join(cwd, 'docs/PHASES/roadmap.md'))) {
|
|
269
|
+
writeFileSync(join(cwd, 'docs/PHASES/roadmap.md'), '# Fases\n\n## Fase 1\n**Estado:** Actual\n**Objetivo:** _definir_\n', 'utf-8')
|
|
270
|
+
}
|
|
271
|
+
if (!existsSync(join(cwd, 'docs/COMMITS/INDEX.md'))) {
|
|
272
|
+
writeFileSync(join(cwd, 'docs/COMMITS/INDEX.md'), '# Índice de Commits\n\n| Fecha | Versión | Descripción |\n|---|---|---|\n', 'utf-8')
|
|
273
|
+
}
|
|
274
|
+
console.log(chalk.green(' ✅ Estructura docs/'))
|
|
275
|
+
}
|
|
276
|
+
}
|
|
220
277
|
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
|
|
278
|
+
if (rebuild) {
|
|
279
|
+
// Rebuild mode: always set up build plugins
|
|
280
|
+
const viteConfig = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs'].find(f => existsSync(join(cwd, f)))
|
|
281
|
+
if (viteConfig) {
|
|
282
|
+
const vitePath = join(cwd, viteConfig)
|
|
283
|
+
const existing = readFileSync(vitePath, 'utf-8')
|
|
284
|
+
if (!existing.includes('openPromptAnnotations')) {
|
|
285
|
+
const finalContent = `import { openPromptAnnotations } from "openprompt-lang/vite-plugin";\n${existing.replace(/plugins\s*:\s*\[/, 'plugins: [\n openPromptAnnotations(),')}`
|
|
286
|
+
writeFileSync(vitePath, finalContent, 'utf-8')
|
|
287
|
+
console.log(chalk.green(` ✅ Plugin Vite agregado a ${viteConfig}`))
|
|
288
|
+
}
|
|
224
289
|
}
|
|
225
|
-
|
|
226
|
-
|
|
290
|
+
|
|
291
|
+
const tsconfig = ['tsconfig.json', 'tsconfig.app.json'].find(f => existsSync(join(cwd, f)))
|
|
292
|
+
if (tsconfig) {
|
|
293
|
+
const tsPath = join(cwd, tsconfig)
|
|
294
|
+
const tsConfig = JSON.parse(readFileSync(tsPath, 'utf-8'))
|
|
295
|
+
tsConfig.compilerOptions = tsConfig.compilerOptions || {}
|
|
296
|
+
tsConfig.compilerOptions.plugins = tsConfig.compilerOptions.plugins || []
|
|
297
|
+
if (!tsConfig.compilerOptions.plugins.some(p => p.name?.includes('openprompt'))) {
|
|
298
|
+
tsConfig.compilerOptions.plugins.push({ name: 'openprompt-lang/ts-plugin' })
|
|
299
|
+
writeFileSync(tsPath, `${JSON.stringify(tsConfig, null, 2)}\n`, 'utf-8')
|
|
300
|
+
console.log(chalk.green(` ✅ TS plugin agregado a ${tsconfig}`))
|
|
301
|
+
}
|
|
227
302
|
}
|
|
228
|
-
|
|
229
|
-
|
|
303
|
+
|
|
304
|
+
// Rebuild mode: always integrate all editors
|
|
305
|
+
try {
|
|
306
|
+
const { integrate } = await import('./integrate.js')
|
|
307
|
+
console.log(chalk.cyan('\n🔄 Reconstruyendo integración de editores...'))
|
|
308
|
+
await integrate({ dir: cwd, all: true, silent: true })
|
|
309
|
+
} catch {
|
|
310
|
+
console.log(chalk.yellow(' ⚠️ No se pudo ejecutar integrate automáticamente.'))
|
|
230
311
|
}
|
|
231
|
-
|
|
232
|
-
|
|
312
|
+
|
|
313
|
+
// Apply pending migrations (upgrade)
|
|
314
|
+
try {
|
|
315
|
+
const { upgrade } = await import('./opl-upgrade.js')
|
|
316
|
+
console.log(chalk.cyan('🔄 Aplicando migraciones pendientes...'))
|
|
317
|
+
await upgrade({ dir: cwd, yes: true })
|
|
318
|
+
} catch {
|
|
319
|
+
console.log(chalk.yellow(' ⚠️ No se pudo ejecutar upgrade automáticamente.'))
|
|
233
320
|
}
|
|
234
|
-
|
|
321
|
+
|
|
322
|
+
console.log(chalk.cyan(`\n✅ Integración OLP reconstruida para: ${projectName}`))
|
|
323
|
+
console.log(chalk.cyan(` Versión OPL: ${config.oplVersion || 'desconocida'}`))
|
|
324
|
+
console.log(chalk.gray(' Archivos generados forzaron actualización.'))
|
|
325
|
+
console.log(chalk.gray(' Las personalizaciones del usuario fueron preservadas en prompt-lang.json.\n'))
|
|
326
|
+
return
|
|
235
327
|
}
|
|
236
328
|
|
|
237
329
|
const { setupBuild } = await inquirer.prompt([{
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
// @use(kind, contract, limit, learn-error, generated)
|
|
2
|
+
// @kind(feature)
|
|
3
|
+
// @contract(in: options -> out: void, sideEffect: genera archivos de integración en el proyecto)
|
|
4
|
+
// @limit(lines: 700)
|
|
2
5
|
import { writeFileSync, existsSync, mkdirSync, readFileSync, readdirSync } from 'fs'
|
|
3
6
|
import { join, relative } from 'path'
|
|
4
7
|
import os from 'os'
|
package/src/commands/learning.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @use(kind, contract, limit)
|
|
2
2
|
// @kind(util)
|
|
3
3
|
// @contract(in: args -> out: void, sideEffect: gestión de aprendizaje semántico)
|
|
4
|
-
// @limit(lines:
|
|
4
|
+
// @limit(lines: 500)
|
|
5
5
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'fs'
|
|
6
6
|
import { join, relative, dirname, isAbsolute } from 'path'
|
|
7
7
|
import chalk from 'chalk'
|