playwright-locator-healer 0.1.3

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 (137) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/LICENSE +21 -0
  3. package/README.md +338 -0
  4. package/USAGE.md +217 -0
  5. package/dist/healing/audit-log.d.ts +9 -0
  6. package/dist/healing/audit-log.d.ts.map +1 -0
  7. package/dist/healing/audit-log.js +22 -0
  8. package/dist/healing/audit-log.js.map +1 -0
  9. package/dist/healing/auto-fixture.d.ts +14 -0
  10. package/dist/healing/auto-fixture.d.ts.map +1 -0
  11. package/dist/healing/auto-fixture.js +430 -0
  12. package/dist/healing/auto-fixture.js.map +1 -0
  13. package/dist/healing/cache.d.ts +11 -0
  14. package/dist/healing/cache.d.ts.map +1 -0
  15. package/dist/healing/cache.js +128 -0
  16. package/dist/healing/cache.js.map +1 -0
  17. package/dist/healing/circuit-breaker.d.ts +11 -0
  18. package/dist/healing/circuit-breaker.d.ts.map +1 -0
  19. package/dist/healing/circuit-breaker.js +34 -0
  20. package/dist/healing/circuit-breaker.js.map +1 -0
  21. package/dist/healing/cost-tracker.d.ts +30 -0
  22. package/dist/healing/cost-tracker.d.ts.map +1 -0
  23. package/dist/healing/cost-tracker.js +101 -0
  24. package/dist/healing/cost-tracker.js.map +1 -0
  25. package/dist/healing/dom-extractor.d.ts +9 -0
  26. package/dist/healing/dom-extractor.d.ts.map +1 -0
  27. package/dist/healing/dom-extractor.js +268 -0
  28. package/dist/healing/dom-extractor.js.map +1 -0
  29. package/dist/healing/errors.d.ts +33 -0
  30. package/dist/healing/errors.d.ts.map +1 -0
  31. package/dist/healing/errors.js +40 -0
  32. package/dist/healing/errors.js.map +1 -0
  33. package/dist/healing/heal/caller-context.d.ts +8 -0
  34. package/dist/healing/heal/caller-context.d.ts.map +1 -0
  35. package/dist/healing/heal/caller-context.js +46 -0
  36. package/dist/healing/heal/caller-context.js.map +1 -0
  37. package/dist/healing/heal/orchestrator-helpers.d.ts +84 -0
  38. package/dist/healing/heal/orchestrator-helpers.d.ts.map +1 -0
  39. package/dist/healing/heal/orchestrator-helpers.js +117 -0
  40. package/dist/healing/heal/orchestrator-helpers.js.map +1 -0
  41. package/dist/healing/heal/orchestrator.d.ts +47 -0
  42. package/dist/healing/heal/orchestrator.d.ts.map +1 -0
  43. package/dist/healing/heal/orchestrator.js +644 -0
  44. package/dist/healing/heal/orchestrator.js.map +1 -0
  45. package/dist/healing/heal/playwright-code.d.ts +26 -0
  46. package/dist/healing/heal/playwright-code.d.ts.map +1 -0
  47. package/dist/healing/heal/playwright-code.js +134 -0
  48. package/dist/healing/heal/playwright-code.js.map +1 -0
  49. package/dist/healing/heal/preflight.d.ts +8 -0
  50. package/dist/healing/heal/preflight.d.ts.map +1 -0
  51. package/dist/healing/heal/preflight.js +77 -0
  52. package/dist/healing/heal/preflight.js.map +1 -0
  53. package/dist/healing/heal/prompt.d.ts +9 -0
  54. package/dist/healing/heal/prompt.d.ts.map +1 -0
  55. package/dist/healing/heal/prompt.js +22 -0
  56. package/dist/healing/heal/prompt.js.map +1 -0
  57. package/dist/healing/heal/report.d.ts +11 -0
  58. package/dist/healing/heal/report.d.ts.map +1 -0
  59. package/dist/healing/heal/report.js +28 -0
  60. package/dist/healing/heal/report.js.map +1 -0
  61. package/dist/healing/heal/source-trace.d.ts +17 -0
  62. package/dist/healing/heal/source-trace.d.ts.map +1 -0
  63. package/dist/healing/heal/source-trace.js +59 -0
  64. package/dist/healing/heal/source-trace.js.map +1 -0
  65. package/dist/healing/index.d.ts +6 -0
  66. package/dist/healing/index.d.ts.map +1 -0
  67. package/dist/healing/index.js +3 -0
  68. package/dist/healing/index.js.map +1 -0
  69. package/dist/healing/llm-client.d.ts +58 -0
  70. package/dist/healing/llm-client.d.ts.map +1 -0
  71. package/dist/healing/llm-client.js +258 -0
  72. package/dist/healing/llm-client.js.map +1 -0
  73. package/dist/healing/logger.d.ts +18 -0
  74. package/dist/healing/logger.d.ts.map +1 -0
  75. package/dist/healing/logger.js +38 -0
  76. package/dist/healing/logger.js.map +1 -0
  77. package/dist/healing/models.d.ts +26 -0
  78. package/dist/healing/models.d.ts.map +1 -0
  79. package/dist/healing/models.js +109 -0
  80. package/dist/healing/models.js.map +1 -0
  81. package/dist/healing/overlay/bridge.d.ts +46 -0
  82. package/dist/healing/overlay/bridge.d.ts.map +1 -0
  83. package/dist/healing/overlay/bridge.js +2 -0
  84. package/dist/healing/overlay/bridge.js.map +1 -0
  85. package/dist/healing/overlay/dock.css.d.ts +2 -0
  86. package/dist/healing/overlay/dock.css.d.ts.map +1 -0
  87. package/dist/healing/overlay/dock.css.js +448 -0
  88. package/dist/healing/overlay/dock.css.js.map +1 -0
  89. package/dist/healing/overlay/dock.html.d.ts +46 -0
  90. package/dist/healing/overlay/dock.html.d.ts.map +1 -0
  91. package/dist/healing/overlay/dock.html.js +248 -0
  92. package/dist/healing/overlay/dock.html.js.map +1 -0
  93. package/dist/healing/overlay/drag.d.ts +17 -0
  94. package/dist/healing/overlay/drag.d.ts.map +1 -0
  95. package/dist/healing/overlay/drag.js +68 -0
  96. package/dist/healing/overlay/drag.js.map +1 -0
  97. package/dist/healing/overlay/inject.d.ts +41 -0
  98. package/dist/healing/overlay/inject.d.ts.map +1 -0
  99. package/dist/healing/overlay/inject.js +277 -0
  100. package/dist/healing/overlay/inject.js.map +1 -0
  101. package/dist/healing/overlay/keybinds.d.ts +33 -0
  102. package/dist/healing/overlay/keybinds.d.ts.map +1 -0
  103. package/dist/healing/overlay/keybinds.js +105 -0
  104. package/dist/healing/overlay/keybinds.js.map +1 -0
  105. package/dist/healing/prompts/heal-v21.d.ts +8 -0
  106. package/dist/healing/prompts/heal-v21.d.ts.map +1 -0
  107. package/dist/healing/prompts/heal-v21.js +204 -0
  108. package/dist/healing/prompts/heal-v21.js.map +1 -0
  109. package/dist/healing/retry-policy.d.ts +37 -0
  110. package/dist/healing/retry-policy.d.ts.map +1 -0
  111. package/dist/healing/retry-policy.js +46 -0
  112. package/dist/healing/retry-policy.js.map +1 -0
  113. package/dist/healing/session-cost.d.ts +44 -0
  114. package/dist/healing/session-cost.d.ts.map +1 -0
  115. package/dist/healing/session-cost.js +95 -0
  116. package/dist/healing/session-cost.js.map +1 -0
  117. package/dist/healing/test-fixture.d.ts +9 -0
  118. package/dist/healing/test-fixture.d.ts.map +1 -0
  119. package/dist/healing/test-fixture.js +37 -0
  120. package/dist/healing/test-fixture.js.map +1 -0
  121. package/dist/healing/types.d.ts +399 -0
  122. package/dist/healing/types.d.ts.map +1 -0
  123. package/dist/healing/types.js +162 -0
  124. package/dist/healing/types.js.map +1 -0
  125. package/dist/healing/validator.d.ts +64 -0
  126. package/dist/healing/validator.d.ts.map +1 -0
  127. package/dist/healing/validator.js +286 -0
  128. package/dist/healing/validator.js.map +1 -0
  129. package/dist/scripts/heal-report.d.ts +23 -0
  130. package/dist/scripts/heal-report.d.ts.map +1 -0
  131. package/dist/scripts/heal-report.js +106 -0
  132. package/dist/scripts/heal-report.js.map +1 -0
  133. package/dist/scripts/init.d.ts +3 -0
  134. package/dist/scripts/init.d.ts.map +1 -0
  135. package/dist/scripts/init.js +132 -0
  136. package/dist/scripts/init.js.map +1 -0
  137. package/package.json +84 -0
@@ -0,0 +1,46 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ const FRAME_RE = /\s+at\s+(?:.*?\s+\()?([^()\s]+):(\d+):(\d+)\)?$/;
4
+ function isLibraryFrame(file) {
5
+ return (file.includes('node_modules') ||
6
+ file.includes('/healing/') ||
7
+ file.includes('/dist/') ||
8
+ file.startsWith('node:') ||
9
+ file === '<anonymous>');
10
+ }
11
+ /**
12
+ * Walk the stack of `new Error()` and find the first frame that lives outside
13
+ * `healing/` and `node_modules/` — that's the test/POM source line that
14
+ * triggered the heal. Returns a trimmed snippet (the failing line plus the
15
+ * comment immediately above it, if any) for use as the LLM `description`.
16
+ */
17
+ export function inferDescriptionFromCallsite(stack) {
18
+ const s = stack ?? new Error().stack ?? '';
19
+ for (const line of s.split('\n')) {
20
+ const m = line.match(FRAME_RE);
21
+ if (!m)
22
+ continue;
23
+ const [, file, lineNoStr] = m;
24
+ if (isLibraryFrame(file))
25
+ continue;
26
+ const fileClean = file.startsWith('file://') ? file.replace(/^file:\/\//, '') : file;
27
+ const abs = path.isAbsolute(fileClean) ? fileClean : path.resolve(process.cwd(), fileClean);
28
+ let content;
29
+ try {
30
+ content = fs.readFileSync(abs, 'utf-8').split('\n');
31
+ }
32
+ catch {
33
+ return '';
34
+ }
35
+ const lineNo = Number(lineNoStr);
36
+ const idx = lineNo - 1;
37
+ if (idx < 0 || idx >= content.length)
38
+ return '';
39
+ const cur = (content[idx] ?? '').trim();
40
+ const prev = (content[idx - 1] ?? '').trim();
41
+ const isComment = prev.startsWith('//') || prev.startsWith('*');
42
+ return isComment ? `${prev}\n${cur}` : cur;
43
+ }
44
+ return '';
45
+ }
46
+ //# sourceMappingURL=caller-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caller-context.js","sourceRoot":"","sources":["../../../healing/heal/caller-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,QAAQ,GAAG,iDAAiD,CAAC;AAEnE,SAAS,cAAc,CAAC,IAAY;IAClC,OAAO,CACL,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;QAC7B,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QACxB,IAAI,KAAK,aAAa,CACvB,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAAC,KAAc;IACzD,MAAM,CAAC,GAAG,KAAK,IAAI,IAAI,KAAK,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,cAAc,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACrF,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC;QAC5F,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,OAAO,EAAE,CAAC;QAAC,CAAC;QACjF,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,CAAC;QACvB,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAChD,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAChE,OAAO,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * healing/heal/orchestrator-helpers.ts
3
+ *
4
+ * Small pure helpers split out of orchestrator.ts so the top-level state
5
+ * machine stays focused. All exports here are internal — the public
6
+ * surface (`healAction`, `synthEntry`, `HealActionInput`, `toPlaywrightCode`)
7
+ * remains on `./orchestrator.ts`.
8
+ */
9
+ import type { Page } from '@playwright/test';
10
+ import type { HealEntryV2 } from '../types.js';
11
+ /**
12
+ * Best-effort `page.locator(sel).count()` — invalid selectors throw on
13
+ * `.count()`, so we treat any throw as "0 matches" and let the heal flow
14
+ * fall through to the LLM rounds.
15
+ *
16
+ * @param page - Playwright page.
17
+ * @param selector - Raw selector string.
18
+ * @returns Match count, or 0 on any error.
19
+ */
20
+ export declare function safeCount(page: Page, selector: string): Promise<number>;
21
+ /**
22
+ * Evaluate a JS expression that must return a single visible `Element` on
23
+ * the page. Used for round-4 `js` tier suggestions which bypass the
24
+ * normal locator validator.
25
+ *
26
+ * @param page - Playwright page.
27
+ * @param jsExpr - JS expression body (no leading `return`).
28
+ * @returns `true` iff the expression returned a visible element.
29
+ */
30
+ export declare function validateJs(page: Page, jsExpr: string): Promise<boolean>;
31
+ /**
32
+ * Map a `selectorType` string to its baseline tier (used when the LLM
33
+ * suggestion didn't include an explicit `tier`). Plain semantic types
34
+ * come first, testid second, then chained scope, then CSS / xpath / js.
35
+ *
36
+ * @param t - Selector kind: `role`, `label`, `text`, `testid`,
37
+ * `filter-chain`, `css`, `xpath`, or `js`.
38
+ * @returns Tier number (1 best – 7 worst). Unknown types default to 4.
39
+ */
40
+ export declare function tierOfType(t: string): number;
41
+ /**
42
+ * DOM-side function executed via `pickedHandle.evaluate(...)`. Pulls the
43
+ * full ancestor-chain HTML (up to 3 levels) and a structured snapshot of
44
+ * the picked element's properties.
45
+ *
46
+ * NOTE: this function is serialized + run in the page context — it must
47
+ * not reference any module-level imports or closure state.
48
+ *
49
+ * @param el - The picked Element (provided by Playwright at runtime).
50
+ * @returns `{ ancestorsHtml, structured }` matching the shape
51
+ * `requestHealedLocator` consumes.
52
+ */
53
+ export declare function extractStructured(el: Element): {
54
+ ancestorsHtml: string;
55
+ structured: {
56
+ tag: string;
57
+ id: string;
58
+ classes: string[];
59
+ text: string;
60
+ ariaLabel: string;
61
+ ariaRole: string;
62
+ accessibleName: string;
63
+ dataTestId: string;
64
+ dataAttrs: Record<string, string>;
65
+ name: string;
66
+ type: string;
67
+ placeholder: string;
68
+ href: string;
69
+ associatedLabel: string;
70
+ parentRole: string;
71
+ siblingsSameTag: number;
72
+ outerHTML: string;
73
+ };
74
+ };
75
+ /**
76
+ * Foreground LLM-upgrade stub. When a cache hit returns a fragile-tier
77
+ * selector (≥5: class-chain CSS, xpath, JS), the orchestrator can try
78
+ * one more LLM round to upgrade to a stable tier. Currently a no-op
79
+ * placeholder; wiring is a future task.
80
+ *
81
+ * @returns `null` — always falls back to the cached entry.
82
+ */
83
+ export declare function tryForegroundUpgrade(): Promise<HealEntryV2 | null>;
84
+ //# sourceMappingURL=orchestrator-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-helpers.d.ts","sourceRoot":"","sources":["../../../healing/heal/orchestrator-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAO7E;AAED;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAW7E;AAED;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI5C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,OAAO,GAAG;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE;QACV,GAAG,EAAE,MAAM,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,cAAc,EAAE,MAAM,CAAC;QACvB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,MAAM,CAAC;QACnB,eAAe,EAAE,MAAM,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAwCA;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAExE"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Best-effort `page.locator(sel).count()` — invalid selectors throw on
3
+ * `.count()`, so we treat any throw as "0 matches" and let the heal flow
4
+ * fall through to the LLM rounds.
5
+ *
6
+ * @param page - Playwright page.
7
+ * @param selector - Raw selector string.
8
+ * @returns Match count, or 0 on any error.
9
+ */
10
+ export async function safeCount(page, selector) {
11
+ // intentionally swallowed: invalid selectors throw on count() → treat as zero matches
12
+ try {
13
+ return await page.locator(selector).count();
14
+ }
15
+ catch {
16
+ return 0;
17
+ }
18
+ }
19
+ /**
20
+ * Evaluate a JS expression that must return a single visible `Element` on
21
+ * the page. Used for round-4 `js` tier suggestions which bypass the
22
+ * normal locator validator.
23
+ *
24
+ * @param page - Playwright page.
25
+ * @param jsExpr - JS expression body (no leading `return`).
26
+ * @returns `true` iff the expression returned a visible element.
27
+ */
28
+ export async function validateJs(page, jsExpr) {
29
+ try {
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ const handle = await page.evaluateHandle(new Function(`return (${jsExpr})`));
32
+ const el = handle.asElement();
33
+ if (!el)
34
+ return false;
35
+ return await el.isVisible();
36
+ }
37
+ catch {
38
+ // intentionally swallowed: js-eval errors mean the suggestion is invalid → caller treats as failed validate
39
+ return false;
40
+ }
41
+ }
42
+ /**
43
+ * Map a `selectorType` string to its baseline tier (used when the LLM
44
+ * suggestion didn't include an explicit `tier`). Plain semantic types
45
+ * come first, testid second, then chained scope, then CSS / xpath / js.
46
+ *
47
+ * @param t - Selector kind: `role`, `label`, `text`, `testid`,
48
+ * `filter-chain`, `css`, `xpath`, or `js`.
49
+ * @returns Tier number (1 best – 7 worst). Unknown types default to 4.
50
+ */
51
+ export function tierOfType(t) {
52
+ return ({ role: 1, label: 1, text: 1, testid: 2, 'filter-chain': 3, css: 4, xpath: 6, js: 7 }[t] ?? 4);
53
+ }
54
+ /**
55
+ * DOM-side function executed via `pickedHandle.evaluate(...)`. Pulls the
56
+ * full ancestor-chain HTML (up to 3 levels) and a structured snapshot of
57
+ * the picked element's properties.
58
+ *
59
+ * NOTE: this function is serialized + run in the page context — it must
60
+ * not reference any module-level imports or closure state.
61
+ *
62
+ * @param el - The picked Element (provided by Playwright at runtime).
63
+ * @returns `{ ancestorsHtml, structured }` matching the shape
64
+ * `requestHealedLocator` consumes.
65
+ */
66
+ export function extractStructured(el) {
67
+ const e = el;
68
+ let anc = '';
69
+ let n = e;
70
+ let d = 0;
71
+ while (n && d < 3) {
72
+ anc = n.outerHTML.slice(0, 300) + '\n' + anc;
73
+ n = n.parentElement;
74
+ d++;
75
+ }
76
+ const tag = e.tagName.toLowerCase();
77
+ const id = e.id ?? '';
78
+ const classes = Array.from(e.classList);
79
+ const text = (e.textContent ?? '').trim().replace(/\s+/g, ' ').slice(0, 120);
80
+ return {
81
+ ancestorsHtml: anc,
82
+ structured: {
83
+ tag,
84
+ id,
85
+ classes,
86
+ text,
87
+ ariaLabel: e.getAttribute('aria-label') ?? '',
88
+ ariaRole: e.getAttribute('role') ?? '',
89
+ accessibleName: e.getAttribute('aria-label') || text,
90
+ dataTestId: e.getAttribute('data-testid') ??
91
+ e.getAttribute('data-test') ??
92
+ e.getAttribute('data-cy') ??
93
+ '',
94
+ dataAttrs: {},
95
+ name: e.getAttribute('name') ?? '',
96
+ type: e.getAttribute('type') ?? '',
97
+ placeholder: e.getAttribute('placeholder') ?? '',
98
+ href: e.getAttribute('href') ?? '',
99
+ associatedLabel: '',
100
+ parentRole: '',
101
+ siblingsSameTag: 0,
102
+ outerHTML: e.outerHTML.slice(0, 800),
103
+ },
104
+ };
105
+ }
106
+ /**
107
+ * Foreground LLM-upgrade stub. When a cache hit returns a fragile-tier
108
+ * selector (≥5: class-chain CSS, xpath, JS), the orchestrator can try
109
+ * one more LLM round to upgrade to a stable tier. Currently a no-op
110
+ * placeholder; wiring is a future task.
111
+ *
112
+ * @returns `null` — always falls back to the cached entry.
113
+ */
114
+ export async function tryForegroundUpgrade() {
115
+ return null;
116
+ }
117
+ //# sourceMappingURL=orchestrator-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator-helpers.js","sourceRoot":"","sources":["../../../healing/heal/orchestrator-helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { Page } from '@playwright/test';
2
+ import type { HealEntryV2 } from '../types.js';
3
+ /**
4
+ * Caller input for `healAction`. The orchestrator owns cache lookup,
5
+ * overlay injection, LLM rounds, and confirmation — the caller only
6
+ * supplies the page + the locator that needs healing.
7
+ */
8
+ export interface HealActionInput {
9
+ /** Live Playwright `Page` against which to validate candidate locators. */
10
+ page: Page;
11
+ /** The selector string the developer originally wrote (the one that broke). */
12
+ originalSelector: string;
13
+ /** Playwright action verb (`click`, `fill`, `expect.toBeVisible`, …). */
14
+ action: string;
15
+ /** Optional natural-language hint about what the element is for. */
16
+ description?: string;
17
+ /** Caller test file path — used as the cache scope key. */
18
+ testFile: string;
19
+ /** Override `.healed-locators` cache directory. Defaults to `cwd/.healed-locators`. */
20
+ cacheDir?: string;
21
+ /** Caller stack captured at proxy entry (P2-2) — keeps user frame visible. */
22
+ callerStack?: string;
23
+ }
24
+ /**
25
+ * Top-level heal entry point. Five-stage flow:
26
+ * 0. live re-check — maybe the page changed and the original works now
27
+ * 1. cache lookup — return a previously-healed selector if it still resolves
28
+ * 2. overlay + pick — developer clicks the right element
29
+ * 3. preflight — try cheap deterministic locators (testid, role+name, …)
30
+ * 4. progressive LLM rounds — 4 rounds with increasing tier permissions
31
+ *
32
+ * Returns the persisted `HealEntryV2` so the caller (auto-fixture or
33
+ * manual code) can build a Playwright `Locator` from the result and retry.
34
+ *
35
+ * @param input - See `HealActionInput`.
36
+ * @returns The healed entry (selector + selectorType + tier + trace).
37
+ * @throws HealCancelledError, HealExhaustedError, HealLLMError on the
38
+ * respective failure modes; HealingError(circuit-open) when the LLM
39
+ * circuit breaker is open.
40
+ */
41
+ export declare function healAction(input: HealActionInput): Promise<HealEntryV2>;
42
+ export { toPlaywrightCode } from './playwright-code.js';
43
+ export declare function synthEntry(original: string, type: HealEntryV2['selectorType'], healed: string, intent: string, action: string, trace: {
44
+ callSite: string;
45
+ pomFrame: string;
46
+ }, tier?: number, fingerprint?: HealEntryV2['fingerprint']): HealEntryV2;
47
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../healing/heal/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAiB,MAAM,kBAAkB,CAAC;AAqB5D,OAAO,KAAK,EAAE,WAAW,EAAqD,MAAM,aAAa,CAAC;AAGlG;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,IAAI,EAAE,IAAI,CAAC;IACX,+EAA+E;IAC/E,gBAAgB,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAkE7E;AA8ZD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AA6HxD,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,WAAW,CAAC,cAAc,CAAC,EACjC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC7C,IAAI,SAAI,EACR,WAAW,CAAC,EAAE,WAAW,CAAC,aAAa,CAAC,GACvC,WAAW,CAQb"}