sela-core 1.0.6 → 1.0.7
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 +1 -1
- package/dist/config/ConfigLoader.d.ts +1 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +10 -0
- package/dist/config/DryRunGuard.d.ts +14 -0
- package/dist/config/DryRunGuard.d.ts.map +1 -0
- package/dist/config/DryRunGuard.js +79 -0
- package/dist/config/SelaConfig.d.ts +15 -1
- package/dist/config/SelaConfig.d.ts.map +1 -1
- package/dist/config/SelaConfig.js +27 -1
- package/dist/engine/SelaEngine.d.ts +12 -9
- package/dist/engine/SelaEngine.d.ts.map +1 -1
- package/dist/engine/SelaEngine.js +249 -72
- package/dist/errors/SelaError.d.ts +133 -0
- package/dist/errors/SelaError.d.ts.map +1 -0
- package/dist/errors/SelaError.js +155 -0
- package/dist/fixtures/expectProxy.d.ts.map +1 -1
- package/dist/fixtures/expectProxy.js +7 -0
- package/dist/fixtures/index.d.ts +7 -1
- package/dist/fixtures/index.d.ts.map +1 -1
- package/dist/fixtures/index.js +15 -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 +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/reporter/SelaReporter.d.ts +110 -0
- package/dist/reporter/SelaReporter.d.ts.map +1 -0
- package/dist/reporter/SelaReporter.js +328 -0
- package/dist/services/ASTSourceUpdater.d.ts +19 -0
- package/dist/services/ASTSourceUpdater.d.ts.map +1 -1
- package/dist/services/ASTSourceUpdater.js +173 -29
- package/dist/services/HealReportService.d.ts +42 -0
- package/dist/services/HealReportService.d.ts.map +1 -1
- package/dist/services/HealReportService.js +80 -1
- package/dist/services/HealingCacheService.d.ts +135 -0
- package/dist/services/HealingCacheService.d.ts.map +1 -0
- package/dist/services/HealingCacheService.js +460 -0
- package/dist/services/InitializerUpdater.d.ts.map +1 -1
- package/dist/services/InitializerUpdater.js +20 -1
- package/dist/services/IntentAuditor.d.ts +18 -1
- package/dist/services/IntentAuditor.d.ts.map +1 -1
- package/dist/services/IntentAuditor.js +19 -6
- package/dist/services/InteractiveReview.d.ts +24 -0
- package/dist/services/InteractiveReview.d.ts.map +1 -0
- package/dist/services/InteractiveReview.js +218 -0
- package/dist/services/LLMService.d.ts +17 -1
- package/dist/services/LLMService.d.ts.map +1 -1
- package/dist/services/LLMService.js +18 -8
- package/dist/services/PRAutomationService.d.ts +14 -1
- package/dist/services/PRAutomationService.d.ts.map +1 -1
- package/dist/services/PRAutomationService.js +260 -69
- package/dist/services/PendingPromptLedger.d.ts +44 -0
- package/dist/services/PendingPromptLedger.d.ts.map +1 -0
- package/dist/services/PendingPromptLedger.js +180 -0
- package/dist/services/ReportGenerator.d.ts +70 -0
- package/dist/services/ReportGenerator.d.ts.map +1 -0
- package/dist/services/ReportGenerator.js +191 -0
- package/dist/services/SafetyGuard.d.ts +27 -1
- package/dist/services/SafetyGuard.d.ts.map +1 -1
- package/dist/services/SafetyGuard.js +58 -12
- package/dist/services/SourceUpdater.d.ts.map +1 -1
- package/dist/services/SourceUpdater.js +44 -13
- package/dist/services/WorkspaceSnapshotService.d.ts +71 -0
- package/dist/services/WorkspaceSnapshotService.d.ts.map +1 -0
- package/dist/services/WorkspaceSnapshotService.js +202 -0
- package/dist/utils/IsolatedDiff.d.ts +45 -0
- package/dist/utils/IsolatedDiff.d.ts.map +1 -0
- package/dist/utils/IsolatedDiff.js +379 -0
- package/package.json +71 -67
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/utils/IsolatedDiff.ts
|
|
3
|
+
//
|
|
4
|
+
// Pure-JS unified-diff generator. No external `diff` package, no shell-out to
|
|
5
|
+
// `git diff` — the result is guaranteed to be a function ONLY of the two
|
|
6
|
+
// in-memory buffers passed in, never of any global working-tree state.
|
|
7
|
+
//
|
|
8
|
+
// This is the foundation of the Clean-Room Architecture: the HTML report
|
|
9
|
+
// renders diffs computed here, so a developer's pre-existing uncommitted
|
|
10
|
+
// edits CANNOT leak into Sela's report.
|
|
11
|
+
//
|
|
12
|
+
// Algorithm: classic LCS over lines, then a unified-diff emitter with
|
|
13
|
+
// configurable context. Memory is O(N*M) which is fine for the spec files
|
|
14
|
+
// Sela mutates (typically a few thousand lines max).
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.generateUnifiedDiff = generateUnifiedDiff;
|
|
17
|
+
exports.extractChangeBlocks = extractChangeBlocks;
|
|
18
|
+
exports.applyChangeBlocks = applyChangeBlocks;
|
|
19
|
+
/**
|
|
20
|
+
* Generate a `git`-style unified diff between two in-memory strings.
|
|
21
|
+
* Returns `""` when the two buffers are identical.
|
|
22
|
+
*/
|
|
23
|
+
function generateUnifiedDiff(before, after, opts = {}) {
|
|
24
|
+
if (before === after)
|
|
25
|
+
return "";
|
|
26
|
+
const context = Math.max(0, opts.context ?? 3);
|
|
27
|
+
const a = splitKeepEol(before);
|
|
28
|
+
const b = splitKeepEol(after);
|
|
29
|
+
const ops = diffLines(a, b);
|
|
30
|
+
if (ops.length === 0)
|
|
31
|
+
return "";
|
|
32
|
+
const hunks = groupHunks(ops, { a, b, context });
|
|
33
|
+
if (hunks.length === 0)
|
|
34
|
+
return "";
|
|
35
|
+
const out = [];
|
|
36
|
+
if (opts.filePath) {
|
|
37
|
+
const p = opts.filePath.split(/[\\/]/).join("/");
|
|
38
|
+
out.push(`diff --git a/${p} b/${p}`);
|
|
39
|
+
out.push(`--- a/${p}`);
|
|
40
|
+
out.push(`+++ b/${p}`);
|
|
41
|
+
}
|
|
42
|
+
for (const hunk of hunks) {
|
|
43
|
+
out.push(formatHunkHeader(hunk));
|
|
44
|
+
for (const row of hunk.rows)
|
|
45
|
+
out.push(row);
|
|
46
|
+
}
|
|
47
|
+
return out.join("\n") + "\n";
|
|
48
|
+
}
|
|
49
|
+
// ────────────────────────────────────────────────────────────────────
|
|
50
|
+
// LINE SPLITTER — preserves trailing newline / CRLF so we can emit the
|
|
51
|
+
// canonical `` marker when needed.
|
|
52
|
+
// ────────────────────────────────────────────────────────────────────
|
|
53
|
+
function splitKeepEol(text) {
|
|
54
|
+
if (text.length === 0)
|
|
55
|
+
return [];
|
|
56
|
+
const out = [];
|
|
57
|
+
let start = 0;
|
|
58
|
+
for (let i = 0; i < text.length; i++) {
|
|
59
|
+
if (text.charCodeAt(i) === 10 /* \n */) {
|
|
60
|
+
out.push(text.slice(start, i + 1));
|
|
61
|
+
start = i + 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (start < text.length)
|
|
65
|
+
out.push(text.slice(start));
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
function stripEol(line) {
|
|
69
|
+
if (line.endsWith("\r\n"))
|
|
70
|
+
return line.slice(0, -2);
|
|
71
|
+
if (line.endsWith("\n"))
|
|
72
|
+
return line.slice(0, -1);
|
|
73
|
+
return line;
|
|
74
|
+
}
|
|
75
|
+
function hasEol(line) {
|
|
76
|
+
return line.endsWith("\n");
|
|
77
|
+
}
|
|
78
|
+
function diffLines(a, b) {
|
|
79
|
+
const m = a.length;
|
|
80
|
+
const n = b.length;
|
|
81
|
+
const w = n + 1;
|
|
82
|
+
const dp = new Uint32Array((m + 1) * w);
|
|
83
|
+
for (let i = m - 1; i >= 0; i--) {
|
|
84
|
+
const ai = a[i];
|
|
85
|
+
for (let j = n - 1; j >= 0; j--) {
|
|
86
|
+
if (ai === b[j]) {
|
|
87
|
+
dp[i * w + j] = dp[(i + 1) * w + (j + 1)] + 1;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const down = dp[(i + 1) * w + j];
|
|
91
|
+
const right = dp[i * w + (j + 1)];
|
|
92
|
+
dp[i * w + j] = down >= right ? down : right;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const ops = [];
|
|
97
|
+
let i = 0;
|
|
98
|
+
let j = 0;
|
|
99
|
+
while (i < m && j < n) {
|
|
100
|
+
if (a[i] === b[j]) {
|
|
101
|
+
ops.push({ kind: "eq", a: i, b: j });
|
|
102
|
+
i++;
|
|
103
|
+
j++;
|
|
104
|
+
}
|
|
105
|
+
else if (dp[(i + 1) * w + j] >= dp[i * w + (j + 1)]) {
|
|
106
|
+
ops.push({ kind: "del", a: i });
|
|
107
|
+
i++;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
ops.push({ kind: "add", b: j });
|
|
111
|
+
j++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
while (i < m) {
|
|
115
|
+
ops.push({ kind: "del", a: i });
|
|
116
|
+
i++;
|
|
117
|
+
}
|
|
118
|
+
while (j < n) {
|
|
119
|
+
ops.push({ kind: "add", b: j });
|
|
120
|
+
j++;
|
|
121
|
+
}
|
|
122
|
+
return ops;
|
|
123
|
+
}
|
|
124
|
+
function groupHunks(ops, ctx) {
|
|
125
|
+
const hunks = [];
|
|
126
|
+
const ctxN = ctx.context;
|
|
127
|
+
let i = 0;
|
|
128
|
+
while (i < ops.length) {
|
|
129
|
+
// Locate the next non-equal op.
|
|
130
|
+
let firstChange = -1;
|
|
131
|
+
for (let k = i; k < ops.length; k++) {
|
|
132
|
+
if (ops[k].kind !== "eq") {
|
|
133
|
+
firstChange = k;
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (firstChange === -1)
|
|
138
|
+
break;
|
|
139
|
+
// Leading-context start, bounded by previous hunk end.
|
|
140
|
+
let hunkStart = firstChange - ctxN;
|
|
141
|
+
if (hunkStart < i)
|
|
142
|
+
hunkStart = i;
|
|
143
|
+
if (hunkStart < 0)
|
|
144
|
+
hunkStart = 0;
|
|
145
|
+
let hunkEnd = firstChange;
|
|
146
|
+
// Extend by merging change groups separated by <= 2*ctxN equality lines.
|
|
147
|
+
// Avoid merging across the very end of `ops`.
|
|
148
|
+
while (true) {
|
|
149
|
+
let cursor = hunkEnd + 1;
|
|
150
|
+
let runEqs = 0;
|
|
151
|
+
let nextChange = -1;
|
|
152
|
+
while (cursor < ops.length) {
|
|
153
|
+
if (ops[cursor].kind === "eq") {
|
|
154
|
+
runEqs++;
|
|
155
|
+
cursor++;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
nextChange = cursor;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
if (nextChange !== -1 && runEqs <= 2 * ctxN) {
|
|
162
|
+
hunkEnd = nextChange;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Trailing context.
|
|
169
|
+
let trailing = 0;
|
|
170
|
+
while (hunkEnd + 1 < ops.length &&
|
|
171
|
+
ops[hunkEnd + 1].kind === "eq" &&
|
|
172
|
+
trailing < ctxN) {
|
|
173
|
+
hunkEnd++;
|
|
174
|
+
trailing++;
|
|
175
|
+
}
|
|
176
|
+
// Materialise rows + compute header coordinates.
|
|
177
|
+
const rows = [];
|
|
178
|
+
let oldStartIdx = -1;
|
|
179
|
+
let newStartIdx = -1;
|
|
180
|
+
let oldLen = 0;
|
|
181
|
+
let newLen = 0;
|
|
182
|
+
for (let k = hunkStart; k <= hunkEnd; k++) {
|
|
183
|
+
const op = ops[k];
|
|
184
|
+
if (op.kind === "eq") {
|
|
185
|
+
if (oldStartIdx === -1)
|
|
186
|
+
oldStartIdx = op.a;
|
|
187
|
+
if (newStartIdx === -1)
|
|
188
|
+
newStartIdx = op.b;
|
|
189
|
+
const line = ctx.a[op.a];
|
|
190
|
+
rows.push(" " + stripEol(line));
|
|
191
|
+
oldLen++;
|
|
192
|
+
newLen++;
|
|
193
|
+
if (!hasEol(line))
|
|
194
|
+
rows.push("\");
|
|
195
|
+
}
|
|
196
|
+
else if (op.kind === "del") {
|
|
197
|
+
if (oldStartIdx === -1)
|
|
198
|
+
oldStartIdx = op.a;
|
|
199
|
+
if (newStartIdx === -1) {
|
|
200
|
+
// Anchor on the corresponding `b` position. For pure-deletions at
|
|
201
|
+
// the top of file `op.a === 0` ⇒ newStart should be 0 (special
|
|
202
|
+
// header form `+0,0`). For mid-file deletions use the running b
|
|
203
|
+
// cursor — derive it from prior ops.
|
|
204
|
+
newStartIdx = computeBAnchor(ops, k);
|
|
205
|
+
}
|
|
206
|
+
const line = ctx.a[op.a];
|
|
207
|
+
rows.push("-" + stripEol(line));
|
|
208
|
+
oldLen++;
|
|
209
|
+
if (!hasEol(line))
|
|
210
|
+
rows.push("\");
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
if (newStartIdx === -1)
|
|
214
|
+
newStartIdx = op.b;
|
|
215
|
+
if (oldStartIdx === -1)
|
|
216
|
+
oldStartIdx = computeAAnchor(ops, k);
|
|
217
|
+
const line = ctx.b[op.b];
|
|
218
|
+
rows.push("+" + stripEol(line));
|
|
219
|
+
newLen++;
|
|
220
|
+
if (!hasEol(line))
|
|
221
|
+
rows.push("\");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
hunks.push({
|
|
225
|
+
oldStart: oldLen === 0 ? oldStartIdx : oldStartIdx + 1,
|
|
226
|
+
oldLen,
|
|
227
|
+
newStart: newLen === 0 ? newStartIdx : newStartIdx + 1,
|
|
228
|
+
newLen,
|
|
229
|
+
rows,
|
|
230
|
+
});
|
|
231
|
+
i = hunkEnd + 1;
|
|
232
|
+
}
|
|
233
|
+
return hunks;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* For a pure-add op at position `k`, walk backwards to find the prior
|
|
237
|
+
* `a` index (so we know which line of the old file the hunk starts at).
|
|
238
|
+
*/
|
|
239
|
+
function computeAAnchor(ops, k) {
|
|
240
|
+
for (let p = k - 1; p >= 0; p--) {
|
|
241
|
+
const op = ops[p];
|
|
242
|
+
if (op.kind === "eq")
|
|
243
|
+
return op.a + 1;
|
|
244
|
+
if (op.kind === "del")
|
|
245
|
+
return op.a + 1;
|
|
246
|
+
}
|
|
247
|
+
return 0;
|
|
248
|
+
}
|
|
249
|
+
function computeBAnchor(ops, k) {
|
|
250
|
+
for (let p = k - 1; p >= 0; p--) {
|
|
251
|
+
const op = ops[p];
|
|
252
|
+
if (op.kind === "eq")
|
|
253
|
+
return op.b + 1;
|
|
254
|
+
if (op.kind === "add")
|
|
255
|
+
return op.b + 1;
|
|
256
|
+
}
|
|
257
|
+
return 0;
|
|
258
|
+
}
|
|
259
|
+
function formatHunkHeader(hunk) {
|
|
260
|
+
const oldPart = hunk.oldLen === 1 ? `${hunk.oldStart}` : `${hunk.oldStart},${hunk.oldLen}`;
|
|
261
|
+
const newPart = hunk.newLen === 1 ? `${hunk.newStart}` : `${hunk.newStart},${hunk.newLen}`;
|
|
262
|
+
return `@@ -${oldPart} +${newPart} @@`;
|
|
263
|
+
}
|
|
264
|
+
function extractChangeBlocks(before, after) {
|
|
265
|
+
if (before === after)
|
|
266
|
+
return [];
|
|
267
|
+
const a = splitKeepEol(before);
|
|
268
|
+
const b = splitKeepEol(after);
|
|
269
|
+
const ops = diffLines(a, b);
|
|
270
|
+
const blocks = [];
|
|
271
|
+
let i = 0;
|
|
272
|
+
while (i < ops.length) {
|
|
273
|
+
if (ops[i].kind === "eq") {
|
|
274
|
+
i++;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
const start = i;
|
|
278
|
+
while (i < ops.length && ops[i].kind !== "eq")
|
|
279
|
+
i++;
|
|
280
|
+
const oldLines = [];
|
|
281
|
+
const newLines = [];
|
|
282
|
+
let oldStart = -1;
|
|
283
|
+
let newStart = -1;
|
|
284
|
+
for (let k = start; k < i; k++) {
|
|
285
|
+
const op = ops[k];
|
|
286
|
+
if (op.kind === "del") {
|
|
287
|
+
if (oldStart === -1)
|
|
288
|
+
oldStart = op.a;
|
|
289
|
+
oldLines.push(a[op.a]);
|
|
290
|
+
}
|
|
291
|
+
else if (op.kind === "add") {
|
|
292
|
+
if (newStart === -1)
|
|
293
|
+
newStart = op.b;
|
|
294
|
+
newLines.push(b[op.b]);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
let anchorBefore = null;
|
|
298
|
+
if (oldLines.length === 0) {
|
|
299
|
+
// Pure addition — find preceding unchanged anchor line.
|
|
300
|
+
for (let k = start - 1; k >= 0; k--) {
|
|
301
|
+
const op = ops[k];
|
|
302
|
+
if (op.kind === "eq") {
|
|
303
|
+
anchorBefore = a[op.a];
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
blocks.push({
|
|
309
|
+
oldBlock: oldLines.join(""),
|
|
310
|
+
newBlock: newLines.join(""),
|
|
311
|
+
oldLineStart: oldStart >= 0 ? oldStart + 1 : 0,
|
|
312
|
+
newLineStart: newStart >= 0 ? newStart + 1 : 0,
|
|
313
|
+
anchorBefore,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
return blocks;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Replay a list of change blocks against a fresh base buffer (typically
|
|
320
|
+
* the file's `HEAD` blob). Each block is applied via UNIQUE substring
|
|
321
|
+
* replacement — when the old block is missing or ambiguous in the base,
|
|
322
|
+
* we fail loudly rather than silently mutating the wrong spot.
|
|
323
|
+
*/
|
|
324
|
+
function applyChangeBlocks(base, blocks) {
|
|
325
|
+
let working = base;
|
|
326
|
+
for (const block of blocks) {
|
|
327
|
+
if (block.oldBlock.length === 0) {
|
|
328
|
+
// Pure addition.
|
|
329
|
+
if (block.anchorBefore === null) {
|
|
330
|
+
if (working.length === 0) {
|
|
331
|
+
// Empty file — prepend.
|
|
332
|
+
working = block.newBlock + working;
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
// Prepend at top of file.
|
|
336
|
+
working = block.newBlock + working;
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const idx = working.indexOf(block.anchorBefore);
|
|
340
|
+
if (idx === -1) {
|
|
341
|
+
return {
|
|
342
|
+
ok: false,
|
|
343
|
+
reason: `pure-add anchor not found in clean base: "${snippet(block.anchorBefore)}"`,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
const lastIdx = working.lastIndexOf(block.anchorBefore);
|
|
347
|
+
if (idx !== lastIdx) {
|
|
348
|
+
return {
|
|
349
|
+
ok: false,
|
|
350
|
+
reason: `pure-add anchor is not unique in clean base: "${snippet(block.anchorBefore)}"`,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
const insertAt = idx + block.anchorBefore.length;
|
|
354
|
+
working = working.slice(0, insertAt) + block.newBlock + working.slice(insertAt);
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
const idx = working.indexOf(block.oldBlock);
|
|
358
|
+
if (idx === -1) {
|
|
359
|
+
return {
|
|
360
|
+
ok: false,
|
|
361
|
+
reason: `block not found in clean base — developer's dirty state likely overlaps Sela's mutation site: "${snippet(block.oldBlock)}"`,
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const lastIdx = working.lastIndexOf(block.oldBlock);
|
|
365
|
+
if (idx !== lastIdx) {
|
|
366
|
+
return {
|
|
367
|
+
ok: false,
|
|
368
|
+
reason: `block matches multiple locations in clean base — refusing to guess: "${snippet(block.oldBlock)}"`,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
working =
|
|
372
|
+
working.slice(0, idx) + block.newBlock + working.slice(idx + block.oldBlock.length);
|
|
373
|
+
}
|
|
374
|
+
return { ok: true, result: working };
|
|
375
|
+
}
|
|
376
|
+
function snippet(s) {
|
|
377
|
+
const flat = s.replace(/\r?\n/g, "\\n");
|
|
378
|
+
return flat.length > 80 ? flat.slice(0, 77) + "..." : flat;
|
|
379
|
+
}
|
package/package.json
CHANGED
|
@@ -1,67 +1,71 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "sela-core",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "AI self-healing Playwright wrapper — drop-in replacement for @playwright/test",
|
|
5
|
-
"main": "./dist/index.js",
|
|
6
|
-
"types": "./dist/index.d.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"types": "./dist/index.d.ts",
|
|
10
|
-
"default": "./dist/index.js"
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"test
|
|
30
|
-
"test-
|
|
31
|
-
"test-
|
|
32
|
-
"test-
|
|
33
|
-
"test-
|
|
34
|
-
"test-
|
|
35
|
-
"test-
|
|
36
|
-
"test-
|
|
37
|
-
"test-
|
|
38
|
-
"test-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "sela-core",
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "AI self-healing Playwright wrapper — drop-in replacement for @playwright/test",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./reporter": {
|
|
13
|
+
"types": "./dist/reporter/SelaReporter.d.ts",
|
|
14
|
+
"default": "./dist/reporter/SelaReporter.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"bin"
|
|
20
|
+
],
|
|
21
|
+
"bin": {
|
|
22
|
+
"sela": "bin/sela.js"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"sela": "tsx src/cli/index.ts",
|
|
26
|
+
"build": "tsc -p tsconfig.build.json",
|
|
27
|
+
"build:watch": "tsc -p tsconfig.build.json --watch",
|
|
28
|
+
"prepublishOnly": "npm run build",
|
|
29
|
+
"test": "npx playwright test demo.spec.ts --headed --retries=0",
|
|
30
|
+
"test-shadow": "npx playwright test shadow.spec.ts --headed --retries=0",
|
|
31
|
+
"test-core": "npx playwright test tests/Core/CoreExample.spec.ts --headed --retries=0",
|
|
32
|
+
"test-DNA": "npx playwright test tests/DnaSurvival/DnaSurvival.spec.ts --headed --retries=0",
|
|
33
|
+
"test-advanced": "npx playwright test tests/AdvancedLogic/AdvancedLogic.spec.ts --headed --retries=0",
|
|
34
|
+
"test-isolation": "npx playwright test tests/Isolation/Isolation.spec.ts --headed --retries=0",
|
|
35
|
+
"test-playwright-actions": "npx playwright test tests/PlaywrightActions/BasicActions/BasicActions.spec.ts --headed --retries=0",
|
|
36
|
+
"test-forms-actions": "npx playwright test tests/PlaywrightActions/FormsActions/FormsActions.spec.ts --headed --retries=0",
|
|
37
|
+
"test-locators-actions": "npx playwright test tests/PlaywrightActions/LocatorsActions/LocatorsActions.spec.ts --headed --retries=0",
|
|
38
|
+
"test-config": "npx playwright test tests/TestConfig/TestConfig.spec.ts --headed --retries=0",
|
|
39
|
+
"test-safety-guard": "npx playwright test tests/SafetyGuard/SafetyGuard.spec.ts --headed --retries=0",
|
|
40
|
+
"test-improve-methods": "npx playwright test tests/ImproveMethods/ImproveMethods.spec.ts --headed --retries=0",
|
|
41
|
+
"test-shadow-dom": "npx playwright test tests/ShadowDom/ShadowDom.spec.ts --headed --retries=0",
|
|
42
|
+
"test-ut": "npx vitest run tests/unit/safetyguard/ tests/unit/engine/ tests/unit/ast/ tests/unit/proxy/ tests/unit/_harness/ tests/unit/config/ tests/unit/services/ tests/unit/reporter/ tests/unit/utils/"
|
|
43
|
+
},
|
|
44
|
+
"author": "",
|
|
45
|
+
"license": "ISC",
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@playwright/test": ">=1.40.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@anthropic-ai/sdk": "^0.80.0",
|
|
51
|
+
"axios": "^1.13.6",
|
|
52
|
+
"chalk": "^4.1.2",
|
|
53
|
+
"cli-table3": "^0.6.5",
|
|
54
|
+
"commander": "^14.0.3",
|
|
55
|
+
"dotenv": "^17.3.1",
|
|
56
|
+
"enquirer": "^2.4.1",
|
|
57
|
+
"ora": "^5.4.1",
|
|
58
|
+
"playwright": "^1.58.2",
|
|
59
|
+
"ts-morph": "^27.0.2"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@playwright/test": "^1.60.0",
|
|
63
|
+
"@types/jest": "^30.0.0",
|
|
64
|
+
"@types/node": "^25.6.2",
|
|
65
|
+
"jest": "^30.3.0",
|
|
66
|
+
"jsdom": "^29.0.1",
|
|
67
|
+
"ts-jest": "^29.4.6",
|
|
68
|
+
"tsx": "^4.21.0",
|
|
69
|
+
"vitest": "^4.1.1"
|
|
70
|
+
}
|
|
71
|
+
}
|