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
@@ -1,4 +1,4 @@
1
- import type { DnaIndex, HealthReport } from './types.js';
1
+ import type { DnaIndex, HealthReport } from "./types.js";
2
2
  export interface IHealthReportService {
3
3
  generate(index: DnaIndex): HealthReport;
4
4
  format(report: HealthReport): string;
@@ -1 +1 @@
1
- {"version":3,"file":"HealthReportService.d.ts","sourceRoot":"","sources":["../../src/services/HealthReportService.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAa,YAAY,EAAE,MAAM,YAAY,CAAC;AAEpE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,YAAY,CAAC;IACxC,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC;CACtC;AAkBD,qBAAa,mBAAoB,YAAW,oBAAoB;IAC9D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,YAAY;IAgBvC,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM;CA6ErC"}
1
+ {"version":3,"file":"HealthReportService.d.ts","sourceRoot":"","sources":["../../src/services/HealthReportService.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAa,YAAY,EAAE,MAAM,YAAY,CAAC;AAEpE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,YAAY,CAAC;IACxC,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC;CACtC;AAoBD,qBAAa,mBAAoB,YAAW,oBAAoB;IAC9D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,YAAY;IAkBvC,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM;CA0FrC"}
@@ -28,48 +28,48 @@ class HealthReportService {
28
28
  snapshotDir,
29
29
  total: records.length,
30
30
  orphaned: records.filter((r) => r.isOrphaned),
31
- unverifiedHeals: records.filter((r) => !r.isOrphaned && r.status === 'healed'),
31
+ unverifiedHeals: records.filter((r) => !r.isOrphaned && r.status === "healed"),
32
32
  recentlyHealed: records.filter((r) => r.lastHealed !== null && isWithin7Days(r.lastHealed)),
33
33
  neverHealed: records.filter((r) => r.lastHealed === null),
34
34
  topHealedFiles: topHealedFiles(records),
35
35
  };
36
36
  }
37
37
  format(report) {
38
- const lines = [''];
39
- lines.push(chalk_1.default.bold.cyan(' Sela Health Report') +
38
+ const lines = [""];
39
+ lines.push(chalk_1.default.bold.cyan(" Sela Health Report") +
40
40
  chalk_1.default.dim(` (${new Date(report.generatedAt).toISOString()})`));
41
- lines.push('');
41
+ lines.push("");
42
42
  const row = (label, value) => ` ${chalk_1.default.dim(label.padEnd(20))} ${value}`;
43
- lines.push(row('Total DNAs', chalk_1.default.bold(String(report.total))));
43
+ lines.push(row("Total DNAs", chalk_1.default.bold(String(report.total))));
44
44
  const orphanCount = report.orphaned.length;
45
- lines.push(row('Orphaned', orphanCount > 0
46
- ? chalk_1.default.yellow(`${orphanCount} ⚠`)
47
- : chalk_1.default.green('0')));
45
+ lines.push(row("Orphaned", orphanCount > 0 ? chalk_1.default.yellow(`${orphanCount} ⚠`) : chalk_1.default.green("0")));
48
46
  const unverifiedCount = report.unverifiedHeals.length;
49
- lines.push(row('Unverified heals', unverifiedCount > 0
50
- ? chalk_1.default.yellow(`${unverifiedCount} ⚠ ${chalk_1.default.dim('(AI-healed, needs review)')}`)
51
- : chalk_1.default.green('0')));
47
+ lines.push(row("Unverified heals", unverifiedCount > 0
48
+ ? chalk_1.default.yellow(`${unverifiedCount} ⚠ ${chalk_1.default.dim("(AI-healed, needs review)")}`)
49
+ : chalk_1.default.green("0")));
52
50
  const brokenTotal = orphanCount + unverifiedCount;
53
51
  const brokenRatio = report.total > 0
54
52
  ? ((brokenTotal / report.total) * 100).toFixed(1)
55
- : '0.0';
56
- lines.push(row('Broken ratio', (brokenTotal > 0 ? chalk_1.default.yellow : chalk_1.default.green)(`${brokenRatio}% ${chalk_1.default.dim(`(${brokenTotal}/${report.total})`)}`)));
57
- lines.push(row('Healed (7 days)', chalk_1.default.bold(String(report.recentlyHealed.length))));
58
- lines.push(row('Healed (all time)', chalk_1.default.bold(String(report.total - report.neverHealed.length))));
59
- lines.push(row('Never healed', chalk_1.default.bold(String(report.neverHealed.length))));
53
+ : "0.0";
54
+ lines.push(row("Broken ratio", (brokenTotal > 0 ? chalk_1.default.yellow : chalk_1.default.green)(`${brokenRatio}% ${chalk_1.default.dim(`(${brokenTotal}/${report.total})`)}`)));
55
+ lines.push(row("Healed (7 days)", chalk_1.default.bold(String(report.recentlyHealed.length))));
56
+ lines.push(row("Healed (all time)", chalk_1.default.bold(String(report.total - report.neverHealed.length))));
57
+ lines.push(row("Never healed", chalk_1.default.bold(String(report.neverHealed.length))));
60
58
  if (report.topHealedFiles.length > 0) {
61
- lines.push('');
62
- lines.push(` ${chalk_1.default.bold('Top healed files:')}`);
59
+ lines.push("");
60
+ lines.push(` ${chalk_1.default.bold("Top healed files:")}`);
63
61
  for (const { sourceFile, count } of report.topHealedFiles.slice(0, 5)) {
64
62
  const rel = path_1.default.relative(process.cwd(), sourceFile);
65
- const label = (rel.length < sourceFile.length ? rel : sourceFile).slice(-60).padEnd(62);
66
- const noun = count === 1 ? 'heal' : 'heals';
67
- lines.push(` ${chalk_1.default.cyan(label)} ${chalk_1.default.dim('—')} ${chalk_1.default.bold(String(count))} ${chalk_1.default.dim(noun)}`);
63
+ const label = (rel.length < sourceFile.length ? rel : sourceFile)
64
+ .slice(-60)
65
+ .padEnd(62);
66
+ const noun = count === 1 ? "heal" : "heals";
67
+ lines.push(` ${chalk_1.default.cyan(label)} ${chalk_1.default.dim("-")} ${chalk_1.default.bold(String(count))} ${chalk_1.default.dim(noun)}`);
68
68
  }
69
69
  }
70
70
  if (report.orphaned.length > 0) {
71
- lines.push('');
72
- lines.push(` ${chalk_1.default.yellow.bold('Orphaned DNA files:')}`);
71
+ lines.push("");
72
+ lines.push(` ${chalk_1.default.yellow.bold("Orphaned DNA files:")}`);
73
73
  for (const r of report.orphaned.slice(0, 10)) {
74
74
  lines.push(` ${chalk_1.default.dim(r.key)} ${chalk_1.default.yellow(r.sourceFile)}`);
75
75
  }
@@ -77,8 +77,8 @@ class HealthReportService {
77
77
  lines.push(chalk_1.default.dim(` … and ${report.orphaned.length - 10} more`));
78
78
  }
79
79
  }
80
- lines.push('');
81
- return lines.join('\n');
80
+ lines.push("");
81
+ return lines.join("\n");
82
82
  }
83
83
  }
84
84
  exports.HealthReportService = HealthReportService;
@@ -24,14 +24,14 @@ class InitializerUpdater {
24
24
  else {
25
25
  return null;
26
26
  }
27
- // Centralised write gate mirrors ASTSourceUpdater._persistChanges.
27
+ // Centralised write gate - mirrors ASTSourceUpdater._persistChanges.
28
28
  // InitializerUpdater is the canonical write-head for definition-site
29
29
  // mutations (SemanticDispatch → tracer-resolved identifier / property
30
30
  // access / cross-file paths all converge here), so the Clean-Room
31
31
  // snapshot ledger and DryRunGuard MUST be enforced here too.
32
32
  // Without this, an upstream-traced fix (e.g. global StringLiteral at
33
33
  // top of file) writes to disk but `WorkspaceSnapshotService` never
34
- // sees it `getMutatedSnapshots()` returns empty and PR automation
34
+ // sees it - `getMutatedSnapshots()` returns empty and PR automation
35
35
  // skips the heal entirely.
36
36
  const fp = sourceFile.getFilePath();
37
37
  if (DryRunGuard_1.DryRunGuard.active()) {
@@ -1 +1 @@
1
- {"version":3,"file":"IntentAuditor.d.ts","sourceRoot":"","sources":["../../src/services/IntentAuditor.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAOpD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,WAAW,GAAG,QAAQ,CAAC;IAEjC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,YAAY,EAAE,CAAC;IAC7B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;IAC9B,+CAA+C;IAC/C,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,qEAAqE;IACrE,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B;AAED,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,cAAc,GAAG,YAAY,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,UAAU,GAAG,cAAc,GAAG,OAAO,GAAG,UAAU,GAAG,IAAI,CAAC;IACzE,yEAAyE;IACzE,cAAc,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5E;AAkED;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,IAAI,GAAE,oBAAyB;IA+BrC,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IA4G3D,sBAAsB,CACpB,OAAO,EAAE,YAAY,EAAE,EACvB,QAAQ,EAAE,YAAY,EAAE,GACvB,MAAM;IA4CT,kBAAkB,CAChB,UAAU,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACzC,WAAW,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GACzC,MAAM;IAmCT,OAAO,CAAC,YAAY;CA8CrB"}
1
+ {"version":3,"file":"IntentAuditor.d.ts","sourceRoot":"","sources":["../../src/services/IntentAuditor.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAOpD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,WAAW,GAAG,QAAQ,CAAC;IAEjC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,YAAY,EAAE,CAAC;IAC7B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,YAAY,EAAE,CAAC;IAC9B,+CAA+C;IAC/C,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,qEAAqE;IACrE,WAAW,CAAC,EAAE,UAAU,CAAC;CAC1B;AAED,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,cAAc,GAAG,YAAY,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,UAAU,GAAG,cAAc,GAAG,OAAO,GAAG,UAAU,GAAG,IAAI,CAAC;IACzE,yEAAyE;IACzE,cAAc,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5E;AAkED;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAU;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,IAAI,GAAE,oBAAyB;IA+BrC,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;IAyH3D,sBAAsB,CACpB,OAAO,EAAE,YAAY,EAAE,EACvB,QAAQ,EAAE,YAAY,EAAE,GACvB,MAAM;IA4CT,kBAAkB,CAChB,UAAU,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EACzC,WAAW,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,GACzC,MAAM;IAmCT,OAAO,CAAC,YAAY;CA8CrB"}
@@ -46,15 +46,15 @@ dotenv.config();
46
46
  const FALLBACK_VERDICT = {
47
47
  verdict: "SUSPICIOUS",
48
48
  confidence: 0,
49
- reason: "Auditor unavailable defaulting to cautious SUSPICIOUS verdict",
49
+ reason: "Auditor unavailable - defaulting to cautious SUSPICIOUS verdict",
50
50
  inversionType: null,
51
51
  };
52
52
  // Ancestry drift penalties (spec §2.1).
53
53
  // Applied as negative adjustments to the LLM's confidence score.
54
54
  // Maximum combined penalty: −30 pts.
55
55
  const DRIFT_PENALTIES = [
56
- { full: -20, partial: -10 }, // depth 1 direct parent
57
- { full: -10, partial: -5 }, // depth 2 grandparent
56
+ { full: -20, partial: -10 }, // depth 1 - direct parent
57
+ { full: -10, partial: -5 }, // depth 2 - grandparent
58
58
  ];
59
59
  // Anchor bonuses: positive-only (spec §3.3).
60
60
  // closestLabel exact match: +10 pts
@@ -85,8 +85,8 @@ RULES:
85
85
  3. Minor reformatting is irrelevant. "Save Changes" and "Save" are CONSISTENT.
86
86
  4. Role/aria context matters. A button that was "Submit" becoming "Cancel" is INCONSISTENT (identity inversion).
87
87
  5. When both texts are very short (3 chars or less) and differ, prefer SUSPICIOUS unless an obvious opposite pair.
88
- 6. In "assertion" mode, be stricter lean toward SUSPICIOUS or INCONSISTENT when the change is ambiguous.
89
- 7. In "action" mode, be more lenient lean toward CONSISTENT when the change looks like a UI refactor.
88
+ 6. In "assertion" mode, be stricter - lean toward SUSPICIOUS or INCONSISTENT when the change is ambiguous.
89
+ 7. In "action" mode, be more lenient - lean toward CONSISTENT when the change looks like a UI refactor.
90
90
 
91
91
  RESPONSE FORMAT (strict JSON, no other text):
92
92
  {
@@ -102,7 +102,7 @@ class IntentAuditor {
102
102
  model;
103
103
  constructor(opts = {}) {
104
104
  this.model = opts.model ?? DEFAULT_AUDITOR_MODEL;
105
- // Explicit `null` from the caller forces disabled mode used by tests.
105
+ // Explicit `null` from the caller forces disabled mode - used by tests.
106
106
  if (opts.anthropic === null) {
107
107
  this.anthropic = null;
108
108
  this.disabled = true;
@@ -117,7 +117,7 @@ class IntentAuditor {
117
117
  // Otherwise fall back to env-based construction (legacy default).
118
118
  const apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY;
119
119
  if (!apiKey) {
120
- console.warn("[IntentAuditor] ANTHROPIC_API_KEY not set auditor disabled, will return SUSPICIOUS for all audited heals");
120
+ console.warn("[IntentAuditor] ANTHROPIC_API_KEY not set - auditor disabled, will return SUSPICIOUS for all audited heals");
121
121
  this.anthropic = null;
122
122
  this.disabled = true;
123
123
  }
@@ -154,7 +154,7 @@ class IntentAuditor {
154
154
  // ── Structural scoring ────────────────────────────────────────
155
155
  // Apply ancestry drift penalty and anchor bonus to the LLM's raw
156
156
  // confidence. The semantic verdict category (CONSISTENT / SUSPICIOUS /
157
- // INCONSISTENT) is never changed by scoring only the confidence value.
157
+ // INCONSISTENT) is never changed by scoring - only the confidence value.
158
158
  // The low-confidence CONSISTENT→SUSPICIOUS downgrade is re-evaluated
159
159
  // after scoring so the adjusted value is used for the threshold.
160
160
  const penalty = this.computeAncestryPenalty(req.dnaAncestry ?? [], req.liveAncestry ?? []);
@@ -172,7 +172,11 @@ class IntentAuditor {
172
172
  // Re-apply low-confidence CONSISTENT downgrade with the adjusted value.
173
173
  // The raw check in parseVerdict used the pre-adjustment confidence; a
174
174
  // penalty may push a borderline CONSISTENT below the 50% threshold.
175
- const scoring = { rawConfidence: rawVerdict.confidence, penalty, bonus };
175
+ const scoring = {
176
+ rawConfidence: rawVerdict.confidence,
177
+ penalty,
178
+ bonus,
179
+ };
176
180
  if (rawVerdict.verdict === "CONSISTENT" && adjConf < 50) {
177
181
  finalVerdict = {
178
182
  verdict: "SUSPICIOUS",
@@ -184,22 +188,29 @@ class IntentAuditor {
184
188
  console.log(`[IntentAuditor] CONSISTENT→SUSPICIOUS after scoring (${rawVerdict.confidence}%→${adjConf}%)`);
185
189
  }
186
190
  else {
187
- finalVerdict = { ...rawVerdict, confidence: adjConf, scoreBreakdown: scoring };
191
+ finalVerdict = {
192
+ ...rawVerdict,
193
+ confidence: adjConf,
194
+ scoreBreakdown: scoring,
195
+ };
188
196
  }
189
197
  }
190
198
  else {
191
199
  finalVerdict = rawVerdict;
192
200
  }
193
- console.log(`[IntentAuditor] verdict=${finalVerdict.verdict} (${finalVerdict.confidence}%) ${finalVerdict.reason}`);
201
+ console.log(`[IntentAuditor] verdict=${finalVerdict.verdict} (${finalVerdict.confidence}%) - ${finalVerdict.reason}`);
194
202
  return finalVerdict;
195
203
  }
196
204
  catch (err) {
197
- console.warn(`[IntentAuditor] Warning: Auditor call failed: ${err.message} returning SUSPICIOUS`);
198
- return { ...FALLBACK_VERDICT, reason: `Auditor call failed: ${err.message}` };
205
+ console.warn(`[IntentAuditor] Warning: Auditor call failed: ${err.message} - returning SUSPICIOUS`);
206
+ return {
207
+ ...FALLBACK_VERDICT,
208
+ reason: `Auditor call failed: ${err.message}`,
209
+ };
199
210
  }
200
211
  }
201
212
  // ─────────────────────────────────────────────────────────────
202
- // computeAncestryPenalty DNA v2 Ancestry Drift (spec §2)
213
+ // computeAncestryPenalty - DNA v2 Ancestry Drift (spec §2)
203
214
  //
204
215
  // Compares at most 2 ancestor depths between the DNA baseline and
205
216
  // the live candidate. Returns a value in [−30, 0]; 0 = no drift.
@@ -216,7 +227,7 @@ class IntentAuditor {
216
227
  // ─────────────────────────────────────────────────────────────
217
228
  computeAncestryPenalty(dnaPath, livePath) {
218
229
  if (dnaPath.length === 0)
219
- return 0; // v1 migrated snapshot skip
230
+ return 0; // v1 migrated snapshot - skip
220
231
  let totalPenalty = 0;
221
232
  const maxDepth = Math.min(dnaPath.length, livePath.length, 2);
222
233
  for (let i = 0; i < maxDepth; i++) {
@@ -229,21 +240,21 @@ class IntentAuditor {
229
240
  const depthLabel = i === 0 ? "depth-1 (parent)" : "depth-2 (grandparent)";
230
241
  if (dna.tag !== live.tag) {
231
242
  totalPenalty += full;
232
- console.log(`[IntentAuditor] 🏗️ Ancestry drift ${full} pts ${depthLabel}: ` +
243
+ console.log(`[IntentAuditor] 🏗️ Ancestry drift ${full} pts - ${depthLabel}: ` +
233
244
  `tag mismatch (${dna.fingerprint} → ${live.fingerprint})`);
234
245
  }
235
246
  else {
236
247
  totalPenalty += partial;
237
- console.log(`[IntentAuditor] 🏗️ Ancestry drift ${partial} pts ${depthLabel}: ` +
248
+ console.log(`[IntentAuditor] 🏗️ Ancestry drift ${partial} pts - ${depthLabel}: ` +
238
249
  `same tag, id/class changed (${dna.fingerprint} → ${live.fingerprint})`);
239
250
  }
240
251
  }
241
252
  return totalPenalty;
242
253
  }
243
254
  // ─────────────────────────────────────────────────────────────
244
- // computeAnchorBonus DNA v2 Anchor Confirmation (spec §3.3)
255
+ // computeAnchorBonus - DNA v2 Anchor Confirmation (spec §3.3)
245
256
  //
246
- // Anchors only provide positive confirmation no penalty for
257
+ // Anchors only provide positive confirmation - no penalty for
247
258
  // mismatch. Returns a value in [0, +15].
248
259
  //
249
260
  // closestLabel exact match (case-insensitive): +10 pts
@@ -257,13 +268,13 @@ class IntentAuditor {
257
268
  const liveLabel = liveAnchors.closestLabel?.toLowerCase().trim();
258
269
  if (dnaLabel && liveLabel && dnaLabel === liveLabel) {
259
270
  bonus += ANCHOR_BONUS_LABEL;
260
- console.log(`[IntentAuditor] 🎯 Anchor +${ANCHOR_BONUS_LABEL} pts closestLabel match: "${dnaAnchors.closestLabel}"`);
271
+ console.log(`[IntentAuditor] 🎯 Anchor +${ANCHOR_BONUS_LABEL} pts - closestLabel match: "${dnaAnchors.closestLabel}"`);
261
272
  }
262
273
  const dnaRow = dnaAnchors.rowAnchor?.toLowerCase().trim();
263
274
  const liveRow = liveAnchors.rowAnchor?.toLowerCase().trim();
264
275
  if (dnaRow && liveRow && dnaRow === liveRow) {
265
276
  bonus += ANCHOR_BONUS_ROW;
266
- console.log(`[IntentAuditor] 🎯 Anchor +${ANCHOR_BONUS_ROW} pts rowAnchor match: "${dnaAnchors.rowAnchor}"`);
277
+ console.log(`[IntentAuditor] 🎯 Anchor +${ANCHOR_BONUS_ROW} pts - rowAnchor match: "${dnaAnchors.rowAnchor}"`);
267
278
  }
268
279
  return bonus;
269
280
  }
@@ -1,24 +1,15 @@
1
1
  import type { PendingPromptEntry } from "./PendingPromptLedger";
2
- export interface InteractiveReviewDeps {
2
+ export interface PrintReviewDeps {
3
3
  entries: PendingPromptEntry[];
4
- /** Override the prompt tests stub Y/N answers without spinning up readline. */
5
- prompt?: (question: string) => Promise<string>;
6
- /** Override the console sink — tests capture output for assertions. */
4
+ /** Override the console sink - tests capture output for assertions. */
7
5
  log?: (msg: string) => void;
8
- /** Override the filesystem rollback (rewrites contentBefore). Tests stub. */
9
- rollback?: (entry: PendingPromptEntry) => void;
10
- }
11
- export interface InteractiveReviewOutcome {
12
- file: string;
13
- applied: boolean;
6
+ /** Absolute path of the rendered Sela Insights HTML report, when present. */
7
+ reportHtmlPath?: string | null;
14
8
  }
15
9
  /**
16
- * Run the post-run interactive review loop sequentially across every
17
- * pending entry. Returns one outcome per entry so callers can log / test
18
- * the resulting Apply / Reject decisions.
19
- *
20
- * Sequential by design — every prompt `await`s before the next entry is
21
- * rendered. Concurrent prompts on a single TTY would interleave output.
10
+ * Print the post-run review summary. Returns immediately - never blocks
11
+ * on stdin. Safe to call from the reporter's onEnd() in any environment
12
+ * (TTY, piped CI, IDE-integrated runner).
22
13
  */
23
- export declare function runInteractiveReview(deps: InteractiveReviewDeps): Promise<InteractiveReviewOutcome[]>;
14
+ export declare function printHealReview(deps: PrintReviewDeps): void;
24
15
  //# sourceMappingURL=InteractiveReview.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"InteractiveReview.d.ts","sourceRoot":"","sources":["../../src/services/InteractiveReview.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,iFAAiF;IACjF,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/C,uEAAuE;IACvE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAChD;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAID;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,wBAAwB,EAAE,CAAC,CA+CrC"}
1
+ {"version":3,"file":"InteractiveReview.d.ts","sourceRoot":"","sources":["../../src/services/InteractiveReview.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,kBAAkB,EAAE,CAAC;IAC9B,uEAAuE;IACvE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CA0B3D"}
@@ -1,21 +1,18 @@
1
1
  "use strict";
2
2
  // src/services/InteractiveReview.ts
3
3
  //
4
- // Local DX Interactive CLI review of post-run heals.
4
+ // Local DX - Post-run summary printer (MVP write-and-notify).
5
5
  //
6
- // Runs in the REPORTER (main process) only — workers must never block on
7
- // stdin. The reporter reads cross-process state from
8
- // `PendingPromptLedger` and calls `runInteractiveReview()` with the
9
- // merged entry list.
6
+ // The MVP flow is write-on-disk-then-notify: workers (and the engine)
7
+ // already mutated the source files in-place during execution. The
8
+ // reporter calls printHealReview() at the end purely to display:
9
+ // a banner with the number of mutated files,
10
+ // • per-file isolated unified diff (clean room - never the working tree),
11
+ // • a vscode://file deeplink to the mutated line,
12
+ // • an optional deeplink to the generated HTML insights report.
10
13
  //
11
- // For every entry: prints `[Sela] 🔧 Healed selector in <FileName>`, the
12
- // isolated unified diff, a clickable `vscode://file/<abs>:<line>`
13
- // deeplink, then prompts the developer. 'Y' / 'y' / Enter keeps the
14
- // on-disk fix (the worker already wrote it); 'N' / 'n' rewrites the file
15
- // back to `contentBefore` (the pre-heal state captured by
16
- // `WorkspaceSnapshotService.preWrite()` in the worker).
17
- //
18
- // All I/O is injectable so this can be unit-tested without a real TTY.
14
+ // No prompts. No rollback. No blocking on stdin. SIGINT handling lives
15
+ // in SelaReporter - this module is pure stdout/stderr.
19
16
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
17
  if (k2 === undefined) k2 = k;
21
18
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -53,55 +50,34 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
53
50
  return (mod && mod.__esModule) ? mod : { "default": mod };
54
51
  };
55
52
  Object.defineProperty(exports, "__esModule", { value: true });
56
- exports.runInteractiveReview = runInteractiveReview;
57
- const fs = __importStar(require("fs"));
53
+ exports.printHealReview = printHealReview;
58
54
  const path = __importStar(require("path"));
59
- const readline = __importStar(require("readline"));
60
55
  const chalk_1 = __importDefault(require("chalk"));
61
56
  const IsolatedDiff_1 = require("../utils/IsolatedDiff");
62
- const DEFAULT_PROMPT = "[Sela] Apply this fix? (Y/n): ";
63
57
  /**
64
- * Run the post-run interactive review loop sequentially across every
65
- * pending entry. Returns one outcome per entry so callers can log / test
66
- * the resulting Apply / Reject decisions.
67
- *
68
- * Sequential by design — every prompt `await`s before the next entry is
69
- * rendered. Concurrent prompts on a single TTY would interleave output.
58
+ * Print the post-run review summary. Returns immediately - never blocks
59
+ * on stdin. Safe to call from the reporter's onEnd() in any environment
60
+ * (TTY, piped CI, IDE-integrated runner).
70
61
  */
71
- async function runInteractiveReview(deps) {
62
+ function printHealReview(deps) {
72
63
  const log = deps.log ?? ((m) => process.stdout.write(m + "\n"));
73
- const prompt = deps.prompt ?? defaultPrompt;
74
- const rollback = deps.rollback ?? defaultRollback;
75
64
  const entries = deps.entries ?? [];
76
- const outcomes = [];
77
- if (entries.length === 0)
78
- return outcomes;
79
- // Headline banner — surfaces even when downstream chalk/readline
80
- // output is suppressed by the host terminal multiplexer (e.g.
81
- // Playwright's reporter-level stdio interception).
65
+ const reportHtmlPath = deps.reportHtmlPath ?? null;
66
+ if (entries.length === 0 && !reportHtmlPath)
67
+ return;
82
68
  log("");
83
- log(chalk_1.default.bold.bgCyan.black(` [Sela] Local DX Review — ${entries.length} pending fix(es) `));
84
- for (const entry of entries) {
85
- renderEntry(entry, log);
86
- const answer = await prompt(chalk_1.default.cyan(DEFAULT_PROMPT));
87
- const decision = parseDecision(answer);
88
- if (decision === "apply") {
89
- log(chalk_1.default.green(`[Sela] ✅ Fix kept on disk: ${entry.relativePath}`));
90
- outcomes.push({ file: entry.absolutePath, applied: true });
91
- }
92
- else {
93
- try {
94
- rollback(entry);
95
- log(chalk_1.default.yellow(`[Sela] ↩️ Rolled back: ${entry.relativePath} (restored to pre-heal state)`));
96
- }
97
- catch (err) {
98
- log(chalk_1.default.red(`[Sela] ⚠️ Rollback failed for ${entry.relativePath}: ${err.message}`));
99
- }
100
- outcomes.push({ file: entry.absolutePath, applied: false });
69
+ if (entries.length > 0) {
70
+ log(chalk_1.default.bold.bgCyan.black(` [Sela] Local DX Review - ${entries.length} fix${entries.length === 1 ? "" : "es"} applied to disk `));
71
+ for (const entry of entries) {
72
+ renderEntry(entry, log);
101
73
  }
102
74
  }
75
+ if (reportHtmlPath) {
76
+ log("");
77
+ log(chalk_1.default.bold(`[Sela] 📄 Insights report:`));
78
+ log(` ${chalk_1.default.cyan(buildFileLink(reportHtmlPath))}`);
79
+ }
103
80
  log("");
104
- return outcomes;
105
81
  }
106
82
  function renderEntry(entry, log) {
107
83
  const fileName = path.basename(entry.absolutePath);
@@ -113,9 +89,8 @@ function renderEntry(entry, log) {
113
89
  log("");
114
90
  log(colorizeDiff(diff));
115
91
  log("");
116
- log(`👉 To review and accept this fix directly in VS Code, click here:`);
92
+ log(`👉 Open in VS Code:`);
117
93
  log(` ${chalk_1.default.cyan(buildVsCodeLink(entry.absolutePath, entry.lineNumber))}`);
118
- log("");
119
94
  }
120
95
  function colorizeDiff(diff) {
121
96
  if (!diff)
@@ -144,75 +119,7 @@ function buildVsCodeLink(absPath, line) {
144
119
  ? `vscode://file/${normalised}:${line}`
145
120
  : `vscode://file/${normalised}`;
146
121
  }
147
- function parseDecision(raw) {
148
- const trimmed = (raw ?? "").trim().toLowerCase();
149
- // Empty (Enter) ⇒ apply. 'y' / 'yes' ⇒ apply. 'n' / 'no' ⇒ reject.
150
- // Anything else ⇒ apply (default-safe — never silently destroy work).
151
- if (trimmed === "" || trimmed === "y" || trimmed === "yes")
152
- return "apply";
153
- if (trimmed === "n" || trimmed === "no")
154
- return "reject";
155
- return "apply";
156
- }
157
- /**
158
- * Default rollback — rewrites `contentBefore` to disk. Honours the
159
- * `createdBySela` flag so files Sela CREATED from nothing get unlinked
160
- * instead of being replaced with an empty buffer.
161
- */
162
- function defaultRollback(entry) {
163
- if (entry.createdBySela) {
164
- if (fs.existsSync(entry.absolutePath)) {
165
- fs.unlinkSync(entry.absolutePath);
166
- }
167
- return;
168
- }
169
- fs.writeFileSync(entry.absolutePath, entry.contentBefore, "utf8");
170
- }
171
- /**
172
- * Bind `readline` to the live stdin/stdout. Reporter-only — workers must
173
- * never reach this code path (they have no TTY and would deadlock).
174
- *
175
- * Hardening:
176
- * • If stdin is not a TTY (CI, non-interactive shell, Playwright reporter
177
- * context that detached stdio), default to Apply ('y') without blocking.
178
- * • Explicitly `resume()` stdin — Node pauses it by default once any other
179
- * consumer (readline-from-an-earlier-iteration, raw-mode toggles) lets go.
180
- * • Write the prompt to `stderr` so Playwright's stdout summary buffer does
181
- * not overwrite or strip the question line.
182
- */
183
- function defaultPrompt(question) {
184
- const stdinIsTty = process.stdin.isTTY === true;
185
- if (!stdinIsTty) {
186
- process.stderr.write(question + "y (no TTY — auto-apply)\n");
187
- return Promise.resolve("y");
188
- }
189
- return new Promise((resolve) => {
190
- try {
191
- process.stdin.resume();
192
- }
193
- catch {
194
- // Already resumed / not resumable — readline will still try.
195
- }
196
- // `terminal: false` reads stdin line-buffered without raw-mode tricks.
197
- // This is reliable for both real TTYs AND piped harnesses (CI smoke
198
- // tests, child-process drivers). `terminal: true` only adds history /
199
- // arrow-key support, which we don't need for a single Y/N prompt and
200
- // which mis-parses piped input on Windows.
201
- process.stderr.write(question);
202
- const rl = readline.createInterface({
203
- input: process.stdin,
204
- output: process.stderr,
205
- terminal: false,
206
- });
207
- let settled = false;
208
- const finalise = (answer) => {
209
- if (settled)
210
- return;
211
- settled = true;
212
- rl.close();
213
- resolve(answer);
214
- };
215
- rl.once("line", (line) => finalise(line));
216
- rl.once("close", () => finalise("y"));
217
- });
122
+ function buildFileLink(absPath) {
123
+ const normalised = absPath.split(path.sep).join("/");
124
+ return `file://${normalised}`;
218
125
  }
@@ -79,7 +79,7 @@ export interface FixResponse {
79
79
  originalChainHint?: SmartChainSegment[];
80
80
  /**
81
81
  * Confidence score 0-100. Undefined when the model omitted it or returned a
82
- * non-finite value downstream code must treat undefined as "unknown" and
82
+ * non-finite value - downstream code must treat undefined as "unknown" and
83
83
  * render "n/a" rather than synthesising a 0.
84
84
  */
85
85
  confidence?: number;
@@ -71,11 +71,11 @@ Narrowing: filter, first, last, nth
71
71
  You MUST return a "chainSegments" array for the permanent code fix AND a matching "segments" array for the runtime proxy.
72
72
 
73
73
  Build the chain in this priority order:
74
- PRIORITY 1 getByTestId
75
- PRIORITY 2 getByRole (ALWAYS include "name" if it exists in the DOM to ensure uniqueness)
76
- PRIORITY 3 getByLabel
77
- PRIORITY 4 getByText (use exact: true if possible)
78
- NARROWING Use filter({ hasText: "..." }) to isolate an element within a repeated container.
74
+ PRIORITY 1 - getByTestId
75
+ PRIORITY 2 - getByRole (ALWAYS include "name" if it exists in the DOM to ensure uniqueness)
76
+ PRIORITY 3 - getByLabel
77
+ PRIORITY 4 - getByText (use exact: true if possible)
78
+ NARROWING - Use filter({ hasText: "..." }) to isolate an element within a repeated container.
79
79
 
80
80
  ### PROXY SELECTOR CONSTRUCTION (segments field)
81
81
  The "segments[0].selector" string is used for an immediate "live" retry.
@@ -90,10 +90,10 @@ Preserve the original code's structural pattern from "originalChainHint":
90
90
 
91
91
  ### TEMPLATE LITERAL / FUNCTION SELECTOR PRESERVATION
92
92
  When the failing selector originates from a Template Literal or a function returning a template,
93
- preserve the attribute structure update the value inside the attribute rather than removing it.
93
+ preserve the attribute structure - update the value inside the attribute rather than removing it.
94
94
  For chain selectors: if the original was "#section-B >> input[data-role='user_legacy']"
95
95
  and the DNA shows data-role changed to "user_active", return "#section-B >> input[data-role='user_active']".
96
- NEVER simplify to "#section-B >> input" that loses the attribute and breaks automated source healing.
96
+ NEVER simplify to "#section-B >> input" - that loses the attribute and breaks automated source healing.
97
97
  The healing system depends on the attribute value being present in your response to patch the template variable.
98
98
 
99
99
  ### TYPE SAFETY RULES
@@ -105,21 +105,21 @@ If the element's text changed, you MUST include:
105
105
  "contentChange": { "oldText": "<previous>", "newText": "<current>" }
106
106
 
107
107
  ### CONFIDENCE SCORE (MANDATORY)
108
- You MUST include a numeric "confidence" field an INTEGER in the range 0-100
108
+ You MUST include a numeric "confidence" field - an INTEGER in the range 0-100 -
109
109
  representing how certain you are that the returned chain will resolve the
110
110
  intended element on the next test run. Use this rubric:
111
- - 90-100: stable id, data-testid, or unique role+name zero ambiguity in the DOM.
111
+ - 90-100: stable id, data-testid, or unique role+name - zero ambiguity in the DOM.
112
112
  - 70-89: strong semantic match, but some structural drift or competing candidates.
113
- - 50-69: best-guess match multiple plausible candidates required disambiguation.
114
- - 1-49: speculative match return this only when no better candidate exists.
113
+ - 50-69: best-guess match - multiple plausible candidates required disambiguation.
114
+ - 1-49: speculative match - return this only when no better candidate exists.
115
115
  NEVER omit this field. NEVER return it as a string, boolean, or null.
116
- Reports rendered downstream will show "n/a" when this field is missing which
116
+ Reports rendered downstream will show "n/a" when this field is missing - which
117
117
  is a clear failure signal to the developer reviewing the heal.
118
118
 
119
119
  ### MANDATORY OUTPUT FORMAT
120
120
  Return ONLY valid JSON.
121
121
 
122
- Example output Identifying a specific button in a list row:
122
+ Example output - Identifying a specific button in a list row:
123
123
  {
124
124
  "status": "FIXED",
125
125
  "confidence": 92,
@@ -215,7 +215,7 @@ class LLMService {
215
215
  throw new SelaError_1.SelaError({
216
216
  subsystem: "LLMService",
217
217
  code: SelaError_1.LLM_SERVICE_CODES.NO_API_KEY,
218
- reason: "ANTHROPIC_API_KEY not found pass an `anthropic` client or `apiKey` to LLMService(), or set the env var",
218
+ reason: "ANTHROPIC_API_KEY not found - pass an `anthropic` client or `apiKey` to LLMService(), or set the env var",
219
219
  });
220
220
  }
221
221
  this.anthropic = new sdk_1.default({ apiKey });
@@ -339,7 +339,7 @@ ${request.targetIntent}
339
339
  ### PREVIOUS DNA (Element Fingerprint):
340
340
  ${dnaSummary && Object.keys(dnaSummary).length > 0
341
341
  ? JSON.stringify(dnaSummary, null, 2)
342
- : "NO DNA (First run infer from selector and DOM)"}
342
+ : "NO DNA (First run - infer from selector and DOM)"}
343
343
 
344
344
  ### CURRENT DOM SNIPPET:
345
345
  ${request.currentDom}
@@ -351,7 +351,7 @@ ${request.currentDom}
351
351
  4. Populate "contentChange" if the element's visible text changed.
352
352
  5. Also populate "segments" (legacy format) for backward compatibility.
353
353
 
354
- Return ONLY a raw JSON object no markdown, no preamble.`;
354
+ Return ONLY a raw JSON object - no markdown, no preamble.`;
355
355
  try {
356
356
  const msg = await this.anthropic.messages.create({
357
357
  model: this.model,
@@ -37,14 +37,14 @@ export interface ExecutionResult {
37
37
  * Clean-Room execution lifecycle.
38
38
  *
39
39
  * The legacy flow committed the developer's whole dirty working tree onto
40
- * the PR branch polluting reviewers with `test.only`, commented debug
40
+ * the PR branch - polluting reviewers with `test.only`, commented debug
41
41
  * blocks, etc. This refactor isolates Sela's specific AST changes onto an
42
42
  * ephemeral branch, leaves the developer's local workspace byte-identical
43
43
  * to its pre-Sela state, and is wrapped in a try/finally that restores
44
44
  * the workspace even on mid-flight crashes.
45
45
  */
46
46
  export declare function execute(cfg: ResolvedPRAutomation, decision: StrategyDecision, heals: HealedEvent[], branchInfo: BranchInfo, ctx: ExecuteContext,
47
- /** Injectable for tests defaults to the module singleton. */
47
+ /** Injectable for tests - defaults to the module singleton. */
48
48
  workspace?: WorkspaceSnapshotService): Promise<ExecutionResult>;
49
49
  export declare function handleBugDetected(action: BugAction, events: ProtectedEvent[], branchInfo: BranchInfo, ctx: ExecuteContext): Promise<void>;
50
50
  //# sourceMappingURL=PRAutomationService.d.ts.map