@miguelduran14/knowflow 0.1.1

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 (192) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +182 -0
  3. package/dist/advisories.d.ts +16 -0
  4. package/dist/advisories.js +364 -0
  5. package/dist/advisories.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +104 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/copy-resolver.d.ts +22 -0
  10. package/dist/copy-resolver.js +74 -0
  11. package/dist/copy-resolver.js.map +1 -0
  12. package/dist/dataflow.d.ts +2 -0
  13. package/dist/dataflow.js +88 -0
  14. package/dist/dataflow.js.map +1 -0
  15. package/dist/dossier.d.ts +20 -0
  16. package/dist/dossier.js +331 -0
  17. package/dist/dossier.js.map +1 -0
  18. package/dist/explain/claude.d.ts +14 -0
  19. package/dist/explain/claude.js +91 -0
  20. package/dist/explain/claude.js.map +1 -0
  21. package/dist/explain/explain.d.ts +72 -0
  22. package/dist/explain/explain.js +126 -0
  23. package/dist/explain/explain.js.map +1 -0
  24. package/dist/explain/facts.d.ts +23 -0
  25. package/dist/explain/facts.js +266 -0
  26. package/dist/explain/facts.js.map +1 -0
  27. package/dist/explain/fake.d.ts +14 -0
  28. package/dist/explain/fake.js +27 -0
  29. package/dist/explain/fake.js.map +1 -0
  30. package/dist/explain/openai.d.ts +42 -0
  31. package/dist/explain/openai.js +102 -0
  32. package/dist/explain/openai.js.map +1 -0
  33. package/dist/explain/provider.d.ts +19 -0
  34. package/dist/explain/provider.js +2 -0
  35. package/dist/explain/provider.js.map +1 -0
  36. package/dist/explain/sse.d.ts +10 -0
  37. package/dist/explain/sse.js +44 -0
  38. package/dist/explain/sse.js.map +1 -0
  39. package/dist/flow-parser.d.ts +10 -0
  40. package/dist/flow-parser.js +503 -0
  41. package/dist/flow-parser.js.map +1 -0
  42. package/dist/glossary.d.ts +54 -0
  43. package/dist/glossary.js +340 -0
  44. package/dist/glossary.js.map +1 -0
  45. package/dist/index.d.ts +17 -0
  46. package/dist/index.js +16 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/inventory.d.ts +7 -0
  49. package/dist/inventory.js +453 -0
  50. package/dist/inventory.js.map +1 -0
  51. package/dist/lines.d.ts +15 -0
  52. package/dist/lines.js +53 -0
  53. package/dist/lines.js.map +1 -0
  54. package/dist/linker.d.ts +17 -0
  55. package/dist/linker.js +56 -0
  56. package/dist/linker.js.map +1 -0
  57. package/dist/mermaid.d.ts +27 -0
  58. package/dist/mermaid.js +133 -0
  59. package/dist/mermaid.js.map +1 -0
  60. package/dist/parser.d.ts +19 -0
  61. package/dist/parser.js +442 -0
  62. package/dist/parser.js.map +1 -0
  63. package/dist/pic.d.ts +29 -0
  64. package/dist/pic.js +197 -0
  65. package/dist/pic.js.map +1 -0
  66. package/dist/references.d.ts +24 -0
  67. package/dist/references.js +906 -0
  68. package/dist/references.js.map +1 -0
  69. package/dist/source-lines.d.ts +56 -0
  70. package/dist/source-lines.js +114 -0
  71. package/dist/source-lines.js.map +1 -0
  72. package/dist/types.d.ts +499 -0
  73. package/dist/types.js +2 -0
  74. package/dist/types.js.map +1 -0
  75. package/gui/dist/assets/ChainCanvas-C37KyhnE.js +1 -0
  76. package/gui/dist/assets/FlowCanvas-BRklWBCp.js +3 -0
  77. package/gui/dist/assets/RobotProfessor-BtTDTBDq.js +4220 -0
  78. package/gui/dist/assets/fira-code-cyrillic-400-normal-UC0NFL4U.woff2 +0 -0
  79. package/gui/dist/assets/fira-code-cyrillic-400-normal-dc1q3VD7.woff +0 -0
  80. package/gui/dist/assets/fira-code-cyrillic-500-normal-Bu7VCL72.woff +0 -0
  81. package/gui/dist/assets/fira-code-cyrillic-500-normal-CX35h3Mg.woff2 +0 -0
  82. package/gui/dist/assets/fira-code-cyrillic-600-normal-BD56RyRT.woff +0 -0
  83. package/gui/dist/assets/fira-code-cyrillic-600-normal-CPRdbepc.woff2 +0 -0
  84. package/gui/dist/assets/fira-code-cyrillic-ext-400-normal-Buh61xzB.woff +0 -0
  85. package/gui/dist/assets/fira-code-cyrillic-ext-400-normal-txZ9Fk_1.woff2 +0 -0
  86. package/gui/dist/assets/fira-code-cyrillic-ext-500-normal-CYRspHgm.woff2 +0 -0
  87. package/gui/dist/assets/fira-code-cyrillic-ext-500-normal-CwtLmSFD.woff +0 -0
  88. package/gui/dist/assets/fira-code-cyrillic-ext-600-normal-B9wE0zmr.woff2 +0 -0
  89. package/gui/dist/assets/fira-code-cyrillic-ext-600-normal-DldcyWhZ.woff +0 -0
  90. package/gui/dist/assets/fira-code-greek-400-normal-B2Gh_Y8s.woff2 +0 -0
  91. package/gui/dist/assets/fira-code-greek-400-normal-DobhaxvF.woff +0 -0
  92. package/gui/dist/assets/fira-code-greek-500-normal-CVO0IRNt.woff2 +0 -0
  93. package/gui/dist/assets/fira-code-greek-500-normal-DEXIWiey.woff +0 -0
  94. package/gui/dist/assets/fira-code-greek-600-normal-D_h3X2X5.woff +0 -0
  95. package/gui/dist/assets/fira-code-greek-600-normal-Dxp52_By.woff2 +0 -0
  96. package/gui/dist/assets/fira-code-greek-ext-400-normal-DR7mBgIM.woff2 +0 -0
  97. package/gui/dist/assets/fira-code-greek-ext-400-normal-DSPUheWg.woff +0 -0
  98. package/gui/dist/assets/fira-code-greek-ext-500-normal-BO3iq16n.woff2 +0 -0
  99. package/gui/dist/assets/fira-code-greek-ext-500-normal-CMiNLXER.woff +0 -0
  100. package/gui/dist/assets/fira-code-greek-ext-600-normal-C-cQDoOk.woff +0 -0
  101. package/gui/dist/assets/fira-code-greek-ext-600-normal-DtBpFRLc.woff2 +0 -0
  102. package/gui/dist/assets/fira-code-latin-400-normal-C-QZfXAs.woff +0 -0
  103. package/gui/dist/assets/fira-code-latin-400-normal-DGosTW8U.woff2 +0 -0
  104. package/gui/dist/assets/fira-code-latin-500-normal-B6gioGu8.woff2 +0 -0
  105. package/gui/dist/assets/fira-code-latin-500-normal-aMLC2AMm.woff +0 -0
  106. package/gui/dist/assets/fira-code-latin-600-normal-BmSSHshu.woff +0 -0
  107. package/gui/dist/assets/fira-code-latin-600-normal-CvYZpPHg.woff2 +0 -0
  108. package/gui/dist/assets/fira-code-latin-ext-400-normal-DG73JjOf.woff +0 -0
  109. package/gui/dist/assets/fira-code-latin-ext-400-normal-KSMg0QLl.woff2 +0 -0
  110. package/gui/dist/assets/fira-code-latin-ext-500-normal-CaANqXjI.woff +0 -0
  111. package/gui/dist/assets/fira-code-latin-ext-500-normal-Crd9e_oI.woff2 +0 -0
  112. package/gui/dist/assets/fira-code-latin-ext-600-normal-0PFQL1eg.woff +0 -0
  113. package/gui/dist/assets/fira-code-latin-ext-600-normal-Cb7jxoAi.woff2 +0 -0
  114. package/gui/dist/assets/fira-code-symbols2-400-normal-_QEZCEwe.woff +0 -0
  115. package/gui/dist/assets/fira-code-symbols2-500-normal-DwsgbIjQ.woff +0 -0
  116. package/gui/dist/assets/fira-code-symbols2-600-normal-Dvq6IQE5.woff +0 -0
  117. package/gui/dist/assets/fira-sans-cyrillic-300-normal-BO7tmGom.woff2 +0 -0
  118. package/gui/dist/assets/fira-sans-cyrillic-300-normal-BtNmWoqn.woff +0 -0
  119. package/gui/dist/assets/fira-sans-cyrillic-400-normal-CKu2TFQr.woff2 +0 -0
  120. package/gui/dist/assets/fira-sans-cyrillic-400-normal-D9eUeF-O.woff +0 -0
  121. package/gui/dist/assets/fira-sans-cyrillic-500-normal-CXfldnQ8.woff2 +0 -0
  122. package/gui/dist/assets/fira-sans-cyrillic-500-normal-Daski1k2.woff +0 -0
  123. package/gui/dist/assets/fira-sans-cyrillic-600-normal-CJ5P9t7t.woff +0 -0
  124. package/gui/dist/assets/fira-sans-cyrillic-600-normal-JSBvCpTs.woff2 +0 -0
  125. package/gui/dist/assets/fira-sans-cyrillic-700-normal-Bl-HczEO.woff2 +0 -0
  126. package/gui/dist/assets/fira-sans-cyrillic-700-normal-KyW5QH4H.woff +0 -0
  127. package/gui/dist/assets/fira-sans-cyrillic-ext-300-normal-BRn8Tsce.woff2 +0 -0
  128. package/gui/dist/assets/fira-sans-cyrillic-ext-300-normal-DOtRq9zH.woff +0 -0
  129. package/gui/dist/assets/fira-sans-cyrillic-ext-400-normal-Cycyekte.woff2 +0 -0
  130. package/gui/dist/assets/fira-sans-cyrillic-ext-400-normal-Dd5dApAy.woff +0 -0
  131. package/gui/dist/assets/fira-sans-cyrillic-ext-500-normal-Cixivk4R.woff +0 -0
  132. package/gui/dist/assets/fira-sans-cyrillic-ext-500-normal-Dkk5LlrU.woff2 +0 -0
  133. package/gui/dist/assets/fira-sans-cyrillic-ext-600-normal-BKgjRriM.woff +0 -0
  134. package/gui/dist/assets/fira-sans-cyrillic-ext-600-normal-CE6oUZE1.woff2 +0 -0
  135. package/gui/dist/assets/fira-sans-cyrillic-ext-700-normal-BfO9TR-w.woff2 +0 -0
  136. package/gui/dist/assets/fira-sans-cyrillic-ext-700-normal-Gcpdxicj.woff +0 -0
  137. package/gui/dist/assets/fira-sans-greek-300-normal-D3JfF3y9.woff2 +0 -0
  138. package/gui/dist/assets/fira-sans-greek-300-normal-DSgcXl_1.woff +0 -0
  139. package/gui/dist/assets/fira-sans-greek-400-normal-BFCFncbp.woff2 +0 -0
  140. package/gui/dist/assets/fira-sans-greek-400-normal-DQ8sF22y.woff +0 -0
  141. package/gui/dist/assets/fira-sans-greek-500-normal-C9KT8sAy.woff +0 -0
  142. package/gui/dist/assets/fira-sans-greek-500-normal-Cy-TUuxE.woff2 +0 -0
  143. package/gui/dist/assets/fira-sans-greek-600-normal-BlqpLOpF.woff2 +0 -0
  144. package/gui/dist/assets/fira-sans-greek-600-normal-DfHu91YF.woff +0 -0
  145. package/gui/dist/assets/fira-sans-greek-700-normal-BVfcrbV7.woff2 +0 -0
  146. package/gui/dist/assets/fira-sans-greek-700-normal-CJu31rC4.woff +0 -0
  147. package/gui/dist/assets/fira-sans-greek-ext-300-normal-CodlqOxk.woff +0 -0
  148. package/gui/dist/assets/fira-sans-greek-ext-300-normal-DVDwbKuK.woff2 +0 -0
  149. package/gui/dist/assets/fira-sans-greek-ext-400-normal-ByG7UNQ2.woff2 +0 -0
  150. package/gui/dist/assets/fira-sans-greek-ext-400-normal-ClCfNE6D.woff +0 -0
  151. package/gui/dist/assets/fira-sans-greek-ext-500-normal-Bem4H9fH.woff +0 -0
  152. package/gui/dist/assets/fira-sans-greek-ext-500-normal-nq-cjB3m.woff2 +0 -0
  153. package/gui/dist/assets/fira-sans-greek-ext-600-normal-DPxZoeHL.woff +0 -0
  154. package/gui/dist/assets/fira-sans-greek-ext-600-normal-fS0evUH3.woff2 +0 -0
  155. package/gui/dist/assets/fira-sans-greek-ext-700-normal-C1m6bE4Q.woff2 +0 -0
  156. package/gui/dist/assets/fira-sans-greek-ext-700-normal-C8J5qYMq.woff +0 -0
  157. package/gui/dist/assets/fira-sans-latin-300-normal-B2LrTgQS.woff2 +0 -0
  158. package/gui/dist/assets/fira-sans-latin-300-normal-Dwkm-oZ7.woff +0 -0
  159. package/gui/dist/assets/fira-sans-latin-400-normal-66xCkunx.woff +0 -0
  160. package/gui/dist/assets/fira-sans-latin-400-normal-a0AnQzuD.woff2 +0 -0
  161. package/gui/dist/assets/fira-sans-latin-500-normal-Bkfzcwmr.woff +0 -0
  162. package/gui/dist/assets/fira-sans-latin-500-normal-Bvbxc8ch.woff2 +0 -0
  163. package/gui/dist/assets/fira-sans-latin-600-normal-CXKlxLG9.woff2 +0 -0
  164. package/gui/dist/assets/fira-sans-latin-600-normal-DtSgd811.woff +0 -0
  165. package/gui/dist/assets/fira-sans-latin-700-normal-CRhwpWTq.woff2 +0 -0
  166. package/gui/dist/assets/fira-sans-latin-700-normal-DgqLm3Fi.woff +0 -0
  167. package/gui/dist/assets/fira-sans-latin-ext-300-normal-CAROBYR0.woff +0 -0
  168. package/gui/dist/assets/fira-sans-latin-ext-300-normal-GNF4Ac3G.woff2 +0 -0
  169. package/gui/dist/assets/fira-sans-latin-ext-400-normal-BCUwhuGB.woff +0 -0
  170. package/gui/dist/assets/fira-sans-latin-ext-400-normal-BLG_mAEf.woff2 +0 -0
  171. package/gui/dist/assets/fira-sans-latin-ext-500-normal-CFRf4jcC.woff +0 -0
  172. package/gui/dist/assets/fira-sans-latin-ext-500-normal-OO1QnNpY.woff2 +0 -0
  173. package/gui/dist/assets/fira-sans-latin-ext-600-normal-DLMQsaV4.woff +0 -0
  174. package/gui/dist/assets/fira-sans-latin-ext-600-normal-DTQBTt1m.woff2 +0 -0
  175. package/gui/dist/assets/fira-sans-latin-ext-700-normal-cfTxGFzJ.woff +0 -0
  176. package/gui/dist/assets/fira-sans-latin-ext-700-normal-g2Yrd4J5.woff2 +0 -0
  177. package/gui/dist/assets/fira-sans-vietnamese-300-normal-BO7He0nF.woff2 +0 -0
  178. package/gui/dist/assets/fira-sans-vietnamese-300-normal-CeyOCBN-.woff +0 -0
  179. package/gui/dist/assets/fira-sans-vietnamese-400-normal-DUVG35gE.woff +0 -0
  180. package/gui/dist/assets/fira-sans-vietnamese-400-normal-ljDTQFsx.woff2 +0 -0
  181. package/gui/dist/assets/fira-sans-vietnamese-500-normal-ChEXCnJy.woff2 +0 -0
  182. package/gui/dist/assets/fira-sans-vietnamese-500-normal-UV7M6ot_.woff +0 -0
  183. package/gui/dist/assets/fira-sans-vietnamese-600-normal-Bxjaclsw.woff +0 -0
  184. package/gui/dist/assets/fira-sans-vietnamese-600-normal-Dh2KAvU8.woff2 +0 -0
  185. package/gui/dist/assets/fira-sans-vietnamese-700-normal-DFi88MGY.woff +0 -0
  186. package/gui/dist/assets/fira-sans-vietnamese-700-normal-j5oLGLJY.woff2 +0 -0
  187. package/gui/dist/assets/index-CwQzep9r.js +413 -0
  188. package/gui/dist/assets/index-DUFjnEFT.css +1 -0
  189. package/gui/dist/assets/theme-BnuhLJ6X.css +1 -0
  190. package/gui/dist/assets/theme-G7EkTZY2.js +30 -0
  191. package/gui/dist/index.html +13 -0
  192. package/package.json +62 -0
@@ -0,0 +1,72 @@
1
+ import type { Advisory, Inventory, FlowResult, LinkedFlow, ParseResult } from '../types.js';
2
+ import type { ExplanationProvider } from './provider.js';
3
+ /**
4
+ * Contrato de no-invención (ADR-0003), aplicado por prompt. La otra mitad
5
+ * del contrato es estructural: el modelo solo recibe hechos verificados
6
+ * (renderFacts), nunca el código fuente crudo, y su salida se valida
7
+ * contra esos hechos (un párrafo que no exista se descarta).
8
+ *
9
+ * La salida es JSON estructurado, no markdown libre: así la GUI puede
10
+ * atar cada etapa del recorrido a su párrafo en el diagrama. El reparto
11
+ * es el de siempre — la IA NARRA (resumen + recorrido); los hechos
12
+ * (esquema, flujo, inventario) los pone el parser.
13
+ */
14
+ export declare const SYSTEM_PROMPT = "Eres KnowFlow, un compa\u00F1ero de onboarding para desarrolladores junior de mainframe que heredan programas COBOL.\n\nRecibir\u00E1s HECHOS estructurales extra\u00EDdos por un parser determinista (no el c\u00F3digo fuente). Tu trabajo es narrarlos en lenguaje llano, en espa\u00F1ol, para alguien que est\u00E1 aprendiendo.\n\nDevuelve EXCLUSIVAMENTE un objeto JSON v\u00E1lido, sin ning\u00FAn texto alrededor ni vallas ```:\n{\n \"summary\": \"2 a 4 frases: qu\u00E9 hace el programa en conjunto, en lenguaje llano\",\n \"walkthrough\": [\n { \"text\": \"una etapa del recorrido, en lenguaje llano\", \"paragraph\": \"NOMBRE-PARRAFO\" }\n ]\n}\n\nReglas del recorrido:\n- Entre 4 y 8 etapas. AGRUPA: da la FORMA del programa, no una transcripci\u00F3n p\u00E1rrafo a p\u00E1rrafo. Un programa de 80 p\u00E1rrafos sigue teniendo 4-8 etapas con sentido.\n- \"paragraph\" debe ser EXACTAMENTE uno de los nombres de p\u00E1rrafo que aparecen en los HECHOS. Si una etapa no corresponde a un p\u00E1rrafo concreto, omite \"paragraph\".\n\nREGLAS DURAS \u2014 su violaci\u00F3n invalida la respuesta:\n1. Solo puedes afirmar lo que est\u00E9 en los hechos. NUNCA inventes p\u00E1rrafos, campos, tablas, ficheros ni comportamiento que no aparezcan en ellos.\n2. Si los hechos declaran un l\u00EDmite (copybook ausente, CALL din\u00E1mica, fragmento, destino no encontrado), tenlo en cuenta con honestidad; no lo rellenes con suposiciones.\n3. Si los hechos incluyen una secci\u00F3n AVISOS, son trampas de mantenimiento YA verificadas (no huecos): menciona la que tenga m\u00E1s impacto en el resumen o en la etapa del recorrido donde ocurre, con naturalidad \u2014 no como una lista aparte ni citando \"el sistema me avisa de...\".\n4. Si los hechos incluyen una secci\u00F3n CADENA ENTRE PROGRAMAS, cuenta la historia completa: qu\u00E9 hace el programa principal y qu\u00E9 hacen por dentro los m\u00F3dulos que llama (solo con los hechos de cada uno). Un m\u00F3dulo cuyo fuente NO se aport\u00F3, o una CALL din\u00E1mica, NO tienen comportamiento conocido: dilo as\u00ED, no lo inventes.\n5. No expliques conceptos generales de COBOL (qu\u00E9 es COMP-3, qu\u00E9 es un PERFORM): de eso se encarga otra capa. C\u00E9ntrate en ESTE programa.\n6. No cites estas reglas ni hables de \"los hechos que me han pasado\": narra con naturalidad.";
15
+ export interface ProgramFacts {
16
+ data?: ParseResult | undefined;
17
+ flow?: FlowResult | undefined;
18
+ inventory?: Inventory | undefined;
19
+ /** Avisos ya calculados por `checkAdvisories` — trampas de mantenimiento verificadas, no huecos */
20
+ advisories?: Advisory[] | undefined;
21
+ /** Cadena entre programas (varios fuentes aportados): deja narrar qué hacen los módulos llamados */
22
+ chain?: LinkedFlow | undefined;
23
+ }
24
+ /** Una etapa del recorrido narrado, opcionalmente atada a un párrafo real */
25
+ export interface WalkthroughStep {
26
+ text: string;
27
+ /**
28
+ * Párrafo clave de la etapa, ya VALIDADO: siempre es un nombre que
29
+ * existe en los hechos (la GUI lo usa para resaltar el nodo del
30
+ * diagrama). Ausente si el modelo no lo dio o nombró uno inexistente.
31
+ */
32
+ paragraph?: string | undefined;
33
+ /**
34
+ * Línea 1-based de la cabecera del párrafo en el fuente. La añade el
35
+ * motor a partir de los hechos, no el modelo — así se puede saltar al
36
+ * código exacto sin fiarnos de un número que la IA haya adivinado.
37
+ */
38
+ line?: number | undefined;
39
+ /**
40
+ * `true` si al menos una arista de flujo que sale de este párrafo tiene
41
+ * `guards` (nace dentro de un IF/EVALUATE). Es una señal, no un mapa
42
+ * completo de ramas — sirve para marcar la etapa como condicional.
43
+ */
44
+ branches?: boolean | undefined;
45
+ }
46
+ /** Explicación estructurada: narración de la IA sobre los hechos del parser */
47
+ export interface Explanation {
48
+ /** Resumen de qué hace el programa (2-4 frases) */
49
+ summary: string;
50
+ /** Recorrido curado (4-8 etapas), cada una quizá atada a un párrafo */
51
+ walkthrough: WalkthroughStep[];
52
+ /** Texto crudo devuelto por el modelo — para depurar o como respaldo */
53
+ raw: string;
54
+ /**
55
+ * true si se pudo parsear la estructura; false si el modelo no devolvió
56
+ * JSON válido y `raw` es lo único fiable (la GUI lo muestra tal cual).
57
+ */
58
+ structured: boolean;
59
+ }
60
+ /**
61
+ * Pipeline de explicación: hechos verificados → proveedor → estructura.
62
+ * El modelo solo recibe hechos (nunca el fuente), y su salida se acota a
63
+ * los párrafos que de verdad existen. Cualquier afirmación estructural
64
+ * fuera de los hechos es un bug (testeable con el proveedor fake).
65
+ */
66
+ export declare function explainProgram(facts: ProgramFacts, provider: ExplanationProvider,
67
+ /**
68
+ * Callback opcional de streaming: si se da Y el proveedor implementa
69
+ * `stream`, se emiten fragmentos de texto a medida que llegan (la GUI los
70
+ * muestra en vivo). El resultado final es idéntico al de `complete`.
71
+ */
72
+ onChunk?: (chunk: string) => void): Promise<Explanation>;
@@ -0,0 +1,126 @@
1
+ import { renderFacts } from './facts.js';
2
+ /**
3
+ * Contrato de no-invención (ADR-0003), aplicado por prompt. La otra mitad
4
+ * del contrato es estructural: el modelo solo recibe hechos verificados
5
+ * (renderFacts), nunca el código fuente crudo, y su salida se valida
6
+ * contra esos hechos (un párrafo que no exista se descarta).
7
+ *
8
+ * La salida es JSON estructurado, no markdown libre: así la GUI puede
9
+ * atar cada etapa del recorrido a su párrafo en el diagrama. El reparto
10
+ * es el de siempre — la IA NARRA (resumen + recorrido); los hechos
11
+ * (esquema, flujo, inventario) los pone el parser.
12
+ */
13
+ export const SYSTEM_PROMPT = `Eres KnowFlow, un compañero de onboarding para desarrolladores junior de mainframe que heredan programas COBOL.
14
+
15
+ Recibirás HECHOS estructurales extraídos por un parser determinista (no el código fuente). Tu trabajo es narrarlos en lenguaje llano, en español, para alguien que está aprendiendo.
16
+
17
+ Devuelve EXCLUSIVAMENTE un objeto JSON válido, sin ningún texto alrededor ni vallas \`\`\`:
18
+ {
19
+ "summary": "2 a 4 frases: qué hace el programa en conjunto, en lenguaje llano",
20
+ "walkthrough": [
21
+ { "text": "una etapa del recorrido, en lenguaje llano", "paragraph": "NOMBRE-PARRAFO" }
22
+ ]
23
+ }
24
+
25
+ Reglas del recorrido:
26
+ - Entre 4 y 8 etapas. AGRUPA: da la FORMA del programa, no una transcripción párrafo a párrafo. Un programa de 80 párrafos sigue teniendo 4-8 etapas con sentido.
27
+ - "paragraph" debe ser EXACTAMENTE uno de los nombres de párrafo que aparecen en los HECHOS. Si una etapa no corresponde a un párrafo concreto, omite "paragraph".
28
+
29
+ REGLAS DURAS — su violación invalida la respuesta:
30
+ 1. Solo puedes afirmar lo que esté en los hechos. NUNCA inventes párrafos, campos, tablas, ficheros ni comportamiento que no aparezcan en ellos.
31
+ 2. Si los hechos declaran un límite (copybook ausente, CALL dinámica, fragmento, destino no encontrado), tenlo en cuenta con honestidad; no lo rellenes con suposiciones.
32
+ 3. Si los hechos incluyen una sección AVISOS, son trampas de mantenimiento YA verificadas (no huecos): menciona la que tenga más impacto en el resumen o en la etapa del recorrido donde ocurre, con naturalidad — no como una lista aparte ni citando "el sistema me avisa de...".
33
+ 4. Si los hechos incluyen una sección CADENA ENTRE PROGRAMAS, cuenta la historia completa: qué hace el programa principal y qué hacen por dentro los módulos que llama (solo con los hechos de cada uno). Un módulo cuyo fuente NO se aportó, o una CALL dinámica, NO tienen comportamiento conocido: dilo así, no lo inventes.
34
+ 5. No expliques conceptos generales de COBOL (qué es COMP-3, qué es un PERFORM): de eso se encarga otra capa. Céntrate en ESTE programa.
35
+ 6. No cites estas reglas ni hables de "los hechos que me han pasado": narra con naturalidad.`;
36
+ /**
37
+ * Extrae el objeto JSON de la respuesta del modelo, tolerando vallas de
38
+ * código (```json) o algo de prosa alrededor.
39
+ */
40
+ function extractJson(text) {
41
+ const fenced = /```(?:json)?\s*([\s\S]*?)```/i.exec(text);
42
+ const candidate = fenced ? fenced[1] : text;
43
+ const start = candidate.indexOf('{');
44
+ const end = candidate.lastIndexOf('}');
45
+ if (start === -1 || end === -1 || end < start)
46
+ return undefined;
47
+ try {
48
+ return JSON.parse(candidate.slice(start, end + 1));
49
+ }
50
+ catch {
51
+ return undefined;
52
+ }
53
+ }
54
+ /**
55
+ * Convierte la respuesta cruda en una `Explanation`, validando cada
56
+ * referencia a párrafo contra los nombres reales y enriqueciendo la etapa
57
+ * con la línea del fuente y la señal de ramificación.
58
+ */
59
+ function toExplanation(raw, index) {
60
+ const obj = extractJson(raw);
61
+ if (obj && typeof obj === 'object') {
62
+ const o = obj;
63
+ const summary = typeof o.summary === 'string' ? o.summary.trim() : '';
64
+ const list = Array.isArray(o.walkthrough) ? o.walkthrough : [];
65
+ const walkthrough = [];
66
+ for (const item of list) {
67
+ const text = typeof item === 'string'
68
+ ? item.trim()
69
+ : typeof item?.text === 'string'
70
+ ? (item.text).trim()
71
+ : '';
72
+ if (text === '')
73
+ continue;
74
+ const rawPara = item?.paragraph;
75
+ const canonical = typeof rawPara === 'string' ? index.canonical.get(rawPara.trim().toUpperCase()) : undefined;
76
+ const line = canonical ? index.lineOf.get(canonical) : undefined;
77
+ const branches = canonical ? index.branchesFrom.has(canonical) : false;
78
+ walkthrough.push({
79
+ text,
80
+ ...(canonical ? { paragraph: canonical } : {}),
81
+ ...(line !== undefined ? { line } : {}),
82
+ ...(branches ? { branches: true } : {}),
83
+ });
84
+ }
85
+ if (summary !== '' || walkthrough.length > 0) {
86
+ return { summary, walkthrough, raw, structured: true };
87
+ }
88
+ }
89
+ return { summary: '', walkthrough: [], raw, structured: false };
90
+ }
91
+ /**
92
+ * Pipeline de explicación: hechos verificados → proveedor → estructura.
93
+ * El modelo solo recibe hechos (nunca el fuente), y su salida se acota a
94
+ * los párrafos que de verdad existen. Cualquier afirmación estructural
95
+ * fuera de los hechos es un bug (testeable con el proveedor fake).
96
+ */
97
+ export async function explainProgram(facts, provider,
98
+ /**
99
+ * Callback opcional de streaming: si se da Y el proveedor implementa
100
+ * `stream`, se emiten fragmentos de texto a medida que llegan (la GUI los
101
+ * muestra en vivo). El resultado final es idéntico al de `complete`.
102
+ */
103
+ onChunk) {
104
+ const rendered = renderFacts(facts.data, facts.flow, facts.inventory, facts.advisories, facts.chain);
105
+ if (rendered.trim() === '') {
106
+ throw new Error('No hay hechos que explicar: parsea un programa primero');
107
+ }
108
+ const canonical = new Map();
109
+ const lineOf = new Map();
110
+ for (const para of facts.flow?.paragraphs ?? []) {
111
+ canonical.set(para.name.toUpperCase(), para.name);
112
+ if (para.line !== undefined)
113
+ lineOf.set(para.name, para.line);
114
+ }
115
+ const branchesFrom = new Set();
116
+ for (const edge of facts.flow?.edges ?? []) {
117
+ if (edge.guards && edge.guards.length > 0)
118
+ branchesFrom.add(edge.from);
119
+ }
120
+ const userMessage = `Narra este programa a partir de sus hechos verificados:\n\n${rendered}`;
121
+ const raw = onChunk && provider.stream
122
+ ? await provider.stream(SYSTEM_PROMPT, userMessage, onChunk)
123
+ : await provider.complete(SYSTEM_PROMPT, userMessage);
124
+ return toExplanation(raw, { canonical, lineOf, branchesFrom });
125
+ }
126
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/explain/explain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { Advisory, Inventory, FlowResult, LinkedFlow, ParseResult } from '../types.js';
2
+ /**
3
+ * Nivel de fidelidad de un conjunto de hechos (ADR-0003). Nivel 3 (solo
4
+ * LLM) no aplica aquí: estos hechos siempre vienen del parser.
5
+ */
6
+ export interface FactsFidelity {
7
+ level: 'verified' | 'partial';
8
+ /** Motivos concretos por los que la fidelidad baja a 'partial' */
9
+ reasons: string[];
10
+ }
11
+ /**
12
+ * Calcula la etiqueta de fidelidad de unos hechos. Es el motor quien la
13
+ * decide —no la GUI— para que todas las superficies etiqueten igual.
14
+ */
15
+ export declare function factsFidelity(data: ParseResult | undefined, flow: FlowResult | undefined, inventory?: Inventory | undefined): FactsFidelity;
16
+ /**
17
+ * Convierte los hechos verificados por el parser (datos y/o flujo) en un
18
+ * documento de texto determinista — lo ÚNICO que la capa LLM recibe como
19
+ * descripción del programa. El modelo nunca ve código fuente crudo del
20
+ * que pueda "deducir" estructura sin verificar: si un hecho no está
21
+ * aquí, no existe para la explicación.
22
+ */
23
+ export declare function renderFacts(data: ParseResult | undefined, flow: FlowResult | undefined, inventory?: Inventory | undefined, advisories?: Advisory[] | undefined, chain?: LinkedFlow | undefined): string;
@@ -0,0 +1,266 @@
1
+ /**
2
+ * Calcula la etiqueta de fidelidad de unos hechos. Es el motor quien la
3
+ * decide —no la GUI— para que todas las superficies etiqueten igual.
4
+ */
5
+ export function factsFidelity(data, flow, inventory) {
6
+ const reasons = [];
7
+ if (flow?.fragment)
8
+ reasons.push('fragmento sin PROCEDURE DIVISION');
9
+ if (data && data.missingCopybooks.length > 0) {
10
+ reasons.push(`copybooks ausentes: ${data.missingCopybooks.join(', ')}`);
11
+ }
12
+ if (flow && flow.missingTargets.length > 0) {
13
+ reasons.push(`destinos no encontrados: ${flow.missingTargets.join(', ')}`);
14
+ }
15
+ if (flow?.edges.some(e => e.dynamic))
16
+ reasons.push('hay CALL dinámicas sin destino verificable');
17
+ if (flow && flow.nestedPrograms.length > 0) {
18
+ reasons.push(`programas anidados sin analizar: ${flow.nestedPrograms.join(', ')}`);
19
+ }
20
+ if (inventory && inventory.unresolvedFileOps.length > 0) {
21
+ const targets = [...new Set(inventory.unresolvedFileOps.map(o => o.target))];
22
+ reasons.push(`operaciones de E/S sin fichero resuelto: ${targets.join(', ')}`);
23
+ }
24
+ if (inventory?.execs.some(e => e.dynamic)) {
25
+ reasons.push('hay EXEC SQL/CICS dinámicos: el recurso real solo se conoce en ejecución');
26
+ }
27
+ return { level: reasons.length > 0 ? 'partial' : 'verified', reasons };
28
+ }
29
+ function renderField(field, depth, out) {
30
+ const indent = ' '.repeat(depth);
31
+ if (field.type === 'unresolved-copy') {
32
+ out.push(`${indent}[HUECO] COPY ${field.unresolvedCopyMember} no disponible — estructura desconocida`);
33
+ return;
34
+ }
35
+ const parts = [`${indent}${String(field.level).padStart(2, '0')} ${field.name}`];
36
+ if (field.dataSection)
37
+ parts.push(`sección ${field.dataSection}`);
38
+ if (field.picture)
39
+ parts.push(`PIC ${field.picture}`);
40
+ if (field.usage)
41
+ parts.push(`USAGE ${field.usage}`);
42
+ if (field.value !== undefined)
43
+ parts.push(`VALUE ${field.value} (valor inicial)`);
44
+ if (field.occurs !== undefined)
45
+ parts.push(`OCCURS ${field.occurs}`);
46
+ if (field.occursDepending) {
47
+ parts.push(`OCCURS ${field.occursDepending.min}..${field.occursDepending.max ?? '?'} DEPENDING ON ${field.occursDepending.dependingOn} (longitud variable)`);
48
+ }
49
+ if (field.redefines)
50
+ parts.push(`REDEFINES ${field.redefines} (misma memoria)`);
51
+ if (field.synchronized)
52
+ parts.push('alineado (SYNC): puede haber bytes de relleno delante');
53
+ parts.push(`${field.lengthInBytes} bytes`);
54
+ parts.push(field.offsetUnknown ? 'offset NO verificable (hueco previo)' : `offset ${field.offset}`);
55
+ out.push(parts.join(' | '));
56
+ for (const cond of field.conditionValues ?? []) {
57
+ out.push(`${indent} 88 ${cond.name} = ${cond.values.join(', ')}`);
58
+ }
59
+ for (const group of field.renamesGroups ?? []) {
60
+ const range = group.thru ? `${group.from} THRU ${group.thru}` : group.from;
61
+ const span = group.offset !== undefined && group.lengthInBytes !== undefined
62
+ ? `${group.lengthInBytes} bytes | offset ${group.offset}`
63
+ : 'tramo NO resuelto (algún extremo no está en el fuente aportado)';
64
+ out.push(`${indent} 66 ${group.name} RENAMES ${range} — ${span} (misma memoria)`);
65
+ }
66
+ for (const child of field.children) {
67
+ renderField(child, depth + 1, out);
68
+ }
69
+ }
70
+ /**
71
+ * Convierte los hechos verificados por el parser (datos y/o flujo) en un
72
+ * documento de texto determinista — lo ÚNICO que la capa LLM recibe como
73
+ * descripción del programa. El modelo nunca ve código fuente crudo del
74
+ * que pueda "deducir" estructura sin verificar: si un hecho no está
75
+ * aquí, no existe para la explicación.
76
+ */
77
+ export function renderFacts(data, flow, inventory, advisories, chain) {
78
+ const out = [];
79
+ // Un flujo aporta hechos solo si tiene aristas o algún párrafo REAL del
80
+ // fuente: el nodo de entrada implícito es andamiaje del parser, no un
81
+ // hecho del programa. Emitir una sección de flujo vacía invitaría al
82
+ // modelo a rellenarla — mejor que explainProgram falle sin hechos.
83
+ const flowHasFacts = flow !== undefined && (flow.edges.length > 0 || flow.paragraphs.some(p => !p.implicit));
84
+ if (flow && flowHasFacts) {
85
+ out.push('## FLUJO (verificado por parser)');
86
+ if (flow.programId)
87
+ out.push(`PROGRAM-ID: ${flow.programId}`);
88
+ out.push('Párrafos/secciones en orden de fuente:');
89
+ for (const para of flow.paragraphs) {
90
+ const marks = [
91
+ para.kind === 'section' ? 'SECTION' : '',
92
+ para.section ? `(en ${para.section})` : '',
93
+ para.terminates ? '[termina el programa]' : '',
94
+ para.inDeclaratives ? '[en DECLARATIVES — lo invoca el runtime, no se ejecuta en línea]' : '',
95
+ para.fallsThrough ? '[cae en el párrafo siguiente si no se corta antes]' : '',
96
+ para.implicit ? '[entrada implícita — sentencias antes del primer párrafo]' : '',
97
+ ].filter(Boolean);
98
+ out.push(`- ${para.name}${marks.length > 0 ? ' ' + marks.join(' ') : ''}`);
99
+ }
100
+ if (flow.edges.length > 0) {
101
+ out.push('Aristas de flujo (transferencias de control y caídas naturales, con línea del fuente):');
102
+ for (const edge of flow.edges) {
103
+ const extra = [
104
+ edge.thru ? `THRU ${edge.thru}` : '',
105
+ edge.times !== undefined ? `${edge.times} TIMES` : '',
106
+ edge.condition ?? '',
107
+ // Sin la guarda, el modelo leería una arista condicional como
108
+ // incondicional y explicaría un flujo que el programa no tiene.
109
+ edge.guards ? `[solo si ${edge.guards.join(' AND ')}]` : '',
110
+ edge.dynamic ? '[dinámica: destino real solo se conoce en ejecución]' : '',
111
+ edge.kind === 'fall-through'
112
+ ? '[caída natural: no hay sentencia que la provoque; si se llegó por PERFORM/SORT, al final se vuelve al llamador]'
113
+ : '',
114
+ ].filter(Boolean);
115
+ out.push(`- L${edge.line}: ${edge.from} -> ${edge.to} (${edge.kind.toUpperCase()}${extra.length > 0 ? ' ' + extra.join(' ') : ''})`);
116
+ }
117
+ }
118
+ }
119
+ const dataHasFacts = data !== undefined && data.records.length > 0;
120
+ if (data && dataHasFacts) {
121
+ out.push('');
122
+ out.push('## DATOS (verificado por parser)');
123
+ for (const record of data.records) {
124
+ renderField(record, 0, out);
125
+ }
126
+ }
127
+ const inventoryHasFacts = inventory !== undefined &&
128
+ (inventory.files.length > 0 || inventory.execs.length > 0 || inventory.unresolvedFileOps.length > 0);
129
+ if (inventory && inventoryHasFacts) {
130
+ out.push('');
131
+ out.push('## QUÉ TOCA EL PROGRAMA (verificado por parser)');
132
+ for (const file of inventory.files) {
133
+ const decl = [
134
+ file.assignTo ? `ASSIGN TO ${file.assignTo}` : '',
135
+ file.organization ? `ORGANIZATION ${file.organization}` : '',
136
+ file.access ? `ACCESS ${file.access}` : '',
137
+ ].filter(Boolean);
138
+ out.push(`- FICHERO ${file.name}${decl.length > 0 ? ' | ' + decl.join(' | ') : ''}`);
139
+ for (const op of file.operations) {
140
+ const where = op.paragraphImplicit
141
+ ? `${op.paragraph} [entrada implícita — no es un párrafo declarado]`
142
+ : op.paragraph;
143
+ out.push(` - ${op.verb}${op.mode ? ' ' + op.mode : ''} en ${where} (L${op.line})`);
144
+ }
145
+ if (file.operations.length === 0) {
146
+ out.push(' - declarado pero SIN operaciones en el fuente aportado');
147
+ }
148
+ }
149
+ for (const table of inventory.tables) {
150
+ out.push(`- TABLA DB2 ${table}`);
151
+ }
152
+ for (const cursor of inventory.cursors) {
153
+ const ops = [
154
+ cursor.declared ? 'DECLARE' : '',
155
+ cursor.opened ? 'OPEN' : '',
156
+ cursor.fetched ? 'FETCH' : '',
157
+ cursor.closed ? 'CLOSE' : '',
158
+ ].filter(Boolean);
159
+ out.push(`- CURSOR ${cursor.name}: ${ops.join(', ') || 'nombrado sin operaciones reconocidas'}` +
160
+ (cursor.tables.length > 0 ? ` sobre ${cursor.tables.join(', ')}` : ''));
161
+ }
162
+ for (const cics of inventory.cicsCommands) {
163
+ out.push(`- CICS ${cics.command} × ${cics.count}`);
164
+ }
165
+ if (inventory.execs.length > 0) {
166
+ out.push('Bloques EXEC en orden de fuente (texto literal, sin interpretar):');
167
+ for (const exec of inventory.execs) {
168
+ const where = exec.paragraph
169
+ ? ` (${exec.paragraph}${exec.paragraphImplicit ? ' — entrada implícita' : ''})`
170
+ : ' (DATA DIVISION)';
171
+ const dyn = exec.dynamic ? ' [DINÁMICO: recurso/tabla real solo se conoce en ejecución]' : '';
172
+ out.push(` - L${exec.line}${where}: ${exec.text}${dyn}`);
173
+ }
174
+ }
175
+ }
176
+ // Sin ningún hecho no hay nada que acotar: devolver solo la sección de
177
+ // límites daría un documento que parece analizable pero está vacío.
178
+ if (!flowHasFacts && !dataHasFacts && !inventoryHasFacts)
179
+ return '';
180
+ // Cadena entre programas: cuando el usuario aporta varios fuentes, el
181
+ // modelo recibe también los hechos de flujo de los OTROS programas (no el
182
+ // principal, cuyo detalle ya está en FLUJO) para poder narrar la historia
183
+ // completa — "este llama a X, que hace Y". Todo son hechos del parser; los
184
+ // módulos no aportados y los destinos dinámicos quedan marcados abajo.
185
+ const chainHasFacts = chain !== undefined && (chain.calls.length > 0 || chain.programs.length > 1);
186
+ if (chain && chainHasFacts) {
187
+ out.push('');
188
+ out.push('## CADENA ENTRE PROGRAMAS (verificado por parser)');
189
+ if (chain.calls.length > 0) {
190
+ out.push('Llamadas que cruzan de un programa a otro:');
191
+ for (const call of chain.calls) {
192
+ const mark = call.dynamic
193
+ ? '[dinámica: destino real solo en ejecución]'
194
+ : call.resolved
195
+ ? '[fuente aportado]'
196
+ : '[fuente NO aportado]';
197
+ out.push(`- L${call.line}: ${call.fromProgram} · ${call.fromParagraph} -> ${call.toProgram} ${mark}`);
198
+ }
199
+ }
200
+ for (const program of chain.programs) {
201
+ // El principal ya está detallado en FLUJO; aquí solo los demás.
202
+ if (flow?.programId && program.name === flow.programId)
203
+ continue;
204
+ const paras = program.flow.paragraphs.filter(p => !p.implicit);
205
+ if (paras.length === 0 && program.flow.edges.length === 0)
206
+ continue;
207
+ out.push(`Programa ${program.name} (aportado) — qué hace por dentro:`);
208
+ if (paras.length > 0) {
209
+ out.push(' Párrafos: ' + paras.map(p => p.name + (p.terminates ? ' [termina]' : '')).join(', '));
210
+ }
211
+ for (const edge of program.flow.edges) {
212
+ if (edge.kind !== 'perform' && edge.kind !== 'call' && edge.kind !== 'goto')
213
+ continue;
214
+ const guard = edge.guards ? ` [solo si ${edge.guards.join(' AND ')}]` : '';
215
+ out.push(` - ${edge.from} -> ${edge.to} (${edge.kind.toUpperCase()}${edge.dynamic ? ' dinámica' : ''}${guard})`);
216
+ }
217
+ }
218
+ }
219
+ // Distinta de LÍMITES DE LO VERIFICADO: un aviso es sobre un hecho que SÍ
220
+ // está verificado, pero es una trampa de mantenimiento conocida (ver
221
+ // `Advisory` en types.ts). Verificado y arriesgado no son lo mismo.
222
+ if (advisories && advisories.length > 0) {
223
+ out.push('');
224
+ out.push('## AVISOS — trampas de mantenimiento verificadas (no límites de fidelidad)');
225
+ for (const advisory of advisories) {
226
+ out.push(`- L${advisory.line}${advisory.paragraph ? ` (${advisory.paragraph})` : ''}: ${advisory.message}`);
227
+ }
228
+ }
229
+ const gaps = [];
230
+ if (flow?.fragment) {
231
+ gaps.push('El fuente es un FRAGMENTO sin PROCEDURE DIVISION: fidelidad parcialmente verificada.');
232
+ }
233
+ for (const member of data?.missingCopybooks ?? []) {
234
+ gaps.push(`Copybook ${member} NO disponible: su estructura es desconocida.`);
235
+ }
236
+ for (const target of flow?.missingTargets ?? []) {
237
+ gaps.push(`El destino ${target} no existe en el fuente aportado.`);
238
+ }
239
+ for (const nested of flow?.nestedPrograms ?? []) {
240
+ gaps.push(`El fuente contiene el programa anidado ${nested}, cuyo flujo NO se ha analizado: no aparece en los párrafos ni en las aristas de arriba.`);
241
+ }
242
+ for (const edge of flow?.edges ?? []) {
243
+ if (edge.dynamic) {
244
+ gaps.push(`CALL dinámica en L${edge.line}: el programa destino (${edge.to}) es una variable.`);
245
+ }
246
+ }
247
+ for (const op of inventory?.unresolvedFileOps ?? []) {
248
+ gaps.push(`${op.verb} ${op.target} en L${op.line}: no hay SELECT ni FD que diga a qué fichero corresponde.`);
249
+ }
250
+ for (const exec of inventory?.execs ?? []) {
251
+ if (exec.dynamic) {
252
+ gaps.push(`EXEC ${exec.kind.toUpperCase()} ${exec.verb} en L${exec.line}: el recurso (tabla o fichero/programa CICS) es una variable, no se conoce en el fuente.`);
253
+ }
254
+ }
255
+ for (const program of chain?.missingPrograms ?? []) {
256
+ gaps.push(`El programa ${program} se llama con CALL literal pero su fuente NO se ha aportado: su comportamiento es desconocido.`);
257
+ }
258
+ if (gaps.length > 0) {
259
+ out.push('');
260
+ out.push('## LÍMITES DE LO VERIFICADO');
261
+ for (const gap of gaps)
262
+ out.push(`- ${gap}`);
263
+ }
264
+ return out.join('\n');
265
+ }
266
+ //# sourceMappingURL=facts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facts.js","sourceRoot":"","sources":["../../src/explain/facts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ExplanationProvider } from './provider.js';
2
+ export interface FakeProvider extends ExplanationProvider {
3
+ /** Registro de llamadas recibidas, para aserciones en tests */
4
+ calls: {
5
+ system: string;
6
+ user: string;
7
+ }[];
8
+ }
9
+ /**
10
+ * Proveedor falso para tests: sin red, sin claves. Es la costura de test
11
+ * secundaria del spec — permite ejercitar el pipeline de explicación
12
+ * completo y verificar qué se le envía exactamente al proveedor.
13
+ */
14
+ export declare function createFakeProvider(cannedResponse?: string): FakeProvider;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Proveedor falso para tests: sin red, sin claves. Es la costura de test
3
+ * secundaria del spec — permite ejercitar el pipeline de explicación
4
+ * completo y verificar qué se le envía exactamente al proveedor.
5
+ */
6
+ export function createFakeProvider(cannedResponse = 'explicación de prueba') {
7
+ const calls = [];
8
+ return {
9
+ id: 'fake',
10
+ calls,
11
+ async complete(system, user) {
12
+ calls.push({ system, user });
13
+ return cannedResponse;
14
+ },
15
+ async stream(system, user, onChunk) {
16
+ calls.push({ system, user });
17
+ // Trocea la respuesta en palabras para ejercitar el camino de streaming
18
+ // sin red: la GUI recibe fragmentos y el resultado final es el mismo.
19
+ for (const word of cannedResponse.split(/(\s+)/)) {
20
+ if (word !== '')
21
+ onChunk(word);
22
+ }
23
+ return cannedResponse;
24
+ },
25
+ };
26
+ }
27
+ //# sourceMappingURL=fake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake.js","sourceRoot":"","sources":["../../src/explain/fake.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,cAAc,GAAG,uBAAuB;IACzE,MAAM,KAAK,GAAuC,EAAE,CAAA;IACpD,OAAO;QACL,EAAE,EAAE,MAAM;QACV,KAAK;QACL,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,IAAY;YACzC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;YAC5B,OAAO,cAAc,CAAA;QACvB,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,MAAc,EAAE,IAAY,EAAE,OAAgC;YACzE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;YAC5B,wEAAwE;YACxE,sEAAsE;YACtE,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;gBACjD,IAAI,IAAI,KAAK,EAAE;oBAAE,OAAO,CAAC,IAAI,CAAC,CAAA;YAChC,CAAC;YACD,OAAO,cAAc,CAAA;QACvB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { ExplanationProvider } from './provider.js';
2
+ export interface OpenAICompatibleOptions {
3
+ /**
4
+ * URL completa del endpoint de chat completions. No se asume ninguna
5
+ * ruta: se pasa tal cual la publique el gateway. Ejemplos:
6
+ * - OpenAI: https://api.openai.com/v1/chat/completions
7
+ * - Azure: https://<rec>.openai.azure.com/openai/deployments/<dep>/chat/completions?api-version=2024-02-01
8
+ * - Gateway corporativo (CODEX/AXET): la URL que te den.
9
+ */
10
+ endpoint: string;
11
+ /** Clave/token del usuario (BYOK) — solo viaja hacia `endpoint` */
12
+ apiKey: string;
13
+ /** Identificador de modelo tal como lo espera el gateway */
14
+ model: string;
15
+ /**
16
+ * Cabecera de autenticación. Por defecto `Authorization: Bearer <clave>`
17
+ * (OpenAI y la mayoría). Azure usa `api-key: <clave>` → { name: 'api-key',
18
+ * prefix: '' }. Un gateway propio puede pedir otra cosa.
19
+ */
20
+ auth?: {
21
+ name?: string | undefined;
22
+ prefix?: string | undefined;
23
+ } | undefined;
24
+ /** Cabeceras extra (org id, versión de API, etc.) */
25
+ headers?: Record<string, string> | undefined;
26
+ /** Etiqueta del proveedor, para distinguirlo en la UI ('codex', 'axet'…) */
27
+ id?: string | undefined;
28
+ maxTokens?: number | undefined;
29
+ }
30
+ /**
31
+ * Adaptador para cualquier API compatible con OpenAI (`/chat/completions`).
32
+ * Vía "lista para conectar" a una IA corporativa cuyo shape exacto aún no se
33
+ * conoce: casi todos los gateways (Azure OpenAI, pasarelas internas, la
34
+ * mayoría de endpoints tipo CODEX/AXET) hablan este formato.
35
+ *
36
+ * Mismo contrato BYOK/local-first que el adaptador Claude: la llamada va
37
+ * directa del navegador del usuario al `endpoint` que él configure. Que ese
38
+ * endpoint acepte código de clientes es su decisión (restricción de IP).
39
+ * Si el gateway NO fuese compatible, la interfaz `ExplanationProvider`
40
+ * permite un adaptador a medida sin tocar el resto del motor.
41
+ */
42
+ export declare function createOpenAICompatibleProvider(options: OpenAICompatibleOptions): ExplanationProvider;