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
@@ -10,12 +10,11 @@ const SelaError_1 = require("../errors/SelaError");
10
10
  const DEFAULT_THRESHOLDS = {
11
11
  confidenceHardStop: 85,
12
12
  confidenceReviewThreshold: 95,
13
- assertionSimilarityFloor: 0.7,
14
13
  auditorConfidenceMin: 75,
15
14
  allowSuspicious: false,
16
15
  auditorStrictness: "balanced",
17
16
  };
18
- // Binary semantic opposites always trigger FAIL_HARD regardless of mode,
17
+ // Binary semantic opposites - always trigger FAIL_HARD regardless of mode,
19
18
  // because they indicate a state inversion (pass→fail, success→error, etc.)
20
19
  // that almost certainly masks a real logical regression.
21
20
  const SEMANTIC_OPPOSITE_PAIRS = new Set([
@@ -190,7 +189,7 @@ const ROLE_KEYWORDS = new Map([
190
189
  ],
191
190
  ]);
192
191
  // Pre-compiled word-boundary regexes for the role classifier. Built
193
- // once at module load classifyFunctionalRole() is on the hot heal
192
+ // once at module load - classifyFunctionalRole() is on the hot heal
194
193
  // path, so we don't pay for regex construction per call.
195
194
  const ROLE_KEYWORD_REGEXES = Array.from(ROLE_KEYWORDS, ([role, keywords]) => ({
196
195
  role,
@@ -242,7 +241,7 @@ class SafetyGuard {
242
241
  return {
243
242
  level: "FAIL_HARD",
244
243
  code: SelaError_1.SAFETY_GUARD_CODES.FAIL_HARD_VISIBILITY_GHOST,
245
- reason: `Visibility Gate: candidate element is a Ghost (${vis.ghostReason}) ` +
244
+ reason: `Visibility Gate: candidate element is a Ghost (${vis.ghostReason}) - ` +
246
245
  `functionally absent from the user's perspective`,
247
246
  canProceed: false,
248
247
  };
@@ -253,12 +252,12 @@ class SafetyGuard {
253
252
  return {
254
253
  level: "FAIL_HARD",
255
254
  code: SelaError_1.SAFETY_GUARD_CODES.FAIL_HARD_VISIBILITY_OCCLUDED,
256
- reason: `Visibility Gate: candidate element is occluded by an overlay on branch "${context.branch}" ` +
255
+ reason: `Visibility Gate: candidate element is occluded by an overlay on branch "${context.branch}" - ` +
257
256
  `hard-fail policy active on main`,
258
257
  canProceed: false,
259
258
  };
260
259
  }
261
- console.warn(`[SafetyGuard] ⚠️ Occlusion detected on branch "${context.branch ?? "unknown"}" ` +
260
+ console.warn(`[SafetyGuard] ⚠️ Occlusion detected on branch "${context.branch ?? "unknown"}" - ` +
262
261
  `escalating to REQUIRES_REVIEW (not hard-failing on non-main branch)`);
263
262
  return {
264
263
  level: "REQUIRES_REVIEW",
@@ -273,7 +272,7 @@ class SafetyGuard {
273
272
  return {
274
273
  level: "BLOCKED",
275
274
  code: SelaError_1.SAFETY_GUARD_CODES.BLOCKED_LOW_CONFIDENCE,
276
- reason: `Confidence too low (${confidence}/100 < ${this.thresholds.confidenceHardStop}) refusing to heal`,
275
+ reason: `Confidence too low (${confidence}/100 < ${this.thresholds.confidenceHardStop}) - refusing to heal`,
277
276
  canProceed: false,
278
277
  };
279
278
  }
@@ -284,16 +283,18 @@ class SafetyGuard {
284
283
  //
285
284
  // When liveText + dnaBaselineText are both available and differ, we
286
285
  // synthesise a contentChange pair and apply the full inversion-check
287
- // pipeline on it regardless of what the AI reported.
286
+ // pipeline on it - regardless of what the AI reported.
288
287
  //
289
288
  // If the AI DID report contentChange we use that (more precise than raw
290
289
  // innerText, which may include child element noise).
291
290
  let effectiveContentChange = aiFix.contentChange;
292
- if (!effectiveContentChange && liveText !== undefined && dnaBaselineText !== undefined) {
291
+ if (!effectiveContentChange &&
292
+ liveText !== undefined &&
293
+ dnaBaselineText !== undefined) {
293
294
  const normLive = liveText.trim();
294
295
  const normDNA = dnaBaselineText.trim();
295
296
  if (normLive !== normDNA && normLive.length > 0 && normDNA.length > 0) {
296
- console.warn(`[SafetyGuard] 🚨 Zero-Trust override AI omitted contentChange but live DOM differs:\n` +
297
+ console.warn(`[SafetyGuard] 🚨 Zero-Trust override - AI omitted contentChange but live DOM differs:\n` +
297
298
  ` DNA baseline : "${normDNA}"\n` +
298
299
  ` Live text : "${normLive}"`);
299
300
  effectiveContentChange = { oldText: normDNA, newText: normLive };
@@ -301,7 +302,9 @@ class SafetyGuard {
301
302
  }
302
303
  // ── 3. Structural-only heal (no text change detected) ────────
303
304
  if (!effectiveContentChange) {
304
- const level = confidence < this.thresholds.confidenceReviewThreshold ? "REQUIRES_REVIEW" : "SAFE";
305
+ const level = confidence < this.thresholds.confidenceReviewThreshold
306
+ ? "REQUIRES_REVIEW"
307
+ : "SAFE";
305
308
  return {
306
309
  level,
307
310
  reason: `Structural selector change only (confidence=${confidence})`,
@@ -313,12 +316,12 @@ class SafetyGuard {
313
316
  console.log(`[SafetyGuard] 🔬 Content change (${source}): "${oldText}" → "${newText}"`);
314
317
  // ── 4. Binary semantic-opposite guard ────────────────────────
315
318
  // Applies in ALL modes: "Enabled"→"Disabled", "Success"→"Error", etc.
316
- // These always indicate a state inversion never safe to auto-heal.
319
+ // These always indicate a state inversion - never safe to auto-heal.
317
320
  if (this.isSemanticOpposite(oldText, newText)) {
318
321
  return {
319
322
  level: "FAIL_HARD",
320
323
  code: SelaError_1.SAFETY_GUARD_CODES.FAIL_HARD_SEMANTIC_INVERSION,
321
- reason: `Semantic inversion detected: "${oldText}" ↔ "${newText}" ` +
324
+ reason: `Semantic inversion detected: "${oldText}" ↔ "${newText}" - ` +
322
325
  `state inversions mask logical regressions`,
323
326
  canProceed: false,
324
327
  };
@@ -334,30 +337,28 @@ class SafetyGuard {
334
337
  return {
335
338
  level: "FAIL_HARD",
336
339
  code: SelaError_1.SAFETY_GUARD_CODES.FAIL_HARD_STATUS_INVERSION,
337
- reason: `Status inversion: "${oldText}" (${oldRole}) → "${newText}" (${newRole}) ` +
340
+ reason: `Status inversion: "${oldText}" (${oldRole}) → "${newText}" (${newRole}) - ` +
338
341
  `masking a logic failure is not permitted`,
339
342
  canProceed: false,
340
343
  };
341
344
  }
342
345
  // Cross-role swap (e.g. DELETE → CANCEL, SUBMIT → NAVIGATE)
343
- if (oldRole !== "UNKNOWN" &&
344
- newRole !== "UNKNOWN" &&
345
- oldRole !== newRole) {
346
+ if (oldRole !== "UNKNOWN" && newRole !== "UNKNOWN" && oldRole !== newRole) {
346
347
  if (mode === "assertion") {
347
348
  // Assertion explicitly checked the old functional text; a different
348
349
  // function being found is almost certainly a wrong element fix.
349
350
  return {
350
351
  level: "BLOCKED",
351
352
  code: SelaError_1.SAFETY_GUARD_CODES.BLOCKED_ROLE_SWAP_ASSERTION,
352
- reason: `Functional role swap in assertion: "${oldText}" (${oldRole}) → "${newText}" (${newRole}) ` +
353
+ reason: `Functional role swap in assertion: "${oldText}" (${oldRole}) → "${newText}" (${newRole}) - ` +
353
354
  `the assertion was verifying a specific functional state`,
354
355
  canProceed: false,
355
356
  };
356
357
  }
357
- // Action mode: allow with warning a UI refactor may rename a control
358
+ // Action mode: allow with warning - a UI refactor may rename a control
358
359
  // (e.g. "Delete" button renamed "Remove" or merged into a menu)
359
360
  console.warn(`[SafetyGuard] ⚠️ Functional role change in action: ` +
360
- `"${oldText}" (${oldRole}) → "${newText}" (${newRole}) review recommended`);
361
+ `"${oldText}" (${oldRole}) → "${newText}" (${newRole}) - review recommended`);
361
362
  return {
362
363
  level: "REQUIRES_REVIEW",
363
364
  reason: `Functional role change in action: "${oldText}" (${oldRole}) → "${newText}" (${newRole})`,
@@ -392,7 +393,7 @@ class SafetyGuard {
392
393
  return {
393
394
  level: "FAIL_HARD",
394
395
  code: SelaError_1.SAFETY_GUARD_CODES.FAIL_HARD_AUDITOR_INCONSISTENT,
395
- reason: `Intent Auditor INCONSISTENT: ${auditVerdict.reason}` +
396
+ reason: `Intent Auditor - INCONSISTENT: ${auditVerdict.reason}` +
396
397
  (auditVerdict.inversionType
397
398
  ? ` [inversion: ${auditVerdict.inversionType}]`
398
399
  : ""),
@@ -409,23 +410,23 @@ class SafetyGuard {
409
410
  return {
410
411
  level: "BLOCKED",
411
412
  code: SelaError_1.SAFETY_GUARD_CODES.BLOCKED_AUDITOR_SUSPICIOUS,
412
- reason: `Intent Auditor SUSPICIOUS in assertion mode: ${auditVerdict.reason}`,
413
+ reason: `Intent Auditor - SUSPICIOUS in assertion mode: ${auditVerdict.reason}`,
413
414
  canProceed: false,
414
415
  meta,
415
416
  };
416
417
  }
417
418
  if (this.thresholds.allowSuspicious && mode === "assertion") {
418
- console.log(`[SafetyGuard] ℹ️ allowSuspicious=true SUSPICIOUS in assertion mode escalated to REQUIRES_REVIEW`);
419
+ console.log(`[SafetyGuard] ℹ️ allowSuspicious=true - SUSPICIOUS in assertion mode escalated to REQUIRES_REVIEW`);
419
420
  }
420
421
  return {
421
422
  level: "REQUIRES_REVIEW",
422
- reason: `Intent Auditor SUSPICIOUS in ${mode} mode: ${auditVerdict.reason}`,
423
+ reason: `Intent Auditor - SUSPICIOUS in ${mode} mode: ${auditVerdict.reason}`,
423
424
  canProceed: true,
424
425
  meta,
425
426
  };
426
427
  }
427
- // CONSISTENT fall through to similarity gate
428
- console.log(`[SafetyGuard] ✅ Intent Auditor CONSISTENT (${auditVerdict.confidence}%): ${auditVerdict.reason}`);
428
+ // CONSISTENT - fall through to confidence tiers
429
+ console.log(`[SafetyGuard] ✅ Intent Auditor - CONSISTENT (${auditVerdict.confidence}%): ${auditVerdict.reason}`);
429
430
  if (auditVerdict.scoreBreakdown) {
430
431
  const { rawConfidence, penalty, bonus } = auditVerdict.scoreBreakdown;
431
432
  if (penalty !== 0 || bonus !== 0) {
@@ -440,32 +441,11 @@ class SafetyGuard {
440
441
  }
441
442
  }
442
443
  }
443
- // ── 8. Semantic similarity gate (same-role or both UNKNOWN) ──
444
- // For same-role pairs (e.g. SUBMIT→SUBMIT: "Submit"→"Send") we skip
445
- // the similarity gate entirely — the role match is sufficient proof
446
- // of functional equivalence.
447
- //
448
- // The gate is only applied when BOTH roles are UNKNOWN in assertion
449
- // mode, where we have no functional category to fall back on.
450
- if (mode === "assertion" && oldRole === "UNKNOWN" && newRole === "UNKNOWN") {
451
- const similarity = this.computeSemanticSimilarity(oldText, newText);
452
- console.log(`[SafetyGuard] 📊 Similarity: "${oldText}" ↔ "${newText}" = ${(similarity * 100).toFixed(1)}%`);
453
- if (similarity < this.thresholds.assertionSimilarityFloor) {
454
- return {
455
- level: "BLOCKED",
456
- code: SelaError_1.SAFETY_GUARD_CODES.BLOCKED_SIMILARITY_FLOOR,
457
- reason: `Text divergence too high in assertion: "${oldText}" → "${newText}" ` +
458
- `(similarity=${(similarity * 100).toFixed(1)}% < ${(this.thresholds.assertionSimilarityFloor * 100).toFixed(0)}%) — ` +
459
- `possible content regression`,
460
- canProceed: false,
461
- };
462
- }
463
- }
464
- // ── 9. Confidence tiers ──────────────────────────────────────
444
+ // ── 8. Confidence tiers ──────────────────────────────────────
465
445
  if (confidence < this.thresholds.confidenceReviewThreshold) {
466
446
  return {
467
447
  level: "REQUIRES_REVIEW",
468
- reason: `Low-confidence fix (${confidence}/100) tagging for manual review`,
448
+ reason: `Low-confidence fix (${confidence}/100) - tagging for manual review`,
469
449
  canProceed: true,
470
450
  meta: localAuditMeta,
471
451
  };
@@ -515,62 +495,5 @@ class SafetyGuard {
515
495
  }
516
496
  return "UNKNOWN";
517
497
  }
518
- // ─────────────────────────────────────────────────────────────
519
- // SEMANTIC SIMILARITY (no external dependencies)
520
- //
521
- // Combined score: 0.5 × levenshtein_similarity + 0.5 × jaccard_similarity
522
- //
523
- // Levenshtein captures character-level similarity (typos, abbreviations).
524
- // Jaccard captures word-level overlap (shared vocabulary, different order).
525
- // The 50/50 blend is robust against short labels where one metric misleads.
526
- // ─────────────────────────────────────────────────────────────
527
- computeSemanticSimilarity(a, b) {
528
- const na = a.toLowerCase().trim();
529
- const nb = b.toLowerCase().trim();
530
- if (na === nb)
531
- return 1;
532
- const maxLen = Math.max(na.length, nb.length);
533
- const levSim = maxLen === 0 ? 1 : 1 - this.levenshteinDistance(na, nb) / maxLen;
534
- const jaccard = this.jaccardSimilarity(na, nb);
535
- return 0.5 * levSim + 0.5 * jaccard;
536
- }
537
- // ─────────────────────────────────────────────────────────────
538
- // PRIVATE: Levenshtein distance (space-optimised two-row DP)
539
- // ─────────────────────────────────────────────────────────────
540
- levenshteinDistance(a, b) {
541
- const m = a.length;
542
- const n = b.length;
543
- if (m === 0)
544
- return n;
545
- if (n === 0)
546
- return m;
547
- let prev = Array.from({ length: n + 1 }, (_, i) => i);
548
- let curr = new Array(n + 1);
549
- for (let i = 1; i <= m; i++) {
550
- curr[0] = i;
551
- for (let j = 1; j <= n; j++) {
552
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
553
- curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
554
- }
555
- [prev, curr] = [curr, prev];
556
- }
557
- return prev[n];
558
- }
559
- // ─────────────────────────────────────────────────────────────
560
- // PRIVATE: Jaccard word-set similarity
561
- // ─────────────────────────────────────────────────────────────
562
- jaccardSimilarity(a, b) {
563
- const setA = new Set(a.split(/\s+/).filter(Boolean));
564
- const setB = new Set(b.split(/\s+/).filter(Boolean));
565
- if (setA.size === 0 && setB.size === 0)
566
- return 1;
567
- let intersection = 0;
568
- for (const w of setA) {
569
- if (setB.has(w))
570
- intersection++;
571
- }
572
- const union = setA.size + setB.size - intersection;
573
- return union === 0 ? 1 : intersection / union;
574
- }
575
498
  }
576
499
  exports.SafetyGuard = SafetyGuard;
@@ -67,12 +67,12 @@ class SnapshotService {
67
67
  return raw;
68
68
  }
69
69
  // ─────────────────────────────────────────────────────────────
70
- // captureElement single-pass atomic extraction of all v2 metrics.
70
+ // captureElement - single-pass atomic extraction of all v2 metrics.
71
71
  //
72
72
  // All data collection (core props, ancestry, visibility, anchors,
73
73
  // shadow-DOM flag) runs inside ONE page.evaluate() call so the
74
74
  // browser serialises a single IPC payload. Returns null on any
75
- // failure callers must treat null as "capture skipped" and not
75
+ // failure - callers must treat null as "capture skipped" and not
76
76
  // block the heal.
77
77
  // ─────────────────────────────────────────────────────────────
78
78
  async captureElement(page, selector, framePath = []) {
@@ -219,7 +219,7 @@ class SnapshotService {
219
219
  closestLabel = t;
220
220
  }
221
221
  }
222
- // P4: implicit <label> wrapper clone and strip the form element
222
+ // P4: implicit <label> wrapper - clone and strip the form element
223
223
  if (!closestLabel) {
224
224
  const wrapper = el.closest("label");
225
225
  if (wrapper) {
@@ -318,10 +318,10 @@ class SnapshotService {
318
318
  }
319
319
  }
320
320
  // ─────────────────────────────────────────────────────────────
321
- // migrateToV2 backfills default v2 fields onto a v1 snapshot.
321
+ // migrateToV2 - backfills default v2 fields onto a v1 snapshot.
322
322
  //
323
323
  // ancestry, visibility, and anchors are empty / safe defaults.
324
- // The migrated snapshot is NOT re-saved to disk automatically
324
+ // The migrated snapshot is NOT re-saved to disk automatically -
325
325
  // the engine decides when to flush.
326
326
  // ─────────────────────────────────────────────────────────────
327
327
  migrateToV2(v1) {
@@ -1,5 +1,5 @@
1
- import { type ASTUpdateResult } from './ASTSourceUpdater.js';
2
- import type { DnaRecord, DnaEditPatch } from './types.js';
1
+ import { type ASTUpdateResult } from "./ASTSourceUpdater.js";
2
+ import type { DnaRecord, DnaEditPatch } from "./types.js";
3
3
  interface CallerContext {
4
4
  filePath: string;
5
5
  line: number;
@@ -1 +1 @@
1
- {"version":3,"file":"SourceLinkService.d.ts","sourceRoot":"","sources":["../../src/services/SourceLinkService.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1D,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAiDD,MAAM,WAAW,kBAAkB;IACjC,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IACvD,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAAC;IAC9E,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACrF;AAED,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGrB;IAEH,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa;IAItD,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAyDvE,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC;CAyD1F"}
1
+ {"version":3,"file":"SourceLinkService.d.ts","sourceRoot":"","sources":["../../src/services/SourceLinkService.ts"],"names":[],"mappings":"AAQA,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1D,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAoDD,MAAM,WAAW,kBAAkB;IACjC,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IACvD,uBAAuB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAAC;IAC9E,iBAAiB,CACf,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,eAAe,CAAC,CAAC;CAC7B;AAED,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGrB;IAEH,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa;IAItD,uBAAuB,CACrB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,kBAAkB,EAAE;IAyDjB,iBAAiB,CACrB,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,eAAe,CAAC;CAuE5B"}
@@ -10,15 +10,15 @@ const ts_morph_1 = require("ts-morph");
10
10
  const ASTSourceUpdater_js_1 = require("./ASTSourceUpdater.js");
11
11
  // Mirror of ASTSourceUpdater's module-scoped ALL_SELECTOR_METHODS.
12
12
  const ALL_SELECTOR_METHODS = new Set([
13
- 'locator',
14
- 'frameLocator',
15
- 'getByRole',
16
- 'getByLabel',
17
- 'getByText',
18
- 'getByTestId',
19
- 'getByPlaceholder',
20
- 'getByAltText',
21
- 'getByTitle',
13
+ "locator",
14
+ "frameLocator",
15
+ "getByRole",
16
+ "getByLabel",
17
+ "getByText",
18
+ "getByTestId",
19
+ "getByPlaceholder",
20
+ "getByAltText",
21
+ "getByTitle",
22
22
  ]);
23
23
  function dnaError(message, code) {
24
24
  const err = new Error(message);
@@ -33,11 +33,12 @@ function extractSelector(call) {
33
33
  return null;
34
34
  const first = args[0];
35
35
  const kind = first.getKind();
36
- if (kind === ts_morph_1.SyntaxKind.StringLiteral || kind === ts_morph_1.SyntaxKind.NoSubstitutionTemplateLiteral) {
36
+ if (kind === ts_morph_1.SyntaxKind.StringLiteral ||
37
+ kind === ts_morph_1.SyntaxKind.NoSubstitutionTemplateLiteral) {
37
38
  const raw = first.getText();
38
39
  return raw.slice(1, -1); // strip surrounding quotes/backticks
39
40
  }
40
- // For template literals with expressions, identifiers, etc. return raw text.
41
+ // For template literals with expressions, identifiers, etc. - return raw text.
41
42
  return first.getText();
42
43
  }
43
44
  // Get the method name from a CallExpression's callee.
@@ -68,7 +69,7 @@ class SourceLinkService {
68
69
  return [];
69
70
  let sf;
70
71
  try {
71
- // addSourceFileAtPath throws if already added use getOrAdd pattern.
72
+ // addSourceFileAtPath throws if already added - use getOrAdd pattern.
72
73
  sf =
73
74
  this.project.getSourceFile(absPath) ??
74
75
  this.project.addSourceFileAtPath(absPath);
@@ -91,7 +92,7 @@ class SourceLinkService {
91
92
  if (selector === null)
92
93
  return;
93
94
  const raw = call.getText();
94
- const preview = raw.length > 80 ? raw.slice(0, 79) + '' : raw;
95
+ const preview = raw.length > 80 ? raw.slice(0, 79) + "" : raw;
95
96
  candidates.push({
96
97
  col: call.getStart(),
97
98
  preview,
@@ -110,16 +111,24 @@ class SourceLinkService {
110
111
  }
111
112
  async applySourceUpdate(record, patch) {
112
113
  if (!record.sourceFile) {
113
- return { success: false, reason: 'DNA record has no sourceFile', strategy: 'none' };
114
+ return {
115
+ success: false,
116
+ reason: "DNA record has no sourceFile",
117
+ strategy: "none",
118
+ };
114
119
  }
115
120
  if (!(0, fs_1.existsSync)(path_1.default.resolve(record.sourceFile))) {
116
- throw dnaError(`Source file not found: ${record.sourceFile}`, 'SOURCE_FILE_MISSING');
121
+ throw dnaError(`Source file not found: ${record.sourceFile}`, "SOURCE_FILE_MISSING");
117
122
  }
118
123
  if (record.sourceLine <= 0) {
119
- return { success: false, reason: 'DNA record has no valid sourceLine', strategy: 'none' };
124
+ return {
125
+ success: false,
126
+ reason: "DNA record has no valid sourceLine",
127
+ strategy: "none",
128
+ };
120
129
  }
121
130
  const caller = this.resolveCallerContext(record);
122
- if (patch.field === 'selector') {
131
+ if (patch.field === "selector") {
123
132
  const newSelector = patch.newValue;
124
133
  // Resolve oldSelector: prefer patch.oldValue, fall back to the locator
125
134
  // at patch.locatorIndex on the recorded line.
@@ -131,25 +140,25 @@ class SourceLinkService {
131
140
  return {
132
141
  success: false,
133
142
  reason: `No locator found at index ${patch.locatorIndex} on line ${record.sourceLine}`,
134
- strategy: 'none',
143
+ strategy: "none",
135
144
  };
136
145
  }
137
146
  oldSelector = target.selector;
138
147
  }
139
148
  return this.updater.update(caller, oldSelector, newSelector);
140
149
  }
141
- if (patch.field === 'text') {
150
+ if (patch.field === "text") {
142
151
  // Use ASTSourceUpdater's contentChange path for text-content edits.
143
152
  const contentChange = {
144
- oldText: String(patch.oldValue ?? ''),
145
- newText: String(patch.newValue ?? ''),
153
+ oldText: String(patch.oldValue ?? ""),
154
+ newText: String(patch.newValue ?? ""),
146
155
  };
147
156
  return this.updater.update(caller, record.selector, record.selector, undefined, undefined, contentChange);
148
157
  }
149
158
  return {
150
159
  success: false,
151
160
  reason: `Source update not supported for field: ${patch.field}`,
152
- strategy: 'none',
161
+ strategy: "none",
153
162
  };
154
163
  }
155
164
  }
@@ -4,7 +4,7 @@ interface UpdateResult {
4
4
  success: boolean;
5
5
  reason: string;
6
6
  lineUpdated?: number;
7
- /** Canonical locator string written to disk use this for runtime execution. */
7
+ /** Canonical locator string written to disk - use this for runtime execution. */
8
8
  healedLocatorString?: string;
9
9
  /** Populated by semantic dispatch: where the definition was mutated. */
10
10
  definitionSite?: {
@@ -1 +1 @@
1
- {"version":3,"file":"SourceUpdater.d.ts","sourceRoot":"","sources":["../../src/services/SourceUpdater.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AA4BtD,UAAU,YAAY;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,cAAc,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAqZD,qBAAa,aAAa;IAMxB,MAAM,CAAC,MAAM,CACX,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,EACpB,mBAAmB,CAAC,EAAE,MAAM,EAC5B,UAAU,CAAC,EAAE,eAAe,EAAE,EAC9B,aAAa,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EACpD,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,EACxC,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,EACvC,cAAc,CAAC,EAAE,SAAS,GAAG,aAAa,GAAG,QAAQ,EACrD,UAAU,CAAC,EAAE,OAAO,GACnB,YAAY;IAoDf,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAwC/B,OAAO,CAAC,MAAM,CAAC,WAAW;IAiT1B,OAAO,CAAC,MAAM,CAAC,2BAA2B;IA8E1C,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA8EvC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAoErC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAsBjC,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA6DpC,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAuCpC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA6CvC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAqCrC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAqGrC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IA0BjC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAatC,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAgBlD,MAAM,CAAC,cAAc,CACnB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,YAAY;IA0Cf,0FAA0F;IAC1F,MAAM,CAAC,eAAe,IAAI,IAAI;CAG/B"}
1
+ {"version":3,"file":"SourceUpdater.d.ts","sourceRoot":"","sources":["../../src/services/SourceUpdater.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AA4BtD,UAAU,YAAY;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,cAAc,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,aAAa;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAqZD,qBAAa,aAAa;IAMxB,MAAM,CAAC,MAAM,CACX,MAAM,EAAE,aAAa,EACrB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,EACpB,mBAAmB,CAAC,EAAE,MAAM,EAC5B,UAAU,CAAC,EAAE,eAAe,EAAE,EAC9B,aAAa,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EACpD,kBAAkB,CAAC,EAAE,iBAAiB,EAAE,EACxC,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,EACvC,cAAc,CAAC,EAAE,SAAS,GAAG,aAAa,GAAG,QAAQ,EACrD,UAAU,CAAC,EAAE,OAAO,GACnB,YAAY;IAoDf,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAwC/B,OAAO,CAAC,MAAM,CAAC,WAAW;IAkT1B,OAAO,CAAC,MAAM,CAAC,2BAA2B;IA8E1C,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA8EvC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAoErC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAsBjC,OAAO,CAAC,MAAM,CAAC,qBAAqB;IA6DpC,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAuCpC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IA6CvC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAqCrC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAqGrC,OAAO,CAAC,MAAM,CAAC,kBAAkB;IA0BjC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAatC,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAgBlD,MAAM,CAAC,cAAc,CACnB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,YAAY;IA0Cf,0FAA0F;IAC1F,MAAM,CAAC,eAAe,IAAI,IAAI;CAG/B"}