sela-core 0.1.0-alpha.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 (267) hide show
  1. package/README.md +103 -0
  2. package/bin/sela.js +3 -0
  3. package/dist/cli/ErrorHandler.d.ts +10 -0
  4. package/dist/cli/ErrorHandler.d.ts.map +1 -0
  5. package/dist/cli/ErrorHandler.js +70 -0
  6. package/dist/cli/commands/bulk.d.ts +3 -0
  7. package/dist/cli/commands/bulk.d.ts.map +1 -0
  8. package/dist/cli/commands/bulk.js +158 -0
  9. package/dist/cli/commands/find.d.ts +3 -0
  10. package/dist/cli/commands/find.d.ts.map +1 -0
  11. package/dist/cli/commands/find.js +51 -0
  12. package/dist/cli/commands/init.d.ts +3 -0
  13. package/dist/cli/commands/init.d.ts.map +1 -0
  14. package/dist/cli/commands/init.js +166 -0
  15. package/dist/cli/commands/list.d.ts +3 -0
  16. package/dist/cli/commands/list.d.ts.map +1 -0
  17. package/dist/cli/commands/list.js +56 -0
  18. package/dist/cli/commands/merge.d.ts +13 -0
  19. package/dist/cli/commands/merge.d.ts.map +1 -0
  20. package/dist/cli/commands/merge.js +119 -0
  21. package/dist/cli/commands/refactor.d.ts +3 -0
  22. package/dist/cli/commands/refactor.d.ts.map +1 -0
  23. package/dist/cli/commands/refactor.js +30 -0
  24. package/dist/cli/commands/showReport.d.ts +3 -0
  25. package/dist/cli/commands/showReport.d.ts.map +1 -0
  26. package/dist/cli/commands/showReport.js +82 -0
  27. package/dist/cli/commands/status.d.ts +3 -0
  28. package/dist/cli/commands/status.d.ts.map +1 -0
  29. package/dist/cli/commands/status.js +51 -0
  30. package/dist/cli/commands/sync.d.ts +3 -0
  31. package/dist/cli/commands/sync.d.ts.map +1 -0
  32. package/dist/cli/commands/sync.js +131 -0
  33. package/dist/cli/index.d.ts +2 -0
  34. package/dist/cli/index.d.ts.map +1 -0
  35. package/dist/cli/index.js +94 -0
  36. package/dist/cli/ui/DnaTable.d.ts +3 -0
  37. package/dist/cli/ui/DnaTable.d.ts.map +1 -0
  38. package/dist/cli/ui/DnaTable.js +77 -0
  39. package/dist/cli/ui/LocatorPicker.d.ts +8 -0
  40. package/dist/cli/ui/LocatorPicker.d.ts.map +1 -0
  41. package/dist/cli/ui/LocatorPicker.js +33 -0
  42. package/dist/cli/ui/ProgressReporter.d.ts +11 -0
  43. package/dist/cli/ui/ProgressReporter.d.ts.map +1 -0
  44. package/dist/cli/ui/ProgressReporter.js +33 -0
  45. package/dist/cli/ui/RefactorWizard.d.ts +26 -0
  46. package/dist/cli/ui/RefactorWizard.d.ts.map +1 -0
  47. package/dist/cli/ui/RefactorWizard.js +295 -0
  48. package/dist/config/ConfigLoader.d.ts +16 -0
  49. package/dist/config/ConfigLoader.d.ts.map +1 -0
  50. package/dist/config/ConfigLoader.js +185 -0
  51. package/dist/config/DryRunGuard.d.ts +14 -0
  52. package/dist/config/DryRunGuard.d.ts.map +1 -0
  53. package/dist/config/DryRunGuard.js +80 -0
  54. package/dist/config/PathScopeGuard.d.ts +42 -0
  55. package/dist/config/PathScopeGuard.d.ts.map +1 -0
  56. package/dist/config/PathScopeGuard.js +192 -0
  57. package/dist/config/SelaConfig.d.ts +178 -0
  58. package/dist/config/SelaConfig.d.ts.map +1 -0
  59. package/dist/config/SelaConfig.js +141 -0
  60. package/dist/config/defineConfig.d.ts +3 -0
  61. package/dist/config/defineConfig.d.ts.map +1 -0
  62. package/dist/config/defineConfig.js +9 -0
  63. package/dist/engine/FixwrightEngine.d.ts +24 -0
  64. package/dist/engine/FixwrightEngine.d.ts.map +1 -0
  65. package/dist/engine/FixwrightEngine.js +403 -0
  66. package/dist/engine/HealingRegistry.d.ts +40 -0
  67. package/dist/engine/HealingRegistry.d.ts.map +1 -0
  68. package/dist/engine/HealingRegistry.js +99 -0
  69. package/dist/engine/SelaEngine.d.ts +57 -0
  70. package/dist/engine/SelaEngine.d.ts.map +1 -0
  71. package/dist/engine/SelaEngine.js +1146 -0
  72. package/dist/engine/singleton.d.ts +3 -0
  73. package/dist/engine/singleton.d.ts.map +1 -0
  74. package/dist/engine/singleton.js +5 -0
  75. package/dist/errors/SelaError.d.ts +146 -0
  76. package/dist/errors/SelaError.d.ts.map +1 -0
  77. package/dist/errors/SelaError.js +168 -0
  78. package/dist/fixtures/expectProxy.d.ts +12 -0
  79. package/dist/fixtures/expectProxy.d.ts.map +1 -0
  80. package/dist/fixtures/expectProxy.js +246 -0
  81. package/dist/fixtures/index.d.ts +30 -0
  82. package/dist/fixtures/index.d.ts.map +1 -0
  83. package/dist/fixtures/index.js +765 -0
  84. package/dist/fixtures/moduleExpect.d.ts +2 -0
  85. package/dist/fixtures/moduleExpect.d.ts.map +1 -0
  86. package/dist/fixtures/moduleExpect.js +54 -0
  87. package/dist/fixtures/proxyTag.d.ts +12 -0
  88. package/dist/fixtures/proxyTag.d.ts.map +1 -0
  89. package/dist/fixtures/proxyTag.js +45 -0
  90. package/dist/index.d.ts +9 -0
  91. package/dist/index.d.ts.map +1 -0
  92. package/dist/index.js +31 -0
  93. package/dist/reporter/SelaReporter.d.ts +165 -0
  94. package/dist/reporter/SelaReporter.d.ts.map +1 -0
  95. package/dist/reporter/SelaReporter.js +517 -0
  96. package/dist/services/ASTSourceUpdater.d.ts +143 -0
  97. package/dist/services/ASTSourceUpdater.d.ts.map +1 -0
  98. package/dist/services/ASTSourceUpdater.js +3514 -0
  99. package/dist/services/AnchorResolver.d.ts +157 -0
  100. package/dist/services/AnchorResolver.d.ts.map +1 -0
  101. package/dist/services/AnchorResolver.js +289 -0
  102. package/dist/services/ArgumentTypeAnalyzer.d.ts +26 -0
  103. package/dist/services/ArgumentTypeAnalyzer.d.ts.map +1 -0
  104. package/dist/services/ArgumentTypeAnalyzer.js +92 -0
  105. package/dist/services/BlastRadiusAnalyzer.d.ts +15 -0
  106. package/dist/services/BlastRadiusAnalyzer.d.ts.map +1 -0
  107. package/dist/services/BlastRadiusAnalyzer.js +107 -0
  108. package/dist/services/ChainValidator.d.ts +76 -0
  109. package/dist/services/ChainValidator.d.ts.map +1 -0
  110. package/dist/services/ChainValidator.js +570 -0
  111. package/dist/services/CrossFileHealer.d.ts +6 -0
  112. package/dist/services/CrossFileHealer.d.ts.map +1 -0
  113. package/dist/services/CrossFileHealer.js +135 -0
  114. package/dist/services/DecisionEngine.d.ts +51 -0
  115. package/dist/services/DecisionEngine.d.ts.map +1 -0
  116. package/dist/services/DecisionEngine.js +260 -0
  117. package/dist/services/DefinitionTracer.d.ts +41 -0
  118. package/dist/services/DefinitionTracer.d.ts.map +1 -0
  119. package/dist/services/DefinitionTracer.js +366 -0
  120. package/dist/services/DnaEditorService.d.ts +31 -0
  121. package/dist/services/DnaEditorService.d.ts.map +1 -0
  122. package/dist/services/DnaEditorService.js +217 -0
  123. package/dist/services/DnaIndexService.d.ts +24 -0
  124. package/dist/services/DnaIndexService.d.ts.map +1 -0
  125. package/dist/services/DnaIndexService.js +131 -0
  126. package/dist/services/HealBudget.d.ts +32 -0
  127. package/dist/services/HealBudget.d.ts.map +1 -0
  128. package/dist/services/HealBudget.js +85 -0
  129. package/dist/services/HealReportService.d.ts +161 -0
  130. package/dist/services/HealReportService.d.ts.map +1 -0
  131. package/dist/services/HealReportService.js +1039 -0
  132. package/dist/services/HealingAdvisory.d.ts +30 -0
  133. package/dist/services/HealingAdvisory.d.ts.map +1 -0
  134. package/dist/services/HealingAdvisory.js +51 -0
  135. package/dist/services/HealingCacheService.d.ts +135 -0
  136. package/dist/services/HealingCacheService.d.ts.map +1 -0
  137. package/dist/services/HealingCacheService.js +404 -0
  138. package/dist/services/HealthReportService.d.ts +10 -0
  139. package/dist/services/HealthReportService.d.ts.map +1 -0
  140. package/dist/services/HealthReportService.js +84 -0
  141. package/dist/services/InitializerUpdater.d.ts +16 -0
  142. package/dist/services/InitializerUpdater.d.ts.map +1 -0
  143. package/dist/services/InitializerUpdater.js +73 -0
  144. package/dist/services/IntentAuditor.d.ts +56 -0
  145. package/dist/services/IntentAuditor.d.ts.map +1 -0
  146. package/dist/services/IntentAuditor.js +326 -0
  147. package/dist/services/InteractiveReview.d.ts +15 -0
  148. package/dist/services/InteractiveReview.d.ts.map +1 -0
  149. package/dist/services/InteractiveReview.js +128 -0
  150. package/dist/services/LLMService.d.ts +121 -0
  151. package/dist/services/LLMService.d.ts.map +1 -0
  152. package/dist/services/LLMService.js +475 -0
  153. package/dist/services/MutationApplier.d.ts +69 -0
  154. package/dist/services/MutationApplier.d.ts.map +1 -0
  155. package/dist/services/MutationApplier.js +360 -0
  156. package/dist/services/PRAutomationService.d.ts +50 -0
  157. package/dist/services/PRAutomationService.d.ts.map +1 -0
  158. package/dist/services/PRAutomationService.js +760 -0
  159. package/dist/services/PendingPromptLedger.d.ts +51 -0
  160. package/dist/services/PendingPromptLedger.d.ts.map +1 -0
  161. package/dist/services/PendingPromptLedger.js +205 -0
  162. package/dist/services/ReportGenerator.d.ts +156 -0
  163. package/dist/services/ReportGenerator.d.ts.map +1 -0
  164. package/dist/services/ReportGenerator.js +278 -0
  165. package/dist/services/ReportMergeService.d.ts +95 -0
  166. package/dist/services/ReportMergeService.d.ts.map +1 -0
  167. package/dist/services/ReportMergeService.js +0 -0
  168. package/dist/services/SafetyGuard.d.ts +112 -0
  169. package/dist/services/SafetyGuard.d.ts.map +1 -0
  170. package/dist/services/SafetyGuard.js +87 -0
  171. package/dist/services/Sanitizer.d.ts +28 -0
  172. package/dist/services/Sanitizer.d.ts.map +1 -0
  173. package/dist/services/Sanitizer.js +142 -0
  174. package/dist/services/SanitizingAnthropic.d.ts +19 -0
  175. package/dist/services/SanitizingAnthropic.d.ts.map +1 -0
  176. package/dist/services/SanitizingAnthropic.js +84 -0
  177. package/dist/services/SelectorSanitizer.d.ts +52 -0
  178. package/dist/services/SelectorSanitizer.d.ts.map +1 -0
  179. package/dist/services/SelectorSanitizer.js +318 -0
  180. package/dist/services/SnapshotService.d.ts +11 -0
  181. package/dist/services/SnapshotService.d.ts.map +1 -0
  182. package/dist/services/SnapshotService.js +352 -0
  183. package/dist/services/SourceLinkService.d.ts +26 -0
  184. package/dist/services/SourceLinkService.d.ts.map +1 -0
  185. package/dist/services/SourceLinkService.js +165 -0
  186. package/dist/services/SourceUpdater.d.ts +45 -0
  187. package/dist/services/SourceUpdater.d.ts.map +1 -0
  188. package/dist/services/SourceUpdater.js +1091 -0
  189. package/dist/services/TemplateDiffService.d.ts +25 -0
  190. package/dist/services/TemplateDiffService.d.ts.map +1 -0
  191. package/dist/services/TemplateDiffService.js +334 -0
  192. package/dist/services/TraceBackEngine.d.ts +67 -0
  193. package/dist/services/TraceBackEngine.d.ts.map +1 -0
  194. package/dist/services/TraceBackEngine.js +672 -0
  195. package/dist/services/WorkspaceSnapshotService.d.ts +71 -0
  196. package/dist/services/WorkspaceSnapshotService.d.ts.map +1 -0
  197. package/dist/services/WorkspaceSnapshotService.js +200 -0
  198. package/dist/services/safety/PipelineContext.d.ts +63 -0
  199. package/dist/services/safety/PipelineContext.d.ts.map +1 -0
  200. package/dist/services/safety/PipelineContext.js +34 -0
  201. package/dist/services/safety/roleClassifier.d.ts +4 -0
  202. package/dist/services/safety/roleClassifier.d.ts.map +1 -0
  203. package/dist/services/safety/roleClassifier.js +233 -0
  204. package/dist/services/safety/rules/ConfidenceTierRule.d.ts +3 -0
  205. package/dist/services/safety/rules/ConfidenceTierRule.d.ts.map +1 -0
  206. package/dist/services/safety/rules/ConfidenceTierRule.js +32 -0
  207. package/dist/services/safety/rules/DangerousSinkRule.d.ts +10 -0
  208. package/dist/services/safety/rules/DangerousSinkRule.d.ts.map +1 -0
  209. package/dist/services/safety/rules/DangerousSinkRule.js +53 -0
  210. package/dist/services/safety/rules/FunctionalRoleRule.d.ts +3 -0
  211. package/dist/services/safety/rules/FunctionalRoleRule.d.ts.map +1 -0
  212. package/dist/services/safety/rules/FunctionalRoleRule.js +64 -0
  213. package/dist/services/safety/rules/HardConfidenceRule.d.ts +3 -0
  214. package/dist/services/safety/rules/HardConfidenceRule.d.ts.map +1 -0
  215. package/dist/services/safety/rules/HardConfidenceRule.js +22 -0
  216. package/dist/services/safety/rules/IntentAuditorRule.d.ts +3 -0
  217. package/dist/services/safety/rules/IntentAuditorRule.d.ts.map +1 -0
  218. package/dist/services/safety/rules/IntentAuditorRule.js +97 -0
  219. package/dist/services/safety/rules/SemanticOppositeRule.d.ts +3 -0
  220. package/dist/services/safety/rules/SemanticOppositeRule.d.ts.map +1 -0
  221. package/dist/services/safety/rules/SemanticOppositeRule.js +30 -0
  222. package/dist/services/safety/rules/StructuralOnlyRule.d.ts +3 -0
  223. package/dist/services/safety/rules/StructuralOnlyRule.d.ts.map +1 -0
  224. package/dist/services/safety/rules/StructuralOnlyRule.js +38 -0
  225. package/dist/services/safety/rules/VisibilityRule.d.ts +3 -0
  226. package/dist/services/safety/rules/VisibilityRule.d.ts.map +1 -0
  227. package/dist/services/safety/rules/VisibilityRule.js +53 -0
  228. package/dist/services/safety/rules/ZeroTrustRule.d.ts +3 -0
  229. package/dist/services/safety/rules/ZeroTrustRule.d.ts.map +1 -0
  230. package/dist/services/safety/rules/ZeroTrustRule.js +37 -0
  231. package/dist/services/safety/rules/index.d.ts +3 -0
  232. package/dist/services/safety/rules/index.d.ts.map +1 -0
  233. package/dist/services/safety/rules/index.js +34 -0
  234. package/dist/services/types.d.ts +59 -0
  235. package/dist/services/types.d.ts.map +1 -0
  236. package/dist/services/types.js +2 -0
  237. package/dist/storage/SnapshotManager.d.ts +5 -0
  238. package/dist/storage/SnapshotManager.d.ts.map +1 -0
  239. package/dist/storage/SnapshotManager.js +32 -0
  240. package/dist/types/index.d.ts +95 -0
  241. package/dist/types/index.d.ts.map +1 -0
  242. package/dist/types/index.js +7 -0
  243. package/dist/utils/DOMUtils.d.ts +49 -0
  244. package/dist/utils/DOMUtils.d.ts.map +1 -0
  245. package/dist/utils/DOMUtils.js +466 -0
  246. package/dist/utils/FileLock.d.ts +44 -0
  247. package/dist/utils/FileLock.d.ts.map +1 -0
  248. package/dist/utils/FileLock.js +189 -0
  249. package/dist/utils/IsolatedDiff.d.ts +45 -0
  250. package/dist/utils/IsolatedDiff.d.ts.map +1 -0
  251. package/dist/utils/IsolatedDiff.js +382 -0
  252. package/dist/utils/StackUtils.d.ts +11 -0
  253. package/dist/utils/StackUtils.d.ts.map +1 -0
  254. package/dist/utils/StackUtils.js +120 -0
  255. package/dist/utils/SummaryTable.d.ts +17 -0
  256. package/dist/utils/SummaryTable.d.ts.map +1 -0
  257. package/dist/utils/SummaryTable.js +37 -0
  258. package/dist/utils/atomicWrite.d.ts +9 -0
  259. package/dist/utils/atomicWrite.d.ts.map +1 -0
  260. package/dist/utils/atomicWrite.js +83 -0
  261. package/dist/utils/logger.d.ts +59 -0
  262. package/dist/utils/logger.d.ts.map +1 -0
  263. package/dist/utils/logger.js +123 -0
  264. package/dist/vendor/enquirer.d.ts +33 -0
  265. package/dist/vendor/enquirer.d.ts.map +1 -0
  266. package/dist/vendor/enquirer.js +11 -0
  267. package/package.json +71 -0
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DnaIndexService = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const fs_1 = require("fs");
9
+ const path_1 = __importDefault(require("path"));
10
+ // Supports /regex/flags syntax or plain substring (case-insensitive).
11
+ function toRegExp(pattern) {
12
+ const m = pattern.match(/^\/(.+)\/([gimsuy]*)$/);
13
+ if (m)
14
+ return new RegExp(m[1], m[2]);
15
+ return new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i");
16
+ }
17
+ function deriveSelector(snap) {
18
+ if (snap.selector)
19
+ return snap.selector;
20
+ if (snap.id)
21
+ return `#${snap.id}`;
22
+ if (snap.classes.length > 0)
23
+ return `.${snap.classes.join(".")}`;
24
+ return snap.tagName;
25
+ }
26
+ function isWithin7Days(iso) {
27
+ return new Date(iso).getTime() >= Date.now() - 7 * 24 * 60 * 60 * 1000;
28
+ }
29
+ function toRecord(filePath, raw) {
30
+ const key = path_1.default.basename(filePath, ".json");
31
+ const sourceFile = raw.sourceFile ?? "";
32
+ return {
33
+ key,
34
+ filePath,
35
+ testTitle: raw.testTitle ?? "",
36
+ sourceFile,
37
+ sourceLine: raw.sourceLine ?? 0,
38
+ selector: deriveSelector(raw),
39
+ tagName: raw.tagName,
40
+ text: raw.text ?? null,
41
+ lastHealed: raw.lastHealed ?? null,
42
+ schemaVersion: raw.schemaVersion ?? 1,
43
+ // Only flag orphaned when sourceFile is known - engine snapshots have no sourceFile
44
+ isOrphaned: sourceFile !== "" && !(0, fs_1.existsSync)(sourceFile),
45
+ status: raw.status,
46
+ };
47
+ }
48
+ async function collectJsonFiles(dir) {
49
+ const results = [];
50
+ let entries;
51
+ try {
52
+ entries = await promises_1.default.readdir(dir, { withFileTypes: true });
53
+ }
54
+ catch {
55
+ return results;
56
+ }
57
+ await Promise.all(entries.map(async (entry) => {
58
+ const full = path_1.default.join(dir, entry.name);
59
+ if (entry.isDirectory()) {
60
+ results.push(...(await collectJsonFiles(full)));
61
+ }
62
+ else if (entry.isFile() &&
63
+ entry.name.endsWith(".json") &&
64
+ !entry.name.endsWith(".bak") &&
65
+ !entry.name.endsWith(".tmp")) {
66
+ results.push(full);
67
+ }
68
+ }));
69
+ return results;
70
+ }
71
+ class DnaIndexService {
72
+ cachedIndex = null;
73
+ async buildIndex(snapshotDir) {
74
+ const files = await collectJsonFiles(snapshotDir);
75
+ const settled = await Promise.allSettled(files.map(async (filePath) => {
76
+ const content = await promises_1.default.readFile(filePath, "utf-8");
77
+ return toRecord(filePath, JSON.parse(content));
78
+ }));
79
+ const records = settled
80
+ .filter((r) => r.status === "fulfilled")
81
+ .map((r) => r.value);
82
+ const healedAllTime = records.filter((r) => r.lastHealed !== null).length;
83
+ const healedLast7Days = records.filter((r) => r.lastHealed !== null && isWithin7Days(r.lastHealed)).length;
84
+ this.cachedIndex = {
85
+ generatedAt: new Date().toISOString(),
86
+ snapshotDir,
87
+ records,
88
+ stats: {
89
+ total: records.length,
90
+ orphaned: records.filter((r) => r.isOrphaned).length,
91
+ healedLast7Days,
92
+ healedAllTime,
93
+ },
94
+ };
95
+ return this.cachedIndex;
96
+ }
97
+ findBySelector(pattern) {
98
+ const re = toRegExp(pattern);
99
+ return this.requireIndex().records.filter((r) => re.test(r.selector));
100
+ }
101
+ findByText(pattern) {
102
+ const re = toRegExp(pattern);
103
+ return this.requireIndex().records.filter((r) => r.text !== null && re.test(r.text));
104
+ }
105
+ findBySourceFile(filePath) {
106
+ const needle = path_1.default.normalize(filePath).toLowerCase();
107
+ return this.requireIndex().records.filter((r) => path_1.default.normalize(r.sourceFile).toLowerCase().includes(needle));
108
+ }
109
+ findByTestTitle(pattern) {
110
+ const re = toRegExp(pattern);
111
+ return this.requireIndex().records.filter((r) => re.test(r.testTitle));
112
+ }
113
+ getByKey(key) {
114
+ return this.requireIndex().records.find((r) => r.key === key) ?? null;
115
+ }
116
+ getIndex() {
117
+ return this.requireIndex();
118
+ }
119
+ refresh() {
120
+ this.cachedIndex = null;
121
+ }
122
+ requireIndex() {
123
+ if (!this.cachedIndex) {
124
+ const err = new Error("Index not built - call buildIndex() first");
125
+ err.code = "SNAPSHOT_DIR_MISSING";
126
+ throw err;
127
+ }
128
+ return this.cachedIndex;
129
+ }
130
+ }
131
+ exports.DnaIndexService = DnaIndexService;
@@ -0,0 +1,32 @@
1
+ export declare class HealBudget {
2
+ private _limit;
3
+ private _consumed;
4
+ private _warned;
5
+ /**
6
+ * (Re)configure the budget for a run. `null` = unlimited. Resets the
7
+ * consumed counter and the one-shot warning latch.
8
+ */
9
+ configure(limit: number | null): void;
10
+ /**
11
+ * Atomically reserve one heal slot. Returns true when the heal may proceed,
12
+ * false when the budget is exhausted. Synchronous by contract — callers MUST
13
+ * NOT `await` between calling this and acting on the result.
14
+ */
15
+ tryConsume(): boolean;
16
+ consumed(): number;
17
+ limit(): number | null;
18
+ /** Remaining slots, or null when unlimited. */
19
+ remaining(): number | null;
20
+ /** True once a bounded limit has been fully consumed. */
21
+ exhausted(): boolean;
22
+ /**
23
+ * One-shot warning latch: returns true exactly once after the budget is
24
+ * first hit, false on every subsequent call. Lets the engine emit a single
25
+ * "limit reached" warning instead of one per skipped selector.
26
+ */
27
+ shouldWarnOnce(): boolean;
28
+ /** Clears all state — test isolation (mirrors sharedHealReport.clear()). */
29
+ reset(): void;
30
+ }
31
+ export declare const sharedHealBudget: HealBudget;
32
+ //# sourceMappingURL=HealBudget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HealBudget.d.ts","sourceRoot":"","sources":["../../src/services/HealBudget.ts"],"names":[],"mappings":"AAsBA,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAS;IAExB;;;OAGG;IACH,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAMrC;;;;OAIG;IACH,UAAU,IAAI,OAAO;IAQrB,QAAQ,IAAI,MAAM;IAIlB,KAAK,IAAI,MAAM,GAAG,IAAI;IAItB,+CAA+C;IAC/C,SAAS,IAAI,MAAM,GAAG,IAAI;IAK1B,yDAAyD;IACzD,SAAS,IAAI,OAAO;IAIpB;;;;OAIG;IACH,cAAc,IAAI,OAAO;IAMzB,4EAA4E;IAC5E,KAAK,IAAI,IAAI;CAKd;AAED,eAAO,MAAM,gBAAgB,YAAmB,CAAC"}
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ // src/services/HealBudget.ts
3
+ //
4
+ // Per-run heal budget (T2 — maxHealsPerRun).
5
+ //
6
+ // Tracks how many LLM-backed heals a single run has consumed. Once the
7
+ // configured limit is reached, `tryConsume()` returns false so the engine
8
+ // stops triggering the LLM, finalizes the fixes already applied, and warns
9
+ // the user. Cache replays do NOT call `tryConsume()` and therefore never
10
+ // count against the budget — the limit reflects real LLM spend / blast
11
+ // radius, not cheap re-runs.
12
+ //
13
+ // Process-global singleton, mirroring `sharedHealReport`. The engine seeds it
14
+ // from resolved config in its constructor.
15
+ //
16
+ // CONCURRENCY: heals can run concurrently across `await` points.
17
+ // `tryConsume()` does a synchronous check-and-reserve with NO `await` between
18
+ // the read and the write, so Node's single-threaded event loop guarantees
19
+ // that exactly `limit` reservations succeed even under a burst of concurrent
20
+ // callers. A reserved slot is NEVER refunded on later failure/rejection: the
21
+ // LLM call the budget bounds has already been authorized, and refunding would
22
+ // reopen a check-then-act race.
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.sharedHealBudget = exports.HealBudget = void 0;
25
+ class HealBudget {
26
+ _limit = null;
27
+ _consumed = 0;
28
+ _warned = false;
29
+ /**
30
+ * (Re)configure the budget for a run. `null` = unlimited. Resets the
31
+ * consumed counter and the one-shot warning latch.
32
+ */
33
+ configure(limit) {
34
+ this._limit = limit;
35
+ this._consumed = 0;
36
+ this._warned = false;
37
+ }
38
+ /**
39
+ * Atomically reserve one heal slot. Returns true when the heal may proceed,
40
+ * false when the budget is exhausted. Synchronous by contract — callers MUST
41
+ * NOT `await` between calling this and acting on the result.
42
+ */
43
+ tryConsume() {
44
+ if (this._limit !== null && this._consumed >= this._limit) {
45
+ return false;
46
+ }
47
+ this._consumed += 1;
48
+ return true;
49
+ }
50
+ consumed() {
51
+ return this._consumed;
52
+ }
53
+ limit() {
54
+ return this._limit;
55
+ }
56
+ /** Remaining slots, or null when unlimited. */
57
+ remaining() {
58
+ if (this._limit === null)
59
+ return null;
60
+ return Math.max(0, this._limit - this._consumed);
61
+ }
62
+ /** True once a bounded limit has been fully consumed. */
63
+ exhausted() {
64
+ return this._limit !== null && this._consumed >= this._limit;
65
+ }
66
+ /**
67
+ * One-shot warning latch: returns true exactly once after the budget is
68
+ * first hit, false on every subsequent call. Lets the engine emit a single
69
+ * "limit reached" warning instead of one per skipped selector.
70
+ */
71
+ shouldWarnOnce() {
72
+ if (this._warned)
73
+ return false;
74
+ this._warned = true;
75
+ return true;
76
+ }
77
+ /** Clears all state — test isolation (mirrors sharedHealReport.clear()). */
78
+ reset() {
79
+ this._limit = null;
80
+ this._consumed = 0;
81
+ this._warned = false;
82
+ }
83
+ }
84
+ exports.HealBudget = HealBudget;
85
+ exports.sharedHealBudget = new HealBudget();
@@ -0,0 +1,161 @@
1
+ import type { AuditVerdict, AuditVerdictValue } from "./IntentAuditor";
2
+ import type { ElementSnapshotV2 } from "../types";
3
+ import { type ReportData } from "./ReportGenerator";
4
+ export type HealEventKind = "HEALED" | "FAILED" | "PROTECTED";
5
+ export interface DnaSummary {
6
+ tagName: string;
7
+ text: string | null;
8
+ role: string | null;
9
+ classes: string[];
10
+ attributes: Record<string, string>;
11
+ ancestry: string[];
12
+ closestLabel: string | null;
13
+ rowAnchor: string | null;
14
+ isGhost: boolean;
15
+ ghostReason: string | null;
16
+ isOccluded: boolean;
17
+ isInShadowDom: boolean;
18
+ }
19
+ export interface AuditorBlock {
20
+ verdict: AuditVerdictValue;
21
+ confidence?: number;
22
+ reason: string;
23
+ inversionType: AuditVerdict["inversionType"];
24
+ rawConfidence?: number;
25
+ penalty?: number;
26
+ bonus?: number;
27
+ }
28
+ interface HealEventBase {
29
+ kind: HealEventKind;
30
+ stableId: string;
31
+ sourceFile: string;
32
+ sourceLine: number;
33
+ testTitle?: string;
34
+ timestamp: string;
35
+ framePath: string[];
36
+ inIframe: boolean;
37
+ inShadowDom: boolean;
38
+ }
39
+ export interface HealedEvent extends HealEventBase {
40
+ kind: "HEALED";
41
+ dryRun?: boolean;
42
+ oldSelector: string;
43
+ newSelector: string;
44
+ oldCodeLine: string;
45
+ newCodeLine: string;
46
+ newLineNumber: number;
47
+ gitUnifiedDiff?: string;
48
+ aiConfidence?: number;
49
+ aiExplanation: string;
50
+ aiAlternatives: string[];
51
+ reasoningSteps: string[];
52
+ auditor: AuditorBlock | null;
53
+ dnaBefore: DnaSummary;
54
+ dnaAfter: DnaSummary | null;
55
+ diffStrategy: string;
56
+ blastRadius?: number;
57
+ definitionSite?: {
58
+ file: string;
59
+ line: number;
60
+ };
61
+ contentChange?: {
62
+ oldText: string;
63
+ newText: string;
64
+ };
65
+ }
66
+ export interface FailedEvent extends HealEventBase {
67
+ kind: "FAILED";
68
+ oldSelector: string;
69
+ reason: string;
70
+ aiConfidence?: number;
71
+ aiExplanation?: string;
72
+ dnaBefore: DnaSummary | null;
73
+ failureScreenshotPng?: string;
74
+ }
75
+ export interface ProtectedEvent extends HealEventBase {
76
+ kind: "PROTECTED";
77
+ oldSelector: string;
78
+ candidateNewSelector?: string;
79
+ reason: string;
80
+ safetyLevel: string;
81
+ auditor: AuditorBlock | null;
82
+ aiConfidence?: number;
83
+ aiExplanation: string;
84
+ dnaBefore: DnaSummary | null;
85
+ dnaAfter: DnaSummary | null;
86
+ contentChange?: {
87
+ oldText: string;
88
+ newText: string;
89
+ };
90
+ }
91
+ export type HealEvent = HealedEvent | FailedEvent | ProtectedEvent;
92
+ /** Directory holding this run's per-worker report shards. */
93
+ export declare function reportShardDir(cwd: string): string;
94
+ /** Remove the shard directory and every shard beneath it. Idempotent. */
95
+ export declare function clearReportShards(cwd: string): void;
96
+ export declare function summariseSnapshot(s: ElementSnapshotV2 | null | undefined): DnaSummary | null;
97
+ export declare class HealReportService {
98
+ private events;
99
+ private startedAt;
100
+ record(event: HealEvent): void;
101
+ size(): number;
102
+ clear(): void;
103
+ hasContent(): boolean;
104
+ getHealedEvents(): HealedEvent[];
105
+ getProtectedEvents(): ProtectedEvent[];
106
+ getFailedEvents(): FailedEvent[];
107
+ /**
108
+ * Attach a Playwright failure screenshot (Base64 PNG, no data: prefix)
109
+ * onto the FAILED event(s) matching the supplied identity hints.
110
+ * Returns the number of events updated.
111
+ */
112
+ attachFailureScreenshot(match: {
113
+ sourceFile?: string;
114
+ testTitle?: string;
115
+ stableId?: string;
116
+ }, base64Png: string): number;
117
+ private readHistory;
118
+ private writeHistory;
119
+ /**
120
+ * Generate and write `sela-report.html` + `sela-report.json` to targetDir.
121
+ * Also updates `.sela-history.json` with the current run's stats.
122
+ * Returns the absolute path of the HTML report, or null when there is
123
+ * nothing to write.
124
+ */
125
+ flushToDisk(targetDir?: string, opts?: {
126
+ runId?: string;
127
+ }): string | null;
128
+ /**
129
+ * Render and persist a pre-computed {@link ReportData} payload to `targetDir`:
130
+ * • `.sela-history.json` (the rolling window from `data.historical_runs`)
131
+ * • `sela-report.html` (the embedded dashboard)
132
+ * • `sela-report.json` (the raw payload for CI consumers)
133
+ *
134
+ * Extracted from {@link flushToDisk} so the CI merge path
135
+ * (`ReportMergeService`) writes a shard-aggregated report through the exact
136
+ * same rendering / serialisation logic — no duplication.
137
+ *
138
+ * Unlike `flushToDisk`, this writes unconditionally: an empty-event payload
139
+ * still produces a report and a `healed:0` history row. That is the desired
140
+ * CI behaviour — a clean, zero-heal pipeline is a healthy data point that
141
+ * must keep the trend chart's x-axis cadence intact.
142
+ *
143
+ * Returns the absolute path of the written HTML report.
144
+ */
145
+ writeReportData(targetDir: string, data: ReportData): string;
146
+ /**
147
+ * Write THIS worker's buffered events to a private shard file under
148
+ * `<cwd>/.sela/report-shards/` — one file per worker process (pid +
149
+ * timestamp + random tag), so concurrent workers never contend on a shared
150
+ * report path. The main-process reporter fans them in via
151
+ * {@link ReportMergeService} at onEnd. Returns the shard path, or null when
152
+ * there is nothing to flush.
153
+ *
154
+ * Shard shape is `{ startedAt, events }`, which ReportMergeService.readShard
155
+ * Events accepts (it also tolerates a bare event array).
156
+ */
157
+ flushShard(cwd?: string): string | null;
158
+ }
159
+ export declare const sharedHealReport: HealReportService;
160
+ export {};
161
+ //# sourceMappingURL=HealReportService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HealReportService.d.ts","sourceRoot":"","sources":["../../src/services/HealReportService.ts"],"names":[],"mappings":"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"}