@ia-qa/self-healing 0.1.0

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 (54) hide show
  1. package/README.md +91 -0
  2. package/TUTORIAL.md +399 -0
  3. package/dist/aom.d.ts +22 -0
  4. package/dist/aom.js +58 -0
  5. package/dist/aom.js.map +1 -0
  6. package/dist/browser/contract.d.ts +1 -0
  7. package/dist/browser/contract.js +107 -0
  8. package/dist/browser/contract.js.map +1 -0
  9. package/dist/browser/extract.d.ts +25 -0
  10. package/dist/browser/extract.js +194 -0
  11. package/dist/browser/extract.js.map +1 -0
  12. package/dist/browser/match.d.ts +88 -0
  13. package/dist/browser/match.js +179 -0
  14. package/dist/browser/match.js.map +1 -0
  15. package/dist/cli/diff.d.ts +13 -0
  16. package/dist/cli/diff.js +143 -0
  17. package/dist/cli/diff.js.map +1 -0
  18. package/dist/cli/fix.d.ts +17 -0
  19. package/dist/cli/fix.js +144 -0
  20. package/dist/cli/fix.js.map +1 -0
  21. package/dist/cli/index.d.ts +2 -0
  22. package/dist/cli/index.js +50 -0
  23. package/dist/cli/index.js.map +1 -0
  24. package/dist/cli/init.d.ts +8 -0
  25. package/dist/cli/init.js +185 -0
  26. package/dist/cli/init.js.map +1 -0
  27. package/dist/cli/map.d.ts +9 -0
  28. package/dist/cli/map.js +118 -0
  29. package/dist/cli/map.js.map +1 -0
  30. package/dist/config.d.ts +55 -0
  31. package/dist/config.js +111 -0
  32. package/dist/config.js.map +1 -0
  33. package/dist/fixEngine.d.ts +49 -0
  34. package/dist/fixEngine.js +154 -0
  35. package/dist/fixEngine.js.map +1 -0
  36. package/dist/index.d.ts +12 -0
  37. package/dist/index.js +29 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/launcher.d.ts +38 -0
  40. package/dist/launcher.js +38 -0
  41. package/dist/launcher.js.map +1 -0
  42. package/dist/mapUrl.d.ts +34 -0
  43. package/dist/mapUrl.js +90 -0
  44. package/dist/mapUrl.js.map +1 -0
  45. package/dist/markdown.d.ts +10 -0
  46. package/dist/markdown.js +54 -0
  47. package/dist/markdown.js.map +1 -0
  48. package/dist/mcp/server.d.ts +2 -0
  49. package/dist/mcp/server.js +251 -0
  50. package/dist/mcp/server.js.map +1 -0
  51. package/dist/playwright/healer.d.ts +39 -0
  52. package/dist/playwright/healer.js +84 -0
  53. package/dist/playwright/healer.js.map +1 -0
  54. package/package.json +54 -0
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runDiff = runDiff;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const match_1 = require("../browser/match");
40
+ /**
41
+ * `ia-qa-heal diff <baseline.json> <current.json>` — CI-gate verdict.
42
+ *
43
+ * Reads two mappings (produced by `ia-qa-heal map` or the browser snippet on
44
+ * ia-qa.com) and reports which selectors survived, which the runtime healer
45
+ * would recover, and which will hard-fail. Same engine as the web tool.
46
+ *
47
+ * Exit codes (so a pipeline can gate on it):
48
+ * 0 — PASS, or FIX without `--strict`
49
+ * 1 — BLOCK (a selector broke with no semantic match), or FIX with `--strict`
50
+ * 2 — bad usage / unreadable input
51
+ */
52
+ async function runDiff(args) {
53
+ const strict = args.includes('--strict');
54
+ const json = args.includes('--json');
55
+ const files = args.filter((a) => !a.startsWith('--'));
56
+ if (files.length !== 2) {
57
+ console.error('Usage: ia-qa-heal diff <baseline.json> <current.json> [--strict] [--json]');
58
+ process.exitCode = 2;
59
+ return;
60
+ }
61
+ const [baseline, current] = files.map((f) => readMapping(f));
62
+ const report = (0, match_1.diffMappings)(baseline, current);
63
+ if (json) {
64
+ console.log(JSON.stringify(report, null, 2));
65
+ }
66
+ else {
67
+ printHuman(report, files);
68
+ }
69
+ const failing = report.verdict === 'BLOCK' || (strict && report.verdict === 'FIX');
70
+ process.exitCode = failing ? 1 : 0;
71
+ }
72
+ function readMapping(file) {
73
+ let raw;
74
+ try {
75
+ raw = fs.readFileSync(file, 'utf8');
76
+ }
77
+ catch {
78
+ console.error(`❌ Cannot read "${file}".`);
79
+ process.exit(2);
80
+ }
81
+ let parsed;
82
+ try {
83
+ parsed = JSON.parse(raw);
84
+ }
85
+ catch (e) {
86
+ console.error(`❌ "${file}" is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
87
+ process.exit(2);
88
+ }
89
+ if (!parsed || !Array.isArray(parsed.elements)) {
90
+ console.error(`❌ "${file}" has no "elements" array — is it a mapping file?`);
91
+ process.exit(2);
92
+ }
93
+ return parsed;
94
+ }
95
+ function printHuman(report, files) {
96
+ const { verdict, counts, rows, added } = report;
97
+ const icon = verdict === 'PASS' ? '✅' : verdict === 'FIX' ? '🔧' : '⛔';
98
+ console.log(`\n${icon} ${verdict}`);
99
+ console.log(` ${path.basename(files[0])} → ${path.basename(files[1])} · ` +
100
+ `${counts.ok} ok · ${counts.renamed} renamed · ${counts.healable} healable · ` +
101
+ `${counts.ambiguous} ambiguous · ${counts.lost} lost · ${counts.added} new\n`);
102
+ const drift = rows.filter((r) => r.status !== 'ok');
103
+ for (const r of drift) {
104
+ if (r.status === 'healable') {
105
+ const how = r.matchType === 'exact' ? 'exact name' : `fuzzy ${Math.round((r.score ?? 0) * 100)}%`;
106
+ const by = r.disambiguatedBy === 'context' ? `, by context "${r.context}"` : '';
107
+ console.log(` 🔧 healable ${label(r)}\n ${r.selector} → ${r.healedSelector} (${how}${by})`);
108
+ }
109
+ else if (r.status === 'renamed') {
110
+ console.log(` ✏️ renamed ${label(r)}\n name "${r.name}" → "${r.newName}" · selector still valid: ${r.selector}`);
111
+ }
112
+ else if (r.status === 'ambiguous') {
113
+ console.log(` ❓ ambiguous ${label(r)}\n ${r.selector} → ${r.candidateCount} equally-good matches, context "${r.context || ''}" won't disambiguate — human decides`);
114
+ }
115
+ else {
116
+ console.log(` ⛔ lost ${label(r)}\n ${r.selector} → (no match)`);
117
+ }
118
+ }
119
+ for (const r of added) {
120
+ console.log(` ➕ new ${label(r)}\n ${r.selector}`);
121
+ }
122
+ console.log('');
123
+ if (counts.lost > 0) {
124
+ console.log(' ⛔ Lost selectors have no match — self-healing cannot recover them; a human must fix or delete the test.');
125
+ }
126
+ if (counts.ambiguous > 0) {
127
+ console.log(' ❓ Ambiguous selectors match several elements — healing would be a guess; a human decides (or add a data-testid).');
128
+ }
129
+ if (counts.healable > 0) {
130
+ console.log(' 🔧 Healable selectors have a deterministic old→new rewrite — apply with `ia-qa-heal fix`.');
131
+ }
132
+ if (counts.renamed > 0) {
133
+ console.log(' ✏️ Renamed elements still pass (selector valid) but the label changed — check it is intended, not a regression.');
134
+ }
135
+ if (verdict === 'PASS' && counts.renamed === 0) {
136
+ console.log(' ✅ No drift — your suite is safe to run.');
137
+ }
138
+ console.log('');
139
+ }
140
+ function label(r) {
141
+ return `${r.role} "${r.name || '(no name)'}"`;
142
+ }
143
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `ia-qa-heal fix <before.json> <after.json> <test-paths…> [--dry-run]`
3
+ *
4
+ * The deterministic half of self-healing. Diffs two mappings, takes ONLY the
5
+ * `healable` rows (selector broke, role + name + context still identify exactly
6
+ * one element → unambiguous old→new selector), and rewrites those selectors in
7
+ * your test files — only where they appear as a quoted string literal, so a
8
+ * substring like `button#login` never corrupts `button#login-btn`.
9
+ *
10
+ * It **prepares the ground, the human decides**: it edits the working tree and
11
+ * never commits. LOST / AMBIGUOUS / RENAMED are printed but never touched.
12
+ * Presentation only — the engine lives in `../fixEngine` and is shared with the
13
+ * MCP server's `fix_tests` tool.
14
+ *
15
+ * Exit codes: 0 on a successful run (even with 0 rewrites); 2 = bad input.
16
+ */
17
+ export declare function runFix(args: string[]): Promise<void>;
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runFix = runFix;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const match_1 = require("../browser/match");
40
+ const fixEngine_1 = require("../fixEngine");
41
+ /**
42
+ * `ia-qa-heal fix <before.json> <after.json> <test-paths…> [--dry-run]`
43
+ *
44
+ * The deterministic half of self-healing. Diffs two mappings, takes ONLY the
45
+ * `healable` rows (selector broke, role + name + context still identify exactly
46
+ * one element → unambiguous old→new selector), and rewrites those selectors in
47
+ * your test files — only where they appear as a quoted string literal, so a
48
+ * substring like `button#login` never corrupts `button#login-btn`.
49
+ *
50
+ * It **prepares the ground, the human decides**: it edits the working tree and
51
+ * never commits. LOST / AMBIGUOUS / RENAMED are printed but never touched.
52
+ * Presentation only — the engine lives in `../fixEngine` and is shared with the
53
+ * MCP server's `fix_tests` tool.
54
+ *
55
+ * Exit codes: 0 on a successful run (even with 0 rewrites); 2 = bad input.
56
+ */
57
+ async function runFix(args) {
58
+ const dryRun = args.includes('--dry-run');
59
+ const rest = args.filter((a) => !a.startsWith('--'));
60
+ const [beforeFile, afterFile, ...testPaths] = rest;
61
+ if (!beforeFile || !afterFile || testPaths.length === 0) {
62
+ console.error('Usage: ia-qa-heal fix <before.json> <after.json> <test-file-or-dir…> [--dry-run]');
63
+ process.exitCode = 2;
64
+ return;
65
+ }
66
+ const before = readMapping(beforeFile);
67
+ const after = readMapping(afterFile);
68
+ const report = (0, match_1.diffMappings)(before, after);
69
+ const rewrites = (0, fixEngine_1.computeRewrites)(report.rows);
70
+ const files = (0, fixEngine_1.collectFiles)(testPaths, (p) => console.error(`⚠ Skipping "${p}" — not found.`));
71
+ if (files.length === 0) {
72
+ console.error(`No test files found under: ${testPaths.join(', ')}`);
73
+ process.exitCode = 2;
74
+ return;
75
+ }
76
+ console.log(`\n🔧 ia-qa-heal fix — deterministic selector rewrite${dryRun ? ' (dry run)' : ''}`);
77
+ console.log(` ${rewrites.size} healable rewrite${rewrites.size === 1 ? '' : 's'} · ${files.length} file${files.length === 1 ? '' : 's'} scanned\n`);
78
+ const result = (0, fixEngine_1.applyRewrites)(files, rewrites, dryRun);
79
+ if (rewrites.size === 0) {
80
+ console.log(' No healable rewrites in this diff — nothing to apply.');
81
+ }
82
+ else if (result.edits.length === 0) {
83
+ console.log(' No test file referenced any of the healable selectors — nothing to rewrite.');
84
+ }
85
+ else {
86
+ for (const edit of result.edits) {
87
+ console.log(` ${dryRun ? 'would edit' : '✎ edited'} ${path.relative(process.cwd(), edit.file)}`);
88
+ for (const r of edit.replacements)
89
+ console.log(` ${r.count}× ${r.from} → ${r.to}`);
90
+ }
91
+ }
92
+ printNeedsHuman(report);
93
+ console.log(`\n ${dryRun ? 'Would apply' : 'Applied'} ${result.totalReplacements} replacement${result.totalReplacements === 1 ? '' : 's'} in ${result.edits.length} file${result.edits.length === 1 ? '' : 's'}.` +
94
+ (dryRun ? ' (dry run — nothing written.)' : ''));
95
+ if (!dryRun && result.totalReplacements > 0) {
96
+ console.log(' Review with `git diff`, then commit and push if it looks right. Nothing was committed.\n');
97
+ }
98
+ else {
99
+ console.log('');
100
+ }
101
+ process.exitCode = 0;
102
+ }
103
+ function printNeedsHuman(report) {
104
+ const flagged = report.rows.filter((r) => r.status === 'lost' || r.status === 'ambiguous' || r.status === 'renamed');
105
+ if (flagged.length === 0)
106
+ return;
107
+ console.log('\n Not applied — needs your judgment:');
108
+ for (const r of flagged) {
109
+ const who = `${r.role} "${r.name || '(no name)'}"`;
110
+ if (r.status === 'lost') {
111
+ console.log(` ⛔ lost ${who} · ${r.selector} has no match — fix or delete the test by hand.`);
112
+ }
113
+ else if (r.status === 'ambiguous') {
114
+ console.log(` ❓ ambiguous ${who} · ${r.candidateCount} equal matches — pick one, or add a data-testid.`);
115
+ }
116
+ else {
117
+ console.log(` ✏️ renamed ${who} · name → "${r.newName}" — selector still valid; confirm it's intended.`);
118
+ }
119
+ }
120
+ }
121
+ function readMapping(file) {
122
+ let raw;
123
+ try {
124
+ raw = fs.readFileSync(file, 'utf8');
125
+ }
126
+ catch {
127
+ console.error(`❌ Cannot read "${file}".`);
128
+ process.exit(2);
129
+ }
130
+ let parsed;
131
+ try {
132
+ parsed = JSON.parse(raw);
133
+ }
134
+ catch (e) {
135
+ console.error(`❌ "${file}" is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
136
+ process.exit(2);
137
+ }
138
+ if (!parsed || !Array.isArray(parsed.elements)) {
139
+ console.error(`❌ "${file}" has no "elements" array — is it a mapping file?`);
140
+ process.exit(2);
141
+ }
142
+ return parsed;
143
+ }
144
+ //# sourceMappingURL=fix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix.js","sourceRoot":"","sources":["../../src/cli/fix.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const init_1 = require("./init");
5
+ const map_1 = require("./map");
6
+ const diff_1 = require("./diff");
7
+ const fix_1 = require("./fix");
8
+ const HELP = `ia-qa-heal — self-healing E2E toolkit (MVP)
9
+
10
+ Usage:
11
+ ia-qa-heal init Interactive setup wizard (writes .ia-qa/config.json)
12
+ ia-qa-heal map [page] Map configured pages → .ia-qa/mapping/<page>.json + .md
13
+ ia-qa-heal diff <before> <after> Diff two mappings → PASS/FIX/BLOCK verdict (CI gate)
14
+ --strict fail on FIX too --json machine-readable output
15
+ ia-qa-heal fix <before> <after> <tests…> Apply the deterministic healable rewrites to your test files
16
+ --dry-run show the plan without writing. Never commits.
17
+ ia-qa-heal help Show this help
18
+ `;
19
+ async function main() {
20
+ const [, , command, ...rest] = process.argv;
21
+ const arg = rest[0];
22
+ switch (command) {
23
+ case 'init':
24
+ await (0, init_1.runInit)();
25
+ break;
26
+ case 'map':
27
+ await (0, map_1.runMap)(arg);
28
+ break;
29
+ case 'diff':
30
+ await (0, diff_1.runDiff)(rest);
31
+ break;
32
+ case 'fix':
33
+ await (0, fix_1.runFix)(rest);
34
+ break;
35
+ case 'help':
36
+ case '--help':
37
+ case '-h':
38
+ case undefined:
39
+ console.log(HELP);
40
+ break;
41
+ default:
42
+ console.error(`Unknown command "${command}".\n\n${HELP}`);
43
+ process.exit(1);
44
+ }
45
+ }
46
+ main().catch((err) => {
47
+ console.error(`\n❌ ${err instanceof Error ? err.message : String(err)}`);
48
+ process.exit(1);
49
+ });
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AACA,iCAAiC;AACjC,+BAA+B;AAC/B,iCAAiC;AACjC,+BAA+B;AAE/B,MAAM,IAAI,GAAG;;;;;;;;;;CAUZ,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,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,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,8 @@
1
+ /**
2
+ * `ia-qa-heal init` — interactive wizard.
3
+ *
4
+ * Guides the user through target framework, secret storage (local .env or AWS
5
+ * SSM Parameter Store), optional login flow, and the pages to map. Writes
6
+ * `.ia-qa/config.json` containing only secret *references* — never a value.
7
+ */
8
+ export declare function runInit(): Promise<void>;
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runInit = runInit;
7
+ const prompts_1 = __importDefault(require("prompts"));
8
+ const config_1 = require("../config");
9
+ /**
10
+ * `ia-qa-heal init` — interactive wizard.
11
+ *
12
+ * Guides the user through target framework, secret storage (local .env or AWS
13
+ * SSM Parameter Store), optional login flow, and the pages to map. Writes
14
+ * `.ia-qa/config.json` containing only secret *references* — never a value.
15
+ */
16
+ async function runInit() {
17
+ console.log('\n🔧 ia-qa self-healing — project setup\n');
18
+ const onCancel = () => {
19
+ console.error('\nSetup aborted — nothing was written.');
20
+ process.exit(1);
21
+ };
22
+ const base = await (0, prompts_1.default)([
23
+ {
24
+ type: 'select',
25
+ name: 'framework',
26
+ message: 'Target test framework',
27
+ choices: [{ title: 'Playwright', value: 'playwright' }],
28
+ initial: 0,
29
+ },
30
+ {
31
+ type: 'text',
32
+ name: 'baseUrl',
33
+ message: 'Base URL of the application under test',
34
+ initial: 'https://staging.example.com',
35
+ validate: (v) => {
36
+ try {
37
+ new URL(v);
38
+ return true;
39
+ }
40
+ catch {
41
+ return 'Enter a full URL, e.g. https://staging.example.com';
42
+ }
43
+ },
44
+ },
45
+ {
46
+ type: 'confirm',
47
+ name: 'needsAuth',
48
+ message: 'Does the app require a login step before mapping?',
49
+ initial: true,
50
+ },
51
+ ], { onCancel });
52
+ const secrets = {};
53
+ let auth;
54
+ if (base.needsAuth) {
55
+ const store = await (0, prompts_1.default)({
56
+ type: 'select',
57
+ name: 'source',
58
+ message: 'Where are the test credentials stored?',
59
+ choices: [
60
+ { title: 'Local .env file (read from process.env at runtime)', value: 'env' },
61
+ { title: 'AWS SSM Parameter Store (fetched via your local AWS credentials)', value: 'aws-ssm' },
62
+ ],
63
+ }, { onCancel });
64
+ const source = store.source;
65
+ if (source === 'env') {
66
+ const env = await (0, prompts_1.default)([
67
+ {
68
+ type: 'text',
69
+ name: 'usernameKey',
70
+ message: 'Env var holding the username',
71
+ initial: 'E2E_USERNAME',
72
+ },
73
+ {
74
+ type: 'text',
75
+ name: 'passwordKey',
76
+ message: 'Env var holding the password',
77
+ initial: 'E2E_PASSWORD',
78
+ },
79
+ ], { onCancel });
80
+ secrets.username = { source, key: env.usernameKey };
81
+ secrets.password = { source, key: env.passwordKey };
82
+ }
83
+ else {
84
+ const ssm = await (0, prompts_1.default)([
85
+ {
86
+ type: 'text',
87
+ name: 'usernameParam',
88
+ message: 'SSM parameter name for the username',
89
+ initial: '/staging/app/username',
90
+ },
91
+ {
92
+ type: 'text',
93
+ name: 'passwordParam',
94
+ message: 'SSM parameter name for the password (SecureString recommended)',
95
+ initial: '/staging/app/password',
96
+ },
97
+ {
98
+ type: 'text',
99
+ name: 'region',
100
+ message: 'AWS region',
101
+ initial: 'eu-west-3',
102
+ },
103
+ ], { onCancel });
104
+ secrets.username = { source, key: ssm.usernameParam, region: ssm.region };
105
+ secrets.password = { source, key: ssm.passwordParam, region: ssm.region };
106
+ }
107
+ const form = await (0, prompts_1.default)([
108
+ { type: 'text', name: 'loginUrl', message: 'Login page path', initial: '/login' },
109
+ {
110
+ type: 'text',
111
+ name: 'usernameSelector',
112
+ message: 'Username/email input selector',
113
+ initial: 'input[name="email"]',
114
+ },
115
+ {
116
+ type: 'text',
117
+ name: 'passwordSelector',
118
+ message: 'Password input selector',
119
+ initial: 'input[type="password"]',
120
+ },
121
+ {
122
+ type: 'text',
123
+ name: 'submitSelector',
124
+ message: 'Submit button selector',
125
+ initial: 'button[type="submit"]',
126
+ },
127
+ {
128
+ type: 'text',
129
+ name: 'successSelector',
130
+ message: 'Selector visible once logged in (optional, blank to skip)',
131
+ initial: '',
132
+ },
133
+ ], { onCancel });
134
+ auth = {
135
+ loginUrl: form.loginUrl,
136
+ usernameSelector: form.usernameSelector,
137
+ passwordSelector: form.passwordSelector,
138
+ submitSelector: form.submitSelector,
139
+ usernameSecret: 'username',
140
+ passwordSecret: 'password',
141
+ ...(form.successSelector ? { successSelector: form.successSelector } : {}),
142
+ };
143
+ }
144
+ const pagesAnswer = await (0, prompts_1.default)({
145
+ type: 'text',
146
+ name: 'pagesRaw',
147
+ message: 'Pages to map — comma-separated "name=path" pairs',
148
+ initial: 'home=/',
149
+ validate: (v) => parsePages(v).length > 0 || 'Expected format: home=/,dashboard=/dashboard',
150
+ }, { onCancel });
151
+ const pages = parsePages(pagesAnswer.pagesRaw);
152
+ const config = {
153
+ framework: base.framework,
154
+ baseUrl: base.baseUrl,
155
+ secrets,
156
+ ...(auth ? { auth } : {}),
157
+ pages,
158
+ };
159
+ const file = (0, config_1.saveConfig)(config);
160
+ console.log(`\n✅ Wrote ${file}`);
161
+ console.log(` Secrets are stored as references only — values stay in ${auth ? describeStore(secrets) : 'your environment'}.`);
162
+ console.log('\nNext steps:');
163
+ console.log(' 1. ia-qa-heal map # map every configured page');
164
+ console.log(' 2. import { aiClick } from "@ia-qa/self-healing" in your Playwright tests\n');
165
+ }
166
+ function parsePages(raw) {
167
+ return raw
168
+ .split(',')
169
+ .map((pair) => pair.trim())
170
+ .filter(Boolean)
171
+ .map((pair) => {
172
+ const eq = pair.indexOf('=');
173
+ if (eq <= 0)
174
+ return null;
175
+ const name = pair.slice(0, eq).trim();
176
+ const url = pair.slice(eq + 1).trim();
177
+ return name && url ? { name, url } : null;
178
+ })
179
+ .filter((p) => p !== null);
180
+ }
181
+ function describeStore(secrets) {
182
+ const first = Object.values(secrets)[0];
183
+ return first?.source === 'aws-ssm' ? 'AWS SSM Parameter Store' : `your local .env (${config_1.CONFIG_DIR} never holds values)`;
184
+ }
185
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * `ia-qa-heal map [pageName]` — scraping & DOM compression engine.
3
+ *
4
+ * Loads `.ia-qa/config.json`, resolves credentials at runtime (env or AWS SSM,
5
+ * see `resolveSecret`), launches headless Chromium, logs in if configured,
6
+ * then visits each target page and writes a compressed accessibility mapping
7
+ * to `.ia-qa/mapping/<page-name>.json`.
8
+ */
9
+ export declare function runMap(pageNameArg?: string): Promise<void>;