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
@@ -4,7 +4,15 @@ export declare enum AdvisoryCode {
4
4
  CROSS_FILE_MUTATION = "CROSS_FILE_MUTATION",
5
5
  MANUAL_REVIEW_TEMPLATE_COMPLEX = "MANUAL_REVIEW_TEMPLATE_COMPLEX",
6
6
  MANUAL_REVIEW_CONDITIONAL_RETURN = "MANUAL_REVIEW_CONDITIONAL_RETURN",
7
- POST_MUTATION_TYPE_ERROR = "POST_MUTATION_TYPE_ERROR"
7
+ POST_MUTATION_TYPE_ERROR = "POST_MUTATION_TYPE_ERROR",
8
+ /**
9
+ * A definition-site string constant was healed to a valid PUBLIC selector
10
+ * string (e.g. `role=button[name="…"]`) because the constant is consumed by
11
+ * `.locator(VAR)` and cannot hold a semantic locator. The AI's preferred
12
+ * semantic method form (e.g. `getByRole(...)`) is suggested as a cleaner,
13
+ * optional refactor.
14
+ */
15
+ SEMANTIC_UPGRADE_SUGGESTED = "SEMANTIC_UPGRADE_SUGGESTED"
8
16
  }
9
17
  export interface Advisory {
10
18
  code: AdvisoryCode;
@@ -1 +1 @@
1
- {"version":3,"file":"HealingAdvisory.d.ts","sourceRoot":"","sources":["../../src/services/HealingAdvisory.ts"],"names":[],"mappings":"AAQA,oBAAY,YAAY;IACtB,oBAAoB,yBAAyB;IAC7C,oBAAoB,yBAAyB;IAC7C,mBAAmB,wBAAwB;IAC3C,8BAA8B,mCAAmC;IACjE,gCAAgC,qCAAqC;IACrE,wBAAwB,6BAA6B;CACtD;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAkB;IAE/B,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAI9B,KAAK,IAAI,IAAI;IAab,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF"}
1
+ {"version":3,"file":"HealingAdvisory.d.ts","sourceRoot":"","sources":["../../src/services/HealingAdvisory.ts"],"names":[],"mappings":"AAQA,oBAAY,YAAY;IACtB,oBAAoB,yBAAyB;IAC7C,oBAAoB,yBAAyB;IAC7C,mBAAmB,wBAAwB;IAC3C,8BAA8B,mCAAmC;IACjE,gCAAgC,qCAAqC;IACrE,wBAAwB,6BAA6B;IACrD;;;;;;OAMG;IACH,0BAA0B,+BAA+B;CAC1D;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAkB;IAE/B,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAI9B,KAAK,IAAI,IAAI;IAab,IAAI,MAAM,IAAI,MAAM,CAEnB;CACF"}
@@ -4,7 +4,7 @@
4
4
  //
5
5
  // Typed advisory system for definition-site mutations.
6
6
  // Advisories are buffered during the AST phase and flushed AFTER
7
- // Playwright prints its test result prevents interleaving.
7
+ // Playwright prints its test result - prevents interleaving.
8
8
  // ═══════════════════════════════════════════════════════════════════
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.AdvisoryBuffer = exports.AdvisoryCode = void 0;
@@ -16,6 +16,14 @@ var AdvisoryCode;
16
16
  AdvisoryCode["MANUAL_REVIEW_TEMPLATE_COMPLEX"] = "MANUAL_REVIEW_TEMPLATE_COMPLEX";
17
17
  AdvisoryCode["MANUAL_REVIEW_CONDITIONAL_RETURN"] = "MANUAL_REVIEW_CONDITIONAL_RETURN";
18
18
  AdvisoryCode["POST_MUTATION_TYPE_ERROR"] = "POST_MUTATION_TYPE_ERROR";
19
+ /**
20
+ * A definition-site string constant was healed to a valid PUBLIC selector
21
+ * string (e.g. `role=button[name="…"]`) because the constant is consumed by
22
+ * `.locator(VAR)` and cannot hold a semantic locator. The AI's preferred
23
+ * semantic method form (e.g. `getByRole(...)`) is suggested as a cleaner,
24
+ * optional refactor.
25
+ */
26
+ AdvisoryCode["SEMANTIC_UPGRADE_SUGGESTED"] = "SEMANTIC_UPGRADE_SUGGESTED";
19
27
  })(AdvisoryCode || (exports.AdvisoryCode = AdvisoryCode = {}));
20
28
  class AdvisoryBuffer {
21
29
  items = [];
@@ -3,11 +3,11 @@ export type HealCacheMode = "action" | "assertion";
3
3
  export interface CacheKeyInput {
4
4
  /** Absolute or project-relative spec path containing the failing locator. */
5
5
  filePath: string;
6
- /** 1-based line of the failing call site paired with filePath as a fingerprint. */
6
+ /** 1-based line of the failing call site - paired with filePath as a fingerprint. */
7
7
  line: number;
8
8
  /**
9
9
  * Stable content hash of the DNA snapshot used to drive the heal. When the
10
- * DNA rewrites, this changes every cached entry for the old DNA
10
+ * DNA rewrites, this changes - every cached entry for the old DNA
11
11
  * silently stops matching and ages out via TTL.
12
12
  */
13
13
  dnaContentHash: string;
@@ -66,7 +66,7 @@ export interface HealingCacheSetInput extends CacheKeyInput {
66
66
  }
67
67
  export declare function computeCacheKey(input: CacheKeyInput): string;
68
68
  /**
69
- * Convenience helper fingerprint the JSON form of a DNA snapshot so
69
+ * Convenience helper - fingerprint the JSON form of a DNA snapshot so
70
70
  * the cache key changes whenever the DNA is rewritten.
71
71
  */
72
72
  export declare function hashDnaContent(dna: unknown): string;
@@ -83,7 +83,7 @@ export declare class HealingCacheService {
83
83
  });
84
84
  /**
85
85
  * Read-only lookup. Bumps `hitCount` / `lastHitAt` IN-MEMORY only on
86
- * the returned entry reference never persisted on the get() path.
86
+ * the returned entry reference - never persisted on the get() path.
87
87
  * This eliminates the read-write race where parallel workers each
88
88
  * call get() and serialise full entries-map snapshots back to disk,
89
89
  * overwriting peer set() operations.
@@ -96,7 +96,7 @@ export declare class HealingCacheService {
96
96
  * deadlocks downstream callers.
97
97
  */
98
98
  set(input: HealingCacheSetInput): Promise<void>;
99
- /** Synchronous variant used by teardown / CLI paths. */
99
+ /** Synchronous variant - used by teardown / CLI paths. */
100
100
  setSync(input: HealingCacheSetInput): void;
101
101
  /** Wipe every entry. Used by tests and the (forthcoming) `sela cache clear` CLI. */
102
102
  clear(): void;
@@ -105,7 +105,7 @@ export declare class HealingCacheService {
105
105
  /** Absolute path of the on-disk cache file. */
106
106
  filePath(): string;
107
107
  /**
108
- * Prunes expired entries. Cheap O(n) scan intended for engine
108
+ * Prunes expired entries. Cheap O(n) scan - intended for engine
109
109
  * startup. Returns the number of entries removed.
110
110
  */
111
111
  pruneExpired(): number;
@@ -115,13 +115,13 @@ export declare class HealingCacheService {
115
115
  /**
116
116
  * Reads + parses the cache file. Tolerates every realistic failure
117
117
  * (missing, empty, malformed, wrong schema version) by returning a
118
- * fresh empty shell the contract is "cache misses are silent".
118
+ * fresh empty shell - the contract is "cache misses are silent".
119
119
  */
120
120
  private safeRead;
121
121
  /**
122
122
  * Atomic write: write to `<file>.tmp`, copy current to `<file>.bak`,
123
123
  * then rename `<file>.tmp` → `<file>`. The rename is the single
124
- * commit point a crash between bak and rename leaves the bak file
124
+ * commit point - a crash between bak and rename leaves the bak file
125
125
  * intact for future recovery.
126
126
  */
127
127
  private atomicWrite;
@@ -1 +1 @@
1
- {"version":3,"file":"HealingCacheService.d.ts","sourceRoot":"","sources":["../../src/services/HealingCacheService.ts"],"names":[],"mappings":"AA8DA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAMvE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEnD,MAAM,WAAW,aAAa;IAC5B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,aAAa,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACpC,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,SAAS;IACjB,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACpC,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAmBD,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAc5D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAQnD;AAMD,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IAIpC,OAAO,CAAC,QAAQ,CAAoC;gBAExC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE;IAU3D;;;;;;OAMG;IACH,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,iBAAiB,GAAG,IAAI;IAgBnD;;;;;OAKG;IACG,GAAG,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgCrD,0DAA0D;IAC1D,OAAO,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI;IAU1C,oFAAoF;IACpF,KAAK,IAAI,IAAI;IAeb,oEAAoE;IACpE,IAAI,IAAI,SAAS;IAIjB,+CAA+C;IAC/C,QAAQ,IAAI,MAAM;IAIlB;;;OAGG;IACH,YAAY,IAAI,MAAM;IAmBtB,OAAO,CAAC,SAAS;YAOH,WAAW;IAkBzB,OAAO,CAAC,UAAU;IA8BlB;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAqChB;;;;;OAKG;IACH,OAAO,CAAC,WAAW;YA4BL,sBAAsB;IAUpC,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,WAAW;CAOpB;AAqBD,eAAO,MAAM,kBAAkB,qBAA4B,CAAC"}
1
+ {"version":3,"file":"HealingCacheService.d.ts","sourceRoot":"","sources":["../../src/services/HealingCacheService.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,14 @@
1
1
  "use strict";
2
2
  // src/services/HealingCacheService.ts
3
3
  //
4
- // Local healing cache short-circuits the LLM round-trip when an
4
+ // Local healing cache - short-circuits the LLM round-trip when an
5
5
  // identical heal-context has been resolved successfully in a prior
6
6
  // session.
7
7
  //
8
8
  // Cache key (matches DX MVP Phase 6 plan):
9
9
  // SHA1(filePath + ":" + line + "::" + dnaContentHash + "::" + brokenSelector + "::" + mode)
10
10
  // Including `dnaContentHash` means a DNA rewrite automatically
11
- // invalidates every entry keyed against that fingerprint old
11
+ // invalidates every entry keyed against that fingerprint - old
12
12
  // entries simply stop matching and age out via TTL.
13
13
  //
14
14
  // Cache value:
@@ -31,7 +31,7 @@
31
31
  // callers.
32
32
  //
33
33
  // 2. Cross-process file lock
34
- // Playwright workers run as separate processes atomic
34
+ // Playwright workers run as separate processes - atomic
35
35
  // `mkdir <cacheDir>/.sela-cache.lock` is used as the mutex. Second
36
36
  // process gets `EEXIST`, polls with exponential backoff
37
37
  // (50ms → 800ms, max 6 retries ≈ 3.15 s ceiling). Lock is held
@@ -39,7 +39,7 @@
39
39
  //
40
40
  // 3. Atomic write via temp + rename
41
41
  // Write to `.sela-cache.json.tmp`, copy the previous file to
42
- // `.sela-cache.json.bak`, then `fs.renameSync(tmp, target)`
42
+ // `.sela-cache.json.bak`, then `fs.renameSync(tmp, target)` -
43
43
  // atomic on POSIX and on Windows (Node ≥14) when source and
44
44
  // target share a volume (always true here).
45
45
  //
@@ -48,13 +48,13 @@
48
48
  // acquires the LLM via the normal path; cache writes happen post-success.
49
49
  //
50
50
  // `get()` is strictly read-only on disk: hit-count / lastHitAt are
51
- // bumped IN-MEMORY only they never trigger a disk write. This avoids
51
+ // bumped IN-MEMORY only - they never trigger a disk write. This avoids
52
52
  // the documented bug where concurrent worker `get()` calls would
53
53
  // overwrite valid `set()` operations from peer workers.
54
54
  //
55
55
  // Failure tolerance: any read failure (missing, malformed JSON, wrong
56
56
  // schema, EACCES, …) returns "no entries" instead of throwing. The
57
- // cache is a latency optimisation never a hard dependency of the
57
+ // cache is a latency optimisation - never a hard dependency of the
58
58
  // heal pipeline.
59
59
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
60
60
  if (k2 === undefined) k2 = k;
@@ -126,7 +126,7 @@ function computeCacheKey(input) {
126
126
  .digest("hex");
127
127
  }
128
128
  /**
129
- * Convenience helper fingerprint the JSON form of a DNA snapshot so
129
+ * Convenience helper - fingerprint the JSON form of a DNA snapshot so
130
130
  * the cache key changes whenever the DNA is rewritten.
131
131
  */
132
132
  function hashDnaContent(dna) {
@@ -148,7 +148,7 @@ class HealingCacheService {
148
148
  tmpSuffix = ".tmp";
149
149
  bakSuffix = ".bak";
150
150
  // In-process serialisation. Every new set() chains onto the prior
151
- // tail Promise. The chain is fault-tolerant see `set()` below.
151
+ // tail Promise. The chain is fault-tolerant - see `set()` below.
152
152
  inFlight = Promise.resolve();
153
153
  constructor(opts) {
154
154
  this.cacheDir = opts?.cacheDir ?? process.cwd();
@@ -160,7 +160,7 @@ class HealingCacheService {
160
160
  // ─────────────────────────────────────────────────────────────
161
161
  /**
162
162
  * Read-only lookup. Bumps `hitCount` / `lastHitAt` IN-MEMORY only on
163
- * the returned entry reference never persisted on the get() path.
163
+ * the returned entry reference - never persisted on the get() path.
164
164
  * This eliminates the read-write race where parallel workers each
165
165
  * call get() and serialise full entries-map snapshots back to disk,
166
166
  * overwriting peer set() operations.
@@ -175,7 +175,7 @@ class HealingCacheService {
175
175
  return null;
176
176
  if (this.isExpired(entry))
177
177
  return null;
178
- // In-memory only DO NOT write back. Hit-count drift across workers
178
+ // In-memory only - DO NOT write back. Hit-count drift across workers
179
179
  // is acceptable; corrupting peer writes is not.
180
180
  entry.hitCount = (entry.hitCount ?? 0) + 1;
181
181
  entry.lastHitAt = new Date().toISOString();
@@ -195,11 +195,11 @@ class HealingCacheService {
195
195
  // Chain onto the previous tail, but swallow rejections via a
196
196
  // `.catch(noop)` adapter. Without this, an earlier rejected set()
197
197
  // would propagate through every subsequent `await prev` and either
198
- // throw at the wrong caller or worse leak through the finally
198
+ // throw at the wrong caller or - worse - leak through the finally
199
199
  // block without releasing the queue. The wrapper guarantees the
200
200
  // queue is FIFO and rejection-safe.
201
201
  const prev = this.inFlight.catch(() => {
202
- /* swallow upstream failure handled by its own caller */
202
+ /* swallow - upstream failure handled by its own caller */
203
203
  });
204
204
  let release;
205
205
  const myTurn = new Promise((res) => {
@@ -211,12 +211,12 @@ class HealingCacheService {
211
211
  await this.lockedWrite(input);
212
212
  }
213
213
  finally {
214
- // Always release even on throw so the next queued caller
214
+ // Always release - even on throw - so the next queued caller
215
215
  // unblocks. Errors still propagate up to *this* caller normally.
216
216
  release();
217
217
  }
218
218
  }
219
- /** Synchronous variant used by teardown / CLI paths. */
219
+ /** Synchronous variant - used by teardown / CLI paths. */
220
220
  setSync(input) {
221
221
  if (DryRunGuard_1.DryRunGuard.active())
222
222
  return;
@@ -253,7 +253,7 @@ class HealingCacheService {
253
253
  return path.join(this.cacheDir, this.filename);
254
254
  }
255
255
  /**
256
- * Prunes expired entries. Cheap O(n) scan intended for engine
256
+ * Prunes expired entries. Cheap O(n) scan - intended for engine
257
257
  * startup. Returns the number of entries removed.
258
258
  */
259
259
  pruneExpired() {
@@ -272,7 +272,7 @@ class HealingCacheService {
272
272
  return removed;
273
273
  }
274
274
  // ─────────────────────────────────────────────────────────────
275
- // INTERNAL read / write / lock
275
+ // INTERNAL - read / write / lock
276
276
  // ─────────────────────────────────────────────────────────────
277
277
  isExpired(entry) {
278
278
  if (!entry.ttlExpiresAt)
@@ -285,7 +285,7 @@ class HealingCacheService {
285
285
  async lockedWrite(input) {
286
286
  const acquired = await this.acquireLockWithBackoff();
287
287
  if (!acquired) {
288
- console.warn(`[HealingCache] ⚠️ Could not acquire lock at ${this.lockDir} write skipped`);
288
+ console.warn(`[HealingCache] ⚠️ Could not acquire lock at ${this.lockDir} - write skipped`);
289
289
  return;
290
290
  }
291
291
  try {
@@ -326,7 +326,7 @@ class HealingCacheService {
326
326
  /**
327
327
  * Reads + parses the cache file. Tolerates every realistic failure
328
328
  * (missing, empty, malformed, wrong schema version) by returning a
329
- * fresh empty shell the contract is "cache misses are silent".
329
+ * fresh empty shell - the contract is "cache misses are silent".
330
330
  */
331
331
  safeRead() {
332
332
  const target = path.join(this.cacheDir, this.filename);
@@ -345,7 +345,7 @@ class HealingCacheService {
345
345
  parsed = JSON.parse(raw);
346
346
  }
347
347
  catch (err) {
348
- console.warn(`[HealingCache] ⚠️ Corrupt cache file at ${target} starting fresh (${err.message})`);
348
+ console.warn(`[HealingCache] ⚠️ Corrupt cache file at ${target} - starting fresh (${err.message})`);
349
349
  return { schemaVersion: 1, entries: {} };
350
350
  }
351
351
  if (!parsed ||
@@ -355,7 +355,7 @@ class HealingCacheService {
355
355
  typeof parsed.entries !== "object" ||
356
356
  parsed.entries === null ||
357
357
  Array.isArray(parsed.entries)) {
358
- console.warn(`[HealingCache] ⚠️ Unknown cache schema at ${target} starting fresh`);
358
+ console.warn(`[HealingCache] ⚠️ Unknown cache schema at ${target} - starting fresh`);
359
359
  return { schemaVersion: 1, entries: {} };
360
360
  }
361
361
  return parsed;
@@ -363,7 +363,7 @@ class HealingCacheService {
363
363
  /**
364
364
  * Atomic write: write to `<file>.tmp`, copy current to `<file>.bak`,
365
365
  * then rename `<file>.tmp` → `<file>`. The rename is the single
366
- * commit point a crash between bak and rename leaves the bak file
366
+ * commit point - a crash between bak and rename leaves the bak file
367
367
  * intact for future recovery.
368
368
  */
369
369
  atomicWrite(file) {
@@ -386,7 +386,7 @@ class HealingCacheService {
386
386
  fs.renameSync(tmp, target);
387
387
  }
388
388
  // ─────────────────────────────────────────────────────────────
389
- // FILE LOCK atomic mkdir as a cross-process mutex
389
+ // FILE LOCK - atomic mkdir as a cross-process mutex
390
390
  // ─────────────────────────────────────────────────────────────
391
391
  async acquireLockWithBackoff() {
392
392
  const delaysMs = [50, 100, 200, 400, 800, 800];
@@ -430,7 +430,7 @@ class HealingCacheService {
430
430
  break;
431
431
  sleepBusy(delaysMs[attempt]);
432
432
  }
433
- console.warn(`[HealingCache] ⚠️ Lock acquire failed (sync) operation skipped`);
433
+ console.warn(`[HealingCache] ⚠️ Lock acquire failed (sync) - operation skipped`);
434
434
  }
435
435
  releaseLock() {
436
436
  try {
@@ -455,6 +455,6 @@ function sleepBusy(ms) {
455
455
  }
456
456
  }
457
457
  // ═══════════════════════════════════════════════════════════════════
458
- // Module-level singleton engines reuse the same cache file by default
458
+ // Module-level singleton - engines reuse the same cache file by default
459
459
  // ═══════════════════════════════════════════════════════════════════
460
460
  exports.sharedHealingCache = new HealingCacheService();
@@ -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;
@@ -1 +1 @@
1
- {"version":3,"file":"InitializerUpdater.d.ts","sourceRoot":"","sources":["../../src/services/InitializerUpdater.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAiB,MAAM,UAAU,CAAC;AAc3D,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,kBAAkB;IAC7B;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CACV,SAAS,EAAE,IAAI,EACf,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACf,iBAAiB,GAAG,IAAI;CAsC5B"}
1
+ {"version":3,"file":"InitializerUpdater.d.ts","sourceRoot":"","sources":["../../src/services/InitializerUpdater.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,UAAU,EAAiB,MAAM,UAAU,CAAC;AAe3D,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,kBAAkB;IAC7B;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CACV,SAAS,EAAE,IAAI,EACf,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,GACf,iBAAiB,GAAG,IAAI;CAkD5B"}
@@ -5,6 +5,7 @@ const ts_morph_1 = require("ts-morph");
5
5
  const TemplateDiffService_js_1 = require("./TemplateDiffService.js");
6
6
  const DryRunGuard_1 = require("../config/DryRunGuard");
7
7
  const WorkspaceSnapshotService_1 = require("./WorkspaceSnapshotService");
8
+ const SelectorSanitizer_1 = require("./SelectorSanitizer");
8
9
  class InitializerUpdater {
9
10
  /**
10
11
  * Mutate a StringLiteral or NoSubstitutionTemplateLiteral node to
@@ -14,6 +15,15 @@ class InitializerUpdater {
14
15
  * mutation throws (caller should fall through to existing strategies).
15
16
  */
16
17
  static apply(valueNode, sourceFile, newValue) {
18
+ // ABSOLUTE GUARD: never serialise a Playwright internal engine selector
19
+ // into a string-literal definition. `.locator()` strings cannot express
20
+ // a semantic locator (getByRole/…), so writing `internal:role=…` here is
21
+ // the bug that leaks engine internals into user source. Refuse → the
22
+ // caller escalates to a semantic-guard (no regex fallback corruption).
23
+ if ((0, SelectorSanitizer_1.isInternalEngineSelector)(newValue)) {
24
+ console.warn(`[InitializerUpdater] ⛔ refusing to write internal engine selector into source: "${newValue.slice(0, 64)}"`);
25
+ return null;
26
+ }
17
27
  try {
18
28
  if (ts_morph_1.Node.isStringLiteral(valueNode)) {
19
29
  valueNode.setLiteralValue(newValue);
@@ -24,14 +34,14 @@ class InitializerUpdater {
24
34
  else {
25
35
  return null;
26
36
  }
27
- // Centralised write gate mirrors ASTSourceUpdater._persistChanges.
37
+ // Centralised write gate - mirrors ASTSourceUpdater._persistChanges.
28
38
  // InitializerUpdater is the canonical write-head for definition-site
29
39
  // mutations (SemanticDispatch → tracer-resolved identifier / property
30
40
  // access / cross-file paths all converge here), so the Clean-Room
31
41
  // snapshot ledger and DryRunGuard MUST be enforced here too.
32
42
  // Without this, an upstream-traced fix (e.g. global StringLiteral at
33
43
  // top of file) writes to disk but `WorkspaceSnapshotService` never
34
- // sees it `getMutatedSnapshots()` returns empty and PR automation
44
+ // sees it - `getMutatedSnapshots()` returns empty and PR automation
35
45
  // skips the heal entirely.
36
46
  const fp = sourceFile.getFilePath();
37
47
  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
  }