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
@@ -17,7 +17,7 @@ exports.CHAIN_VALIDATOR_CODES = exports.REPORT_CODES = exports.REGISTRY_CODES =
17
17
  exports.isSelaError = isSelaError;
18
18
  exports.isSelaErrorFrom = isSelaErrorFrom;
19
19
  // ───────────────────────────────────────────────────────────────────
20
- // SelaError single class for the whole hierarchy.
20
+ // SelaError - single class for the whole hierarchy.
21
21
  //
22
22
  // We intentionally avoid a tree of subclasses; `instanceof SelaError` +
23
23
  // `err.subsystem === "X"` is more flexible for callers and keeps the
@@ -31,7 +31,7 @@ class SelaError extends Error {
31
31
  context;
32
32
  constructor(init) {
33
33
  if (!CODE_PATTERN.test(init.code)) {
34
- throw new Error(`[SelaError] invalid code "${init.code}" must match ${CODE_PATTERN}`);
34
+ throw new Error(`[SelaError] invalid code "${init.code}" - must match ${CODE_PATTERN}`);
35
35
  }
36
36
  const formatted = SelaError.formatMessage(init.subsystem, init.code, init.reason);
37
37
  super(formatted);
@@ -45,9 +45,9 @@ class SelaError extends Error {
45
45
  }
46
46
  // Maintain prototype chain through transpilation (ES5 target).
47
47
  Object.setPrototypeOf(this, new.target.prototype);
48
- if (typeof Error.captureStackTrace === "function") {
49
- Error
50
- .captureStackTrace(this, new.target);
48
+ if (typeof Error.captureStackTrace ===
49
+ "function") {
50
+ Error.captureStackTrace(this, new.target);
51
51
  }
52
52
  }
53
53
  static formatMessage(subsystem, code, reason) {
@@ -81,7 +81,7 @@ function isSelaErrorFrom(err, subsystem) {
81
81
  // ───────────────────────────────────────────────────────────────────
82
82
  // Canonical code catalogue
83
83
  //
84
- // Tests assert against these constants never hand-write code strings
84
+ // Tests assert against these constants - never hand-write code strings
85
85
  // at throw sites. Adding a new code requires adding it here first so
86
86
  // the catalogue stays in sync with the error-indicativity contract.
87
87
  // ───────────────────────────────────────────────────────────────────
@@ -94,7 +94,6 @@ exports.SAFETY_GUARD_CODES = {
94
94
  BLOCKED_ROLE_SWAP_ASSERTION: "SG_BLOCKED_ROLE_SWAP_ASSERTION",
95
95
  FAIL_HARD_AUDITOR_INCONSISTENT: "SG_FAIL_HARD_AUDITOR_INCONSISTENT",
96
96
  BLOCKED_AUDITOR_SUSPICIOUS: "SG_BLOCKED_AUDITOR_SUSPICIOUS",
97
- BLOCKED_SIMILARITY_FLOOR: "SG_BLOCKED_SIMILARITY_FLOOR",
98
97
  /** Generic dispatcher when SafetyDecision arrives without an explicit code. */
99
98
  GENERIC_REJECTION: "SG_GENERIC_REJECTION",
100
99
  };
@@ -145,6 +144,14 @@ exports.REPORT_CODES = {
145
144
  INVALID_FIELD_TYPE: "REP_INVALID_FIELD_TYPE",
146
145
  /** Disk write failed during flushToDisk(). */
147
146
  FLUSH_FAILED: "REP_FLUSH_FAILED",
147
+ /**
148
+ * A prior `.sela-history.json` existed on disk but could not be parsed as
149
+ * a JSON array. The merge path refuses to silently overwrite it with a
150
+ * fresh window (which would destroy the rolling history), so it aborts.
151
+ */
152
+ HISTORY_CORRUPT: "REP_HISTORY_CORRUPT",
153
+ /** A shard report file existed but was not valid JSON / had no events array. */
154
+ SHARD_UNREADABLE: "REP_SHARD_UNREADABLE",
148
155
  };
149
156
  exports.CHAIN_VALIDATOR_CODES = {
150
157
  TYPE_FLOW: "CV_TYPE_FLOW",
@@ -1,9 +1,9 @@
1
1
  import { Locator } from "@playwright/test";
2
2
  import { SelaEngine } from "../engine/SelaEngine";
3
3
  /**
4
- * createHealingExpect drop-in replacement for Playwright's expect().
4
+ * createHealingExpect - drop-in replacement for Playwright's expect().
5
5
  *
6
- * @param resolveProxy Optional callback that unwraps a Fixwright proxy
6
+ * @param resolveProxy Optional callback that unwraps a Sela proxy
7
7
  * to its current live Locator. Supplied by
8
8
  * fixtures/index.ts which owns proxyToActiveLocator.
9
9
  */
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // src/fixtures/expectProxy.ts full replacement
2
+ // src/fixtures/expectProxy.ts - full replacement
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.createHealingExpect = createHealingExpect;
5
5
  const test_1 = require("@playwright/test");
@@ -17,8 +17,8 @@ function isElementNotFoundError(err) {
17
17
  return ELEMENT_NOT_FOUND_PATTERNS.some((p) => p.test(err.message));
18
18
  }
19
19
  /**
20
- * Returns true only for genuine Playwright Locator instances
21
- * not FrameLocator proxies or Fixwright proxy objects.
20
+ * Returns true only for genuine Playwright Locator instances -
21
+ * not FrameLocator proxies or Sela proxy objects.
22
22
  *
23
23
  * A real Locator has _frame internally.
24
24
  * A FrameLocator has _frameSelector instead.
@@ -30,10 +30,10 @@ function isRealLocator(value) {
30
30
  return false;
31
31
  if (typeof value !== "object")
32
32
  return false;
33
- // Fixwright locator proxies expose `_fixwrightSelector`. The proxy forwards
34
- // `_frame` via Reflect.get so `hasFrame` would lie explicitly reject them
33
+ // Sela locator proxies expose `_selaSelector`. The proxy forwards
34
+ // `_frame` via Reflect.get so `hasFrame` would lie - explicitly reject them
35
35
  // here. Callers should unwrap via `resolveProxy` first.
36
- if (value._fixwrightSelector !== undefined)
36
+ if (value._selaSelector !== undefined)
37
37
  return false;
38
38
  const hasFrame = value._frame !== undefined ||
39
39
  value._impl?._frame !== undefined;
@@ -63,13 +63,13 @@ function extractSelectorFromLocator(locator) {
63
63
  * frame segments (e.g. "#modern-frame-container >> #status-label-v2").
64
64
  *
65
65
  * A plain page.locator() call with a frame >> element string is NOT
66
- * a valid locator for frame content Playwright rejects it with
66
+ * a valid locator for frame content - Playwright rejects it with
67
67
  * "toHaveText can be only used with Locator object".
68
68
  *
69
69
  * This function correctly chains frameLocator() calls for each frame
70
70
  * segment, then calls .locator() for the final element segment.
71
71
  *
72
- * Convention used by FixwrightEngine segments:
72
+ * Convention used by SelaEngine segments:
73
73
  * - Frame segments look like CSS selectors for iframes (#id, .class)
74
74
  * but produce a FrameLocator, not a Locator.
75
75
  * - The last segment is always the element selector.
@@ -128,13 +128,13 @@ function wrapMatcher(matcher, locator, matcherName, engine, page, ctx) {
128
128
  if (!rawSelector)
129
129
  throw err;
130
130
  console.log(`[Sela] ⚠️ Assertion failed for "${rawSelector}", attempting heal…`);
131
- // Fast path already healed in this test via registry
131
+ // Fast path - already healed in this test via registry
132
132
  const resolved = HealingRegistry_1.HealingRegistry.getInstance().resolveSelector(rawSelector, ctx);
133
133
  let healedSelector = resolved;
134
134
  if (resolved === rawSelector) {
135
- // Slow path ask the engine + LLM.
135
+ // Slow path - ask the engine + LLM.
136
136
  // engine.heal() writes the fix to disk AND returns the canonical
137
- // healedLocatorString from SourceUpdater the exact same string
137
+ // healedLocatorString from SourceUpdater - the exact same string
138
138
  // that was saved to the file. This is the handshake that guarantees
139
139
  // disk and runtime are in sync (no "ghost failures").
140
140
  const stableId = require("crypto")
@@ -182,9 +182,9 @@ const WRAPPED_MATCHERS = [
182
182
  "toBeFocused",
183
183
  ];
184
184
  /**
185
- * createHealingExpect drop-in replacement for Playwright's expect().
185
+ * createHealingExpect - drop-in replacement for Playwright's expect().
186
186
  *
187
- * @param resolveProxy Optional callback that unwraps a Fixwright proxy
187
+ * @param resolveProxy Optional callback that unwraps a Sela proxy
188
188
  * to its current live Locator. Supplied by
189
189
  * fixtures/index.ts which owns proxyToActiveLocator.
190
190
  */
@@ -204,7 +204,7 @@ resolveProxy) {
204
204
  return initialLine;
205
205
  };
206
206
  const actualLine = getCallerLine(); // כאן אנחנו מקבלים את השורה הנכונה!
207
- // Step 1 unwrap Fixwright proxy to real active Locator
207
+ // Step 1 - unwrap Sela proxy to real active Locator
208
208
  let resolved = locatorOrValue;
209
209
  if (resolveProxy) {
210
210
  const unwrapped = resolveProxy(locatorOrValue);
@@ -217,7 +217,7 @@ resolveProxy) {
217
217
  if (base === null || typeof base !== "object") {
218
218
  return base;
219
219
  }
220
- // Step 2 only wrap matchers for genuine page-level Locator objects.
220
+ // Step 2 - only wrap matchers for genuine page-level Locator objects.
221
221
  if (!isRealLocator(resolved)) {
222
222
  return base;
223
223
  }
@@ -226,7 +226,7 @@ resolveProxy) {
226
226
  const ctx = { filePath, line: actualLine };
227
227
  const proxy = new Proxy(base, {
228
228
  get(target, prop) {
229
- // Sela proxy identity honored before any string-only branch so
229
+ // Sela proxy identity - honored before any string-only branch so
230
230
  // callers can detect a Sela expect proxy via Symbol.for("sela.proxy").
231
231
  if (prop === proxyTag_1.SELA_PROXY)
232
232
  return "expect";
@@ -1,6 +1,6 @@
1
1
  import { Locator, Page } from "@playwright/test";
2
2
  import { createHealingExpect } from "./expectProxy";
3
- export declare function resolveFixwrightProxy(value: unknown): Locator | null;
3
+ export declare function resolveSelaProxy(value: unknown): Locator | null;
4
4
  export declare function createFrameLocatorProxy(rawFrameLocator: any, frameSelector: string, rawPage: Page, testTitle: string, actionCounter: {
5
5
  value: number;
6
6
  }, parentChain: string): any;
@@ -9,6 +9,22 @@ export declare function createLocatorProxy(rawLocator: Locator, selector: string
9
9
  }, elementSelectorOnly?: string): any;
10
10
  export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & {
11
11
  expect: ReturnType<typeof createHealingExpect>;
12
- }, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
12
+ }, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions & {
13
+ /**
14
+ * Worker-scoped lifecycle anchor. Its teardown runs EXACTLY ONCE per
15
+ * worker process - after every test in that worker has finished - which
16
+ * is the only correct place to flush the suite-wide healing report.
17
+ *
18
+ * Why a worker fixture and not the reporter's onEnd():
19
+ * Playwright runs tests in worker processes; the reporter lives in the
20
+ * main process. The `sharedHealReport` buffer, `HealingRegistry`, and
21
+ * `sharedWorkspaceSnapshot` singletons that accumulate heal events all
22
+ * live in the WORKER. The main-process reporter cannot see them, so the
23
+ * flush MUST happen worker-side. The reporter's cross-process
24
+ * PendingPromptLedger (written here, drained in onEnd) is what carries
25
+ * the DX-review summary back to the main process.
26
+ */
27
+ _selaWorkerLifecycle: void;
28
+ }>;
13
29
  export { createHealingExpect } from "./expectProxy";
14
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAI/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAYpD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAIpE;AA2jBD,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,GAAG,EACpB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,IAAI,EACb,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAChC,WAAW,EAAE,MAAM,GAClB,GAAG,CAuCL;AAaD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,OAAO,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,IAAI,EACb,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAChC,mBAAmB,CAAC,EAAE,MAAM,GAC3B,GAAG,CAkPL;AAQD,eAAO,MAAM,IAAI;YACP,UAAU,CAAC,OAAO,mBAAmB,CAAC;wGAkG9C,CAAC;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAI/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAYpD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAI/D;AA2jBD,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,GAAG,EACpB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,IAAI,EACb,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAChC,WAAW,EAAE,MAAM,GAClB,GAAG,CAuCL;AAaD,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,OAAO,EACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,IAAI,EACb,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,EAChC,mBAAmB,CAAC,EAAE,MAAM,GAC3B,GAAG,CAkPL;AAQD,eAAO,MAAM,IAAI;YAEL,UAAU,CAAC,OAAO,mBAAmB,CAAC;;IAG9C;;;;;;;;;;;;;OAaG;0BACmB,IAAI;EAwH5B,CAAC;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.createHealingExpect = exports.test = void 0;
37
- exports.resolveFixwrightProxy = resolveFixwrightProxy;
37
+ exports.resolveSelaProxy = resolveSelaProxy;
38
38
  exports.createFrameLocatorProxy = createFrameLocatorProxy;
39
39
  exports.createLocatorProxy = createLocatorProxy;
40
40
  const test_1 = require("@playwright/test");
@@ -47,10 +47,10 @@ const fs = __importStar(require("fs"));
47
47
  const path = __importStar(require("path"));
48
48
  const registry = HealingRegistry_1.HealingRegistry.getInstance();
49
49
  const proxyToActiveLocator = new WeakMap();
50
- // Module-level resolver moduleExpect.ts uses this to unwrap a Fixwright
50
+ // Module-level resolver - moduleExpect.ts uses this to unwrap a Sela
51
51
  // locator proxy back to its live underlying Playwright Locator without
52
52
  // needing access to the WeakMap directly.
53
- function resolveFixwrightProxy(value) {
53
+ function resolveSelaProxy(value) {
54
54
  if (!value || typeof value !== "object")
55
55
  return null;
56
56
  const getActive = proxyToActiveLocator.get(value);
@@ -157,7 +157,7 @@ const GET_BY_METHODS = {
157
157
  getByTitle: (args) => `internal:attr=[title=${JSON.stringify(args[0])}]`,
158
158
  };
159
159
  // ─────────────────────────────────────────────────────────────────
160
- // buildLiveLocator registry-aware
160
+ // buildLiveLocator - registry-aware
161
161
  //
162
162
  // NEW: resolves the selector through the HealingRegistry before
163
163
  // constructing the Playwright Locator. Zero cost when no heal has
@@ -240,7 +240,7 @@ function buildHealedArgs(prop, args, timeout = 8000) {
240
240
  // runWithHealArgument (unchanged from original)
241
241
  // ─────────────────────────────────────────────────────────────────
242
242
  async function runWithHealArgument(rawPage, prop, args, fullSelector, stableId, callerInfo, originalError) {
243
- console.log(`[Sela] 💡 Element visible, action '${prop}' failed healing argument…`);
243
+ console.log(`[Sela] 💡 Element visible, action '${prop}' failed - healing argument…`);
244
244
  const oldArgument = typeof args[0] === "string" ? args[0] : JSON.stringify(args[0]);
245
245
  const newArgument = await singleton_1.sharedEngine.healArgument(rawPage, fullSelector, prop, oldArgument, stableId, callerInfo.filePath, callerInfo.line);
246
246
  if (!newArgument)
@@ -250,11 +250,11 @@ async function runWithHealArgument(rawPage, prop, args, fullSelector, stableId,
250
250
  return await locator[prop](...healedArgs);
251
251
  }
252
252
  // ─────────────────────────────────────────────────────────────────
253
- // runWithHeal pre-flight registry check added
253
+ // runWithHeal - pre-flight registry check added
254
254
  //
255
255
  // NEW: Before the first Playwright attempt, resolve the selector
256
256
  // through the registry. If a previous heal already mapped it, the
257
- // first attempt uses the healed selector and succeeds immediately
257
+ // first attempt uses the healed selector and succeeds immediately -
258
258
  // no timeout, no AI call, no file write.
259
259
  // ─────────────────────────────────────────────────────────────────
260
260
  async function runWithHeal(rawPage, prop, args, fullSelector, elementSelectorOnly, stableId, callerInfo) {
@@ -451,7 +451,7 @@ function createFrameLocatorProxy(rawFrameLocator, frameSelector, rawPage, testTi
451
451
  : frameSelector;
452
452
  return new Proxy(rawFrameLocator, {
453
453
  get(fTarget, fProp) {
454
- // Sela proxy identity honor before the string-only fast path so
454
+ // Sela proxy identity - honor before the string-only fast path so
455
455
  // symbol probes from tests / debuggers return the kind tag.
456
456
  if (fProp === proxyTag_1.SELA_PROXY)
457
457
  return "framelocator";
@@ -468,14 +468,14 @@ function createFrameLocatorProxy(rawFrameLocator, frameSelector, rawPage, testTi
468
468
  });
469
469
  }
470
470
  // ─────────────────────────────────────────────────────────────────
471
- // createLocatorProxy Runtime Selector Injection added
471
+ // createLocatorProxy - Runtime Selector Injection added
472
472
  //
473
473
  // NEW additions vs original:
474
474
  // 1. Resolves selector through registry on creation (handles proxies
475
475
  // born after a heal has already broadcast).
476
476
  // 2. Subscribes to registry so any future broadcast swaps
477
- // activeLocator on the same tick before the next await.
478
- // 3. Exposes _fixwrightUnsubscribe so the fixture can clean up.
477
+ // activeLocator on the same tick - before the next await.
478
+ // 3. Exposes _selaUnsubscribe so the fixture can clean up.
479
479
  // ─────────────────────────────────────────────────────────────────
480
480
  function createLocatorProxy(rawLocator, selector, rawPage, testTitle, actionCounter, elementSelectorOnly) {
481
481
  // Defensive: Proxy ctor throws "Cannot create proxy with a non-object as target"
@@ -494,7 +494,7 @@ function createLocatorProxy(rawLocator, selector, rawPage, testTitle, actionCoun
494
494
  ? buildLiveLocator(rawPage, initialResolved) // already healed
495
495
  : rawLocator; // fresh, use as-is
496
496
  // ── Subscribe: swap activeLocator when a heal fires ──────────
497
- // Inside createLocatorProxy full updated subscribe block
497
+ // Inside createLocatorProxy - full updated subscribe block
498
498
  // בתוך createLocatorProxy - תחליף את הבלוק של ה-subscribe בזה:
499
499
  const unsubscribe = registry.subscribe((fp, oldSel, newSel) => {
500
500
  // בדיקה אם הסלקטור הנוכחי מכיל את הישן או שהוא הישן בעצמו
@@ -524,24 +524,24 @@ function createLocatorProxy(rawLocator, selector, rawPage, testTitle, actionCoun
524
524
  });
525
525
  const proxy = new Proxy(rawLocator, {
526
526
  get(target, prop, receiver) {
527
- // Sela proxy identity must be honored before any string-only branch
527
+ // Sela proxy identity - must be honored before any string-only branch
528
528
  // so callers can reliably detect a Sela proxy via Symbol.for("sela.proxy").
529
529
  if (prop === proxyTag_1.SELA_PROXY)
530
530
  return "locator";
531
531
  if (typeof prop !== "string")
532
532
  return Reflect.get(target, prop, receiver);
533
533
  // ── Internal accessors ───────────────────────────────────
534
- if (prop === "_fixwrightSelector")
534
+ if (prop === "_selaSelector")
535
535
  return currentFullSelector;
536
- if (prop === "_fixwrightPage")
536
+ if (prop === "_selaPage")
537
537
  return rawPage;
538
- if (prop === "_fixwrightTestTitle")
538
+ if (prop === "_selaTestTitle")
539
539
  return testTitle;
540
- if (prop === "_fixwrightActionCounter")
540
+ if (prop === "_selaActionCounter")
541
541
  return actionCounter;
542
- if (prop === "_fixwrightElementSelector")
542
+ if (prop === "_selaElementSelector")
543
543
  return currentElementSelector;
544
- if (prop === "_fixwrightUnsubscribe")
544
+ if (prop === "_selaUnsubscribe")
545
545
  return unsubscribe;
546
546
  // ── getBy* ───────────────────────────────────────────────
547
547
  if (prop in GET_BY_METHODS) {
@@ -657,10 +657,25 @@ function createLocatorProxy(rawLocator, selector, rawPage, testTitle, actionCoun
657
657
  return proxy;
658
658
  }
659
659
  // ─────────────────────────────────────────────────────────────────
660
- // test fixture teardown added
660
+ // test fixture - teardown added
661
661
  // ─────────────────────────────────────────────────────────────────
662
- // ─── expect healing proxy replacing the plain baseExpect proxy ──────────────
662
+ // ─── expect - healing proxy replacing the plain baseExpect proxy ──────────────
663
663
  exports.test = test_1.test.extend({
664
+ // ── Worker-scoped flush anchor (auto) ───────────────────────────────
665
+ // Setup is a no-op; the teardown after `use()` is the suite-end flush.
666
+ // Aggregation spans the ENTIRE worker run because commitUpdates() is no
667
+ // longer called per test - the report buffer, registry heal-map, and
668
+ // workspace snapshot accumulate across all tests and flush once here.
669
+ _selaWorkerLifecycle: [
670
+ async ({}, use) => {
671
+ await use();
672
+ // Single suite-wide commit: saves DNA snapshots, flushes the Insights
673
+ // report + .sela-history.json ONCE, and writes the DX-review ledger
674
+ // with the full set of healed events from the whole worker run.
675
+ await singleton_1.sharedEngine.commitUpdates();
676
+ },
677
+ { scope: "worker", auto: true },
678
+ ],
664
679
  page: async ({ page }, use, testInfo) => {
665
680
  page.on("console", (msg) => {
666
681
  if (msg.text().includes("[DOM-EXTRACT]")) {
@@ -672,7 +687,7 @@ exports.test = test_1.test.extend({
672
687
  const unsubscribers = [];
673
688
  const pageProxy = new Proxy(page, {
674
689
  get(target, prop) {
675
- // Sela proxy identity honored before any other branch so callers
690
+ // Sela proxy identity - honored before any other branch so callers
676
691
  // can reliably detect a Sela page proxy via Symbol.for("sela.proxy").
677
692
  if (prop === proxyTag_1.SELA_PROXY)
678
693
  return "page";
@@ -683,7 +698,7 @@ exports.test = test_1.test.extend({
683
698
  if (prop === "locator") {
684
699
  return (selector) => {
685
700
  const p = createLocatorProxy(target.locator(selector), selector, rawPage, testInfo.title, actionCounter, selector);
686
- const u = p._fixwrightUnsubscribe;
701
+ const u = p._selaUnsubscribe;
687
702
  if (u)
688
703
  unsubscribers.push(u);
689
704
  return p;
@@ -696,7 +711,7 @@ exports.test = test_1.test.extend({
696
711
  return (...args) => {
697
712
  const semanticSelector = GET_BY_METHODS[prop](args);
698
713
  const p = createLocatorProxy(target[prop](...args), semanticSelector, rawPage, testInfo.title, actionCounter, semanticSelector);
699
- const u = p._fixwrightUnsubscribe;
714
+ const u = p._selaUnsubscribe;
700
715
  if (u)
701
716
  unsubscribers.push(u);
702
717
  return p;
@@ -706,15 +721,20 @@ exports.test = test_1.test.extend({
706
721
  },
707
722
  });
708
723
  await use(pageProxy);
709
- // ── Teardown ─────────────────────────────────────────────────
724
+ // ── Per-test teardown ─────────────────────────────────────────
725
+ // Release this test's proxy registry subscriptions and drop per-test
726
+ // listeners. We deliberately DO NOT call engine.commitUpdates() here -
727
+ // flushing per test is what produced the per-test report writes, the
728
+ // duplicated .sela-history.json entries (each "healed":1), and the
729
+ // last-test-only DX diff. The suite-wide flush lives in the
730
+ // worker-scoped `_selaWorkerLifecycle` teardown above.
710
731
  for (const u of unsubscribers)
711
732
  u();
712
733
  registry.clearForTest();
713
- await singleton_1.sharedEngine.commitUpdates();
714
734
  },
715
735
  expect: async ({ page }, use, testInfo) => {
716
736
  const healingExpect = (0, expectProxy_1.createHealingExpect)(singleton_1.sharedEngine, page, testInfo.file, 0,
717
- // Inject proxy resolver gives expectProxy.ts access to the live
737
+ // Inject proxy resolver - gives expectProxy.ts access to the live
718
738
  // active Locator without exposing the WeakMap directly.
719
739
  (value) => {
720
740
  if (value && typeof value === "object") {
@@ -9,14 +9,14 @@ const singleton_js_1 = require("../engine/singleton.js");
9
9
  const expectProxy_js_1 = require("./expectProxy.js");
10
10
  const index_js_1 = require("./index.js");
11
11
  function extractPage(value) {
12
- if (!value || typeof value !== 'object')
12
+ if (!value || typeof value !== "object")
13
13
  return null;
14
- // Fixwright locator proxy exposes _fixwrightPage directly
15
- const proxied = value._fixwrightPage;
14
+ // Sela locator proxy exposes _selaPage directly
15
+ const proxied = value._selaPage;
16
16
  if (proxied)
17
17
  return proxied;
18
18
  // Playwright public API: Locator.page()
19
- if (typeof value.page === 'function') {
19
+ if (typeof value.page === "function") {
20
20
  try {
21
21
  return value.page();
22
22
  }
@@ -27,7 +27,7 @@ function extractPage(value) {
27
27
  return null;
28
28
  }
29
29
  function getCallerFile() {
30
- const lines = new Error().stack?.split('\n') ?? [];
30
+ const lines = new Error().stack?.split("\n") ?? [];
31
31
  // Match BOTH frame shapes V8 emits:
32
32
  // " at fnName (D:\\path\\file.spec.ts:17:20)"
33
33
  // " at D:\\path\\file.spec.ts:17:20"
@@ -42,13 +42,13 @@ function getCallerFile() {
42
42
  if (m && m[1])
43
43
  return m[1].trim();
44
44
  }
45
- return '';
45
+ return "";
46
46
  }
47
47
  function expect(value) {
48
48
  const page = extractPage(value);
49
49
  if (page) {
50
50
  const filePath = getCallerFile();
51
- return (0, expectProxy_js_1.createHealingExpect)(singleton_js_1.sharedEngine, page, filePath, 0, index_js_1.resolveFixwrightProxy)(value);
51
+ return (0, expectProxy_js_1.createHealingExpect)(singleton_js_1.sharedEngine, page, filePath, 0, index_js_1.resolveSelaProxy)(value);
52
52
  }
53
53
  return (0, test_1.expect)(value);
54
54
  }
@@ -3,7 +3,7 @@ export type SelaProxyKind = "locator" | "framelocator" | "page" | "expect";
3
3
  /**
4
4
  * Returns the proxy kind if `v` is a Sela proxy, otherwise `null`.
5
5
  *
6
- * Performs no instanceof checks against Playwright internals relies
6
+ * Performs no instanceof checks against Playwright internals - relies
7
7
  * solely on the `SELA_PROXY` symbol contract. Always safe to call on
8
8
  * arbitrary values (null/undefined/primitive → null).
9
9
  */
@@ -4,9 +4,9 @@
4
4
  // Single source of truth for the Sela proxy tag.
5
5
  //
6
6
  // Every Sela-created Proxy (locator, frame-locator, page, expect) honors a
7
- // `get` trap on this symbol and returns the kind string. Consumers the
8
- // surface-diff test, internal helpers, debuggers can identify Sela
9
- // proxies without touching the brittle "_fixwrightSelector" heuristic.
7
+ // `get` trap on this symbol and returns the kind string. Consumers - the
8
+ // surface-diff test, internal helpers, debuggers - can identify Sela
9
+ // proxies without touching the brittle "_selaSelector" heuristic.
10
10
  //
11
11
  // We use Symbol.for() (a registered symbol) so the identity survives
12
12
  // across module boundaries when multiple bundles end up in the same
@@ -19,7 +19,7 @@ exports.SELA_PROXY = Symbol.for("sela.proxy");
19
19
  /**
20
20
  * Returns the proxy kind if `v` is a Sela proxy, otherwise `null`.
21
21
  *
22
- * Performs no instanceof checks against Playwright internals relies
22
+ * Performs no instanceof checks against Playwright internals - relies
23
23
  * solely on the `SELA_PROXY` symbol contract. Always safe to call on
24
24
  * arbitrary values (null/undefined/primitive → null).
25
25
  */
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { defineConfig } from './config/defineConfig.js';
2
- export type { SelaConfig, ResolvedConfig } from './config/SelaConfig.js';
3
- export type * from '@playwright/test';
4
- export { chromium, firefox, webkit, devices, selectors } from '@playwright/test';
5
- export { test } from './fixtures/index.js';
6
- export { expect } from './fixtures/moduleExpect.js';
7
- export { SelaReporter } from './reporter/SelaReporter.js';
8
- export type { SelaReporterOpts, ReporterEngine, ReporterLogger } from './reporter/SelaReporter.js';
1
+ export { defineConfig } from "./config/defineConfig.js";
2
+ export type { SelaConfig, ResolvedConfig } from "./config/SelaConfig.js";
3
+ export type * from "@playwright/test";
4
+ export { chromium, firefox, webkit, devices, selectors, } from "@playwright/test";
5
+ export { test } from "./fixtures/index.js";
6
+ export { expect } from "./fixtures/moduleExpect.js";
7
+ export { SelaReporter } from "./reporter/SelaReporter.js";
8
+ export type { SelaReporterOpts, ReporterEngine, ReporterLogger, } from "./reporter/SelaReporter.js";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGzE,mBAAmB,kBAAkB,CAAC;AAGtC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIjF,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAI3C,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAKpD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGzE,mBAAmB,kBAAkB,CAAC;AAGtC,OAAO,EACL,QAAQ,EACR,OAAO,EACP,MAAM,EACN,OAAO,EACP,SAAS,GACV,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAI3C,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AAKpD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,YAAY,EACV,gBAAgB,EAChB,cAAc,EACd,cAAc,GACf,MAAM,4BAA4B,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // sela-core AI self-healing Playwright wrapper
2
+ // sela-core - AI self-healing Playwright wrapper
3
3
  //
4
4
  // Drop-in replacement for @playwright/test:
5
5
  // import { test, expect } from 'sela-core'
@@ -16,15 +16,15 @@ Object.defineProperty(exports, "firefox", { enumerable: true, get: function () {
16
16
  Object.defineProperty(exports, "webkit", { enumerable: true, get: function () { return test_1.webkit; } });
17
17
  Object.defineProperty(exports, "devices", { enumerable: true, get: function () { return test_1.devices; } });
18
18
  Object.defineProperty(exports, "selectors", { enumerable: true, get: function () { return test_1.selectors; } });
19
- // Sela's extended test includes DNA capture, trace collection,
19
+ // Sela's extended test - includes DNA capture, trace collection,
20
20
  // locator proxy, and fixture-scoped healing expect
21
21
  var index_js_1 = require("./fixtures/index.js");
22
22
  Object.defineProperty(exports, "test", { enumerable: true, get: function () { return index_js_1.test; } });
23
- // Sela's healing expect works standalone (import { expect } from 'sela-core')
23
+ // Sela's healing expect - works standalone (import { expect } from 'sela-core')
24
24
  // Detects page from locator, falls back to raw PW expect for non-locators
25
25
  var moduleExpect_js_1 = require("./fixtures/moduleExpect.js");
26
26
  Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return moduleExpect_js_1.expect; } });
27
- // Playwright Reporter drop into `reporter: [['sela-core/reporter']]`
27
+ // Playwright Reporter - drop into `reporter: [['sela-core/reporter']]`
28
28
  // in playwright.config.ts to drive heal-and-report at the reporter layer
29
29
  // (safety net for worker crashes + Playwright failure screenshot capture).
30
30
  var SelaReporter_js_1 = require("./reporter/SelaReporter.js");