sela-core 1.0.7 → 1.0.9

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 (146) hide show
  1. package/README.md +27 -17
  2. package/dist/cli/ErrorHandler.d.ts +1 -1
  3. package/dist/cli/ErrorHandler.js +14 -14
  4. package/dist/cli/commands/bulk.d.ts +1 -1
  5. package/dist/cli/commands/bulk.d.ts.map +1 -1
  6. package/dist/cli/commands/bulk.js +51 -33
  7. package/dist/cli/commands/init.d.ts +1 -1
  8. package/dist/cli/commands/init.d.ts.map +1 -1
  9. package/dist/cli/commands/init.js +26 -18
  10. package/dist/cli/commands/merge.d.ts +13 -0
  11. package/dist/cli/commands/merge.d.ts.map +1 -0
  12. package/dist/cli/commands/merge.js +119 -0
  13. package/dist/cli/commands/showReport.d.ts +1 -1
  14. package/dist/cli/commands/showReport.d.ts.map +1 -1
  15. package/dist/cli/commands/showReport.js +12 -10
  16. package/dist/cli/commands/status.d.ts +1 -1
  17. package/dist/cli/commands/status.d.ts.map +1 -1
  18. package/dist/cli/commands/status.js +8 -8
  19. package/dist/cli/commands/sync.d.ts +1 -1
  20. package/dist/cli/commands/sync.d.ts.map +1 -1
  21. package/dist/cli/commands/sync.js +38 -30
  22. package/dist/cli/index.js +12 -9
  23. package/dist/cli/ui/DnaTable.d.ts +1 -1
  24. package/dist/cli/ui/DnaTable.d.ts.map +1 -1
  25. package/dist/cli/ui/DnaTable.js +23 -16
  26. package/dist/cli/ui/RefactorWizard.d.ts +3 -3
  27. package/dist/cli/ui/RefactorWizard.d.ts.map +1 -1
  28. package/dist/cli/ui/RefactorWizard.js +108 -82
  29. package/dist/config/ConfigLoader.d.ts +2 -2
  30. package/dist/config/ConfigLoader.d.ts.map +1 -1
  31. package/dist/config/ConfigLoader.js +15 -15
  32. package/dist/config/DryRunGuard.d.ts +1 -1
  33. package/dist/config/DryRunGuard.js +7 -7
  34. package/dist/config/SelaConfig.d.ts +13 -17
  35. package/dist/config/SelaConfig.d.ts.map +1 -1
  36. package/dist/config/SelaConfig.js +32 -26
  37. package/dist/engine/HealingRegistry.d.ts +1 -1
  38. package/dist/engine/HealingRegistry.js +3 -3
  39. package/dist/engine/SelaEngine.d.ts +1 -1
  40. package/dist/engine/SelaEngine.d.ts.map +1 -1
  41. package/dist/engine/SelaEngine.js +117 -51
  42. package/dist/errors/SelaError.d.ts +8 -1
  43. package/dist/errors/SelaError.d.ts.map +1 -1
  44. package/dist/errors/SelaError.js +14 -7
  45. package/dist/fixtures/expectProxy.d.ts +2 -2
  46. package/dist/fixtures/expectProxy.js +16 -16
  47. package/dist/fixtures/index.d.ts +18 -2
  48. package/dist/fixtures/index.d.ts.map +1 -1
  49. package/dist/fixtures/index.js +47 -27
  50. package/dist/fixtures/moduleExpect.js +7 -7
  51. package/dist/fixtures/proxyTag.d.ts +1 -1
  52. package/dist/fixtures/proxyTag.js +4 -4
  53. package/dist/index.d.ts +8 -8
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +4 -4
  56. package/dist/reporter/SelaReporter.d.ts +45 -12
  57. package/dist/reporter/SelaReporter.d.ts.map +1 -1
  58. package/dist/reporter/SelaReporter.js +139 -39
  59. package/dist/services/ASTSourceUpdater.d.ts +48 -3
  60. package/dist/services/ASTSourceUpdater.d.ts.map +1 -1
  61. package/dist/services/ASTSourceUpdater.js +283 -105
  62. package/dist/services/AnchorResolver.d.ts +157 -0
  63. package/dist/services/AnchorResolver.d.ts.map +1 -0
  64. package/dist/services/AnchorResolver.js +289 -0
  65. package/dist/services/ArgumentTypeAnalyzer.js +7 -7
  66. package/dist/services/BlastRadiusAnalyzer.d.ts.map +1 -1
  67. package/dist/services/BlastRadiusAnalyzer.js +5 -2
  68. package/dist/services/ChainValidator.js +22 -22
  69. package/dist/services/CrossFileHealer.js +7 -7
  70. package/dist/services/DecisionEngine.d.ts +51 -0
  71. package/dist/services/DecisionEngine.d.ts.map +1 -0
  72. package/dist/services/DecisionEngine.js +260 -0
  73. package/dist/services/DefinitionTracer.d.ts +1 -1
  74. package/dist/services/DefinitionTracer.d.ts.map +1 -1
  75. package/dist/services/DefinitionTracer.js +28 -13
  76. package/dist/services/DnaEditorService.d.ts +2 -2
  77. package/dist/services/DnaEditorService.d.ts.map +1 -1
  78. package/dist/services/DnaEditorService.js +81 -62
  79. package/dist/services/DnaIndexService.d.ts +1 -1
  80. package/dist/services/DnaIndexService.d.ts.map +1 -1
  81. package/dist/services/DnaIndexService.js +14 -14
  82. package/dist/services/HealReportService.d.ts +31 -55
  83. package/dist/services/HealReportService.d.ts.map +1 -1
  84. package/dist/services/HealReportService.js +864 -1240
  85. package/dist/services/HealingAdvisory.d.ts +9 -1
  86. package/dist/services/HealingAdvisory.d.ts.map +1 -1
  87. package/dist/services/HealingAdvisory.js +9 -1
  88. package/dist/services/HealingCacheService.d.ts +8 -8
  89. package/dist/services/HealingCacheService.d.ts.map +1 -1
  90. package/dist/services/HealingCacheService.js +24 -24
  91. package/dist/services/HealthReportService.d.ts +1 -1
  92. package/dist/services/HealthReportService.d.ts.map +1 -1
  93. package/dist/services/HealthReportService.js +25 -25
  94. package/dist/services/InitializerUpdater.d.ts.map +1 -1
  95. package/dist/services/InitializerUpdater.js +12 -2
  96. package/dist/services/IntentAuditor.d.ts.map +1 -1
  97. package/dist/services/IntentAuditor.js +32 -21
  98. package/dist/services/InteractiveReview.d.ts +8 -17
  99. package/dist/services/InteractiveReview.d.ts.map +1 -1
  100. package/dist/services/InteractiveReview.js +34 -124
  101. package/dist/services/LLMService.d.ts +1 -1
  102. package/dist/services/LLMService.js +16 -16
  103. package/dist/services/MutationApplier.d.ts +55 -0
  104. package/dist/services/MutationApplier.d.ts.map +1 -0
  105. package/dist/services/MutationApplier.js +322 -0
  106. package/dist/services/PRAutomationService.d.ts +2 -2
  107. package/dist/services/PRAutomationService.d.ts.map +1 -1
  108. package/dist/services/PRAutomationService.js +43 -39
  109. package/dist/services/PendingPromptLedger.d.ts +9 -2
  110. package/dist/services/PendingPromptLedger.d.ts.map +1 -1
  111. package/dist/services/PendingPromptLedger.js +31 -6
  112. package/dist/services/ReportGenerator.d.ts +116 -30
  113. package/dist/services/ReportGenerator.d.ts.map +1 -1
  114. package/dist/services/ReportGenerator.js +149 -62
  115. package/dist/services/ReportMergeService.d.ts +95 -0
  116. package/dist/services/ReportMergeService.d.ts.map +1 -0
  117. package/dist/services/ReportMergeService.js +0 -0
  118. package/dist/services/SafetyGuard.d.ts +4 -7
  119. package/dist/services/SafetyGuard.d.ts.map +1 -1
  120. package/dist/services/SafetyGuard.js +29 -106
  121. package/dist/services/SelectorSanitizer.d.ts +52 -0
  122. package/dist/services/SelectorSanitizer.d.ts.map +1 -0
  123. package/dist/services/SelectorSanitizer.js +318 -0
  124. package/dist/services/SnapshotService.js +6 -6
  125. package/dist/services/SourceLinkService.d.ts +2 -2
  126. package/dist/services/SourceLinkService.d.ts.map +1 -1
  127. package/dist/services/SourceLinkService.js +31 -22
  128. package/dist/services/SourceUpdater.d.ts +1 -1
  129. package/dist/services/SourceUpdater.d.ts.map +1 -1
  130. package/dist/services/SourceUpdater.js +44 -26
  131. package/dist/services/TemplateDiffService.d.ts.map +1 -1
  132. package/dist/services/TemplateDiffService.js +18 -15
  133. package/dist/services/TraceBackEngine.d.ts +67 -0
  134. package/dist/services/TraceBackEngine.d.ts.map +1 -0
  135. package/dist/services/TraceBackEngine.js +672 -0
  136. package/dist/services/WorkspaceSnapshotService.d.ts +6 -6
  137. package/dist/services/WorkspaceSnapshotService.d.ts.map +1 -1
  138. package/dist/services/WorkspaceSnapshotService.js +10 -12
  139. package/dist/types/index.d.ts +1 -1
  140. package/dist/utils/DOMUtils.d.ts +18 -2
  141. package/dist/utils/DOMUtils.d.ts.map +1 -1
  142. package/dist/utils/DOMUtils.js +335 -49
  143. package/dist/utils/IsolatedDiff.d.ts +2 -2
  144. package/dist/utils/IsolatedDiff.d.ts.map +1 -1
  145. package/dist/utils/IsolatedDiff.js +13 -10
  146. package/package.json +2 -2
@@ -41,7 +41,8 @@ const ASTSourceUpdater_1 = require("./ASTSourceUpdater");
41
41
  const DryRunGuard_1 = require("../config/DryRunGuard");
42
42
  const WorkspaceSnapshotService_1 = require("./WorkspaceSnapshotService");
43
43
  const SelaError_1 = require("../errors/SelaError");
44
- // Centralised write gate — every disk-mutating `fs.writeFileSync` call in
44
+ const SelectorSanitizer_1 = require("./SelectorSanitizer");
45
+ // Centralised write gate - every disk-mutating `fs.writeFileSync` call in
45
46
  // this module routes through `persistFile` so the SELA_DRY_RUN bypass is
46
47
  // enforced in one place, and the Clean-Room WorkspaceSnapshotService
47
48
  // records contentBefore/contentAfter for isolated in-memory diffing.
@@ -310,19 +311,19 @@ function updateTemplateLiteralPreservingVars(line, oldSelector, newSelector, dom
310
311
  // GIT HELPER (used by branch strategy and autoCommit)
311
312
  //
312
313
  // Design goals:
313
- // • Lean no stash, no branch-switching, no complex state management.
314
- // • Commit-based write first (inPlace), then commit. If git fails,
314
+ // • Lean - no stash, no branch-switching, no complex state management.
315
+ // • Commit-based - write first (inPlace), then commit. If git fails,
315
316
  // the fix is still on disk (silent inPlace fallback).
316
- // • Detached HEAD aware skips silently in CI environments that check
317
+ // • Detached HEAD aware - skips silently in CI environments that check
317
318
  // out a specific SHA without a branch ref.
318
319
  // ─────────────────────────────────────────────────────────────────
319
320
  function runGitOperations(absoluteFilePath, createBranch, relativeFilePath) {
320
321
  const filename = path.basename(relativeFilePath);
321
- // Dry-run gate suppress branch creation, `git add`, and auto-commit.
322
+ // Dry-run gate - suppress branch creation, `git add`, and auto-commit.
322
323
  // Mirrors the persistFile() skip so a dry run is fully observable in CI
323
324
  // without ever producing a commit.
324
325
  if (DryRunGuard_1.DryRunGuard.active()) {
325
- console.log(`[SourceUpdater] 🌵 Dry Run skip git operations for ${filename}`);
326
+ console.log(`[SourceUpdater] 🌵 Dry Run - skip git operations for ${filename}`);
326
327
  return;
327
328
  }
328
329
  try {
@@ -331,7 +332,7 @@ function runGitOperations(absoluteFilePath, createBranch, relativeFilePath) {
331
332
  (0, child_process_1.execSync)("git symbolic-ref HEAD", { stdio: "pipe" });
332
333
  }
333
334
  catch {
334
- console.warn(`[SourceUpdater] ⚠️ Detached HEAD git operations skipped (fix is saved to disk)`);
335
+ console.warn(`[SourceUpdater] ⚠️ Detached HEAD - git operations skipped (fix is saved to disk)`);
335
336
  return;
336
337
  }
337
338
  if (createBranch) {
@@ -346,7 +347,7 @@ function runGitOperations(absoluteFilePath, createBranch, relativeFilePath) {
346
347
  console.log(`[SourceUpdater] ✅ Auto-committed fix in: ${filename}`);
347
348
  }
348
349
  catch (err) {
349
- console.warn(`[SourceUpdater] ⚠️ Git operation failed: ${err.message} fix written to disk (inPlace fallback)`);
350
+ console.warn(`[SourceUpdater] ⚠️ Git operation failed: ${err.message} - fix written to disk (inPlace fallback)`);
350
351
  }
351
352
  }
352
353
  class SourceUpdater {
@@ -376,7 +377,7 @@ class SourceUpdater {
376
377
  return result;
377
378
  }
378
379
  // ─────────────────────────────────────────────────────────────
379
- // commentOnly helper inserts a TODO comment above the failing
380
+ // commentOnly helper - inserts a TODO comment above the failing
380
381
  // call site and returns success:false so the engine knows the
381
382
  // source was NOT rewritten (no retry suppression needed).
382
383
  // ─────────────────────────────────────────────────────────────
@@ -402,12 +403,12 @@ class SourceUpdater {
402
403
  catch (err) {
403
404
  return {
404
405
  success: false,
405
- reason: `COMMENT_ONLY: write failed ${err.message}`,
406
+ reason: `COMMENT_ONLY: write failed - ${err.message}`,
406
407
  };
407
408
  }
408
409
  }
409
410
  // ─────────────────────────────────────────────────────────────
410
- // CORE UPDATE Layered Healing (AST primary, Regex fallback)
411
+ // CORE UPDATE - Layered Healing (AST primary, Regex fallback)
411
412
  // Called by update(); never call directly from outside the class.
412
413
  // ─────────────────────────────────────────────────────────────
413
414
  static _coreUpdate(caller, oldSelector, newSelector, domContext, dnaAttrHint, fullSelectorContext, aiSegments, contentChange, smartChainSegments, originalChainHint) {
@@ -442,7 +443,7 @@ class SourceUpdater {
442
443
  if (astResult.success) {
443
444
  console.log(`[SourceUpdater] ✅ AST Strategy ${astResult.strategy} SUCCESS` +
444
445
  (astResult.lineUpdated !== undefined
445
- ? ` line ${astResult.lineUpdated + 1}`
446
+ ? ` - line ${astResult.lineUpdated + 1}`
446
447
  : ""));
447
448
  return {
448
449
  success: true,
@@ -458,28 +459,45 @@ class SourceUpdater {
458
459
  // PROPERTY_ACCESS / TEMPLATE_LITERAL) but could not safely resolve the new
459
460
  // value. Regex cannot do better and will corrupt the definition site.
460
461
  if (astResult.strategy === "semantic-guard") {
461
- console.warn(`[SourceUpdater] 🛑 Regex blocked semantic guard fired. ` +
462
+ console.warn(`[SourceUpdater] 🛑 Regex blocked - semantic guard fired. ` +
462
463
  `Source unchanged. Reason: ${astResult.reason}`);
463
464
  return { success: false, reason: astResult.reason };
464
465
  }
465
466
  console.log(`[SourceUpdater] ⚠️ AST engine exhausted (${astResult.reason}), falling back to Regex`);
466
467
  }
467
468
  catch (astError) {
468
- // Developer pinned the failing statement with `// sela-fail-fast`
469
+ // Developer pinned the failing statement with `// sela-fail-fast` -
469
470
  // propagate the directive instead of swallowing into the Regex
470
471
  // fallback chain (which would defeat the whole point of the gate).
471
472
  if ((0, SelaError_1.isSelaErrorFrom)(astError, "ASTUpdater") &&
472
- astError.code === SelaError_1.AST_UPDATER_CODES.HEAL_DISABLED_BY_DIRECTIVE) {
473
+ astError.code ===
474
+ SelaError_1.AST_UPDATER_CODES.HEAL_DISABLED_BY_DIRECTIVE) {
473
475
  throw astError;
474
476
  }
475
477
  console.warn(`[SourceUpdater] ⚠️ AST engine error: ${astError.message}. Falling back to Regex`);
476
478
  }
479
+ // ── ABSOLUTE GUARD: internal engine selector ───────────────────
480
+ // The AST engine declined to mutate (could not method-shift). The regex
481
+ // fallback only does RAW string substitution of `oldSelector → newSelector`,
482
+ // which would stamp the private `internal:role=…` engine string into the
483
+ // developer's source (the bug this guard kills). A `.locator()` string
484
+ // cannot express a semantic locator, so there is no safe regex outcome:
485
+ // refuse, leave source untouched. The in-memory proxy swap already keeps
486
+ // this run green; the correct method-shift is the new composeHeal pipeline.
487
+ if ((0, SelectorSanitizer_1.isInternalEngineSelector)(effectiveNewSelector)) {
488
+ console.warn(`[SourceUpdater] 🛑 Regex blocked - internal engine selector cannot be ` +
489
+ `string-substituted into source. Method-shift required. Source unchanged.`);
490
+ return {
491
+ success: false,
492
+ reason: "INTERNAL_SELECTOR_GUARD: refusing regex string-substitution of an internal engine selector (method-shift required)",
493
+ };
494
+ }
477
495
  // ── 2. Regex Fallback ──────────────────────────────────────────
478
496
  console.log(`[SourceUpdater] 🔄 Using Regex fallback strategies...`);
479
497
  const raw = fs.readFileSync(filePath, "utf8");
480
498
  const lines = raw.split(/\r?\n/);
481
499
  if (caller.line <= 0) {
482
- console.log(`[SourceUpdater] ⚠️ line ${caller.line} invalid running Regex Strategy G only`);
500
+ console.log(`[SourceUpdater] ⚠️ line ${caller.line} invalid - running Regex Strategy G only`);
483
501
  if (contentChange) {
484
502
  const assertResult = SourceUpdater.strategyAssertionHealing(lines, 1, contentChange, true);
485
503
  if (assertResult.success) {
@@ -511,7 +529,7 @@ class SourceUpdater {
511
529
  if (layeredResult.success) {
512
530
  tryAssertionHealing();
513
531
  persistFile(filePath, lines.join("\n"));
514
- console.log(`[SourceUpdater] ✅ Strategy 0 (Layered Healing) SUCCESS line ${layeredResult.lineUpdated + 1}`);
532
+ console.log(`[SourceUpdater] ✅ Strategy 0 (Layered Healing) SUCCESS - line ${layeredResult.lineUpdated + 1}`);
515
533
  return layeredResult;
516
534
  }
517
535
  }
@@ -587,7 +605,7 @@ class SourceUpdater {
587
605
  };
588
606
  }
589
607
  // ─────────────────────────────────────────────────────────────
590
- // STRATEGY F (Regex) Full Chain Collapsing
608
+ // STRATEGY F (Regex) - Full Chain Collapsing
591
609
  // ─────────────────────────────────────────────────────────────
592
610
  static strategyChainCollapse_Regex(lines, callerLine, oldSelector, newSelector) {
593
611
  console.log(`[Strategy-F] ⛓️ Starting Regex Chain Collapse...`);
@@ -638,7 +656,7 @@ class SourceUpdater {
638
656
  return { success: false, reason: "chain detected but could not replace" };
639
657
  }
640
658
  // ─────────────────────────────────────────────────────────────
641
- // STRATEGY G (Regex) Assertion Healing
659
+ // STRATEGY G (Regex) - Assertion Healing
642
660
  // ─────────────────────────────────────────────────────────────
643
661
  static strategyAssertionHealing(lines, callerLine, contentChange, wholeFile = false) {
644
662
  const { oldText, newText } = contentChange;
@@ -693,7 +711,7 @@ class SourceUpdater {
693
711
  return { success: false, reason: "no assertions to heal" };
694
712
  }
695
713
  // ─────────────────────────────────────────────────────────────
696
- // STRATEGY 0 Layered Healing (Upstream Variable Tracing)
714
+ // STRATEGY 0 - Layered Healing (Upstream Variable Tracing)
697
715
  // ─────────────────────────────────────────────────────────────
698
716
  static strategyLayeredHealing(lines, callerLine, oldElementSelector, aiSegments, fullSelectorContext) {
699
717
  console.log(`[SourceUpdater] 🧠 Strategy 0: Starting Layered Healing...`);
@@ -746,7 +764,7 @@ class SourceUpdater {
746
764
  return null;
747
765
  }
748
766
  // ─────────────────────────────────────────────────────────────
749
- // STRATEGY 1 Chain Collapse (leaf-only precision replacement)
767
+ // STRATEGY 1 - Chain Collapse (leaf-only precision replacement)
750
768
  // ─────────────────────────────────────────────────────────────
751
769
  static strategyChainCollapse(lines, callerLine, oldSelector, newSelector) {
752
770
  const oldLeaf = oldSelector
@@ -788,7 +806,7 @@ class SourceUpdater {
788
806
  };
789
807
  }
790
808
  // ─────────────────────────────────────────────────────────────
791
- // STRATEGY 2 Direct Literal
809
+ // STRATEGY 2 - Direct Literal
792
810
  // ─────────────────────────────────────────────────────────────
793
811
  static strategyDirectLiteral(lines, callerLine, oldSelector, newSelector) {
794
812
  const windowSize = 10;
@@ -821,7 +839,7 @@ class SourceUpdater {
821
839
  return { success: false, reason: "no direct literal" };
822
840
  }
823
841
  // ─────────────────────────────────────────────────────────────
824
- // STRATEGY 3 Upstream Variable/Const
842
+ // STRATEGY 3 - Upstream Variable/Const
825
843
  // ─────────────────────────────────────────────────────────────
826
844
  static strategyUpstreamVariable(lines, callerLine, oldSelector, newSelector) {
827
845
  const callBlock = lines
@@ -858,7 +876,7 @@ class SourceUpdater {
858
876
  return { success: false, reason: "no upstream variable" };
859
877
  }
860
878
  // ─────────────────────────────────────────────────────────────
861
- // STRATEGY 4 Chained Locator Dedup
879
+ // STRATEGY 4 - Chained Locator Dedup
862
880
  // ─────────────────────────────────────────────────────────────
863
881
  static strategyChainedLocator(lines, callerLine, oldSelector, newSelector) {
864
882
  const blockStart = Math.max(0, callerLine - 10);
@@ -885,7 +903,7 @@ class SourceUpdater {
885
903
  return { success: false, reason: "dedup found but literal not replaced" };
886
904
  }
887
905
  // ─────────────────────────────────────────────────────────────
888
- // STRATEGY 5 Function/Template with Variable Preservation
906
+ // STRATEGY 5 - Function/Template with Variable Preservation
889
907
  // ─────────────────────────────────────────────────────────────
890
908
  static strategyFunctionReturn(lines, callerLine, oldSelector, newSelector, domContext, dnaAttrHint) {
891
909
  const callBlock = lines
@@ -970,7 +988,7 @@ class SourceUpdater {
970
988
  return { success: false, reason: "function strategy exhausted" };
971
989
  }
972
990
  // ─────────────────────────────────────────────────────────────
973
- // STRATEGY 6 Global Scan
991
+ // STRATEGY 6 - Global Scan
974
992
  // ─────────────────────────────────────────────────────────────
975
993
  static strategyGlobalScan(lines, oldSelector, newSelector) {
976
994
  const lastOldPart = oldSelector.split(">>").pop().trim();
@@ -1 +1 @@
1
- {"version":3,"file":"TemplateDiffService.d.ts","sourceRoot":"","sources":["../../src/services/TemplateDiffService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,kBAAkB,EAAc,MAAM,UAAU,CAAC;AAMhE,MAAM,MAAM,eAAe,GACvB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,mFAAmF;IACnF,eAAe,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AA6BN,qBAAa,mBAAmB;IAW9B,MAAM,CAAC,YAAY,CACjB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,eAAe;IA6GlB,MAAM,CAAC,gBAAgB,CACrB,YAAY,EAAE,kBAAkB,EAChC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,eAAe;IAoFlB,MAAM,CAAC,qBAAqB,CAC1B,YAAY,EAAE,kBAAkB,EAChC,QAAQ,EAAE,MAAM,GACf,MAAM,EAAE,GAAG,IAAI;CASnB;AAgJD,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtD"}
1
+ {"version":3,"file":"TemplateDiffService.d.ts","sourceRoot":"","sources":["../../src/services/TemplateDiffService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,kBAAkB,EAAc,MAAM,UAAU,CAAC;AAMhE,MAAM,MAAM,eAAe,GACvB;IACE,EAAE,EAAE,IAAI,CAAC;IACT,mFAAmF;IACnF,eAAe,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,qBAAqB,EAAE,MAAM,EAAE,CAAC;CACjC,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AA6BN,qBAAa,mBAAmB;IAW9B,MAAM,CAAC,YAAY,CACjB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,eAAe;IAiHlB,MAAM,CAAC,gBAAgB,CACrB,YAAY,EAAE,kBAAkB,EAChC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,eAAe;IAoFlB,MAAM,CAAC,qBAAqB,CAC1B,YAAY,EAAE,kBAAkB,EAChC,QAAQ,EAAE,MAAM,GACf,MAAM,EAAE,GAAG,IAAI;CASnB;AAgJD,6DAA6D;AAC7D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtD"}
@@ -5,13 +5,13 @@ exports.escapeForTemplate = escapeForTemplate;
5
5
  // ═══════════════════════════════════════════════════════════════════
6
6
  // TemplateDiffService
7
7
  //
8
- // T-8: String-based API diffAndPatch()
8
+ // T-8: String-based API - diffAndPatch()
9
9
  // Given a template source like `input[data-role="${role}_legacy"]`,
10
10
  // its resolved old string, and an AI-proposed new string, compute
11
11
  // the patched template that preserves ${...} spans while updating
12
12
  // only the changed static segments.
13
13
  //
14
- // T-8.1: Node-based API computeNodePatch()
14
+ // T-8.1: Node-based API - computeNodePatch()
15
15
  // Wraps diffAndPatch() using the TemplateExpression AST node as the
16
16
  // source of truth (avoids text-parsing ambiguity). Returns the full
17
17
  // patched template text for use with templateNode.replaceWithText().
@@ -34,7 +34,7 @@ class TemplateDiffService {
34
34
  const exprSegs = segments
35
35
  .filter((s) => s.type === "expr")
36
36
  .map((s) => s.text);
37
- // No spans the "template" is just a plain string.
37
+ // No spans - the "template" is just a plain string.
38
38
  if (exprSegs.length === 0) {
39
39
  if (resolvedOld !== resolvedNew) {
40
40
  return {
@@ -43,18 +43,21 @@ class TemplateDiffService {
43
43
  changedSegmentIndices: [0],
44
44
  };
45
45
  }
46
- return { ok: false, reason: "resolvedOld === resolvedNew — no change needed" };
46
+ return {
47
+ ok: false,
48
+ reason: "resolvedOld === resolvedNew - no change needed",
49
+ };
47
50
  }
48
51
  // Extract span values from resolvedOld using static segments as anchors.
49
52
  const spanValues = extractSpanValues(staticSegs, resolvedOld);
50
53
  if (!spanValues) {
51
54
  return {
52
55
  ok: false,
53
- reason: "template static segments don't align with resolvedOld possible desync. " +
56
+ reason: "template static segments don't align with resolvedOld - possible desync. " +
54
57
  `template="${templateText}", resolvedOld="${resolvedOld}"`,
55
58
  };
56
59
  }
57
- // Verify reconstruction extractSpanValues already guarantees this
60
+ // Verify reconstruction - extractSpanValues already guarantees this
58
61
  // implicitly, but an explicit check catches any edge-case bugs early.
59
62
  {
60
63
  let check = "";
@@ -76,13 +79,13 @@ class TemplateDiffService {
76
79
  return {
77
80
  ok: false,
78
81
  reason: `dynamic span value(s) [${spanValues.map((v) => `"${v}"`).join(", ")}] ` +
79
- `not found in resolvedNew="${resolvedNew}" structural change, manual review required`,
82
+ `not found in resolvedNew="${resolvedNew}" - structural change, manual review required`,
80
83
  };
81
84
  }
82
85
  if (newStaticSegs.length !== staticSegs.length) {
83
86
  return {
84
87
  ok: false,
85
- reason: "static segment count mismatch after alignment structural change",
88
+ reason: "static segment count mismatch after alignment - structural change",
86
89
  };
87
90
  }
88
91
  // Diff: find which static segments changed.
@@ -94,14 +97,14 @@ class TemplateDiffService {
94
97
  if (changedIndices.length === 0) {
95
98
  return {
96
99
  ok: false,
97
- reason: "no static segment changed the difference is in a dynamic span. " +
100
+ reason: "no static segment changed - the difference is in a dynamic span. " +
98
101
  "Update the argument passed to the function instead.",
99
102
  };
100
103
  }
101
104
  if (changedIndices.length > 1) {
102
105
  return {
103
106
  ok: false,
104
- reason: `${changedIndices.length} static segments changed simultaneously ` +
107
+ reason: `${changedIndices.length} static segments changed simultaneously - ` +
105
108
  "ambiguous, manual review required",
106
109
  };
107
110
  }
@@ -119,7 +122,7 @@ class TemplateDiffService {
119
122
  //
120
123
  // Uses the TemplateExpression AST node as the authoritative source
121
124
  // of static/expr segments (avoids text-parsing edge cases).
122
- // Returns `patchedText` pass directly to templateNode.replaceWithText().
125
+ // Returns `patchedText` - pass directly to templateNode.replaceWithText().
123
126
  // ─────────────────────────────────────────────────────────────────
124
127
  static computeNodePatch(templateNode, resolvedOld, resolvedNew) {
125
128
  // Extract static segments and expr texts directly from the AST.
@@ -172,13 +175,13 @@ class TemplateDiffService {
172
175
  if (changedIndices.length === 0) {
173
176
  return {
174
177
  ok: false,
175
- reason: "difference is in dynamic span update call-site argument",
178
+ reason: "difference is in dynamic span - update call-site argument",
176
179
  };
177
180
  }
178
181
  if (changedIndices.length > 1) {
179
182
  return {
180
183
  ok: false,
181
- reason: `${changedIndices.length} static segments changed ambiguous`,
184
+ reason: `${changedIndices.length} static segments changed - ambiguous`,
182
185
  };
183
186
  }
184
187
  const patchedStatics = [...staticSegs];
@@ -238,7 +241,7 @@ function parseTemplateSource(text) {
238
241
  *
239
242
  * Algorithm: iterate over all static segments in order. After consuming
240
243
  * each static segment, find the next static as the delimiter for the
241
- * span value then advance pos to the start of that next static so
244
+ * span value - then advance pos to the start of that next static so
242
245
  * the following iteration can consume it. This ensures pos is always
243
246
  * consistent at the start of each static segment.
244
247
  *
@@ -265,7 +268,7 @@ function extractSpanValues(staticSegments, resolved) {
265
268
  break;
266
269
  }
267
270
  if (nextStatic === "") {
268
- // Empty non-trailing static: adjacent spans boundary is ambiguous.
271
+ // Empty non-trailing static: adjacent spans - boundary is ambiguous.
269
272
  return null;
270
273
  }
271
274
  const delimIdx = resolved.indexOf(nextStatic, pos);
@@ -0,0 +1,67 @@
1
+ import { Node, SourceFile, CallExpression } from "ts-morph";
2
+ import { AnchorKey } from "./AnchorResolver";
3
+ export type MethodCategory = "selector" | "frame" | "modifier" | "action" | "unknown";
4
+ export declare function categorizeMethod(name: string): MethodCategory;
5
+ export type TraceAbortCode = "PARAMETER" | "FACTORY" | "DYNAMIC_SELECTOR" | "DESTRUCTURED" | "REASSIGNED" | "CROSS_FILE" | "DEFINITION_NOT_FOUND" | "MAX_DEPTH" | "UNSUPPORTED";
6
+ export type TraceSeverity = "soft" | "hard";
7
+ export interface ChainMethod {
8
+ name: string;
9
+ category: MethodCategory;
10
+ }
11
+ export type DeclKind = "VariableDeclaration" | "PropertyDeclaration" | "PropertyAssignment" | "InlineCallSite";
12
+ export interface TraceTarget {
13
+ declKind: DeclKind;
14
+ /**
15
+ * The node to mutate at source: the locator-chain expression (a
16
+ * VariableDeclaration's initializer, a POM property's value, or the inline
17
+ * selector chain with trailing actions stripped).
18
+ */
19
+ targetNode: Node;
20
+ /** The owning declaration node; null for an inline call-site. */
21
+ declaration: Node | null;
22
+ /** Variable / property name owning the target, or null. */
23
+ symbolName: string | null;
24
+ /** Stable chain root ("page", "context", …). */
25
+ rootReceiver: string;
26
+ /** Stage-1 identity anchor for the target node. */
27
+ anchor: AnchorKey;
28
+ }
29
+ export type TraceOutcome = {
30
+ status: "target";
31
+ target: TraceTarget;
32
+ /** Methods seen on the failing call-site chain, root→leaf. */
33
+ callSiteChain: ChainMethod[];
34
+ /**
35
+ * For chained cascades (§1.1) — every upstream VariableDeclaration the
36
+ * target depends on, root-most first, target last. Single-element when
37
+ * there is no cascade. Runtime evidence later picks the broken link.
38
+ */
39
+ dependencyChain: TraceTarget[];
40
+ } | {
41
+ status: "abort";
42
+ severity: TraceSeverity;
43
+ code: TraceAbortCode;
44
+ reason: string;
45
+ node?: Node;
46
+ };
47
+ export declare class TraceBackEngine {
48
+ /** Phase 0 convenience: resolve (1-based line, 0-based col) → node → trace. */
49
+ static traceFromPosition(sourceFile: SourceFile, line: number, column: number): TraceOutcome;
50
+ /** Phases 1–5. */
51
+ static traceFromNode(start: Node): TraceOutcome;
52
+ }
53
+ export declare function climbToTopCall(start: Node): CallExpression | null;
54
+ export declare function getLeftmostReceiver(topCall: CallExpression): {
55
+ leftmost: Node;
56
+ chain: ChainMethod[];
57
+ };
58
+ /**
59
+ * Lexical-scope resolution of `name` as seen from `useOffset`. Walks
60
+ * enclosing scopes outward: parameters of enclosing functions, then
61
+ * variable/function declarations introduced in each enclosing block /
62
+ * source file. Pure compiler-API traversal — no language service.
63
+ */
64
+ export declare function resolveValueDeclaration(fromNode: Node, name: string, useOffset: number): Node | null;
65
+ /** Strip trailing action/query calls, returning the locator-chain node. */
66
+ export declare function stripTrailingActions(topCall: CallExpression): Node;
67
+ //# sourceMappingURL=TraceBackEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TraceBackEngine.d.ts","sourceRoot":"","sources":["../../src/services/TraceBackEngine.ts"],"names":[],"mappings":"AAwBA,OAAO,EACL,IAAI,EACJ,UAAU,EACV,cAAc,EAIf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAsC,MAAM,kBAAkB,CAAC;AAsFjF,MAAM,MAAM,cAAc,GACtB,UAAU,GACV,OAAO,GACP,UAAU,GACV,QAAQ,GACR,SAAS,CAAC;AAEd,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAM7D;AAMD,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,SAAS,GACT,kBAAkB,GAClB,cAAc,GACd,YAAY,GACZ,YAAY,GACZ,sBAAsB,GACtB,WAAW,GACX,aAAa,CAAC;AAElB,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,MAAM,QAAQ,GAChB,qBAAqB,GACrB,qBAAqB,GACrB,oBAAoB,GACpB,gBAAgB,CAAC;AAErB,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB;;;;OAIG;IACH,UAAU,EAAE,IAAI,CAAC;IACjB,iEAAiE;IACjE,WAAW,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,2DAA2D;IAC3D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,EAAE,SAAS,CAAC;CACnB;AAED,MAAM,MAAM,YAAY,GACpB;IACE,MAAM,EAAE,QAAQ,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,8DAA8D;IAC9D,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B;;;;OAIG;IACH,eAAe,EAAE,WAAW,EAAE,CAAC;CAChC,GACD;IACE,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,IAAI,CAAC;CACb,CAAC;AAQN,qBAAa,eAAe;IAC1B,+EAA+E;IAC/E,MAAM,CAAC,iBAAiB,CACtB,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,YAAY;IAqBf,kBAAkB;IAClB,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,GAAG,YAAY;CAoChD;AAMD,wBAAgB,cAAc,CAAC,KAAK,EAAE,IAAI,GAAG,cAAc,GAAG,IAAI,CA6BjE;AAMD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,GAAG;IAC5D,QAAQ,EAAE,IAAI,CAAC;IACf,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB,CA6BA;AAuWD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,IAAI,EACd,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,IAAI,GAAG,IAAI,CAmBb;AAmHD,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAelE"}