mindheal 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.
Files changed (255) hide show
  1. package/.env.example +48 -0
  2. package/CHANGELOG.md +27 -0
  3. package/LICENSE +21 -0
  4. package/README.md +481 -0
  5. package/dist/cjs/ai/ai-provider.js +46 -0
  6. package/dist/cjs/ai/ai-provider.js.map +1 -0
  7. package/dist/cjs/ai/anthropic-provider.js +106 -0
  8. package/dist/cjs/ai/anthropic-provider.js.map +1 -0
  9. package/dist/cjs/ai/azure-openai-provider.js +130 -0
  10. package/dist/cjs/ai/azure-openai-provider.js.map +1 -0
  11. package/dist/cjs/ai/bedrock-provider.js +183 -0
  12. package/dist/cjs/ai/bedrock-provider.js.map +1 -0
  13. package/dist/cjs/ai/deepseek-provider.js +118 -0
  14. package/dist/cjs/ai/deepseek-provider.js.map +1 -0
  15. package/dist/cjs/ai/gemini-provider.js +129 -0
  16. package/dist/cjs/ai/gemini-provider.js.map +1 -0
  17. package/dist/cjs/ai/groq-provider.js +118 -0
  18. package/dist/cjs/ai/groq-provider.js.map +1 -0
  19. package/dist/cjs/ai/meta-provider.js +118 -0
  20. package/dist/cjs/ai/meta-provider.js.map +1 -0
  21. package/dist/cjs/ai/ollama-provider.js +127 -0
  22. package/dist/cjs/ai/ollama-provider.js.map +1 -0
  23. package/dist/cjs/ai/openai-provider.js +117 -0
  24. package/dist/cjs/ai/openai-provider.js.map +1 -0
  25. package/dist/cjs/ai/perplexity-provider.js +118 -0
  26. package/dist/cjs/ai/perplexity-provider.js.map +1 -0
  27. package/dist/cjs/ai/prompt-templates.js +174 -0
  28. package/dist/cjs/ai/prompt-templates.js.map +1 -0
  29. package/dist/cjs/ai/qwen-provider.js +118 -0
  30. package/dist/cjs/ai/qwen-provider.js.map +1 -0
  31. package/dist/cjs/analytics/healing-analytics.js +263 -0
  32. package/dist/cjs/analytics/healing-analytics.js.map +1 -0
  33. package/dist/cjs/cli/init.js +517 -0
  34. package/dist/cjs/cli/init.js.map +1 -0
  35. package/dist/cjs/config/config-loader.js +135 -0
  36. package/dist/cjs/config/config-loader.js.map +1 -0
  37. package/dist/cjs/config/defaults.js +109 -0
  38. package/dist/cjs/config/defaults.js.map +1 -0
  39. package/dist/cjs/core/dom-snapshot.js +280 -0
  40. package/dist/cjs/core/dom-snapshot.js.map +1 -0
  41. package/dist/cjs/core/enterprise-strategy.js +702 -0
  42. package/dist/cjs/core/enterprise-strategy.js.map +1 -0
  43. package/dist/cjs/core/healer.js +283 -0
  44. package/dist/cjs/core/healer.js.map +1 -0
  45. package/dist/cjs/core/interceptor.js +945 -0
  46. package/dist/cjs/core/interceptor.js.map +1 -0
  47. package/dist/cjs/core/locator-analyzer.js +172 -0
  48. package/dist/cjs/core/locator-analyzer.js.map +1 -0
  49. package/dist/cjs/core/locator-strategies.js +891 -0
  50. package/dist/cjs/core/locator-strategies.js.map +1 -0
  51. package/dist/cjs/core/self-heal-cache.js +178 -0
  52. package/dist/cjs/core/self-heal-cache.js.map +1 -0
  53. package/dist/cjs/core/smart-retry.js +248 -0
  54. package/dist/cjs/core/smart-retry.js.map +1 -0
  55. package/dist/cjs/core/visual-verification.js +262 -0
  56. package/dist/cjs/core/visual-verification.js.map +1 -0
  57. package/dist/cjs/git/code-modifier.js +184 -0
  58. package/dist/cjs/git/code-modifier.js.map +1 -0
  59. package/dist/cjs/git/git-operations.js +145 -0
  60. package/dist/cjs/git/git-operations.js.map +1 -0
  61. package/dist/cjs/git/pr-creator.js +190 -0
  62. package/dist/cjs/git/pr-creator.js.map +1 -0
  63. package/dist/cjs/index.js +97 -0
  64. package/dist/cjs/index.js.map +1 -0
  65. package/dist/cjs/rag/context-retriever.js +289 -0
  66. package/dist/cjs/rag/context-retriever.js.map +1 -0
  67. package/dist/cjs/rag/embeddings.js +82 -0
  68. package/dist/cjs/rag/embeddings.js.map +1 -0
  69. package/dist/cjs/rag/knowledge-store.js +159 -0
  70. package/dist/cjs/rag/knowledge-store.js.map +1 -0
  71. package/dist/cjs/reporters/heal-report.js +279 -0
  72. package/dist/cjs/reporters/heal-report.js.map +1 -0
  73. package/dist/cjs/reporters/heal-reporter.js +294 -0
  74. package/dist/cjs/reporters/heal-reporter.js.map +1 -0
  75. package/dist/cjs/server/review-server.js +166 -0
  76. package/dist/cjs/server/review-server.js.map +1 -0
  77. package/dist/cjs/server/routes.js +92 -0
  78. package/dist/cjs/server/routes.js.map +1 -0
  79. package/dist/cjs/utils/environment.js +57 -0
  80. package/dist/cjs/utils/environment.js.map +1 -0
  81. package/dist/cjs/utils/file-lock.js +136 -0
  82. package/dist/cjs/utils/file-lock.js.map +1 -0
  83. package/dist/cjs/utils/file-utils.js +49 -0
  84. package/dist/cjs/utils/file-utils.js.map +1 -0
  85. package/dist/cjs/utils/logger.js +78 -0
  86. package/dist/cjs/utils/logger.js.map +1 -0
  87. package/dist/esm/ai/ai-provider.js +44 -0
  88. package/dist/esm/ai/ai-provider.js.map +1 -0
  89. package/dist/esm/ai/anthropic-provider.js +104 -0
  90. package/dist/esm/ai/anthropic-provider.js.map +1 -0
  91. package/dist/esm/ai/azure-openai-provider.js +128 -0
  92. package/dist/esm/ai/azure-openai-provider.js.map +1 -0
  93. package/dist/esm/ai/bedrock-provider.js +181 -0
  94. package/dist/esm/ai/bedrock-provider.js.map +1 -0
  95. package/dist/esm/ai/deepseek-provider.js +116 -0
  96. package/dist/esm/ai/deepseek-provider.js.map +1 -0
  97. package/dist/esm/ai/gemini-provider.js +127 -0
  98. package/dist/esm/ai/gemini-provider.js.map +1 -0
  99. package/dist/esm/ai/groq-provider.js +116 -0
  100. package/dist/esm/ai/groq-provider.js.map +1 -0
  101. package/dist/esm/ai/meta-provider.js +116 -0
  102. package/dist/esm/ai/meta-provider.js.map +1 -0
  103. package/dist/esm/ai/ollama-provider.js +125 -0
  104. package/dist/esm/ai/ollama-provider.js.map +1 -0
  105. package/dist/esm/ai/openai-provider.js +115 -0
  106. package/dist/esm/ai/openai-provider.js.map +1 -0
  107. package/dist/esm/ai/perplexity-provider.js +116 -0
  108. package/dist/esm/ai/perplexity-provider.js.map +1 -0
  109. package/dist/esm/ai/prompt-templates.js +171 -0
  110. package/dist/esm/ai/prompt-templates.js.map +1 -0
  111. package/dist/esm/ai/qwen-provider.js +116 -0
  112. package/dist/esm/ai/qwen-provider.js.map +1 -0
  113. package/dist/esm/analytics/healing-analytics.js +261 -0
  114. package/dist/esm/analytics/healing-analytics.js.map +1 -0
  115. package/dist/esm/cli/init.js +495 -0
  116. package/dist/esm/cli/init.js.map +1 -0
  117. package/dist/esm/config/config-loader.js +132 -0
  118. package/dist/esm/config/config-loader.js.map +1 -0
  119. package/dist/esm/config/defaults.js +107 -0
  120. package/dist/esm/config/defaults.js.map +1 -0
  121. package/dist/esm/core/dom-snapshot.js +278 -0
  122. package/dist/esm/core/dom-snapshot.js.map +1 -0
  123. package/dist/esm/core/enterprise-strategy.js +695 -0
  124. package/dist/esm/core/enterprise-strategy.js.map +1 -0
  125. package/dist/esm/core/healer.js +281 -0
  126. package/dist/esm/core/healer.js.map +1 -0
  127. package/dist/esm/core/interceptor.js +940 -0
  128. package/dist/esm/core/interceptor.js.map +1 -0
  129. package/dist/esm/core/locator-analyzer.js +169 -0
  130. package/dist/esm/core/locator-analyzer.js.map +1 -0
  131. package/dist/esm/core/locator-strategies.js +882 -0
  132. package/dist/esm/core/locator-strategies.js.map +1 -0
  133. package/dist/esm/core/self-heal-cache.js +176 -0
  134. package/dist/esm/core/self-heal-cache.js.map +1 -0
  135. package/dist/esm/core/smart-retry.js +246 -0
  136. package/dist/esm/core/smart-retry.js.map +1 -0
  137. package/dist/esm/core/visual-verification.js +260 -0
  138. package/dist/esm/core/visual-verification.js.map +1 -0
  139. package/dist/esm/git/code-modifier.js +182 -0
  140. package/dist/esm/git/code-modifier.js.map +1 -0
  141. package/dist/esm/git/git-operations.js +143 -0
  142. package/dist/esm/git/git-operations.js.map +1 -0
  143. package/dist/esm/git/pr-creator.js +188 -0
  144. package/dist/esm/git/pr-creator.js.map +1 -0
  145. package/dist/esm/index.js +37 -0
  146. package/dist/esm/index.js.map +1 -0
  147. package/dist/esm/rag/context-retriever.js +287 -0
  148. package/dist/esm/rag/context-retriever.js.map +1 -0
  149. package/dist/esm/rag/embeddings.js +77 -0
  150. package/dist/esm/rag/embeddings.js.map +1 -0
  151. package/dist/esm/rag/knowledge-store.js +157 -0
  152. package/dist/esm/rag/knowledge-store.js.map +1 -0
  153. package/dist/esm/reporters/heal-report.js +277 -0
  154. package/dist/esm/reporters/heal-report.js.map +1 -0
  155. package/dist/esm/reporters/heal-reporter.js +290 -0
  156. package/dist/esm/reporters/heal-reporter.js.map +1 -0
  157. package/dist/esm/server/review-server.js +164 -0
  158. package/dist/esm/server/review-server.js.map +1 -0
  159. package/dist/esm/server/routes.js +90 -0
  160. package/dist/esm/server/routes.js.map +1 -0
  161. package/dist/esm/utils/environment.js +53 -0
  162. package/dist/esm/utils/environment.js.map +1 -0
  163. package/dist/esm/utils/file-lock.js +134 -0
  164. package/dist/esm/utils/file-lock.js.map +1 -0
  165. package/dist/esm/utils/file-utils.js +43 -0
  166. package/dist/esm/utils/file-utils.js.map +1 -0
  167. package/dist/esm/utils/logger.js +75 -0
  168. package/dist/esm/utils/logger.js.map +1 -0
  169. package/dist/types/ai/ai-provider.d.ts +4 -0
  170. package/dist/types/ai/ai-provider.d.ts.map +1 -0
  171. package/dist/types/ai/anthropic-provider.d.ts +11 -0
  172. package/dist/types/ai/anthropic-provider.d.ts.map +1 -0
  173. package/dist/types/ai/azure-openai-provider.d.ts +13 -0
  174. package/dist/types/ai/azure-openai-provider.d.ts.map +1 -0
  175. package/dist/types/ai/bedrock-provider.d.ts +14 -0
  176. package/dist/types/ai/bedrock-provider.d.ts.map +1 -0
  177. package/dist/types/ai/deepseek-provider.d.ts +12 -0
  178. package/dist/types/ai/deepseek-provider.d.ts.map +1 -0
  179. package/dist/types/ai/gemini-provider.d.ts +12 -0
  180. package/dist/types/ai/gemini-provider.d.ts.map +1 -0
  181. package/dist/types/ai/groq-provider.d.ts +12 -0
  182. package/dist/types/ai/groq-provider.d.ts.map +1 -0
  183. package/dist/types/ai/meta-provider.d.ts +12 -0
  184. package/dist/types/ai/meta-provider.d.ts.map +1 -0
  185. package/dist/types/ai/ollama-provider.d.ts +10 -0
  186. package/dist/types/ai/ollama-provider.d.ts.map +1 -0
  187. package/dist/types/ai/openai-provider.d.ts +11 -0
  188. package/dist/types/ai/openai-provider.d.ts.map +1 -0
  189. package/dist/types/ai/perplexity-provider.d.ts +12 -0
  190. package/dist/types/ai/perplexity-provider.d.ts.map +1 -0
  191. package/dist/types/ai/prompt-templates.d.ts +11 -0
  192. package/dist/types/ai/prompt-templates.d.ts.map +1 -0
  193. package/dist/types/ai/qwen-provider.d.ts +12 -0
  194. package/dist/types/ai/qwen-provider.d.ts.map +1 -0
  195. package/dist/types/analytics/healing-analytics.d.ts +36 -0
  196. package/dist/types/analytics/healing-analytics.d.ts.map +1 -0
  197. package/dist/types/cli/init.d.ts +15 -0
  198. package/dist/types/cli/init.d.ts.map +1 -0
  199. package/dist/types/config/config-loader.d.ts +4 -0
  200. package/dist/types/config/config-loader.d.ts.map +1 -0
  201. package/dist/types/config/defaults.d.ts +3 -0
  202. package/dist/types/config/defaults.d.ts.map +1 -0
  203. package/dist/types/core/dom-snapshot.d.ts +12 -0
  204. package/dist/types/core/dom-snapshot.d.ts.map +1 -0
  205. package/dist/types/core/enterprise-strategy.d.ts +56 -0
  206. package/dist/types/core/enterprise-strategy.d.ts.map +1 -0
  207. package/dist/types/core/healer.d.ts +52 -0
  208. package/dist/types/core/healer.d.ts.map +1 -0
  209. package/dist/types/core/interceptor.d.ts +64 -0
  210. package/dist/types/core/interceptor.d.ts.map +1 -0
  211. package/dist/types/core/locator-analyzer.d.ts +31 -0
  212. package/dist/types/core/locator-analyzer.d.ts.map +1 -0
  213. package/dist/types/core/locator-strategies.d.ts +45 -0
  214. package/dist/types/core/locator-strategies.d.ts.map +1 -0
  215. package/dist/types/core/self-heal-cache.d.ts +51 -0
  216. package/dist/types/core/self-heal-cache.d.ts.map +1 -0
  217. package/dist/types/core/smart-retry.d.ts +64 -0
  218. package/dist/types/core/smart-retry.d.ts.map +1 -0
  219. package/dist/types/core/visual-verification.d.ts +46 -0
  220. package/dist/types/core/visual-verification.d.ts.map +1 -0
  221. package/dist/types/git/code-modifier.d.ts +51 -0
  222. package/dist/types/git/code-modifier.d.ts.map +1 -0
  223. package/dist/types/git/git-operations.d.ts +40 -0
  224. package/dist/types/git/git-operations.d.ts.map +1 -0
  225. package/dist/types/git/pr-creator.d.ts +27 -0
  226. package/dist/types/git/pr-creator.d.ts.map +1 -0
  227. package/dist/types/index.d.ts +40 -0
  228. package/dist/types/index.d.ts.map +1 -0
  229. package/dist/types/rag/context-retriever.d.ts +69 -0
  230. package/dist/types/rag/context-retriever.d.ts.map +1 -0
  231. package/dist/types/rag/embeddings.d.ts +32 -0
  232. package/dist/types/rag/embeddings.d.ts.map +1 -0
  233. package/dist/types/rag/index.d.ts +12 -0
  234. package/dist/types/rag/index.d.ts.map +1 -0
  235. package/dist/types/rag/knowledge-store.d.ts +38 -0
  236. package/dist/types/rag/knowledge-store.d.ts.map +1 -0
  237. package/dist/types/reporters/heal-report.d.ts +29 -0
  238. package/dist/types/reporters/heal-report.d.ts.map +1 -0
  239. package/dist/types/reporters/heal-reporter.d.ts +49 -0
  240. package/dist/types/reporters/heal-reporter.d.ts.map +1 -0
  241. package/dist/types/server/review-server.d.ts +20 -0
  242. package/dist/types/server/review-server.d.ts.map +1 -0
  243. package/dist/types/server/routes.d.ts +4 -0
  244. package/dist/types/server/routes.d.ts.map +1 -0
  245. package/dist/types/types/index.d.ts +433 -0
  246. package/dist/types/types/index.d.ts.map +1 -0
  247. package/dist/types/utils/environment.d.ts +10 -0
  248. package/dist/types/utils/environment.d.ts.map +1 -0
  249. package/dist/types/utils/file-lock.d.ts +37 -0
  250. package/dist/types/utils/file-lock.d.ts.map +1 -0
  251. package/dist/types/utils/file-utils.d.ts +7 -0
  252. package/dist/types/utils/file-utils.d.ts.map +1 -0
  253. package/dist/types/utils/logger.d.ts +9 -0
  254. package/dist/types/utils/logger.d.ts.map +1 -0
  255. package/package.json +106 -0
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Lightweight text similarity engine for RAG retrieval.
5
+ *
6
+ * Uses TF-IDF-style term weighting with cosine similarity — no external
7
+ * embedding model or vector DB required. This is intentionally simple so
8
+ * MindHeal works offline (e.g. with Ollama) without any extra infrastructure.
9
+ *
10
+ * For large knowledge bases, consumers can swap in a real vector DB via the
11
+ * `ContextRetriever` interface.
12
+ */
13
+ // ─── Tokenization ────────────────────────────────────────────────────────────
14
+ /**
15
+ * Tokenizes text into lowercase alphanumeric terms, splitting on non-word
16
+ * characters. Also generates bigrams for better matching on locator patterns
17
+ * like "submit-btn" or "getByTestId".
18
+ */
19
+ function tokenize(text) {
20
+ const raw = text.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim().split(/\s+/).filter(Boolean);
21
+ // Add bigrams for compound terms
22
+ const bigrams = [];
23
+ for (let i = 0; i < raw.length - 1; i++) {
24
+ bigrams.push(`${raw[i]}_${raw[i + 1]}`);
25
+ }
26
+ return [...raw, ...bigrams];
27
+ }
28
+ /**
29
+ * Builds a term-frequency vector from a list of tokens.
30
+ */
31
+ function buildTermVector(tokens) {
32
+ const freq = new Map();
33
+ for (const token of tokens) {
34
+ freq.set(token, (freq.get(token) ?? 0) + 1);
35
+ }
36
+ // Normalize by document length
37
+ const len = tokens.length || 1;
38
+ for (const [term, count] of freq) {
39
+ freq.set(term, count / len);
40
+ }
41
+ return freq;
42
+ }
43
+ /**
44
+ * Computes cosine similarity between two term vectors.
45
+ * Returns a value between 0 (completely different) and 1 (identical).
46
+ */
47
+ function cosineSimilarity(a, b) {
48
+ let dotProduct = 0;
49
+ let normA = 0;
50
+ let normB = 0;
51
+ for (const [term, weightA] of a) {
52
+ normA += weightA * weightA;
53
+ const weightB = b.get(term) ?? 0;
54
+ dotProduct += weightA * weightB;
55
+ }
56
+ for (const [, weightB] of b) {
57
+ normB += weightB * weightB;
58
+ }
59
+ const denominator = Math.sqrt(normA) * Math.sqrt(normB);
60
+ if (denominator === 0)
61
+ return 0;
62
+ return dotProduct / denominator;
63
+ }
64
+ /**
65
+ * Computes similarity between two text strings.
66
+ * Convenience wrapper over tokenize → buildTermVector → cosineSimilarity.
67
+ */
68
+ function textSimilarity(textA, textB) {
69
+ const tokensA = tokenize(textA);
70
+ const tokensB = tokenize(textB);
71
+ if (tokensA.length === 0 || tokensB.length === 0)
72
+ return 0;
73
+ const vecA = buildTermVector(tokensA);
74
+ const vecB = buildTermVector(tokensB);
75
+ return cosineSimilarity(vecA, vecB);
76
+ }
77
+
78
+ exports.buildTermVector = buildTermVector;
79
+ exports.cosineSimilarity = cosineSimilarity;
80
+ exports.textSimilarity = textSimilarity;
81
+ exports.tokenize = tokenize;
82
+ //# sourceMappingURL=embeddings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.js","sources":["../../../../src/rag/embeddings.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;;;;;AASG;AAEH;AAEA;;;;AAIG;AACG,SAAU,QAAQ,CAAC,IAAY,EAAA;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;;IAG9F,MAAM,OAAO,GAAa,EAAE;AAC5B,IAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;AACvC,QAAA,OAAO,CAAC,IAAI,CAAC,CAAA,EAAG,GAAG,CAAC,CAAC,CAAC,CAAA,CAAA,EAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA,CAAE,CAAC;IACzC;AAEA,IAAA,OAAO,CAAC,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;AAC7B;AAMA;;AAEG;AACG,SAAU,eAAe,CAAC,MAAgB,EAAA;AAC9C,IAAA,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB;AACtC,IAAA,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAC1B,QAAA,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C;;AAGA,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;QAChC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,GAAG,CAAC;IAC7B;AAEA,IAAA,OAAO,IAAI;AACb;AAEA;;;AAGG;AACG,SAAU,gBAAgB,CAAC,CAAa,EAAE,CAAa,EAAA;IAC3D,IAAI,UAAU,GAAG,CAAC;IAClB,IAAI,KAAK,GAAG,CAAC;IACb,IAAI,KAAK,GAAG,CAAC;IAEb,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE;AAC/B,QAAA,KAAK,IAAI,OAAO,GAAG,OAAO;QAC1B,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AAChC,QAAA,UAAU,IAAI,OAAO,GAAG,OAAO;IACjC;IAEA,KAAK,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE;AAC3B,QAAA,KAAK,IAAI,OAAO,GAAG,OAAO;IAC5B;AAEA,IAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACvD,IAAI,WAAW,KAAK,CAAC;AAAE,QAAA,OAAO,CAAC;IAE/B,OAAO,UAAU,GAAG,WAAW;AACjC;AAEA;;;AAGG;AACG,SAAU,cAAc,CAAC,KAAa,EAAE,KAAa,EAAA;AACzD,IAAA,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC;AAC/B,IAAA,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC;IAE/B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;AAAE,QAAA,OAAO,CAAC;AAE1D,IAAA,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC;AACrC,IAAA,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC;AAErC,IAAA,OAAO,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC;AACrC;;;;;;;"}
@@ -0,0 +1,159 @@
1
+ 'use strict';
2
+
3
+ var embeddings = require('./embeddings.js');
4
+ var logger = require('../utils/logger.js');
5
+ var fileUtils = require('../utils/file-utils.js');
6
+ var path = require('path');
7
+
8
+ /**
9
+ * File-backed knowledge store for RAG context.
10
+ *
11
+ * Stores healing history, page object metadata, git diffs, DOM snapshots,
12
+ * component docs, and test specs as searchable entries. Uses lightweight
13
+ * TF-IDF similarity for retrieval — no vector DB required.
14
+ */
15
+ const STORE_VERSION = '1';
16
+ const MAX_ENTRIES = 2000;
17
+ const ENTRY_EXPIRY_MS = 90 * 24 * 60 * 60 * 1000; // 90 days
18
+ class KnowledgeStore {
19
+ constructor(storePath) {
20
+ this.storePath = storePath;
21
+ this.entries = [];
22
+ this.loaded = false;
23
+ }
24
+ // ─── Load / Save ─────────────────────────────────────────────────────────
25
+ load() {
26
+ logger.logger.debug(`Loading RAG knowledge store from: ${this.storePath}`);
27
+ if (!fileUtils.fileExists(this.storePath)) {
28
+ logger.logger.debug('No existing knowledge store found, starting empty');
29
+ this.entries = [];
30
+ this.loaded = true;
31
+ return;
32
+ }
33
+ try {
34
+ const raw = fileUtils.readJsonFile(this.storePath);
35
+ if (raw && raw.version === STORE_VERSION && Array.isArray(raw.entries)) {
36
+ // Prune expired entries
37
+ const now = Date.now();
38
+ this.entries = raw.entries.filter((e) => now - e.createdAt < ENTRY_EXPIRY_MS);
39
+ const pruned = raw.entries.length - this.entries.length;
40
+ if (pruned > 0) {
41
+ logger.logger.debug(`Pruned ${pruned} expired knowledge entries`);
42
+ }
43
+ }
44
+ else {
45
+ logger.logger.debug('Knowledge store version mismatch, starting fresh');
46
+ this.entries = [];
47
+ }
48
+ }
49
+ catch (err) {
50
+ const msg = err instanceof Error ? err.message : String(err);
51
+ logger.logger.warn(`Failed to load knowledge store: ${msg}. Starting fresh.`);
52
+ this.entries = [];
53
+ }
54
+ this.loaded = true;
55
+ }
56
+ save() {
57
+ try {
58
+ fileUtils.ensureDirectory(path.dirname(this.storePath));
59
+ const store = {
60
+ version: STORE_VERSION,
61
+ entries: this.entries,
62
+ };
63
+ fileUtils.writeJsonFile(this.storePath, store);
64
+ logger.logger.debug(`Knowledge store saved: ${this.entries.length} entries`);
65
+ }
66
+ catch (err) {
67
+ const msg = err instanceof Error ? err.message : String(err);
68
+ logger.logger.warn(`Failed to save knowledge store: ${msg}`);
69
+ }
70
+ }
71
+ // ─── CRUD ─────────────────────────────────────────────────────────────────
72
+ add(entry) {
73
+ const now = Date.now();
74
+ const id = `rag_${now.toString(36)}_${Math.random().toString(36).substring(2, 8)}`;
75
+ const full = {
76
+ ...entry,
77
+ id,
78
+ createdAt: now,
79
+ updatedAt: now,
80
+ };
81
+ this.entries.push(full);
82
+ // Enforce max entries — evict oldest
83
+ if (this.entries.length > MAX_ENTRIES) {
84
+ this.entries.sort((a, b) => b.updatedAt - a.updatedAt);
85
+ this.entries = this.entries.slice(0, MAX_ENTRIES);
86
+ }
87
+ this.save();
88
+ return full;
89
+ }
90
+ /**
91
+ * Add or update an entry. If an entry with matching source + tags exists,
92
+ * update it instead of creating a duplicate.
93
+ */
94
+ upsert(entry) {
95
+ const existing = this.entries.find((e) => e.source === entry.source &&
96
+ e.tags.length === entry.tags.length &&
97
+ e.tags.every((t, i) => t === entry.tags[i]));
98
+ if (existing) {
99
+ existing.content = entry.content;
100
+ existing.metadata = entry.metadata;
101
+ existing.updatedAt = Date.now();
102
+ this.save();
103
+ return existing;
104
+ }
105
+ return this.add(entry);
106
+ }
107
+ getAll() {
108
+ return [...this.entries];
109
+ }
110
+ getBySource(source) {
111
+ return this.entries.filter((e) => e.source === source);
112
+ }
113
+ // ─── Search ───────────────────────────────────────────────────────────────
114
+ /**
115
+ * Search the knowledge store for entries relevant to the query.
116
+ * Returns ranked results above the similarity threshold.
117
+ */
118
+ search(query, options = {}) {
119
+ const { sources, maxResults = 5, similarityThreshold = 0.3, } = options;
120
+ const queryTokens = embeddings.tokenize(query);
121
+ if (queryTokens.length === 0)
122
+ return [];
123
+ const queryVector = embeddings.buildTermVector(queryTokens);
124
+ // Filter by source if specified
125
+ const candidates = sources
126
+ ? this.entries.filter((e) => sources.includes(e.source))
127
+ : this.entries;
128
+ // Score each entry
129
+ const scored = [];
130
+ for (const entry of candidates) {
131
+ // Build a combined text from content + tags for matching
132
+ const entryText = `${entry.content} ${entry.tags.join(' ')}`;
133
+ const entryTokens = embeddings.tokenize(entryText);
134
+ const entryVector = embeddings.buildTermVector(entryTokens);
135
+ const score = embeddings.cosineSimilarity(queryVector, entryVector);
136
+ if (score >= similarityThreshold) {
137
+ scored.push({ entry, score });
138
+ }
139
+ }
140
+ // Sort by score descending
141
+ scored.sort((a, b) => b.score - a.score);
142
+ // Return top results as RAGContextChunks
143
+ return scored.slice(0, maxResults).map(({ entry, score }) => ({
144
+ source: entry.source,
145
+ content: entry.content,
146
+ relevanceScore: score,
147
+ metadata: entry.metadata,
148
+ }));
149
+ }
150
+ /**
151
+ * Get entry count.
152
+ */
153
+ get size() {
154
+ return this.entries.length;
155
+ }
156
+ }
157
+
158
+ exports.KnowledgeStore = KnowledgeStore;
159
+ //# sourceMappingURL=knowledge-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knowledge-store.js","sources":["../../../../src/rag/knowledge-store.ts"],"sourcesContent":[null],"names":["logger","fileExists","readJsonFile","ensureDirectory","dirname","writeJsonFile","tokenize","buildTermVector","cosineSimilarity"],"mappings":"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"}
@@ -0,0 +1,279 @@
1
+ 'use strict';
2
+
3
+ var fileUtils = require('../utils/file-utils.js');
4
+ var logger = require('../utils/logger.js');
5
+ var path = require('path');
6
+
7
+ /**
8
+ * Generates HTML and JSON healing reports summarizing all healing events
9
+ * from a test run.
10
+ */
11
+ class HealReportGenerator {
12
+ /**
13
+ * Serialize a HealReport to a formatted JSON string.
14
+ */
15
+ generateJSON(report) {
16
+ return JSON.stringify(report, null, 2);
17
+ }
18
+ /**
19
+ * Generate a self-contained HTML report with inline styles.
20
+ */
21
+ generateHTML(report) {
22
+ const stats = this.computeStats(report);
23
+ const strategyBreakdown = this.computeStrategyBreakdown(report.events);
24
+ const maxStrategyCount = Math.max(...Object.values(strategyBreakdown), 1);
25
+ const eventsRows = report.events
26
+ .map((event) => this.renderEventRow(event))
27
+ .join('\n');
28
+ const strategyBars = Object.entries(strategyBreakdown)
29
+ .sort(([, a], [, b]) => b - a)
30
+ .map(([strategy, count]) => `<div style="display:flex;align-items:center;margin-bottom:6px;">
31
+ <span style="width:90px;font-size:13px;color:#475569;">${this.escapeHTML(strategy)}</span>
32
+ <div style="flex:1;background:#e2e8f0;border-radius:4px;height:22px;overflow:hidden;">
33
+ <div style="width:${(count / maxStrategyCount) * 100}%;background:${this.strategyColor(strategy)};height:100%;border-radius:4px;transition:width .3s;"></div>
34
+ </div>
35
+ <span style="width:40px;text-align:right;font-size:13px;font-weight:600;color:#334155;">${count}</span>
36
+ </div>`)
37
+ .join('\n');
38
+ return `<!DOCTYPE html>
39
+ <html lang="en">
40
+ <head>
41
+ <meta charset="UTF-8">
42
+ <meta name="viewport" content="width=device-width,initial-scale=1">
43
+ <title>MindHeal Report</title>
44
+ <style>
45
+ *{margin:0;padding:0;box-sizing:border-box}
46
+ body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;background:#f8fafc;color:#1e293b;line-height:1.6;padding:24px}
47
+ .container{max-width:1200px;margin:0 auto}
48
+ h1{font-size:28px;font-weight:700;margin-bottom:4px}
49
+ .subtitle{color:#64748b;font-size:14px;margin-bottom:32px}
50
+ .stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:32px}
51
+ .stat-card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:20px;text-align:center}
52
+ .stat-value{font-size:32px;font-weight:700}
53
+ .stat-label{font-size:13px;color:#64748b;margin-top:4px}
54
+ .stat-healed .stat-value{color:#16a34a}
55
+ .stat-failed .stat-value{color:#dc2626}
56
+ .stat-total .stat-value{color:#2563eb}
57
+ .stat-rate .stat-value{color:#7c3aed}
58
+ .section{background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:24px;margin-bottom:24px}
59
+ .section-title{font-size:18px;font-weight:600;margin-bottom:16px}
60
+ table{width:100%;border-collapse:collapse;font-size:13px}
61
+ th{background:#f1f5f9;text-align:left;padding:10px 12px;font-weight:600;color:#475569;border-bottom:2px solid #e2e8f0}
62
+ td{padding:10px 12px;border-bottom:1px solid #f1f5f9;vertical-align:top}
63
+ tr:hover td{background:#f8fafc}
64
+ .badge{display:inline-block;padding:2px 8px;border-radius:9999px;font-size:11px;font-weight:600;text-transform:uppercase}
65
+ .badge-healed{background:#dcfce7;color:#166534}
66
+ .badge-failed{background:#fee2e2;color:#991b1b}
67
+ .confidence-bar{display:inline-block;width:60px;height:8px;background:#e2e8f0;border-radius:4px;overflow:hidden;vertical-align:middle;margin-right:6px}
68
+ .confidence-fill{height:100%;border-radius:4px}
69
+ .locator-code{font-family:'SF Mono',SFMono-Regular,Consolas,'Liberation Mono',Menlo,monospace;font-size:12px;background:#f1f5f9;padding:3px 6px;border-radius:4px;word-break:break-all;display:inline-block;max-width:280px}
70
+ .timing{color:#64748b;font-size:12px}
71
+ @media print{body{background:#fff;padding:0}.stat-card,.section{break-inside:avoid}}
72
+ @media(max-width:768px){.stats-grid{grid-template-columns:1fr 1fr}table{font-size:12px}td,th{padding:8px 6px}}
73
+ </style>
74
+ </head>
75
+ <body>
76
+ <div class="container">
77
+ <h1>MindHeal Healing Report</h1>
78
+ <p class="subtitle">
79
+ Session <strong>${this.escapeHTML(report.sessionId)}</strong> &mdash;
80
+ ${this.formatDate(report.startTime)} to ${this.formatDate(report.endTime)}
81
+ (${this.formatDuration(report.endTime - report.startTime)})
82
+ </p>
83
+
84
+ <div class="stats-grid">
85
+ <div class="stat-card stat-total">
86
+ <div class="stat-value">${stats.totalHeals}</div>
87
+ <div class="stat-label">Total Healing Attempts</div>
88
+ </div>
89
+ <div class="stat-card stat-healed">
90
+ <div class="stat-value">${stats.successfulHeals}</div>
91
+ <div class="stat-label">Successfully Healed</div>
92
+ </div>
93
+ <div class="stat-card stat-failed">
94
+ <div class="stat-value">${stats.failedHeals}</div>
95
+ <div class="stat-label">Failed</div>
96
+ </div>
97
+ <div class="stat-card stat-rate">
98
+ <div class="stat-value">${stats.successRate}%</div>
99
+ <div class="stat-label">Success Rate</div>
100
+ </div>
101
+ </div>
102
+
103
+ ${Object.keys(strategyBreakdown).length > 0
104
+ ? `<div class="section">
105
+ <div class="section-title">Strategy Breakdown</div>
106
+ ${strategyBars}
107
+ </div>`
108
+ : ''}
109
+
110
+ <div class="section">
111
+ <div class="section-title">Healing Events (${report.events.length})</div>
112
+ ${report.events.length > 0
113
+ ? `<div style="overflow-x:auto;">
114
+ <table>
115
+ <thead>
116
+ <tr>
117
+ <th>Status</th>
118
+ <th>Test</th>
119
+ <th>Action</th>
120
+ <th>Original Locator</th>
121
+ <th>Healed Locator</th>
122
+ <th>Strategy</th>
123
+ <th>Confidence</th>
124
+ <th>Duration</th>
125
+ </tr>
126
+ </thead>
127
+ <tbody>
128
+ ${eventsRows}
129
+ </tbody>
130
+ </table>
131
+ </div>`
132
+ : '<p style="color:#94a3b8;text-align:center;padding:32px 0;">No healing events recorded.</p>'}
133
+ </div>
134
+
135
+ <p style="text-align:center;color:#94a3b8;font-size:12px;margin-top:16px;">
136
+ Generated by MindHeal &mdash; ${this.formatDate(Date.now())}
137
+ </p>
138
+ </div>
139
+ </body>
140
+ </html>`;
141
+ }
142
+ /**
143
+ * Persist the report to disk in JSON and/or HTML format.
144
+ */
145
+ async saveReport(report, outputDir, generateHTML, generateJSON) {
146
+ fileUtils.ensureDirectory(outputDir);
147
+ const timestamp = new Date(report.startTime)
148
+ .toISOString()
149
+ .replace(/[:.]/g, '-')
150
+ .replace('T', '_')
151
+ .slice(0, 19);
152
+ if (generateJSON) {
153
+ const jsonPath = path.resolve(outputDir, `heal-report-${timestamp}.json`);
154
+ try {
155
+ const jsonContent = this.generateJSON(report);
156
+ fileUtils.writeFileContent(jsonPath, jsonContent);
157
+ logger.logger.info(`JSON report saved to ${jsonPath}`);
158
+ }
159
+ catch (error) {
160
+ const message = error instanceof Error ? error.message : String(error);
161
+ logger.logger.error(`Failed to save JSON report: ${message}`);
162
+ }
163
+ }
164
+ if (generateHTML) {
165
+ const htmlPath = path.resolve(outputDir, `heal-report-${timestamp}.html`);
166
+ try {
167
+ const htmlContent = this.generateHTML(report);
168
+ fileUtils.writeFileContent(htmlPath, htmlContent);
169
+ logger.logger.info(`HTML report saved to ${htmlPath}`);
170
+ }
171
+ catch (error) {
172
+ const message = error instanceof Error ? error.message : String(error);
173
+ logger.logger.error(`Failed to save HTML report: ${message}`);
174
+ }
175
+ }
176
+ }
177
+ // ── Private helpers ──────────────────────────────────────────────────────────
178
+ computeStats(report) {
179
+ const totalHeals = report.totalHeals;
180
+ const successfulHeals = report.successfulHeals;
181
+ const failedHeals = report.failedHeals;
182
+ const successRate = totalHeals > 0 ? Math.round((successfulHeals / totalHeals) * 100) : 0;
183
+ return { totalHeals, successfulHeals, failedHeals, successRate };
184
+ }
185
+ computeStrategyBreakdown(events) {
186
+ const breakdown = {};
187
+ for (const event of events) {
188
+ if (event.strategy) {
189
+ breakdown[event.strategy] = (breakdown[event.strategy] ?? 0) + 1;
190
+ }
191
+ }
192
+ return breakdown;
193
+ }
194
+ renderEventRow(event) {
195
+ const statusBadge = event.status === 'healed'
196
+ ? '<span class="badge badge-healed">Healed</span>'
197
+ : '<span class="badge badge-failed">Failed</span>';
198
+ const confidencePercent = Math.round(event.confidence * 100);
199
+ const confidenceColor = this.confidenceColor(event.confidence);
200
+ const healedLocatorDisplay = event.healedLocator
201
+ ? `<span class="locator-code">${this.escapeHTML(event.healedLocator.playwrightExpression)}</span>`
202
+ : '<span style="color:#94a3b8;">N/A</span>';
203
+ const sourceInfo = event.sourceLocation
204
+ ? `${this.escapeHTML(this.shortenPath(event.sourceLocation.filePath))}:${event.sourceLocation.line}`
205
+ : this.escapeHTML(event.testFile || 'unknown');
206
+ return `<tr>
207
+ <td>${statusBadge}</td>
208
+ <td>
209
+ <div style="font-weight:500;">${this.escapeHTML(event.testTitle || 'Unnamed test')}</div>
210
+ <div class="timing">${this.escapeHTML(sourceInfo)}</div>
211
+ </td>
212
+ <td>${this.escapeHTML(event.action)}</td>
213
+ <td><span class="locator-code">${this.escapeHTML(event.originalLocator.playwrightExpression)}</span></td>
214
+ <td>${healedLocatorDisplay}</td>
215
+ <td>${event.strategy ? this.escapeHTML(event.strategy) : '<span style="color:#94a3b8;">N/A</span>'}</td>
216
+ <td>
217
+ <div class="confidence-bar"><div class="confidence-fill" style="width:${confidencePercent}%;background:${confidenceColor};"></div></div>
218
+ <span style="font-size:12px;font-weight:600;color:${confidenceColor};">${confidencePercent}%</span>
219
+ </td>
220
+ <td class="timing">${event.duration}ms</td>
221
+ </tr>`;
222
+ }
223
+ confidenceColor(confidence) {
224
+ if (confidence >= 0.8)
225
+ return '#16a34a';
226
+ if (confidence >= 0.5)
227
+ return '#ca8a04';
228
+ return '#dc2626';
229
+ }
230
+ strategyColor(strategy) {
231
+ const colors = {
232
+ cache: '#6366f1',
233
+ attribute: '#2563eb',
234
+ text: '#0891b2',
235
+ role: '#059669',
236
+ css: '#ca8a04',
237
+ xpath: '#ea580c',
238
+ ai: '#7c3aed',
239
+ };
240
+ return colors[strategy] ?? '#64748b';
241
+ }
242
+ escapeHTML(str) {
243
+ return str
244
+ .replace(/&/g, '&amp;')
245
+ .replace(/</g, '&lt;')
246
+ .replace(/>/g, '&gt;')
247
+ .replace(/"/g, '&quot;')
248
+ .replace(/'/g, '&#39;');
249
+ }
250
+ formatDate(timestamp) {
251
+ return new Date(timestamp).toLocaleString('en-US', {
252
+ year: 'numeric',
253
+ month: 'short',
254
+ day: 'numeric',
255
+ hour: '2-digit',
256
+ minute: '2-digit',
257
+ second: '2-digit',
258
+ });
259
+ }
260
+ formatDuration(ms) {
261
+ if (ms < 1000)
262
+ return `${ms}ms`;
263
+ const seconds = Math.floor(ms / 1000);
264
+ if (seconds < 60)
265
+ return `${seconds}s`;
266
+ const minutes = Math.floor(seconds / 60);
267
+ const remainingSeconds = seconds % 60;
268
+ return `${minutes}m ${remainingSeconds}s`;
269
+ }
270
+ shortenPath(filePath) {
271
+ const parts = filePath.replace(/\\/g, '/').split('/');
272
+ if (parts.length <= 3)
273
+ return parts.join('/');
274
+ return `.../${parts.slice(-3).join('/')}`;
275
+ }
276
+ }
277
+
278
+ exports.HealReportGenerator = HealReportGenerator;
279
+ //# sourceMappingURL=heal-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heal-report.js","sources":["../../../../src/reporters/heal-report.ts"],"sourcesContent":[null],"names":["ensureDirectory","resolve","writeFileContent","logger"],"mappings":"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"}