sela-core 0.1.0-alpha.37 → 0.1.0-alpha.39
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/dist/cli/commands/shadowRegression.d.ts.map +1 -1
- package/dist/cli/commands/shadowRegression.js +7 -4
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +22 -4
- package/dist/engine/SelaEngine.js +1 -1
- package/dist/reporter/SelaReporter.d.ts +9 -0
- package/dist/reporter/SelaReporter.d.ts.map +1 -1
- package/dist/reporter/SelaReporter.js +62 -0
- package/dist/services/RegressionManifestService.d.ts.map +1 -1
- package/dist/services/RegressionManifestService.js +20 -7
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadowRegression.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/shadowRegression.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"shadowRegression.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/shadowRegression.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUzC,OAAO,KAAK,EACV,gBAAgB,EAEjB,MAAM,mCAAmC,CAAC;AAe3C;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoI/D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,GAAG,GAAG,gBAAgB,EAAE,CAqC9D"}
|
|
@@ -62,15 +62,18 @@ function registerShadowRegression(program) {
|
|
|
62
62
|
.command("shadow-regression")
|
|
63
63
|
.description("Verify a bypassed shared-locator heal against its downstream blast radius " +
|
|
64
64
|
"(stateless, in-memory, zero disk mutation)")
|
|
65
|
-
.
|
|
65
|
+
.option("--manifest <path>", `Path to sela-regression-manifest.json (emitted by the primary run). ` +
|
|
66
|
+
`Defaults to <cwd>/.sela/${RegressionManifestService_js_1.REGRESSION_MANIFEST_FILE}`)
|
|
66
67
|
.option("--dir <path>", "Project dir holding sela-report.json (merge target)", process.cwd())
|
|
67
68
|
.option("--config <path>", "Playwright config to pass through to the run")
|
|
68
69
|
.option("--report <path>", "Override path to the base sela-report.json to merge into")
|
|
69
70
|
.action(async (opts) => {
|
|
70
71
|
const targetDir = path.resolve(opts.dir ?? process.cwd());
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
const manifestRaw = opts.manifest ??
|
|
73
|
+
path.join(targetDir, ".sela", RegressionManifestService_js_1.REGRESSION_MANIFEST_FILE);
|
|
74
|
+
const manifestAbs = path.isAbsolute(manifestRaw)
|
|
75
|
+
? manifestRaw
|
|
76
|
+
: path.resolve(process.cwd(), manifestRaw);
|
|
74
77
|
// 1. Load + validate the manifest (throws loudly on bad input).
|
|
75
78
|
let manifest;
|
|
76
79
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../src/config/ConfigLoader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../src/config/ConfigLoader.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAiB,MAAM,cAAc,CAAC;AAgNzE,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA+B;IACtD,OAAO,CAAC,MAAM,CAAC,MAAM,CAAuB;IAK5C,OAAO,CAAC,MAAM,CAAC,aAAa,CAA2B;IAEvD;;;;;;;;OAQG;IACH,MAAM,CAAC,WAAW,IAAI,cAAc;IAqCpC;;;;OAIG;IACH,MAAM,CAAC,YAAY,IAAI,UAAU;IAKjC,OAAO,CAAC,MAAM,CAAC,aAAa;IAsB5B,yEAAyE;IACzE,MAAM,CAAC,SAAS,IAAI,MAAM,GAAG,IAAI;IAKjC,uDAAuD;IACvD,MAAM,CAAC,KAAK,IAAI,IAAI;CAKrB"}
|
|
@@ -167,10 +167,28 @@ function loadRawConfig(configPath) {
|
|
|
167
167
|
lastError = err;
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
|
-
// Every attempt failed
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
|
|
170
|
+
// Every attempt failed. Two cases:
|
|
171
|
+
//
|
|
172
|
+
// 1. The only candidate was a .ts file and the error looks like a missing
|
|
173
|
+
// TypeScript loader (e.g. "Cannot find module" for a .ts import, or
|
|
174
|
+
// "Unknown file extension .ts"). The CLI runs in plain Node.js — no tsx/
|
|
175
|
+
// ts-node — so the config simply cannot be loaded here. Gracefully fall
|
|
176
|
+
// back to defaults rather than crashing a CLI command that doesn't need
|
|
177
|
+
// the config (e.g. `sela shadow-regression`).
|
|
178
|
+
//
|
|
179
|
+
// 2. Genuine config error (syntax, key validation, etc.) → hard throw so CI
|
|
180
|
+
// surfaces the problem instead of silently running on stale defaults.
|
|
181
|
+
const msg = lastError?.message ?? "";
|
|
182
|
+
const isNoTsLoader = configPath.endsWith(".ts") &&
|
|
183
|
+
(msg.includes("Cannot find module") ||
|
|
184
|
+
msg.includes("Unknown file extension") ||
|
|
185
|
+
msg.includes("ERR_UNKNOWN_FILE_EXTENSION"));
|
|
186
|
+
if (isNoTsLoader) {
|
|
187
|
+
logger_1.logger.warn(`[Sela] sela.config.ts found but no TypeScript loader is active — running on defaults. ` +
|
|
188
|
+
`If you need config values in the CLI, add a compiled sela.config.js alongside it.`);
|
|
189
|
+
return {};
|
|
190
|
+
}
|
|
191
|
+
throw new Error(`[Sela] Failed to load ${path.basename(configPath)}: ${msg || "unknown error"}. ` +
|
|
174
192
|
`Ensure a TypeScript loader (Playwright, ts-node, tsx) is active, ` +
|
|
175
193
|
`or provide a compiled sela.config.js alongside sela.config.ts.`);
|
|
176
194
|
}
|
|
@@ -1256,7 +1256,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
|
|
|
1256
1256
|
if (!this.config.regressionActive) {
|
|
1257
1257
|
try {
|
|
1258
1258
|
const records = RegressionManifestService_1.RegressionManifestService.buildRecords(HealReportService_1.sharedHealReport.getBypassedEvents());
|
|
1259
|
-
const manifestPath = RegressionManifestService_1.RegressionManifestService.writeManifest(process.cwd(), records);
|
|
1259
|
+
const manifestPath = RegressionManifestService_1.RegressionManifestService.writeManifest(path.join(process.cwd(), ".sela"), records);
|
|
1260
1260
|
if (manifestPath) {
|
|
1261
1261
|
logger_1.logger.info(` Shadow-regression manifest: ${path.relative(process.cwd(), manifestPath)} ` +
|
|
1262
1262
|
`(${records.length} bypass${records.length !== 1 ? "es" : ""})`);
|
|
@@ -129,6 +129,15 @@ export declare class SelaReporter implements Reporter {
|
|
|
129
129
|
*/
|
|
130
130
|
private collectBypasses;
|
|
131
131
|
private readBypassedEvents;
|
|
132
|
+
/**
|
|
133
|
+
* Read raw (un-prettified) BYPASSED events directly from shard files.
|
|
134
|
+
* Must be called BEFORE mergeShards() — the merge runs
|
|
135
|
+
* normalizeEventsForReport() which converts internal:role=... selector
|
|
136
|
+
* strings to human-readable page.getByRole(...) form. The manifest writer
|
|
137
|
+
* needs the raw internal strings so RegressionInjector.lookup() and
|
|
138
|
+
* buildLiveLocator() can consume them without a round-trip parse.
|
|
139
|
+
*/
|
|
140
|
+
private readRawBypassEventsFromShards;
|
|
132
141
|
private collectRunSummary;
|
|
133
142
|
/**
|
|
134
143
|
* Render the summary table — but only when Sela actually did something.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelaReporter.d.ts","sourceRoot":"","sources":["../../src/reporter/SelaReporter.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EACV,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,UAAU,EACV,KAAK,EACL,UAAU,EACX,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAEL,iBAAiB,EAIjB,KAAK,aAAa,EACnB,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"SelaReporter.d.ts","sourceRoot":"","sources":["../../src/reporter/SelaReporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -67,6 +67,7 @@ const fs = __importStar(require("fs"));
|
|
|
67
67
|
const path = __importStar(require("path"));
|
|
68
68
|
const HealReportService_js_1 = require("../services/HealReportService.js");
|
|
69
69
|
const ReportMergeService_js_1 = require("../services/ReportMergeService.js");
|
|
70
|
+
const RegressionManifestService_js_1 = require("../services/RegressionManifestService.js");
|
|
70
71
|
const singleton_js_1 = require("../engine/singleton.js");
|
|
71
72
|
const SelaError_js_1 = require("../errors/SelaError.js");
|
|
72
73
|
const PendingPromptLedger_js_1 = require("../services/PendingPromptLedger.js");
|
|
@@ -223,6 +224,11 @@ class SelaReporter {
|
|
|
223
224
|
// main-process writer, so it is the safe place to merge them into the
|
|
224
225
|
// final sela-report.{html,json}. CI uses cross-machine `sela merge`.
|
|
225
226
|
if (!this.isCi()) {
|
|
227
|
+
// Capture raw bypass events from shards BEFORE merge — the merge runs
|
|
228
|
+
// normalizeEventsForReport() which prettifies internal:role=... selector
|
|
229
|
+
// strings to page.getByRole(...) form. The manifest needs the raw
|
|
230
|
+
// internal strings so buildLiveLocator() can consume them directly.
|
|
231
|
+
const rawBypassedFromShards = this.readRawBypassEventsFromShards(this.cwd);
|
|
226
232
|
try {
|
|
227
233
|
this.mergeShards(this.cwd);
|
|
228
234
|
}
|
|
@@ -230,6 +236,28 @@ class SelaReporter {
|
|
|
230
236
|
const msg = err instanceof Error ? err.message : String(err);
|
|
231
237
|
this.logger.error(`[Sela] shard merge failed: ${msg}`);
|
|
232
238
|
}
|
|
239
|
+
// Write regression manifest using raw (un-prettified) bypass events.
|
|
240
|
+
// Fall back to readBypassedEvents() only when no shards were present
|
|
241
|
+
// (e.g. single-process run where reporter has in-memory events or the
|
|
242
|
+
// sela-report.json was pre-populated by a previous run).
|
|
243
|
+
try {
|
|
244
|
+
const bypassedEvents = rawBypassedFromShards.length > 0
|
|
245
|
+
? rawBypassedFromShards
|
|
246
|
+
: this.readBypassedEvents();
|
|
247
|
+
if (bypassedEvents.length > 0) {
|
|
248
|
+
const records = RegressionManifestService_js_1.RegressionManifestService.buildRecords(bypassedEvents);
|
|
249
|
+
const manifestPath = RegressionManifestService_js_1.RegressionManifestService.writeManifest(path.join(this.cwd, ".sela"), records);
|
|
250
|
+
if (manifestPath) {
|
|
251
|
+
this.logger.info(` Shadow-regression manifest: ${path.relative(this.cwd, manifestPath)} ` +
|
|
252
|
+
`(${records.length} bypass${records.length !== 1 ? "es" : ""})`);
|
|
253
|
+
this.logger.info(" Verify with: npx sela shadow-regression");
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
259
|
+
this.logger.error(`[Sela] regression manifest write failed: ${msg}`);
|
|
260
|
+
}
|
|
233
261
|
}
|
|
234
262
|
// ── CI: centralized git/PR flow ──────────────────────────────
|
|
235
263
|
//
|
|
@@ -341,6 +369,40 @@ class SelaReporter {
|
|
|
341
369
|
return [];
|
|
342
370
|
}
|
|
343
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Read raw (un-prettified) BYPASSED events directly from shard files.
|
|
374
|
+
* Must be called BEFORE mergeShards() — the merge runs
|
|
375
|
+
* normalizeEventsForReport() which converts internal:role=... selector
|
|
376
|
+
* strings to human-readable page.getByRole(...) form. The manifest writer
|
|
377
|
+
* needs the raw internal strings so RegressionInjector.lookup() and
|
|
378
|
+
* buildLiveLocator() can consume them without a round-trip parse.
|
|
379
|
+
*/
|
|
380
|
+
readRawBypassEventsFromShards(cwd) {
|
|
381
|
+
const shardFiles = ReportMergeService_js_1.ReportMergeService.discoverShardFiles((0, HealReportService_js_1.reportShardDir)(cwd), "sela-shard-*.json");
|
|
382
|
+
if (shardFiles.length === 0)
|
|
383
|
+
return [];
|
|
384
|
+
const seen = new Set();
|
|
385
|
+
const result = [];
|
|
386
|
+
for (const file of shardFiles) {
|
|
387
|
+
try {
|
|
388
|
+
const events = ReportMergeService_js_1.ReportMergeService.readShardEvents(file);
|
|
389
|
+
for (const e of events) {
|
|
390
|
+
if (e.kind !== "BYPASSED")
|
|
391
|
+
continue;
|
|
392
|
+
const dedup = e.deterministicKey ?? e.stableId ?? "";
|
|
393
|
+
if (dedup && seen.has(dedup))
|
|
394
|
+
continue;
|
|
395
|
+
if (dedup)
|
|
396
|
+
seen.add(dedup);
|
|
397
|
+
result.push(e);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
catch {
|
|
401
|
+
// Individual shard failures are non-fatal — merge() already logs them.
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
344
406
|
collectRunSummary() {
|
|
345
407
|
const healed = this.report.getHealedEvents().length;
|
|
346
408
|
const held = this.report.getProtectedEvents().length;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RegressionManifestService.d.ts","sourceRoot":"","sources":["../../src/services/RegressionManifestService.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AAExE,oEAAoE;AACpE,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,cAAc,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,wBAAwB,EAAE,CAAC;CACrC;AAMD,qBAAa,yBAAyB;IACpC,+DAA+D;IAC/D,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,wBAAwB,EAAE;IAexE;;;;OAIG;IACH,MAAM,CAAC,aAAa,CAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,wBAAwB,EAAE,GAClC,MAAM,GAAG,IAAI;IAYhB;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB;IAkBzD,OAAO,CAAC,MAAM,CAAC,QAAQ;CAqDxB;AAED;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;gBAEzC,QAAQ,EAAE,kBAAkB;IAIxC,yEAAyE;IACzE,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB;IAMrD;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"RegressionManifestService.d.ts","sourceRoot":"","sources":["../../src/services/RegressionManifestService.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,eAAO,MAAM,wBAAwB,kCAAkC,CAAC;AAExE,oEAAoE;AACpE,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,cAAc,EAAE,MAAM,CAAC;IACvB,sEAAsE;IACtE,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,wBAAwB,EAAE,CAAC;CACrC;AAMD,qBAAa,yBAAyB;IACpC,+DAA+D;IAC/D,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,wBAAwB,EAAE;IAexE;;;;OAIG;IACH,MAAM,CAAC,aAAa,CAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,wBAAwB,EAAE,GAClC,MAAM,GAAG,IAAI;IAYhB;;;;OAIG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB;IAkBzD,OAAO,CAAC,MAAM,CAAC,QAAQ;CAqDxB;AAED;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6B;gBAEzC,QAAQ,EAAE,kBAAkB;IAIxC,yEAAyE;IACzE,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB;IAMrD;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CA0B3E"}
|
|
@@ -172,18 +172,31 @@ class RegressionInjector {
|
|
|
172
172
|
*/
|
|
173
173
|
lookup(filePath, line, oldSelector) {
|
|
174
174
|
const f = normalizePath(filePath).toLowerCase();
|
|
175
|
-
|
|
175
|
+
// Primary: match on line + file (precise call-site).
|
|
176
|
+
const lineCandidates = this.records.filter((r) => {
|
|
176
177
|
if (r.failureLine !== line)
|
|
177
178
|
return false;
|
|
178
179
|
const rf = normalizePath(r.sourceFile).toLowerCase();
|
|
179
180
|
return f === rf || f.endsWith(rf) || rf.endsWith(f);
|
|
180
181
|
});
|
|
181
|
-
if (
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
182
|
+
if (lineCandidates.length > 0) {
|
|
183
|
+
const exact = lineCandidates.find((r) => r.oldSelector === oldSelector);
|
|
184
|
+
if (exact)
|
|
185
|
+
return exact.healedSelector;
|
|
186
|
+
if (lineCandidates.length === 1)
|
|
187
|
+
return lineCandidates[0].healedSelector;
|
|
188
|
+
}
|
|
189
|
+
// Fallback: shared locators — multiple tests in the same file fail at
|
|
190
|
+
// different lines but share the same broken selector. The manifest stores
|
|
191
|
+
// failureLine from the FIRST failure only, so subsequent tests miss the
|
|
192
|
+
// line match. Widen to selector + file so every caller gets injected.
|
|
193
|
+
const selectorMatch = this.records.find((r) => {
|
|
194
|
+
if (r.oldSelector !== oldSelector)
|
|
195
|
+
return false;
|
|
196
|
+
const rf = normalizePath(r.sourceFile).toLowerCase();
|
|
197
|
+
return f === rf || f.endsWith(rf) || rf.endsWith(f);
|
|
198
|
+
});
|
|
199
|
+
return selectorMatch?.healedSelector ?? null;
|
|
187
200
|
}
|
|
188
201
|
}
|
|
189
202
|
exports.RegressionInjector = RegressionInjector;
|
package/package.json
CHANGED