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.
- package/README.md +103 -0
- package/bin/sela.js +3 -0
- package/dist/cli/ErrorHandler.d.ts +10 -0
- package/dist/cli/ErrorHandler.d.ts.map +1 -0
- package/dist/cli/ErrorHandler.js +70 -0
- package/dist/cli/commands/bulk.d.ts +3 -0
- package/dist/cli/commands/bulk.d.ts.map +1 -0
- package/dist/cli/commands/bulk.js +158 -0
- package/dist/cli/commands/find.d.ts +3 -0
- package/dist/cli/commands/find.d.ts.map +1 -0
- package/dist/cli/commands/find.js +51 -0
- package/dist/cli/commands/init.d.ts +3 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +166 -0
- package/dist/cli/commands/list.d.ts +3 -0
- package/dist/cli/commands/list.d.ts.map +1 -0
- package/dist/cli/commands/list.js +56 -0
- package/dist/cli/commands/merge.d.ts +13 -0
- package/dist/cli/commands/merge.d.ts.map +1 -0
- package/dist/cli/commands/merge.js +119 -0
- package/dist/cli/commands/refactor.d.ts +3 -0
- package/dist/cli/commands/refactor.d.ts.map +1 -0
- package/dist/cli/commands/refactor.js +30 -0
- package/dist/cli/commands/showReport.d.ts +3 -0
- package/dist/cli/commands/showReport.d.ts.map +1 -0
- package/dist/cli/commands/showReport.js +82 -0
- package/dist/cli/commands/status.d.ts +3 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +51 -0
- package/dist/cli/commands/sync.d.ts +3 -0
- package/dist/cli/commands/sync.d.ts.map +1 -0
- package/dist/cli/commands/sync.js +131 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +94 -0
- package/dist/cli/ui/DnaTable.d.ts +3 -0
- package/dist/cli/ui/DnaTable.d.ts.map +1 -0
- package/dist/cli/ui/DnaTable.js +77 -0
- package/dist/cli/ui/LocatorPicker.d.ts +8 -0
- package/dist/cli/ui/LocatorPicker.d.ts.map +1 -0
- package/dist/cli/ui/LocatorPicker.js +33 -0
- package/dist/cli/ui/ProgressReporter.d.ts +11 -0
- package/dist/cli/ui/ProgressReporter.d.ts.map +1 -0
- package/dist/cli/ui/ProgressReporter.js +33 -0
- package/dist/cli/ui/RefactorWizard.d.ts +26 -0
- package/dist/cli/ui/RefactorWizard.d.ts.map +1 -0
- package/dist/cli/ui/RefactorWizard.js +295 -0
- package/dist/config/ConfigLoader.d.ts +16 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +185 -0
- package/dist/config/DryRunGuard.d.ts +14 -0
- package/dist/config/DryRunGuard.d.ts.map +1 -0
- package/dist/config/DryRunGuard.js +80 -0
- package/dist/config/PathScopeGuard.d.ts +42 -0
- package/dist/config/PathScopeGuard.d.ts.map +1 -0
- package/dist/config/PathScopeGuard.js +192 -0
- package/dist/config/SelaConfig.d.ts +178 -0
- package/dist/config/SelaConfig.d.ts.map +1 -0
- package/dist/config/SelaConfig.js +141 -0
- package/dist/config/defineConfig.d.ts +3 -0
- package/dist/config/defineConfig.d.ts.map +1 -0
- package/dist/config/defineConfig.js +9 -0
- package/dist/engine/FixwrightEngine.d.ts +24 -0
- package/dist/engine/FixwrightEngine.d.ts.map +1 -0
- package/dist/engine/FixwrightEngine.js +403 -0
- package/dist/engine/HealingRegistry.d.ts +40 -0
- package/dist/engine/HealingRegistry.d.ts.map +1 -0
- package/dist/engine/HealingRegistry.js +99 -0
- package/dist/engine/SelaEngine.d.ts +57 -0
- package/dist/engine/SelaEngine.d.ts.map +1 -0
- package/dist/engine/SelaEngine.js +1146 -0
- package/dist/engine/singleton.d.ts +3 -0
- package/dist/engine/singleton.d.ts.map +1 -0
- package/dist/engine/singleton.js +5 -0
- package/dist/errors/SelaError.d.ts +146 -0
- package/dist/errors/SelaError.d.ts.map +1 -0
- package/dist/errors/SelaError.js +168 -0
- package/dist/fixtures/expectProxy.d.ts +12 -0
- package/dist/fixtures/expectProxy.d.ts.map +1 -0
- package/dist/fixtures/expectProxy.js +246 -0
- package/dist/fixtures/index.d.ts +30 -0
- package/dist/fixtures/index.d.ts.map +1 -0
- package/dist/fixtures/index.js +765 -0
- package/dist/fixtures/moduleExpect.d.ts +2 -0
- package/dist/fixtures/moduleExpect.d.ts.map +1 -0
- package/dist/fixtures/moduleExpect.js +54 -0
- package/dist/fixtures/proxyTag.d.ts +12 -0
- package/dist/fixtures/proxyTag.d.ts.map +1 -0
- package/dist/fixtures/proxyTag.js +45 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/reporter/SelaReporter.d.ts +165 -0
- package/dist/reporter/SelaReporter.d.ts.map +1 -0
- package/dist/reporter/SelaReporter.js +517 -0
- package/dist/services/ASTSourceUpdater.d.ts +143 -0
- package/dist/services/ASTSourceUpdater.d.ts.map +1 -0
- package/dist/services/ASTSourceUpdater.js +3514 -0
- package/dist/services/AnchorResolver.d.ts +157 -0
- package/dist/services/AnchorResolver.d.ts.map +1 -0
- package/dist/services/AnchorResolver.js +289 -0
- package/dist/services/ArgumentTypeAnalyzer.d.ts +26 -0
- package/dist/services/ArgumentTypeAnalyzer.d.ts.map +1 -0
- package/dist/services/ArgumentTypeAnalyzer.js +92 -0
- package/dist/services/BlastRadiusAnalyzer.d.ts +15 -0
- package/dist/services/BlastRadiusAnalyzer.d.ts.map +1 -0
- package/dist/services/BlastRadiusAnalyzer.js +107 -0
- package/dist/services/ChainValidator.d.ts +76 -0
- package/dist/services/ChainValidator.d.ts.map +1 -0
- package/dist/services/ChainValidator.js +570 -0
- package/dist/services/CrossFileHealer.d.ts +6 -0
- package/dist/services/CrossFileHealer.d.ts.map +1 -0
- package/dist/services/CrossFileHealer.js +135 -0
- package/dist/services/DecisionEngine.d.ts +51 -0
- package/dist/services/DecisionEngine.d.ts.map +1 -0
- package/dist/services/DecisionEngine.js +260 -0
- package/dist/services/DefinitionTracer.d.ts +41 -0
- package/dist/services/DefinitionTracer.d.ts.map +1 -0
- package/dist/services/DefinitionTracer.js +366 -0
- package/dist/services/DnaEditorService.d.ts +31 -0
- package/dist/services/DnaEditorService.d.ts.map +1 -0
- package/dist/services/DnaEditorService.js +217 -0
- package/dist/services/DnaIndexService.d.ts +24 -0
- package/dist/services/DnaIndexService.d.ts.map +1 -0
- package/dist/services/DnaIndexService.js +131 -0
- package/dist/services/HealBudget.d.ts +32 -0
- package/dist/services/HealBudget.d.ts.map +1 -0
- package/dist/services/HealBudget.js +85 -0
- package/dist/services/HealReportService.d.ts +161 -0
- package/dist/services/HealReportService.d.ts.map +1 -0
- package/dist/services/HealReportService.js +1039 -0
- package/dist/services/HealingAdvisory.d.ts +30 -0
- package/dist/services/HealingAdvisory.d.ts.map +1 -0
- package/dist/services/HealingAdvisory.js +51 -0
- package/dist/services/HealingCacheService.d.ts +135 -0
- package/dist/services/HealingCacheService.d.ts.map +1 -0
- package/dist/services/HealingCacheService.js +404 -0
- package/dist/services/HealthReportService.d.ts +10 -0
- package/dist/services/HealthReportService.d.ts.map +1 -0
- package/dist/services/HealthReportService.js +84 -0
- package/dist/services/InitializerUpdater.d.ts +16 -0
- package/dist/services/InitializerUpdater.d.ts.map +1 -0
- package/dist/services/InitializerUpdater.js +73 -0
- package/dist/services/IntentAuditor.d.ts +56 -0
- package/dist/services/IntentAuditor.d.ts.map +1 -0
- package/dist/services/IntentAuditor.js +326 -0
- package/dist/services/InteractiveReview.d.ts +15 -0
- package/dist/services/InteractiveReview.d.ts.map +1 -0
- package/dist/services/InteractiveReview.js +128 -0
- package/dist/services/LLMService.d.ts +121 -0
- package/dist/services/LLMService.d.ts.map +1 -0
- package/dist/services/LLMService.js +475 -0
- package/dist/services/MutationApplier.d.ts +69 -0
- package/dist/services/MutationApplier.d.ts.map +1 -0
- package/dist/services/MutationApplier.js +360 -0
- package/dist/services/PRAutomationService.d.ts +50 -0
- package/dist/services/PRAutomationService.d.ts.map +1 -0
- package/dist/services/PRAutomationService.js +760 -0
- package/dist/services/PendingPromptLedger.d.ts +51 -0
- package/dist/services/PendingPromptLedger.d.ts.map +1 -0
- package/dist/services/PendingPromptLedger.js +205 -0
- package/dist/services/ReportGenerator.d.ts +156 -0
- package/dist/services/ReportGenerator.d.ts.map +1 -0
- package/dist/services/ReportGenerator.js +278 -0
- package/dist/services/ReportMergeService.d.ts +95 -0
- package/dist/services/ReportMergeService.d.ts.map +1 -0
- package/dist/services/ReportMergeService.js +0 -0
- package/dist/services/SafetyGuard.d.ts +112 -0
- package/dist/services/SafetyGuard.d.ts.map +1 -0
- package/dist/services/SafetyGuard.js +87 -0
- package/dist/services/Sanitizer.d.ts +28 -0
- package/dist/services/Sanitizer.d.ts.map +1 -0
- package/dist/services/Sanitizer.js +142 -0
- package/dist/services/SanitizingAnthropic.d.ts +19 -0
- package/dist/services/SanitizingAnthropic.d.ts.map +1 -0
- package/dist/services/SanitizingAnthropic.js +84 -0
- package/dist/services/SelectorSanitizer.d.ts +52 -0
- package/dist/services/SelectorSanitizer.d.ts.map +1 -0
- package/dist/services/SelectorSanitizer.js +318 -0
- package/dist/services/SnapshotService.d.ts +11 -0
- package/dist/services/SnapshotService.d.ts.map +1 -0
- package/dist/services/SnapshotService.js +352 -0
- package/dist/services/SourceLinkService.d.ts +26 -0
- package/dist/services/SourceLinkService.d.ts.map +1 -0
- package/dist/services/SourceLinkService.js +165 -0
- package/dist/services/SourceUpdater.d.ts +45 -0
- package/dist/services/SourceUpdater.d.ts.map +1 -0
- package/dist/services/SourceUpdater.js +1091 -0
- package/dist/services/TemplateDiffService.d.ts +25 -0
- package/dist/services/TemplateDiffService.d.ts.map +1 -0
- package/dist/services/TemplateDiffService.js +334 -0
- package/dist/services/TraceBackEngine.d.ts +67 -0
- package/dist/services/TraceBackEngine.d.ts.map +1 -0
- package/dist/services/TraceBackEngine.js +672 -0
- package/dist/services/WorkspaceSnapshotService.d.ts +71 -0
- package/dist/services/WorkspaceSnapshotService.d.ts.map +1 -0
- package/dist/services/WorkspaceSnapshotService.js +200 -0
- package/dist/services/safety/PipelineContext.d.ts +63 -0
- package/dist/services/safety/PipelineContext.d.ts.map +1 -0
- package/dist/services/safety/PipelineContext.js +34 -0
- package/dist/services/safety/roleClassifier.d.ts +4 -0
- package/dist/services/safety/roleClassifier.d.ts.map +1 -0
- package/dist/services/safety/roleClassifier.js +233 -0
- package/dist/services/safety/rules/ConfidenceTierRule.d.ts +3 -0
- package/dist/services/safety/rules/ConfidenceTierRule.d.ts.map +1 -0
- package/dist/services/safety/rules/ConfidenceTierRule.js +32 -0
- package/dist/services/safety/rules/DangerousSinkRule.d.ts +10 -0
- package/dist/services/safety/rules/DangerousSinkRule.d.ts.map +1 -0
- package/dist/services/safety/rules/DangerousSinkRule.js +53 -0
- package/dist/services/safety/rules/FunctionalRoleRule.d.ts +3 -0
- package/dist/services/safety/rules/FunctionalRoleRule.d.ts.map +1 -0
- package/dist/services/safety/rules/FunctionalRoleRule.js +64 -0
- package/dist/services/safety/rules/HardConfidenceRule.d.ts +3 -0
- package/dist/services/safety/rules/HardConfidenceRule.d.ts.map +1 -0
- package/dist/services/safety/rules/HardConfidenceRule.js +22 -0
- package/dist/services/safety/rules/IntentAuditorRule.d.ts +3 -0
- package/dist/services/safety/rules/IntentAuditorRule.d.ts.map +1 -0
- package/dist/services/safety/rules/IntentAuditorRule.js +97 -0
- package/dist/services/safety/rules/SemanticOppositeRule.d.ts +3 -0
- package/dist/services/safety/rules/SemanticOppositeRule.d.ts.map +1 -0
- package/dist/services/safety/rules/SemanticOppositeRule.js +30 -0
- package/dist/services/safety/rules/StructuralOnlyRule.d.ts +3 -0
- package/dist/services/safety/rules/StructuralOnlyRule.d.ts.map +1 -0
- package/dist/services/safety/rules/StructuralOnlyRule.js +38 -0
- package/dist/services/safety/rules/VisibilityRule.d.ts +3 -0
- package/dist/services/safety/rules/VisibilityRule.d.ts.map +1 -0
- package/dist/services/safety/rules/VisibilityRule.js +53 -0
- package/dist/services/safety/rules/ZeroTrustRule.d.ts +3 -0
- package/dist/services/safety/rules/ZeroTrustRule.d.ts.map +1 -0
- package/dist/services/safety/rules/ZeroTrustRule.js +37 -0
- package/dist/services/safety/rules/index.d.ts +3 -0
- package/dist/services/safety/rules/index.d.ts.map +1 -0
- package/dist/services/safety/rules/index.js +34 -0
- package/dist/services/types.d.ts +59 -0
- package/dist/services/types.d.ts.map +1 -0
- package/dist/services/types.js +2 -0
- package/dist/storage/SnapshotManager.d.ts +5 -0
- package/dist/storage/SnapshotManager.d.ts.map +1 -0
- package/dist/storage/SnapshotManager.js +32 -0
- package/dist/types/index.d.ts +95 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/utils/DOMUtils.d.ts +49 -0
- package/dist/utils/DOMUtils.d.ts.map +1 -0
- package/dist/utils/DOMUtils.js +466 -0
- package/dist/utils/FileLock.d.ts +44 -0
- package/dist/utils/FileLock.d.ts.map +1 -0
- package/dist/utils/FileLock.js +189 -0
- package/dist/utils/IsolatedDiff.d.ts +45 -0
- package/dist/utils/IsolatedDiff.d.ts.map +1 -0
- package/dist/utils/IsolatedDiff.js +382 -0
- package/dist/utils/StackUtils.d.ts +11 -0
- package/dist/utils/StackUtils.d.ts.map +1 -0
- package/dist/utils/StackUtils.js +120 -0
- package/dist/utils/SummaryTable.d.ts +17 -0
- package/dist/utils/SummaryTable.d.ts.map +1 -0
- package/dist/utils/SummaryTable.js +37 -0
- package/dist/utils/atomicWrite.d.ts +9 -0
- package/dist/utils/atomicWrite.d.ts.map +1 -0
- package/dist/utils/atomicWrite.js +83 -0
- package/dist/utils/logger.d.ts +59 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +123 -0
- package/dist/vendor/enquirer.d.ts +33 -0
- package/dist/vendor/enquirer.d.ts.map +1 -0
- package/dist/vendor/enquirer.js +11 -0
- 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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"}
|