openprompt-lang 1.3.0 → 1.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 (52) hide show
  1. package/bin/cli.js +2 -0
  2. package/docs/00-ARCHITECTURE/OPL-BOOST-MULTI-AGENT.md +406 -0
  3. package/docs/02-STANDARDS/AGENTS.template.md +89 -0
  4. package/docs/02-STANDARDS/ticket-driven-development.md +99 -0
  5. package/docs/04-TICKETS/BOOST-001-profile-registry.md +66 -0
  6. package/docs/04-TICKETS/BOOST-002-context-compression.md +58 -0
  7. package/docs/04-TICKETS/BOOST-003-template-hydration.md +69 -0
  8. package/docs/04-TICKETS/BOOST-004-fewshot-engine.md +58 -0
  9. package/docs/04-TICKETS/BOOST-005-agent-pool.md +69 -0
  10. package/docs/04-TICKETS/BOOST-006-specialized-agents.md +53 -0
  11. package/docs/04-TICKETS/BOOST-007-validation-loop.md +56 -0
  12. package/docs/04-TICKETS/BOOST-008-orchestrator.md +71 -0
  13. package/docs/04-TICKETS/BOOST-009-cache-system.md +56 -0
  14. package/docs/04-TICKETS/BOOST-010-cli-mcp.md +67 -0
  15. package/docs/04-TICKETS/BOOST-011-self-learning.md +50 -0
  16. package/docs/04-TICKETS/BOOST-012-prompt-preamble.md +109 -0
  17. package/docs/04-TICKETS/BOOST-013-hydrator-duplicate-code.md +132 -0
  18. package/docs/04-TICKETS/BOOST-014-multiagent-missing-parts.md +87 -0
  19. package/docs/04-TICKETS/BOOST-015-skeleton-type-missing.md +76 -0
  20. package/docs/04-TICKETS/BOOST-016-output-path-duplicate.md +68 -0
  21. package/docs/04-TICKETS/INDEX.md +89 -0
  22. package/docs/04-TICKETS/_archive/BOOST-005-micro-tasking.md +67 -0
  23. package/docs/04-TICKETS/_archive/BOOST-006-validation-loop.md +66 -0
  24. package/docs/04-TICKETS/_archive/BOOST-007-progressive-pipeline.md +69 -0
  25. package/docs/04-TICKETS/_archive/BOOST-008-cli-mcp-integration.md +74 -0
  26. package/docs/AI_CONTEXT.md +16 -0
  27. package/package.json +3 -2
  28. package/src/boost/agent-pool.js +442 -0
  29. package/src/boost/agents/index.js +79 -0
  30. package/src/boost/cache.js +241 -0
  31. package/src/boost/context-compressor.js +354 -0
  32. package/src/boost/fewshot-retriever.js +332 -0
  33. package/src/boost/hardware-detector.js +486 -0
  34. package/src/boost/hydrator.js +398 -0
  35. package/src/boost/index.js +60 -0
  36. package/src/boost/orchestrator.js +615 -0
  37. package/src/boost/preamble.js +217 -0
  38. package/src/boost/profile-registry.js +264 -0
  39. package/src/boost/self-learn.js +247 -0
  40. package/src/boost/skeletons/component.skeleton.js +24 -0
  41. package/src/boost/skeletons/hook.skeleton.js +27 -0
  42. package/src/boost/skeletons/index.js +67 -0
  43. package/src/boost/skeletons/page.skeleton.js +22 -0
  44. package/src/boost/skeletons/service.skeleton.js +20 -0
  45. package/src/boost/skeletons/store.skeleton.js +18 -0
  46. package/src/boost/skeletons/type.skeleton.js +11 -0
  47. package/src/boost/task-dispatcher.js +142 -0
  48. package/src/boost/validation-loop.js +495 -0
  49. package/src/cli/commands-boost.js +394 -0
  50. package/src/mcp-refactor/handlers/boost.js +295 -0
  51. package/src/mcp-refactor/router.js +19 -0
  52. package/src/mcp-refactor/tools.js +113 -0
@@ -0,0 +1,398 @@
1
+ // @use(kind, contract, limit, error)
2
+ // @kind(util)
3
+ // @contract(in: kind, parts, options -> out: hydrate -> { code: string, warnings: string[] } @error: UnknownSkeletonError, MissingRequiredPart)
4
+ // @limit(lines: 200)
5
+
6
+ /**
7
+ * Template Hydration System — Módulo OPL Boost
8
+ *
9
+ * Toma los resultados parciales de los agentes Boost y los inyecta
10
+ * en skeletons predefinidos para producir código OPL-compliant.
11
+ *
12
+ * Uso:
13
+ * import { hydrate, hydrateFromAgentResults } from './boost/hydrator.js'
14
+ *
15
+ * const result = hydrate('hook', {
16
+ * imports: "import { useState } from 'react'",
17
+ * name: "useAuth",
18
+ * params: "userId: string",
19
+ * state: "const [user, setUser] = useState<User | null>(null)",
20
+ * logic: "useEffect(() => { fetchUser(userId).then(setUser) }, [userId])",
21
+ * contractIn: "userId: string",
22
+ * contractOut: "{ user, loading, error }",
23
+ * description: "Custom hook para autenticación con Supabase",
24
+ * })
25
+ * // → { code: "...código completo...", warnings: [] }
26
+ */
27
+
28
+ import { getSkeleton, listSkeletons, hasSkeleton } from "./skeletons/index.js"
29
+
30
+ // ──────────────────────────────────────────────
31
+ // Placeholders por tipo de skeleton
32
+ // ──────────────────────────────────────────────
33
+
34
+ const PLACEHOLDER_MAP = {
35
+ hook: {
36
+ required: ["name"],
37
+ placeholders: {
38
+ PLACEHOLDER_IMPORTS: "imports",
39
+ PLACEHOLDER_TYPES: "types",
40
+ PLACEHOLDER_STATE: "state",
41
+ PLACEHOLDER_LOGIC: "logic",
42
+ PLACEHOLDER_EXPORTS: "exports",
43
+ PLACEHOLDER_NAME: "name",
44
+ PLACEHOLDER_PARAMS: "params",
45
+ PLACEHOLDER_RETURN: "return",
46
+ PLACEHOLDER_RETURN_TYPE: "returnType",
47
+ PLACEHOLDER_DESCRIPTION: "description",
48
+ PLACEHOLDER_CONTRACT_IN: "contractIn",
49
+ PLACEHOLDER_CONTRACT_OUT: "contractOut",
50
+ PLACEHOLDER_CONTRACT_ERROR: "contractError",
51
+ },
52
+ },
53
+ component: {
54
+ required: ["name", "jsx"],
55
+ placeholders: {
56
+ PLACEHOLDER_IMPORTS: "imports",
57
+ PLACEHOLDER_VARIANTS: "variants",
58
+ PLACEHOLDER_PROPS: "props",
59
+ PLACEHOLDER_PROPS_LIST: "propsList",
60
+ PLACEHOLDER_PROPS_DESTRUCTURE: "propsDestructure",
61
+ PLACEHOLDER_NAME: "name",
62
+ PLACEHOLDER_JSX: "jsx",
63
+ },
64
+ },
65
+ page: {
66
+ required: ["name", "layout"],
67
+ placeholders: {
68
+ PLACEHOLDER_IMPORTS: "imports",
69
+ PLACEHOLDER_TYPES: "types",
70
+ PLACEHOLDER_LAYOUT: "layout",
71
+ PLACEHOLDER_DATA: "data",
72
+ PLACEHOLDER_JSX: "jsx",
73
+ PLACEHOLDER_COMPONENTS: "components",
74
+ PLACEHOLDER_NAME: "name",
75
+ PLACEHOLDER_HELPERS: "helpers",
76
+ },
77
+ },
78
+ service: {
79
+ required: ["name"],
80
+ placeholders: {
81
+ PLACEHOLDER_IMPORTS: "imports",
82
+ PLACEHOLDER_TYPES: "types",
83
+ PLACEHOLDER_METHODS: "methods",
84
+ PLACEHOLDER_EXPORTS: "exports",
85
+ PLACEHOLDER_CONTRACT_IN: "contractIn",
86
+ PLACEHOLDER_CONTRACT_OUT: "contractOut",
87
+ PLACEHOLDER_CONTRACT_ERROR: "contractError",
88
+ PLACEHOLDER_BASE_URL: "baseUrl",
89
+ },
90
+ },
91
+ store: {
92
+ required: ["name"],
93
+ placeholders: {
94
+ PLACEHOLDER_IMPORTS: "imports",
95
+ PLACEHOLDER_TYPES: "types",
96
+ PLACEHOLDER_STORE: "store",
97
+ PLACEHOLDER_EXPORTS: "exports",
98
+ PLACEHOLDER_DEPS: "deps",
99
+ },
100
+ },
101
+ type: {
102
+ required: [],
103
+ placeholders: {
104
+ PLACEHOLDER_IMPORTS: "imports",
105
+ PLACEHOLDER_TYPES: "types",
106
+ PLACEHOLDER_EXPORTS: "exports",
107
+ },
108
+ },
109
+ }
110
+
111
+ // ──────────────────────────────────────────────
112
+ // Default values for common placeholders
113
+ // ──────────────────────────────────────────────
114
+
115
+ const DEFAULT_PLACEHOLDERS = {
116
+ imports: "",
117
+ types: "",
118
+ state: "",
119
+ logic: "",
120
+ exports: "default",
121
+ returnType: "void",
122
+ description: "Generated by OPL Boost",
123
+ propsList: "",
124
+ propsDestructure: "",
125
+ contractIn: "unknown",
126
+ contractOut: "unknown",
127
+ contractError: "Error",
128
+ baseUrl: 'const BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3000/api"',
129
+ components: "",
130
+ helpers: "",
131
+ deps: "none",
132
+ variants: "",
133
+ data: "",
134
+ }
135
+
136
+ // ──────────────────────────────────────────────
137
+ // Sistema de validación post-hydration
138
+ // ──────────────────────────────────────────────
139
+
140
+ /**
141
+ * Validaciones post-generación específicas por tipo.
142
+ */
143
+ const POST_VALIDATIONS = {
144
+ hook: [
145
+ {
146
+ name: "has-export-function",
147
+ check: (code) => /export\s+function\s+\w+/.test(code),
148
+ message: "El hook debe exportar una función con nombre",
149
+ },
150
+ {
151
+ name: "has-kind-hook",
152
+ check: (code) => /@kind\(hook\)/.test(code),
153
+ message: "Debe tener anotación @kind(hook)",
154
+ },
155
+ {
156
+ name: "max-lines-80",
157
+ check: (code) => code.split("\n").length <= 80,
158
+ message: "El hook no debe exceder 80 líneas (límite OPL)",
159
+ },
160
+ ],
161
+ component: [
162
+ {
163
+ name: "has-export-function",
164
+ check: (code) => /export\s+function\s+\w+/.test(code),
165
+ message: "El componente debe exportar una función con nombre",
166
+ },
167
+ {
168
+ name: "has-kind-component",
169
+ check: (code) => /@kind\(component\)/.test(code),
170
+ message: "Debe tener anotación @kind(component)",
171
+ },
172
+ {
173
+ name: "has-props-interface",
174
+ check: (code) => /interface\s+\w+Props/.test(code),
175
+ message: "Debe tener una interfaz de props (NameProps)",
176
+ },
177
+ {
178
+ name: "max-lines-120",
179
+ check: (code) => code.split("\n").length <= 120,
180
+ message: "El componente no debe exceder 120 líneas",
181
+ },
182
+ ],
183
+ page: [
184
+ {
185
+ name: "has-default-export",
186
+ check: (code) => /export\s+default\s+function/.test(code),
187
+ message: "La página debe tener export default function",
188
+ },
189
+ {
190
+ name: "has-kind-page",
191
+ check: (code) => /@kind\(page\)/.test(code),
192
+ message: "Debe tener anotación @kind(page)",
193
+ },
194
+ {
195
+ name: "max-lines-200",
196
+ check: (code) => code.split("\n").length <= 200,
197
+ message: "La página no debe exceder 200 líneas",
198
+ },
199
+ ],
200
+ service: [
201
+ {
202
+ name: "has-kind-service",
203
+ check: (code) => /@kind\(service\)/.test(code),
204
+ message: "Debe tener anotación @kind(service)",
205
+ },
206
+ {
207
+ name: "max-lines-150",
208
+ check: (code) => code.split("\n").length <= 150,
209
+ message: "El servicio no debe exceder 150 líneas",
210
+ },
211
+ ],
212
+ store: [
213
+ {
214
+ name: "has-kind-store",
215
+ check: (code) => /@kind\(store\)/.test(code),
216
+ message: "Debe tener anotación @kind(store)",
217
+ },
218
+ {
219
+ name: "max-lines-100",
220
+ check: (code) => code.split("\n").length <= 100,
221
+ message: "El store no debe exceder 100 líneas",
222
+ },
223
+ ],
224
+ type: [
225
+ {
226
+ name: "has-kind-type",
227
+ check: (code) => /@kind\(type\)/.test(code),
228
+ message: "Debe tener anotación @kind(type)",
229
+ },
230
+ {
231
+ name: "has-export",
232
+ check: (code) => /export\s/.test(code),
233
+ message: "El archivo de tipos debe tener exports",
234
+ },
235
+ ],
236
+ }
237
+
238
+ // ──────────────────────────────────────────────
239
+ // API: hydrate
240
+ // ──────────────────────────────────────────────
241
+
242
+ /**
243
+ * Hidrata un skeleton con partes de código.
244
+ *
245
+ * @param {string} kind - Tipo de skeleton (hook, component, page, service, store)
246
+ * @param {object} parts - Objeto con las partes a reemplazar
247
+ * Ejemplo: { name: "useAuth", imports: "...", state: "...", logic: "..." }
248
+ * @param {object} [options] - Opciones adicionales
249
+ * @param {boolean} [options.validate=true] - Ejecutar validaciones post-hydration
250
+ * @param {boolean} [options.skipAnnotations=false] - Omitir anotaciones OPL
251
+ * @returns {{ code: string, warnings: string[], validations: object }}
252
+ */
253
+ export function hydrate(kind, parts, options = {}) {
254
+ const validate = options.validate !== false
255
+
256
+ // 1. Validar que el skeleton exista
257
+ if (!hasSkeleton(kind)) {
258
+ throw new Error(
259
+ `Skeleton desconocido: "${kind}". Tipos: ${listSkeletons().map((s) => s.kind).join(", ")}`
260
+ )
261
+ }
262
+
263
+ // 2. Validar partes requeridas
264
+ const config = PLACEHOLDER_MAP[kind]
265
+ if (!config) {
266
+ throw new Error(`Tipo de skeleton no configurado: "${kind}"`)
267
+ }
268
+
269
+ const missingRequired = config.required.filter((key) => !parts[key])
270
+ if (missingRequired.length > 0) {
271
+ throw new Error(
272
+ `Partes requeridas faltantes para "${kind}": ${missingRequired.join(", ")}`
273
+ )
274
+ }
275
+
276
+ // 3. Cargar skeleton
277
+ let code = getSkeleton(kind)
278
+
279
+ // 4. Reemplazar placeholders
280
+ const warnings = []
281
+ for (const [placeholder, key] of Object.entries(config.placeholders)) {
282
+ const value = parts[key] || DEFAULT_PLACEHOLDERS[key] || ""
283
+ const regex = new RegExp(`\\{\\{${placeholder}\\}\\}`, "g")
284
+
285
+ if (!parts[key] && !DEFAULT_PLACEHOLDERS[key]) {
286
+ warnings.push(`Placeholder {{${placeholder}}} no fue reemplazado (sin valor ni default)`)
287
+ }
288
+
289
+ code = code.replace(regex, value)
290
+ }
291
+
292
+ // 5. Limpiar placeholders no reemplazados
293
+ const remainingPlaceholders = code.match(/\{\{PLACEHOLDER_\w+\}\}/g)
294
+ if (remainingPlaceholders) {
295
+ for (const ph of remainingPlaceholders) {
296
+ code = code.replace(ph, "")
297
+ warnings.push(`Placeholder ${ph} no reemplazado — contenido vacío`)
298
+ }
299
+ }
300
+
301
+ // 6. Formatear: eliminar líneas vacías múltiples
302
+ code = code.replace(/\n{3,}/g, "\n\n")
303
+
304
+ // 7. Validaciones post-hydration
305
+ let validations = []
306
+ if (validate) {
307
+ const checks = POST_VALIDATIONS[kind] || []
308
+ validations = checks.map((check) => {
309
+ const passed = check.check(code)
310
+ if (!passed) {
311
+ warnings.push(`Validación fallida: ${check.message}`)
312
+ }
313
+ return { name: check.name, passed, message: check.message }
314
+ })
315
+ }
316
+
317
+ return {
318
+ code,
319
+ warnings,
320
+ validations,
321
+ }
322
+ }
323
+
324
+ // ──────────────────────────────────────────────
325
+ // API: hydrateFromAgentResults
326
+ // ──────────────────────────────────────────────
327
+
328
+ /**
329
+ * Hidrata un skeleton a partir de los resultados de los agentes Boost.
330
+ * Toma los outputs de los agentes types, state, logic y los mapea
331
+ * automáticamente a las partes del skeleton.
332
+ *
333
+ * @param {string} kind - Tipo de skeleton
334
+ * @param {object} agentResults - Resultados de agentes { types: "...", state: "...", logic: "..." }
335
+ * @param {object} [options] - Opciones adicionales
336
+ * @returns {{ code: string, warnings: string[], validations: object }}
337
+ */
338
+ export function hydrateFromAgentResults(kind, agentResults, options = {}) {
339
+ const { types, state, logic, cleaner, description } = agentResults
340
+
341
+ // Mapear resultados de agentes a partes del skeleton
342
+ const parts = {
343
+ types,
344
+ state: state || "",
345
+ logic: logic || "",
346
+ description: cleaner || description || "Generated by OPL Boost",
347
+ }
348
+
349
+ // Añadir defaults según el tipo
350
+ switch (kind) {
351
+ case "hook":
352
+ parts.imports = parts.imports || types || ""
353
+ parts.exports = parts.exports || "default"
354
+ break
355
+ case "component":
356
+ parts.imports = parts.imports || types || ""
357
+ parts.jsx = parts.jsx || logic || ""
358
+ break
359
+ case "page":
360
+ parts.imports = parts.imports || types || ""
361
+ parts.layout = parts.layout || logic || ""
362
+ break
363
+ case "service":
364
+ parts.imports = parts.imports || types || ""
365
+ parts.methods = logic || ""
366
+ break
367
+ case "store":
368
+ parts.imports = parts.imports || types || ""
369
+ parts.store = logic || ""
370
+ break
371
+ }
372
+
373
+ return hydrate(kind, parts, options)
374
+ }
375
+
376
+ // ──────────────────────────────────────────────
377
+ // API: generatePlaceholderMap
378
+ // ──────────────────────────────────────────────
379
+
380
+ /**
381
+ * Genera un mapa de placeholders para un tipo, útil para UI o debugging.
382
+ *
383
+ * @param {string} kind - Tipo de skeleton
384
+ * @returns {{ placeholders: string[], required: string[], optional: string[] }}
385
+ */
386
+ export function getHydrationSchema(kind) {
387
+ const config = PLACEHOLDER_MAP[kind]
388
+ if (!config) return null
389
+
390
+ const allKeys = Object.values(config.placeholders)
391
+ const optional = allKeys.filter((k) => !config.required.includes(k))
392
+
393
+ return {
394
+ placeholders: Object.keys(config.placeholders),
395
+ required: config.required,
396
+ optional,
397
+ }
398
+ }
@@ -0,0 +1,60 @@
1
+ // @use(kind, contract, limit)
2
+ // @kind(module)
3
+ // @contract(in: task, options -> out: { code, metadata, report } Public API: boost, generateCode, quickValidate, cache)
4
+ // @limit(lines: 60)
5
+
6
+ /**
7
+ * OPL Boost — API pública del módulo.
8
+ *
9
+ * Punto de entrada unificado para todas las funcionalidades Boost.
10
+ *
11
+ * Uso principal:
12
+ * import { boost } from './boost/index.js'
13
+ * const result = await boost('crea hook useAuth', { kind: 'hook' })
14
+ * console.log(result.code)
15
+ *
16
+ * Componentes individuales (import directo para uso avanzado):
17
+ * import { getProfile } from './boost/profile-registry.js'
18
+ * import { agentPool } from './boost/agent-pool.js'
19
+ * import { compressContext } from './boost/context-compressor.js'
20
+ * import { hydrate } from './boost/hydrator.js'
21
+ */
22
+
23
+ // El orquestador importa todos los demás módulos internamente
24
+ export { boost, generateCode } from "./orchestrator.js"
25
+
26
+ // Perfiles
27
+ export { getProfile, setProfile, listProfiles, detectProfile, isBoostEnabled, clearCache } from "./profile-registry.js"
28
+
29
+ // Agent Pool
30
+ export { agentPool, checkOllama, listOllamaModels, selectBestModel, buildPrompt } from "./agent-pool.js"
31
+
32
+ // Hardware
33
+ export { detectHardware, getRuntimeStatus, getSafeParallelism, getRAMWarning, generateBoostConfig, saveBoostConfig } from "./hardware-detector.js"
34
+
35
+ // Compresión de contexto
36
+ export { compressContext, compressTaskContext, compressAgentsMd } from "./context-compressor.js"
37
+
38
+ // Few-shot
39
+ export { retrieveExamples, buildFewShotPrompt, exampleStats } from "./fewshot-retriever.js"
40
+
41
+ // Hydration
42
+ export { hydrate, hydrateFromAgentResults, getHydrationSchema } from "./hydrator.js"
43
+
44
+ // Validation
45
+ export { quickValidate, validateCode, feedbackLoop, buildFeedback, generateReport } from "./validation-loop.js"
46
+
47
+ // Task dispatcher
48
+ export { plan, detectKind, listKinds } from "./task-dispatcher.js"
49
+
50
+ // Agentes
51
+ export { getAgent, listAgents } from "./agents/index.js"
52
+
53
+ // Cache
54
+ export { cache, hashInput, cacheKeys } from "./cache.js"
55
+
56
+ // Self-learning
57
+ export { recordExecution, autoProfile, selfLearnStats } from "./self-learn.js"
58
+
59
+ // Preamble
60
+ export { generatePreamble, writePreamble } from "./preamble.js"