sela-core 1.0.7 → 1.0.8

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 (114) hide show
  1. package/dist/cli/ErrorHandler.d.ts +1 -1
  2. package/dist/cli/ErrorHandler.js +14 -14
  3. package/dist/cli/commands/bulk.d.ts +1 -1
  4. package/dist/cli/commands/bulk.d.ts.map +1 -1
  5. package/dist/cli/commands/bulk.js +51 -33
  6. package/dist/cli/commands/init.d.ts +1 -1
  7. package/dist/cli/commands/init.d.ts.map +1 -1
  8. package/dist/cli/commands/init.js +26 -18
  9. package/dist/cli/commands/showReport.d.ts +1 -1
  10. package/dist/cli/commands/showReport.d.ts.map +1 -1
  11. package/dist/cli/commands/showReport.js +12 -10
  12. package/dist/cli/commands/status.d.ts +1 -1
  13. package/dist/cli/commands/status.d.ts.map +1 -1
  14. package/dist/cli/commands/status.js +8 -8
  15. package/dist/cli/commands/sync.d.ts +1 -1
  16. package/dist/cli/commands/sync.d.ts.map +1 -1
  17. package/dist/cli/commands/sync.js +38 -30
  18. package/dist/cli/index.js +9 -9
  19. package/dist/cli/ui/DnaTable.d.ts +1 -1
  20. package/dist/cli/ui/DnaTable.d.ts.map +1 -1
  21. package/dist/cli/ui/DnaTable.js +23 -16
  22. package/dist/cli/ui/RefactorWizard.d.ts +3 -3
  23. package/dist/cli/ui/RefactorWizard.d.ts.map +1 -1
  24. package/dist/cli/ui/RefactorWizard.js +108 -82
  25. package/dist/config/ConfigLoader.d.ts +2 -2
  26. package/dist/config/ConfigLoader.d.ts.map +1 -1
  27. package/dist/config/ConfigLoader.js +15 -15
  28. package/dist/config/DryRunGuard.d.ts +1 -1
  29. package/dist/config/DryRunGuard.js +7 -7
  30. package/dist/config/SelaConfig.d.ts +12 -16
  31. package/dist/config/SelaConfig.d.ts.map +1 -1
  32. package/dist/config/SelaConfig.js +32 -26
  33. package/dist/engine/HealingRegistry.d.ts +1 -1
  34. package/dist/engine/HealingRegistry.js +3 -3
  35. package/dist/engine/SelaEngine.d.ts +1 -1
  36. package/dist/engine/SelaEngine.d.ts.map +1 -1
  37. package/dist/engine/SelaEngine.js +63 -49
  38. package/dist/errors/SelaError.d.ts +0 -1
  39. package/dist/errors/SelaError.d.ts.map +1 -1
  40. package/dist/errors/SelaError.js +6 -7
  41. package/dist/fixtures/expectProxy.d.ts +1 -1
  42. package/dist/fixtures/expectProxy.js +11 -11
  43. package/dist/fixtures/index.js +14 -14
  44. package/dist/fixtures/proxyTag.d.ts +1 -1
  45. package/dist/fixtures/proxyTag.js +3 -3
  46. package/dist/index.d.ts +8 -8
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +4 -4
  49. package/dist/reporter/SelaReporter.d.ts +45 -12
  50. package/dist/reporter/SelaReporter.d.ts.map +1 -1
  51. package/dist/reporter/SelaReporter.js +139 -39
  52. package/dist/services/ASTSourceUpdater.d.ts +3 -3
  53. package/dist/services/ASTSourceUpdater.d.ts.map +1 -1
  54. package/dist/services/ASTSourceUpdater.js +92 -68
  55. package/dist/services/ArgumentTypeAnalyzer.js +7 -7
  56. package/dist/services/BlastRadiusAnalyzer.d.ts.map +1 -1
  57. package/dist/services/BlastRadiusAnalyzer.js +5 -2
  58. package/dist/services/ChainValidator.js +22 -22
  59. package/dist/services/CrossFileHealer.js +7 -7
  60. package/dist/services/DefinitionTracer.d.ts +1 -1
  61. package/dist/services/DefinitionTracer.d.ts.map +1 -1
  62. package/dist/services/DefinitionTracer.js +28 -13
  63. package/dist/services/DnaEditorService.d.ts +2 -2
  64. package/dist/services/DnaEditorService.d.ts.map +1 -1
  65. package/dist/services/DnaEditorService.js +81 -62
  66. package/dist/services/DnaIndexService.d.ts +1 -1
  67. package/dist/services/DnaIndexService.d.ts.map +1 -1
  68. package/dist/services/DnaIndexService.js +14 -14
  69. package/dist/services/HealReportService.d.ts +6 -6
  70. package/dist/services/HealReportService.d.ts.map +1 -1
  71. package/dist/services/HealReportService.js +33 -29
  72. package/dist/services/HealingAdvisory.js +1 -1
  73. package/dist/services/HealingCacheService.d.ts +8 -8
  74. package/dist/services/HealingCacheService.d.ts.map +1 -1
  75. package/dist/services/HealingCacheService.js +24 -24
  76. package/dist/services/HealthReportService.d.ts +1 -1
  77. package/dist/services/HealthReportService.d.ts.map +1 -1
  78. package/dist/services/HealthReportService.js +25 -25
  79. package/dist/services/InitializerUpdater.js +2 -2
  80. package/dist/services/IntentAuditor.d.ts.map +1 -1
  81. package/dist/services/IntentAuditor.js +32 -21
  82. package/dist/services/InteractiveReview.d.ts +8 -17
  83. package/dist/services/InteractiveReview.d.ts.map +1 -1
  84. package/dist/services/InteractiveReview.js +31 -124
  85. package/dist/services/LLMService.d.ts +1 -1
  86. package/dist/services/LLMService.js +16 -16
  87. package/dist/services/PRAutomationService.d.ts +2 -2
  88. package/dist/services/PRAutomationService.d.ts.map +1 -1
  89. package/dist/services/PRAutomationService.js +43 -39
  90. package/dist/services/PendingPromptLedger.d.ts +2 -2
  91. package/dist/services/PendingPromptLedger.js +6 -6
  92. package/dist/services/ReportGenerator.d.ts +2 -2
  93. package/dist/services/ReportGenerator.d.ts.map +1 -1
  94. package/dist/services/ReportGenerator.js +5 -5
  95. package/dist/services/SafetyGuard.d.ts +3 -6
  96. package/dist/services/SafetyGuard.d.ts.map +1 -1
  97. package/dist/services/SafetyGuard.js +29 -106
  98. package/dist/services/SnapshotService.js +5 -5
  99. package/dist/services/SourceLinkService.d.ts +2 -2
  100. package/dist/services/SourceLinkService.d.ts.map +1 -1
  101. package/dist/services/SourceLinkService.js +31 -22
  102. package/dist/services/SourceUpdater.d.ts +1 -1
  103. package/dist/services/SourceUpdater.d.ts.map +1 -1
  104. package/dist/services/SourceUpdater.js +27 -26
  105. package/dist/services/TemplateDiffService.d.ts.map +1 -1
  106. package/dist/services/TemplateDiffService.js +18 -15
  107. package/dist/services/WorkspaceSnapshotService.d.ts +6 -6
  108. package/dist/services/WorkspaceSnapshotService.d.ts.map +1 -1
  109. package/dist/services/WorkspaceSnapshotService.js +10 -12
  110. package/dist/types/index.d.ts +1 -1
  111. package/dist/utils/IsolatedDiff.d.ts +2 -2
  112. package/dist/utils/IsolatedDiff.d.ts.map +1 -1
  113. package/dist/utils/IsolatedDiff.js +13 -10
  114. package/package.json +2 -2
@@ -91,13 +91,13 @@ class SelaEngine {
91
91
  // pre-scan. Keeping it separate from the SourceUpdater's project avoids
92
92
  // polluting that cache with files we may never actually mutate.
93
93
  this.astDirectiveScanner = new ASTSourceUpdater_1.ASTSourceUpdater();
94
- // Local healing cache short-circuits the LLM call when an identical
94
+ // Local healing cache - short-circuits the LLM call when an identical
95
95
  // (filePath, oldSelector) pair was healed safely in a prior session.
96
96
  // Disabled when SELA_NO_CACHE=1; reads/writes skipped during dry runs.
97
97
  this.healingCache = HealingCacheService_1.sharedHealingCache;
98
98
  }
99
99
  // ─────────────────────────────────────────────────────────────
100
- // healArgument repairs a wrong action argument (e.g. selectOption)
100
+ // healArgument - repairs a wrong action argument (e.g. selectOption)
101
101
  // ─────────────────────────────────────────────────────────────
102
102
  async healArgument(page, selector, action, oldArgument, stableId, filePath, line) {
103
103
  console.log(`[Sela] 🔧 HEALING ARGUMENT for action '${action}': "${oldArgument}"`);
@@ -130,7 +130,7 @@ CRITICAL: Do NOT return a CSS selector like "#my-select". Return plain text only
130
130
  return null;
131
131
  }
132
132
  // ─────────────────────────────────────────────────────────────
133
- // heal repairs a broken selector
133
+ // heal - repairs a broken selector
134
134
  // ─────────────────────────────────────────────────────────────
135
135
  async heal(page, fullSelector, elementSelectorOnly, stableId, filePath, line, healMode = "action") {
136
136
  console.log(`\n[Sela] 🛠️ HEALING START for: ${stableId}`);
@@ -148,7 +148,7 @@ CRITICAL: Do NOT return a CSS selector like "#my-select". Return plain text only
148
148
  catch (directiveErr) {
149
149
  if ((0, SelaError_1.isSelaErrorFrom)(directiveErr, "ASTUpdater") &&
150
150
  directiveErr.code === SelaError_1.AST_UPDATER_CODES.HEAL_DISABLED_BY_DIRECTIVE) {
151
- console.warn(`[Sela] 🛑 Skipped by Developer ${directiveErr.reason}`);
151
+ console.warn(`[Sela] 🛑 Skipped by Developer - ${directiveErr.reason}`);
152
152
  const skipEvent = {
153
153
  kind: "FAILED",
154
154
  stableId,
@@ -218,10 +218,10 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
218
218
  return "";
219
219
  const lines = [];
220
220
  if (anchors.closestLabel) {
221
- lines.push(`- Label: "${anchors.closestLabel}" the UI label or heading associated with this element.`);
221
+ lines.push(`- Label: "${anchors.closestLabel}" - the UI label or heading associated with this element.`);
222
222
  }
223
223
  if (anchors.rowAnchor) {
224
- lines.push(`- Row key: "${anchors.rowAnchor}" unique cell text identifying the table row this element belonged to.`);
224
+ lines.push(`- Row key: "${anchors.rowAnchor}" - unique cell text identifying the table row this element belonged to.`);
225
225
  }
226
226
  if (lines.length === 0)
227
227
  return "";
@@ -236,12 +236,12 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
236
236
  // pair AND SafetyGuard cleared it, replay the cached fix instead
237
237
  // of paying the LLM round-trip. Disabled when SELA_NO_CACHE=1.
238
238
  // The synthetic aiFix is fed through SafetyGuard exactly like a
239
- // fresh LLM response cache is a latency optimisation, never a
239
+ // fresh LLM response - cache is a latency optimisation, never a
240
240
  // safety bypass.
241
241
  let aiFix = null;
242
242
  let cacheHit = false;
243
243
  // Fingerprint inputs the cache key depends on. Recomputed every
244
- // heal so a DNA rewrite which changes `dnaContentHash`
244
+ // heal so a DNA rewrite - which changes `dnaContentHash` -
245
245
  // automatically invalidates every prior entry without an explicit
246
246
  // purge.
247
247
  const dnaContentHash = (0, HealingCacheService_1.hashDnaContent)(lastKnownState ?? null);
@@ -255,13 +255,14 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
255
255
  if (!this.config.noCache) {
256
256
  const cached = this.healingCache.get(cacheKeyInput);
257
257
  if (cached) {
258
- console.log(`[Sela] 🧊 Cache hit (0ms LLM) replaying healed selector "${cached.healedSelector}"`);
258
+ console.log(`[Sela] 🧊 Cache hit (0ms LLM) - replaying healed selector "${cached.healedSelector}"`);
259
259
  aiFix = {
260
260
  status: "FIXED",
261
261
  new_selector: cached.healedSelector,
262
262
  chainSegments: cached.chainSegments,
263
- segments: cached.segments ??
264
- [{ type: "element", selector: cached.healedSelector }],
263
+ segments: cached.segments ?? [
264
+ { type: "element", selector: cached.healedSelector },
265
+ ],
265
266
  confidence: cached.confidence,
266
267
  contentChange: cached.contentChange,
267
268
  explanation: cached.explanation ?? "Replayed from local healing cache",
@@ -308,7 +309,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
308
309
  console.log(`[Sela] 🔍 Step 3.5: Live text fetch skipped (element not yet rendered or non-text)`);
309
310
  }
310
311
  // ── Step 3.6: Atomic v2 capture of the candidate element ──
311
- // Single page.evaluate() call collects visibility, ancestry,
312
+ // Single page.evaluate() call - collects visibility, ancestry,
312
313
  // and anchors of the healed element for SafetyGuard use.
313
314
  // Returns null on any failure; never blocks the heal.
314
315
  const liveSnapshot = await this.snapshotService.captureElement(page, elementOnlySelector, successfulPath);
@@ -321,7 +322,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
321
322
  : "";
322
323
  const occFlag = liveVisibility?.isOccluded ? " 🫥 OCCLUDED" : "";
323
324
  console.log(`[Sela] 🔍 Step 3.6: Live v2 capture complete` +
324
- `${ghostFlag}${occFlag} ancestry depth: ${liveAncestry?.length ?? 0}`);
325
+ `${ghostFlag}${occFlag} - ancestry depth: ${liveAncestry?.length ?? 0}`);
325
326
  }
326
327
  else {
327
328
  console.log(`[Sela] 🔍 Step 3.6: Live v2 capture skipped`);
@@ -355,7 +356,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
355
356
  }
356
357
  // ── Report: PROTECTED (or BLOCKED non-INCONSISTENT) ─────────
357
358
  // The auto-fix was blocked. If the auditor verdict is INCONSISTENT
358
- // this is a "Security Win" a masked regression was caught.
359
+ // this is a "Security Win" - a masked regression was caught.
359
360
  const protectedEvent = {
360
361
  kind: "PROTECTED",
361
362
  stableId,
@@ -407,7 +408,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
407
408
  parts.push(`${breakdown.penalty} ancestry drift`);
408
409
  if (breakdown.bonus !== 0)
409
410
  parts.push(`+${breakdown.bonus} anchor match`);
410
- console.log(`[Sela] 📊 Score AI: ${fmtPctEngine(aiFix.confidence)} | ` +
411
+ console.log(`[Sela] 📊 Score - AI: ${fmtPctEngine(aiFix.confidence)} | ` +
411
412
  `Auditor: ${fmtPctEngine(breakdown.adjustedConfidence)} ` +
412
413
  `(raw ${fmtPctEngine(breakdown.rawConfidence)}, ${parts.join(", ")})`);
413
414
  }
@@ -417,7 +418,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
417
418
  // 1. updateResult.lineUpdated (the strategy's literal write location)
418
419
  // 2. updateResult.definitionSite.line (semantic JumpToDef target,
419
420
  // used when the mutation crossed into a const/variable declaration)
420
- // 3. line (the original failure line last-resort fallback)
421
+ // 3. line (the original failure line - last-resort fallback)
421
422
  // For cross-file definitionSite.file, we still read the new line from
422
423
  // the SAME file that was mutated.
423
424
  const defSite = updateResult.definitionSite;
@@ -430,7 +431,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
430
431
  line;
431
432
  const mutatedFilePath = !sameFileDef && defSite ? defSite.file : filePath;
432
433
  // Clean-Room isolated diff. We diff the in-memory snapshot recorded
433
- // by WorkspaceSnapshotService (contentBefore disk state right
434
+ // by WorkspaceSnapshotService (contentBefore - disk state right
434
435
  // before Sela's first write to this file) against the post-write
435
436
  // disk state. The result contains EXCLUSIVELY Sela's selector swap;
436
437
  // any developer dirty edits sit identically in both buffers and
@@ -441,12 +442,14 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
441
442
  // Backward-compat: keep oldCodeLine/newCodeLine populated from the
442
443
  // first -/+ pair inside the diff. When git produced no diff (file
443
444
  // untracked, git unavailable, …) fall back to a direct disk read of
444
- // the mutated line strictly inferior but preserves old reports.
445
- const oldCodeLine = firstChange.oldLine ?? this._safeReadLine(mutatedFilePath, writtenLine);
446
- const newCodeLine = firstChange.newLine ?? this._safeReadLine(mutatedFilePath, writtenLine);
445
+ // the mutated line - strictly inferior but preserves old reports.
446
+ const oldCodeLine = firstChange.oldLine ??
447
+ this._safeReadLine(mutatedFilePath, writtenLine);
448
+ const newCodeLine = firstChange.newLine ??
449
+ this._safeReadLine(mutatedFilePath, writtenLine);
447
450
  const canonicalSelector = updateResult.healedLocatorString ?? newFullSelector;
448
451
  console.log(`[Sela] ✅ Canonical selector (disk == runtime): "${canonicalSelector}"`);
449
- // Buffer CLI-ready metadata merged into DNA at commitUpdates() time.
452
+ // Buffer CLI-ready metadata - merged into DNA at commitUpdates() time.
450
453
  // Sanitize filePath: strip any residual "at " stack-trace prefix + whitespace,
451
454
  // then resolve to an absolute path before converting to project-relative form.
452
455
  const match = filePath.match(/at\s+(.*)/i);
@@ -515,7 +518,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
515
518
  contentChange: aiFix.contentChange,
516
519
  };
517
520
  HealReportService_1.sharedHealReport.record(healedEvent);
518
- // ── Cache write persist this safe heal for future sessions ──
521
+ // ── Cache write - persist this safe heal for future sessions ──
519
522
  // Best-effort: failures are logged inside the service and never
520
523
  // block the heal return. Skipped automatically during dry runs
521
524
  // and when SELA_NO_CACHE=1.
@@ -536,7 +539,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
536
539
  }
537
540
  return canonicalSelector;
538
541
  }
539
- // AI did not return FIXED record as FAILED.
542
+ // AI did not return FIXED - record as FAILED.
540
543
  const failedEvent = {
541
544
  kind: "FAILED",
542
545
  stableId,
@@ -562,9 +565,12 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
562
565
  // Prefer the structured instanceof check; fall back to message-substring
563
566
  // detection for any legacy throw sites that have not yet been migrated.
564
567
  const isSafetyBlock = (0, SelaError_1.isSelaErrorFrom)(error, "SafetyGuard") ||
565
- (typeof error?.message === "string" && error.message.includes("[Sela-SafetyGuard]")) ||
566
- (typeof error?.message === "string" && error.message.includes("[SafetyGuard]"));
567
- const isNotFoundAlreadyRecorded = typeof error?.message === "string" && error.message === "AI could not provide a fix";
568
+ (typeof error?.message === "string" &&
569
+ error.message.includes("[Sela-SafetyGuard]")) ||
570
+ (typeof error?.message === "string" &&
571
+ error.message.includes("[SafetyGuard]"));
572
+ const isNotFoundAlreadyRecorded = typeof error?.message === "string" &&
573
+ error.message === "AI could not provide a fix";
568
574
  if (!isSafetyBlock && !isNotFoundAlreadyRecorded) {
569
575
  const failedEvent = {
570
576
  kind: "FAILED",
@@ -594,14 +600,20 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
594
600
  if (!filePath)
595
601
  return "";
596
602
  const match = filePath.match(/at\s+(.*)/i);
597
- const cleaned = (match ? match[1] : filePath).replace(/^\(|\)$/g, "").trim();
598
- const abs = path.isAbsolute(cleaned) ? cleaned : path.resolve(process.cwd(), cleaned);
603
+ const cleaned = (match ? match[1] : filePath)
604
+ .replace(/^\(|\)$/g, "")
605
+ .trim();
606
+ const abs = path.isAbsolute(cleaned)
607
+ ? cleaned
608
+ : path.resolve(process.cwd(), cleaned);
599
609
  return path.relative(process.cwd(), abs) || abs;
600
610
  }
601
611
  _safeReadLine(filePath, lineNumber) {
602
612
  try {
603
613
  const cleaned = this._toReportFile(filePath);
604
- const abs = path.isAbsolute(cleaned) ? cleaned : path.resolve(process.cwd(), cleaned);
614
+ const abs = path.isAbsolute(cleaned)
615
+ ? cleaned
616
+ : path.resolve(process.cwd(), cleaned);
605
617
  if (!fs.existsSync(abs))
606
618
  return "";
607
619
  const lines = fs.readFileSync(abs, "utf8").split(/\r?\n/);
@@ -654,7 +666,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
654
666
  * `gitUnifiedDiff` payload yet.
655
667
  *
656
668
  * Carefully skips the diff preamble (--- a/file, +++ b/file, "diff ",
657
- * "index ", rename headers) those lines would otherwise be mistaken for
669
+ * "index ", rename headers) - those lines would otherwise be mistaken for
658
670
  * a -/+ change pair and produce nonsense like the original "line replaced
659
671
  * by itself" output. Real change lines only count once the parser has seen
660
672
  * a "@@" hunk header.
@@ -694,7 +706,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
694
706
  if (!meta || !meta.auditorVerdict)
695
707
  return null;
696
708
  // Keep auditor confidence as `undefined` when SafetyGuard did not produce
697
- // one the renderer fmtPct helper turns it into "n/a" rather than 0%.
709
+ // one - the renderer fmtPct helper turns it into "n/a" rather than 0%.
698
710
  const conf = typeof meta.auditorConfidence === "number" &&
699
711
  Number.isFinite(meta.auditorConfidence)
700
712
  ? meta.auditorConfidence
@@ -766,15 +778,16 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
766
778
  _buildReasoningSteps(ctx) {
767
779
  const steps = [];
768
780
  if (ctx.dnaTag || ctx.dnaText) {
769
- steps.push(`Recovered DNA baseline previously a <${ctx.dnaTag ?? "?"}>` +
770
- (ctx.dnaText ? ` with text "${ctx.dnaText}"` : "") + ".");
781
+ steps.push(`Recovered DNA baseline - previously a <${ctx.dnaTag ?? "?"}>` +
782
+ (ctx.dnaText ? ` with text "${ctx.dnaText}"` : "") +
783
+ ".");
771
784
  }
772
785
  if (ctx.successfulPath.length > 0) {
773
786
  steps.push(`Resolved DOM context inside ${ctx.successfulPath.length} nested frame(s): ${ctx.successfulPath.join(" >> ")}.`);
774
787
  }
775
788
  const firstSeg = ctx.aiFix.chainSegments?.[0];
776
789
  if (firstSeg) {
777
- steps.push(`AI preserved the ${firstSeg.type} pattern semantic locator over raw CSS path.`);
790
+ steps.push(`AI preserved the ${firstSeg.type} pattern - semantic locator over raw CSS path.`);
778
791
  }
779
792
  if (ctx.aiFix.explanation) {
780
793
  steps.push(`AI reasoning: ${ctx.aiFix.explanation}`);
@@ -783,7 +796,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
783
796
  if (ctx.aiFix.contentChange) {
784
797
  steps.push(`Detected content drift: "${ctx.aiFix.contentChange.oldText}" → "${ctx.aiFix.contentChange.newText}".`);
785
798
  }
786
- steps.push(`SafetyGuard verdict: ${ctx.safetyLevel} change cleared for write.`);
799
+ steps.push(`SafetyGuard verdict: ${ctx.safetyLevel} - change cleared for write.`);
787
800
  steps.push(`Source updated via ${ctx.strategy} at line ${ctx.writtenLine}.`);
788
801
  if (ctx.blastRadius != null && ctx.blastRadius > 0) {
789
802
  steps.push(`Blast radius: ${ctx.blastRadius} dependent test reference(s) inherited the fix.`);
@@ -808,7 +821,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
808
821
  this.testTitleBuffer.clear();
809
822
  SourceUpdater_1.SourceUpdater.flushAdvisories();
810
823
  }
811
- // ── Sela Insights render the transparent healing report ───────
824
+ // ── Sela Insights - render the transparent healing report ───────
812
825
  let reportHtmlPath = null;
813
826
  const healedEvents = HealReportService_1.sharedHealReport.getHealedEvents();
814
827
  const protectedEvents = HealReportService_1.sharedHealReport.getProtectedEvents();
@@ -827,11 +840,12 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
827
840
  // ── Dual-Mode post-run lifecycle ─────────────────────────────────
828
841
  //
829
842
  // CI (process.env.CI truthy) → Clean-Room PR automation (existing flow).
830
- // Local DX (CI falsy) → Interactive CLI review of each mutated
831
- // file; Apply keeps the on-disk fix, Reject
832
- // rewinds via WorkspaceSnapshotService.
843
+ // Local DX (CI falsy) → Write-and-notify: AST mutations are
844
+ // already on disk; the reporter prints a
845
+ // diff + vscode:// deeplink + report link
846
+ // via printHealReview() (no Y/N prompt).
833
847
  //
834
- // The interactive branch deliberately bypasses PR automation because:
848
+ // The local branch deliberately bypasses PR automation because:
835
849
  // • AST fixes are ALREADY persisted to disk (the test passed on them).
836
850
  // • Local devs want to inspect + cherry-pick, not auto-commit.
837
851
  if (isCiEnvironment()) {
@@ -858,11 +872,11 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
858
872
  }
859
873
  }
860
874
  else if (healedEvents.length > 0) {
861
- // Local DX: do NOT block this process on stdin — workers have no
862
- // TTY and would deadlock until Playwright's per-test timeout fires.
863
- // Serialise the mutated snapshots to a cross-process ledger; the
864
- // SelaReporter drains it from `onEnd()` in the main process where
865
- // an interactive `readline` is safe.
875
+ // Local DX: serialise the mutated snapshots to a cross-process
876
+ // ledger. The SelaReporter drains it from `onEnd()` in the main
877
+ // process and prints a non-blocking summary (diff + vscode://
878
+ // deeplink). Mutations are already on disk - the ledger only
879
+ // exists so the reporter knows what to narrate.
866
880
  try {
867
881
  (0, PendingPromptLedger_1.writePendingPromptsLedger)({
868
882
  cwd: process.cwd(),
@@ -887,12 +901,12 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
887
901
  WorkspaceSnapshotService_1.sharedWorkspaceSnapshot.clear();
888
902
  }
889
903
  // ─────────────────────────────────────────────────────────────
890
- // fetchLiveText frame-aware innerText fetch (zero-trust probe)
904
+ // fetchLiveText - frame-aware innerText fetch (zero-trust probe)
891
905
  //
892
906
  // Navigates the frame chain encoded in successfulPath, then calls
893
907
  // .first().innerText() on the element-only selector. Uses a short
894
908
  // 1.5 s timeout so it never adds meaningful latency. Returns null
895
- // on ANY failure the caller must treat null as "no data" and skip
909
+ // on ANY failure - the caller must treat null as "no data" and skip
896
910
  // live verification rather than blocking the heal.
897
911
  // ─────────────────────────────────────────────────────────────
898
912
  async fetchLiveText(page, elementOnlySelector, framePath) {
@@ -923,7 +937,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
923
937
  p === "frame" ||
924
938
  p.includes("frame-"));
925
939
  if (aiHasFrameSegments) {
926
- console.log(`[Sela] 🔗 AI returned full frame path using directly: ${aiNewSelector}`);
940
+ console.log(`[Sela] 🔗 AI returned full frame path - using directly: ${aiNewSelector}`);
927
941
  return aiNewSelector;
928
942
  }
929
943
  return [...frameParts, ...aiParts].join(" >> ");
@@ -951,7 +965,7 @@ If the text has NOT changed, omit the "contentChange" field entirely.`;
951
965
  return arrayOfFiles;
952
966
  }
953
967
  // ─────────────────────────────────────────────────────────────
954
- // captureSuccessfulElement capture and buffer a v2 DNA snapshot.
968
+ // captureSuccessfulElement - capture and buffer a v2 DNA snapshot.
955
969
  //
956
970
  // Replaces the previous DOMUtils.getElementDNA() path with a single
957
971
  // captureElement() call that collects all v2 metrics atomically.
@@ -63,7 +63,6 @@ export declare const SAFETY_GUARD_CODES: {
63
63
  readonly BLOCKED_ROLE_SWAP_ASSERTION: "SG_BLOCKED_ROLE_SWAP_ASSERTION";
64
64
  readonly FAIL_HARD_AUDITOR_INCONSISTENT: "SG_FAIL_HARD_AUDITOR_INCONSISTENT";
65
65
  readonly BLOCKED_AUDITOR_SUSPICIOUS: "SG_BLOCKED_AUDITOR_SUSPICIOUS";
66
- readonly BLOCKED_SIMILARITY_FLOOR: "SG_BLOCKED_SIMILARITY_FLOOR";
67
66
  /** Generic dispatcher when SafetyDecision arrives without an explicit code. */
68
67
  readonly GENERIC_REJECTION: "SG_GENERIC_REJECTION";
69
68
  };
@@ -1 +1 @@
1
- {"version":3,"file":"SelaError.d.ts","sourceRoot":"","sources":["../../src/errors/SelaError.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SelaError.d.ts","sourceRoot":"","sources":["../../src/errors/SelaError.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ exports.CHAIN_VALIDATOR_CODES = exports.REPORT_CODES = exports.REGISTRY_CODES =
17
17
  exports.isSelaError = isSelaError;
18
18
  exports.isSelaErrorFrom = isSelaErrorFrom;
19
19
  // ───────────────────────────────────────────────────────────────────
20
- // SelaError single class for the whole hierarchy.
20
+ // SelaError - single class for the whole hierarchy.
21
21
  //
22
22
  // We intentionally avoid a tree of subclasses; `instanceof SelaError` +
23
23
  // `err.subsystem === "X"` is more flexible for callers and keeps the
@@ -31,7 +31,7 @@ class SelaError extends Error {
31
31
  context;
32
32
  constructor(init) {
33
33
  if (!CODE_PATTERN.test(init.code)) {
34
- throw new Error(`[SelaError] invalid code "${init.code}" must match ${CODE_PATTERN}`);
34
+ throw new Error(`[SelaError] invalid code "${init.code}" - must match ${CODE_PATTERN}`);
35
35
  }
36
36
  const formatted = SelaError.formatMessage(init.subsystem, init.code, init.reason);
37
37
  super(formatted);
@@ -45,9 +45,9 @@ class SelaError extends Error {
45
45
  }
46
46
  // Maintain prototype chain through transpilation (ES5 target).
47
47
  Object.setPrototypeOf(this, new.target.prototype);
48
- if (typeof Error.captureStackTrace === "function") {
49
- Error
50
- .captureStackTrace(this, new.target);
48
+ if (typeof Error.captureStackTrace ===
49
+ "function") {
50
+ Error.captureStackTrace(this, new.target);
51
51
  }
52
52
  }
53
53
  static formatMessage(subsystem, code, reason) {
@@ -81,7 +81,7 @@ function isSelaErrorFrom(err, subsystem) {
81
81
  // ───────────────────────────────────────────────────────────────────
82
82
  // Canonical code catalogue
83
83
  //
84
- // Tests assert against these constants never hand-write code strings
84
+ // Tests assert against these constants - never hand-write code strings
85
85
  // at throw sites. Adding a new code requires adding it here first so
86
86
  // the catalogue stays in sync with the error-indicativity contract.
87
87
  // ───────────────────────────────────────────────────────────────────
@@ -94,7 +94,6 @@ exports.SAFETY_GUARD_CODES = {
94
94
  BLOCKED_ROLE_SWAP_ASSERTION: "SG_BLOCKED_ROLE_SWAP_ASSERTION",
95
95
  FAIL_HARD_AUDITOR_INCONSISTENT: "SG_FAIL_HARD_AUDITOR_INCONSISTENT",
96
96
  BLOCKED_AUDITOR_SUSPICIOUS: "SG_BLOCKED_AUDITOR_SUSPICIOUS",
97
- BLOCKED_SIMILARITY_FLOOR: "SG_BLOCKED_SIMILARITY_FLOOR",
98
97
  /** Generic dispatcher when SafetyDecision arrives without an explicit code. */
99
98
  GENERIC_REJECTION: "SG_GENERIC_REJECTION",
100
99
  };
@@ -1,7 +1,7 @@
1
1
  import { Locator } from "@playwright/test";
2
2
  import { SelaEngine } from "../engine/SelaEngine";
3
3
  /**
4
- * createHealingExpect drop-in replacement for Playwright's expect().
4
+ * createHealingExpect - drop-in replacement for Playwright's expect().
5
5
  *
6
6
  * @param resolveProxy Optional callback that unwraps a Fixwright proxy
7
7
  * to its current live Locator. Supplied by
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // src/fixtures/expectProxy.ts full replacement
2
+ // src/fixtures/expectProxy.ts - full replacement
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.createHealingExpect = createHealingExpect;
5
5
  const test_1 = require("@playwright/test");
@@ -17,7 +17,7 @@ function isElementNotFoundError(err) {
17
17
  return ELEMENT_NOT_FOUND_PATTERNS.some((p) => p.test(err.message));
18
18
  }
19
19
  /**
20
- * Returns true only for genuine Playwright Locator instances
20
+ * Returns true only for genuine Playwright Locator instances -
21
21
  * not FrameLocator proxies or Fixwright proxy objects.
22
22
  *
23
23
  * A real Locator has _frame internally.
@@ -31,7 +31,7 @@ function isRealLocator(value) {
31
31
  if (typeof value !== "object")
32
32
  return false;
33
33
  // Fixwright locator proxies expose `_fixwrightSelector`. The proxy forwards
34
- // `_frame` via Reflect.get so `hasFrame` would lie explicitly reject them
34
+ // `_frame` via Reflect.get so `hasFrame` would lie - explicitly reject them
35
35
  // here. Callers should unwrap via `resolveProxy` first.
36
36
  if (value._fixwrightSelector !== undefined)
37
37
  return false;
@@ -63,7 +63,7 @@ function extractSelectorFromLocator(locator) {
63
63
  * frame segments (e.g. "#modern-frame-container >> #status-label-v2").
64
64
  *
65
65
  * A plain page.locator() call with a frame >> element string is NOT
66
- * a valid locator for frame content Playwright rejects it with
66
+ * a valid locator for frame content - Playwright rejects it with
67
67
  * "toHaveText can be only used with Locator object".
68
68
  *
69
69
  * This function correctly chains frameLocator() calls for each frame
@@ -128,13 +128,13 @@ function wrapMatcher(matcher, locator, matcherName, engine, page, ctx) {
128
128
  if (!rawSelector)
129
129
  throw err;
130
130
  console.log(`[Sela] ⚠️ Assertion failed for "${rawSelector}", attempting heal…`);
131
- // Fast path already healed in this test via registry
131
+ // Fast path - already healed in this test via registry
132
132
  const resolved = HealingRegistry_1.HealingRegistry.getInstance().resolveSelector(rawSelector, ctx);
133
133
  let healedSelector = resolved;
134
134
  if (resolved === rawSelector) {
135
- // Slow path ask the engine + LLM.
135
+ // Slow path - ask the engine + LLM.
136
136
  // engine.heal() writes the fix to disk AND returns the canonical
137
- // healedLocatorString from SourceUpdater the exact same string
137
+ // healedLocatorString from SourceUpdater - the exact same string
138
138
  // that was saved to the file. This is the handshake that guarantees
139
139
  // disk and runtime are in sync (no "ghost failures").
140
140
  const stableId = require("crypto")
@@ -182,7 +182,7 @@ const WRAPPED_MATCHERS = [
182
182
  "toBeFocused",
183
183
  ];
184
184
  /**
185
- * createHealingExpect drop-in replacement for Playwright's expect().
185
+ * createHealingExpect - drop-in replacement for Playwright's expect().
186
186
  *
187
187
  * @param resolveProxy Optional callback that unwraps a Fixwright proxy
188
188
  * to its current live Locator. Supplied by
@@ -204,7 +204,7 @@ resolveProxy) {
204
204
  return initialLine;
205
205
  };
206
206
  const actualLine = getCallerLine(); // כאן אנחנו מקבלים את השורה הנכונה!
207
- // Step 1 unwrap Fixwright proxy to real active Locator
207
+ // Step 1 - unwrap Fixwright proxy to real active Locator
208
208
  let resolved = locatorOrValue;
209
209
  if (resolveProxy) {
210
210
  const unwrapped = resolveProxy(locatorOrValue);
@@ -217,7 +217,7 @@ resolveProxy) {
217
217
  if (base === null || typeof base !== "object") {
218
218
  return base;
219
219
  }
220
- // Step 2 only wrap matchers for genuine page-level Locator objects.
220
+ // Step 2 - only wrap matchers for genuine page-level Locator objects.
221
221
  if (!isRealLocator(resolved)) {
222
222
  return base;
223
223
  }
@@ -226,7 +226,7 @@ resolveProxy) {
226
226
  const ctx = { filePath, line: actualLine };
227
227
  const proxy = new Proxy(base, {
228
228
  get(target, prop) {
229
- // Sela proxy identity honored before any string-only branch so
229
+ // Sela proxy identity - honored before any string-only branch so
230
230
  // callers can detect a Sela expect proxy via Symbol.for("sela.proxy").
231
231
  if (prop === proxyTag_1.SELA_PROXY)
232
232
  return "expect";
@@ -47,7 +47,7 @@ const fs = __importStar(require("fs"));
47
47
  const path = __importStar(require("path"));
48
48
  const registry = HealingRegistry_1.HealingRegistry.getInstance();
49
49
  const proxyToActiveLocator = new WeakMap();
50
- // Module-level resolver moduleExpect.ts uses this to unwrap a Fixwright
50
+ // Module-level resolver - moduleExpect.ts uses this to unwrap a Fixwright
51
51
  // locator proxy back to its live underlying Playwright Locator without
52
52
  // needing access to the WeakMap directly.
53
53
  function resolveFixwrightProxy(value) {
@@ -157,7 +157,7 @@ const GET_BY_METHODS = {
157
157
  getByTitle: (args) => `internal:attr=[title=${JSON.stringify(args[0])}]`,
158
158
  };
159
159
  // ─────────────────────────────────────────────────────────────────
160
- // buildLiveLocator registry-aware
160
+ // buildLiveLocator - registry-aware
161
161
  //
162
162
  // NEW: resolves the selector through the HealingRegistry before
163
163
  // constructing the Playwright Locator. Zero cost when no heal has
@@ -240,7 +240,7 @@ function buildHealedArgs(prop, args, timeout = 8000) {
240
240
  // runWithHealArgument (unchanged from original)
241
241
  // ─────────────────────────────────────────────────────────────────
242
242
  async function runWithHealArgument(rawPage, prop, args, fullSelector, stableId, callerInfo, originalError) {
243
- console.log(`[Sela] 💡 Element visible, action '${prop}' failed healing argument…`);
243
+ console.log(`[Sela] 💡 Element visible, action '${prop}' failed - healing argument…`);
244
244
  const oldArgument = typeof args[0] === "string" ? args[0] : JSON.stringify(args[0]);
245
245
  const newArgument = await singleton_1.sharedEngine.healArgument(rawPage, fullSelector, prop, oldArgument, stableId, callerInfo.filePath, callerInfo.line);
246
246
  if (!newArgument)
@@ -250,11 +250,11 @@ async function runWithHealArgument(rawPage, prop, args, fullSelector, stableId,
250
250
  return await locator[prop](...healedArgs);
251
251
  }
252
252
  // ─────────────────────────────────────────────────────────────────
253
- // runWithHeal pre-flight registry check added
253
+ // runWithHeal - pre-flight registry check added
254
254
  //
255
255
  // NEW: Before the first Playwright attempt, resolve the selector
256
256
  // through the registry. If a previous heal already mapped it, the
257
- // first attempt uses the healed selector and succeeds immediately
257
+ // first attempt uses the healed selector and succeeds immediately -
258
258
  // no timeout, no AI call, no file write.
259
259
  // ─────────────────────────────────────────────────────────────────
260
260
  async function runWithHeal(rawPage, prop, args, fullSelector, elementSelectorOnly, stableId, callerInfo) {
@@ -451,7 +451,7 @@ function createFrameLocatorProxy(rawFrameLocator, frameSelector, rawPage, testTi
451
451
  : frameSelector;
452
452
  return new Proxy(rawFrameLocator, {
453
453
  get(fTarget, fProp) {
454
- // Sela proxy identity honor before the string-only fast path so
454
+ // Sela proxy identity - honor before the string-only fast path so
455
455
  // symbol probes from tests / debuggers return the kind tag.
456
456
  if (fProp === proxyTag_1.SELA_PROXY)
457
457
  return "framelocator";
@@ -468,13 +468,13 @@ function createFrameLocatorProxy(rawFrameLocator, frameSelector, rawPage, testTi
468
468
  });
469
469
  }
470
470
  // ─────────────────────────────────────────────────────────────────
471
- // createLocatorProxy Runtime Selector Injection added
471
+ // createLocatorProxy - Runtime Selector Injection added
472
472
  //
473
473
  // NEW additions vs original:
474
474
  // 1. Resolves selector through registry on creation (handles proxies
475
475
  // born after a heal has already broadcast).
476
476
  // 2. Subscribes to registry so any future broadcast swaps
477
- // activeLocator on the same tick before the next await.
477
+ // activeLocator on the same tick - before the next await.
478
478
  // 3. Exposes _fixwrightUnsubscribe so the fixture can clean up.
479
479
  // ─────────────────────────────────────────────────────────────────
480
480
  function createLocatorProxy(rawLocator, selector, rawPage, testTitle, actionCounter, elementSelectorOnly) {
@@ -494,7 +494,7 @@ function createLocatorProxy(rawLocator, selector, rawPage, testTitle, actionCoun
494
494
  ? buildLiveLocator(rawPage, initialResolved) // already healed
495
495
  : rawLocator; // fresh, use as-is
496
496
  // ── Subscribe: swap activeLocator when a heal fires ──────────
497
- // Inside createLocatorProxy full updated subscribe block
497
+ // Inside createLocatorProxy - full updated subscribe block
498
498
  // בתוך createLocatorProxy - תחליף את הבלוק של ה-subscribe בזה:
499
499
  const unsubscribe = registry.subscribe((fp, oldSel, newSel) => {
500
500
  // בדיקה אם הסלקטור הנוכחי מכיל את הישן או שהוא הישן בעצמו
@@ -524,7 +524,7 @@ function createLocatorProxy(rawLocator, selector, rawPage, testTitle, actionCoun
524
524
  });
525
525
  const proxy = new Proxy(rawLocator, {
526
526
  get(target, prop, receiver) {
527
- // Sela proxy identity must be honored before any string-only branch
527
+ // Sela proxy identity - must be honored before any string-only branch
528
528
  // so callers can reliably detect a Sela proxy via Symbol.for("sela.proxy").
529
529
  if (prop === proxyTag_1.SELA_PROXY)
530
530
  return "locator";
@@ -657,9 +657,9 @@ function createLocatorProxy(rawLocator, selector, rawPage, testTitle, actionCoun
657
657
  return proxy;
658
658
  }
659
659
  // ─────────────────────────────────────────────────────────────────
660
- // test fixture teardown added
660
+ // test fixture - teardown added
661
661
  // ─────────────────────────────────────────────────────────────────
662
- // ─── expect healing proxy replacing the plain baseExpect proxy ──────────────
662
+ // ─── expect - healing proxy replacing the plain baseExpect proxy ──────────────
663
663
  exports.test = test_1.test.extend({
664
664
  page: async ({ page }, use, testInfo) => {
665
665
  page.on("console", (msg) => {
@@ -672,7 +672,7 @@ exports.test = test_1.test.extend({
672
672
  const unsubscribers = [];
673
673
  const pageProxy = new Proxy(page, {
674
674
  get(target, prop) {
675
- // Sela proxy identity honored before any other branch so callers
675
+ // Sela proxy identity - honored before any other branch so callers
676
676
  // can reliably detect a Sela page proxy via Symbol.for("sela.proxy").
677
677
  if (prop === proxyTag_1.SELA_PROXY)
678
678
  return "page";
@@ -714,7 +714,7 @@ exports.test = test_1.test.extend({
714
714
  },
715
715
  expect: async ({ page }, use, testInfo) => {
716
716
  const healingExpect = (0, expectProxy_1.createHealingExpect)(singleton_1.sharedEngine, page, testInfo.file, 0,
717
- // Inject proxy resolver gives expectProxy.ts access to the live
717
+ // Inject proxy resolver - gives expectProxy.ts access to the live
718
718
  // active Locator without exposing the WeakMap directly.
719
719
  (value) => {
720
720
  if (value && typeof value === "object") {
@@ -3,7 +3,7 @@ export type SelaProxyKind = "locator" | "framelocator" | "page" | "expect";
3
3
  /**
4
4
  * Returns the proxy kind if `v` is a Sela proxy, otherwise `null`.
5
5
  *
6
- * Performs no instanceof checks against Playwright internals relies
6
+ * Performs no instanceof checks against Playwright internals - relies
7
7
  * solely on the `SELA_PROXY` symbol contract. Always safe to call on
8
8
  * arbitrary values (null/undefined/primitive → null).
9
9
  */