@ia-qa/self-healing 1.0.1 → 1.1.1

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.
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.aiResolve = aiResolve;
4
+ exports.prefilter = prefilter;
5
+ exports.buildPrompt = buildPrompt;
6
+ exports.parseModelJson = parseModelJson;
7
+ const match_1 = require("../browser/match");
8
+ const DEFAULTS = { minConfidence: 0.7, topN: 15, timeoutMs: 15000, temperature: 0 };
9
+ /**
10
+ * Resolve a broken `target` to one of the live `candidates`, or null.
11
+ *
12
+ * Returns null — defer to the deterministic path / a human — whenever there is
13
+ * nothing to choose from, the model is not confident enough, the reply is
14
+ * unparseable, or the network fails. It never throws on any of those.
15
+ */
16
+ async function aiResolve(target, candidates, opts) {
17
+ const minConfidence = opts.minConfidence ?? DEFAULTS.minConfidence;
18
+ const topN = opts.topN ?? DEFAULTS.topN;
19
+ const shortlist = prefilter(target, candidates, topN);
20
+ if (shortlist.length === 0)
21
+ return null;
22
+ const raw = await callModel(buildPrompt(target, shortlist), opts);
23
+ if (!raw)
24
+ return null;
25
+ const { candidateIndex, confidence, rationale } = raw;
26
+ if (!Number.isInteger(candidateIndex) || candidateIndex < 0 || candidateIndex >= shortlist.length) {
27
+ return null;
28
+ }
29
+ if (typeof confidence !== 'number' || confidence < minConfidence)
30
+ return null;
31
+ const candidate = shortlist[candidateIndex];
32
+ return { selector: candidate.selector, confidence, rationale: String(rationale ?? ''), candidate };
33
+ }
34
+ /**
35
+ * Keep only same-role candidates, ranked by name similarity to the target, capped
36
+ * at `topN`. Reuses the deterministic engine's pure metric so the shortlist the
37
+ * model sees is the same neighbourhood the heuristic would have searched — the LLM
38
+ * is asked to break a tie the heuristic couldn't, not to search a different space.
39
+ *
40
+ * A target with no accessible name (icon-only) has nothing for Dice to rank on;
41
+ * every same-role candidate scores 0, so the shortlist is just "same role, first N".
42
+ * That is the vision case (phase 2), and text-only will usually — correctly — not
43
+ * clear the confidence floor on it.
44
+ */
45
+ function prefilter(target, candidates, topN) {
46
+ const wanted = (0, match_1.normalize)(target.name);
47
+ return candidates
48
+ .filter((c) => c.role === target.role)
49
+ .map((c) => ({ c, score: (0, match_1.diceSimilarity)((0, match_1.normalize)(c.name), wanted) }))
50
+ .sort((a, b) => b.score - a.score)
51
+ .slice(0, topN)
52
+ .map((x) => x.c);
53
+ }
54
+ function describe(el) {
55
+ const parts = [`role="${el.role}"`, `name=${JSON.stringify(el.name || '')}`];
56
+ if (el.context)
57
+ parts.push(`context=${JSON.stringify(el.context)}`);
58
+ if (el.hint)
59
+ parts.push(`hint=${JSON.stringify(el.hint)}`);
60
+ return parts.join(' ');
61
+ }
62
+ function buildPrompt(target, shortlist) {
63
+ const list = shortlist.map((c, i) => ` ${i}. ${describe(c)}`).join('\n');
64
+ return (`A UI end-to-end test targeted an element that no longer resolves. The element ` +
65
+ `was identified by its ARIA role and accessible name. The page changed; below are ` +
66
+ `the current interactive elements of the same role.\n\n` +
67
+ `Decide which current element is THE SAME element as the original — same purpose, ` +
68
+ `likely renamed or restyled — not merely similar. If none is clearly the same, be ` +
69
+ `unconfident.\n\n` +
70
+ `ORIGINAL (broken):\n ${describe(target)}\n\n` +
71
+ `CURRENT CANDIDATES (choose by index):\n${list}\n\n` +
72
+ `Reply with ONLY a JSON object, nothing else, in exactly this key order:\n` +
73
+ `{"rationale": "<one sentence: why this candidate is the same element, or why none is>", ` +
74
+ `"confidence": <number 0-1>, "candidateIndex": <integer index into the list above>}\n` +
75
+ `Set confidence to 0 if no candidate is the same element.`);
76
+ }
77
+ /**
78
+ * One provider round-trip, fully defensive: a strict timeout (LLMs hang), any
79
+ * non-2xx (429 rate limit, 5xx) or network error, and any unparseable body all
80
+ * resolve to null instead of throwing. The caller treats null as "no suggestion".
81
+ */
82
+ async function callModel(prompt, opts) {
83
+ const fetchFn = opts.fetchFn ?? globalThis.fetch;
84
+ if (typeof fetchFn !== 'function')
85
+ return null;
86
+ const timeoutMs = opts.timeoutMs ?? DEFAULTS.timeoutMs;
87
+ const temperature = opts.temperature ?? DEFAULTS.temperature;
88
+ // The newest models reject sampling params entirely: Anthropic Opus 4.8 / Sonnet 5 /
89
+ // Fable 5 and OpenAI reasoning models (o-series, gpt-5) 400 on `temperature`. Rather
90
+ // than maintain a per-model capability matrix, send temperature and — only on a 400 —
91
+ // retry once without it. Any model that rejects sampling still works.
92
+ let res = await attempt(fetchFn, opts, prompt, temperature, timeoutMs);
93
+ if (res && res.status === 400) {
94
+ res = await attempt(fetchFn, opts, prompt, undefined, timeoutMs);
95
+ }
96
+ if (!res || !res.ok)
97
+ return null;
98
+ let text;
99
+ try {
100
+ const data = await res.json();
101
+ text = extractText(opts.provider, data);
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ return parseModelJson(text);
107
+ }
108
+ /** One hardened round-trip. Returns the Response (even non-2xx, so the caller can see 400), or null on network/timeout. */
109
+ async function attempt(fetchFn, opts, prompt, temperature, timeoutMs) {
110
+ const req = buildRequest(opts.provider, opts.model, opts.apiKey, prompt, temperature);
111
+ const controller = new AbortController();
112
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
113
+ try {
114
+ return await fetchFn(req.url, { method: 'POST', headers: req.headers, body: JSON.stringify(req.body), signal: controller.signal });
115
+ }
116
+ catch {
117
+ return null; // network error or aborted timeout
118
+ }
119
+ finally {
120
+ clearTimeout(timer);
121
+ }
122
+ }
123
+ function buildRequest(provider, model, apiKey, prompt, temperature) {
124
+ if (provider === 'anthropic') {
125
+ const body = { model, max_tokens: 512, messages: [{ role: 'user', content: prompt }] };
126
+ if (temperature !== undefined)
127
+ body.temperature = temperature;
128
+ return {
129
+ url: 'https://api.anthropic.com/v1/messages',
130
+ headers: { 'content-type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' },
131
+ body,
132
+ };
133
+ }
134
+ if (provider === 'google') {
135
+ const generationConfig = { responseMimeType: 'application/json' };
136
+ if (temperature !== undefined)
137
+ generationConfig.temperature = temperature;
138
+ return {
139
+ // Key in the query string is Google's documented scheme for the Generative Language API.
140
+ url: `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(model)}:generateContent?key=${encodeURIComponent(apiKey)}`,
141
+ headers: { 'content-type': 'application/json' },
142
+ body: { contents: [{ parts: [{ text: prompt }] }], generationConfig },
143
+ };
144
+ }
145
+ const body = { model, messages: [{ role: 'user', content: prompt }] };
146
+ if (temperature !== undefined)
147
+ body.temperature = temperature;
148
+ return {
149
+ url: 'https://api.openai.com/v1/chat/completions',
150
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
151
+ body,
152
+ };
153
+ }
154
+ function extractText(provider, data) {
155
+ if (provider === 'anthropic') {
156
+ const block = Array.isArray(data?.content) ? data.content.find((b) => b?.type === 'text') : null;
157
+ return String(block?.text ?? '');
158
+ }
159
+ if (provider === 'google') {
160
+ const parts = data?.candidates?.[0]?.content?.parts;
161
+ return Array.isArray(parts) ? parts.map((p) => p?.text ?? '').join('') : '';
162
+ }
163
+ return String(data?.choices?.[0]?.message?.content ?? '');
164
+ }
165
+ /**
166
+ * Parse the model's reply. Models drool Markdown fences and prose around JSON, so
167
+ * we take the outermost `{…}` and parse that. Any failure → null.
168
+ */
169
+ function parseModelJson(text) {
170
+ const match = text.match(/\{[\s\S]*\}/);
171
+ if (!match)
172
+ return null;
173
+ let obj;
174
+ try {
175
+ obj = JSON.parse(match[0]);
176
+ }
177
+ catch {
178
+ return null;
179
+ }
180
+ if (!obj || typeof obj !== 'object')
181
+ return null;
182
+ if (typeof obj.confidence !== 'number' || !Number.isInteger(obj.candidateIndex))
183
+ return null;
184
+ return {
185
+ rationale: typeof obj.rationale === 'string' ? obj.rationale : '',
186
+ confidence: obj.confidence,
187
+ candidateIndex: obj.candidateIndex,
188
+ };
189
+ }
190
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/ai/resolver.ts"],"names":[],"mappings":"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"}
package/dist/cli/index.js CHANGED
@@ -8,6 +8,8 @@ const diff_1 = require("./diff");
8
8
  const fix_1 = require("./fix");
9
9
  const ingest_1 = require("./ingest");
10
10
  const run_1 = require("./run");
11
+ // dist/cli/ → package root; npm ships package.json in every tarball.
12
+ const VERSION = require('../../package.json').version;
11
13
  const HELP = `ia-qa-heal — self-healing E2E toolkit (MVP)
12
14
 
13
15
  The loop: init → map → baseline → (change the app) → map → diff → fix
@@ -55,6 +57,7 @@ Usage:
55
57
  --locators emit getByRole locators where provably safe
56
58
  --report [file.html] write a branded ia-qa.com HTML report
57
59
  --open open that report in the browser (local, not CI)
60
+ ia-qa-heal version Print the installed version (also --version, -v)
58
61
  ia-qa-heal help Show this help
59
62
  `;
60
63
  async function main() {
@@ -82,6 +85,11 @@ async function main() {
82
85
  case 'run':
83
86
  await (0, run_1.runRun)(rest);
84
87
  break;
88
+ case 'version':
89
+ case '--version':
90
+ case '-v':
91
+ console.log(VERSION);
92
+ break;
85
93
  case 'help':
86
94
  case '--help':
87
95
  case '-h':
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AACA,iCAAiC;AACjC,+BAA+B;AAC/B,yCAAyC;AACzC,iCAAiC;AACjC,+BAA+B;AAC/B,qCAAqC;AACrC,+BAA+B;AAE/B,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDZ,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,EAAE,AAAD,EAAG,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,MAAM,IAAA,cAAO,GAAE,CAAC;YAChB,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAA,YAAM,EAAC,GAAG,CAAC,CAAC;YAClB,MAAM;QACR,KAAK,UAAU;YACb,MAAM,IAAA,sBAAW,EAAC,IAAI,CAAC,CAAC;YACxB,MAAM;QACR,KAAK,MAAM;YACT,MAAM,IAAA,cAAO,EAAC,IAAI,CAAC,CAAC;YACpB,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAA,YAAM,EAAC,IAAI,CAAC,CAAC;YACnB,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,IAAA,kBAAS,EAAC,IAAI,CAAC,CAAC;YACtB,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAA,YAAM,EAAC,IAAI,CAAC,CAAC;YACnB,MAAM;QACR,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,SAAS,IAAI,EAAE,CAAC,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AACA,iCAAiC;AACjC,+BAA+B;AAC/B,yCAAyC;AACzC,iCAAiC;AACjC,+BAA+B;AAC/B,qCAAqC;AACrC,+BAA+B;AAE/B,qEAAqE;AACrE,MAAM,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC,OAAiB,CAAC;AAEhE,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDZ,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,CAAC,EAAE,AAAD,EAAG,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,MAAM,IAAA,cAAO,GAAE,CAAC;YAChB,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAA,YAAM,EAAC,GAAG,CAAC,CAAC;YAClB,MAAM;QACR,KAAK,UAAU;YACb,MAAM,IAAA,sBAAW,EAAC,IAAI,CAAC,CAAC;YACxB,MAAM;QACR,KAAK,MAAM;YACT,MAAM,IAAA,cAAO,EAAC,IAAI,CAAC,CAAC;YACpB,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAA,YAAM,EAAC,IAAI,CAAC,CAAC;YACnB,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,IAAA,kBAAS,EAAC,IAAI,CAAC,CAAC;YACtB,MAAM;QACR,KAAK,KAAK;YACR,MAAM,IAAA,YAAM,EAAC,IAAI,CAAC,CAAC;YACnB,MAAM;QACR,KAAK,SAAS,CAAC;QACf,KAAK,WAAW,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACrB,MAAM;QACR,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,SAAS,IAAI,EAAE,CAAC,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};