@ia-qa/self-healing 1.6.6 → 1.6.8
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.
- package/README.md +118 -2
- package/TUTORIAL.md +138 -3
- package/assets/logoKawaiiGreenTiny.png +0 -0
- package/dist/cli/args.js +4 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/diff.d.ts +6 -1
- package/dist/cli/diff.js +114 -4
- package/dist/cli/diff.js.map +1 -1
- package/dist/cli/emit.d.ts +71 -0
- package/dist/cli/emit.js +150 -0
- package/dist/cli/emit.js.map +1 -0
- package/dist/cli/fix.js +36 -0
- package/dist/cli/fix.js.map +1 -1
- package/dist/cli/history.d.ts +12 -0
- package/dist/cli/history.js +95 -0
- package/dist/cli/history.js.map +1 -0
- package/dist/cli/index.js +53 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.js +32 -0
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/map.js +60 -0
- package/dist/cli/map.js.map +1 -1
- package/dist/cli/run.js +77 -7
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/ui.d.ts +16 -0
- package/dist/cli/ui.js +275 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/evidence.d.ts +130 -0
- package/dist/evidence.js +232 -0
- package/dist/evidence.js.map +1 -0
- package/dist/history.d.ts +145 -0
- package/dist/history.js +230 -0
- package/dist/history.js.map +1 -0
- package/dist/htmlReport.d.ts +47 -0
- package/dist/htmlReport.js +76 -1
- package/dist/htmlReport.js.map +1 -1
- package/dist/junit.d.ts +53 -0
- package/dist/junit.js +150 -0
- package/dist/junit.js.map +1 -0
- package/dist/mcp/server.js +41 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/ui/icon.d.ts +41 -0
- package/dist/ui/icon.js +115 -0
- package/dist/ui/icon.js.map +1 -0
- package/dist/ui/lock.d.ts +40 -0
- package/dist/ui/lock.js +138 -0
- package/dist/ui/lock.js.map +1 -0
- package/dist/ui/page.d.ts +1 -0
- package/dist/ui/page.js +584 -0
- package/dist/ui/page.js.map +1 -0
- package/dist/ui/registry.d.ts +62 -0
- package/dist/ui/registry.js +139 -0
- package/dist/ui/registry.js.map +1 -0
- package/dist/ui/server.d.ts +67 -0
- package/dist/ui/server.js +604 -0
- package/dist/ui/server.js.map +1 -0
- package/dist/ui/shortcut.d.ts +90 -0
- package/dist/ui/shortcut.js +176 -0
- package/dist/ui/shortcut.js.map +1 -0
- package/package.json +2 -1
- package/skills/ia-qa-heal/SKILL.md +27 -0
|
@@ -0,0 +1,604 @@
|
|
|
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.HEARTBEAT_INTERVAL_MS = void 0;
|
|
37
|
+
exports.actionCatalogue = actionCatalogue;
|
|
38
|
+
exports.isLoopbackHost = isLoopbackHost;
|
|
39
|
+
exports.setActiveProject = setActiveProject;
|
|
40
|
+
exports.getActiveProject = getActiveProject;
|
|
41
|
+
exports.startUi = startUi;
|
|
42
|
+
exports.interpret = interpret;
|
|
43
|
+
const http = __importStar(require("http"));
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const crypto = __importStar(require("crypto"));
|
|
47
|
+
const child_process_1 = require("child_process");
|
|
48
|
+
const config_1 = require("../config");
|
|
49
|
+
const registry_1 = require("./registry");
|
|
50
|
+
const diff_1 = require("../cli/diff");
|
|
51
|
+
const ingest_1 = require("../ingest");
|
|
52
|
+
const evidence_1 = require("../evidence");
|
|
53
|
+
const history_1 = require("../history");
|
|
54
|
+
const page_1 = require("./page");
|
|
55
|
+
/**
|
|
56
|
+
* When the browser goes, the server goes.
|
|
57
|
+
*
|
|
58
|
+
* Closing a tab does not, on its own, stop a process — so without this, every
|
|
59
|
+
* click of the desktop shortcut leaves a Node process holding a port and a
|
|
60
|
+
* session token, and they accumulate silently. An idle event-driven server
|
|
61
|
+
* costs almost no CPU, but "almost nothing, forever, times twenty" is not a
|
|
62
|
+
* defence, and a stale console is a live endpoint into the user's contracts.
|
|
63
|
+
*
|
|
64
|
+
* The page sends a heartbeat, so absence is detected rather than assumed:
|
|
65
|
+
* `GRACE` covers the gap between starting and the browser actually loading the
|
|
66
|
+
* page (a cold browser start is slow), `IDLE` is how long a loaded page may go
|
|
67
|
+
* quiet before it is presumed closed, and `BYE` is the short wait after an
|
|
68
|
+
* explicit goodbye, which a reload would interrupt.
|
|
69
|
+
*/
|
|
70
|
+
const HEARTBEAT_GRACE_MS = 10 * 60 * 1000;
|
|
71
|
+
// Three missed heartbeats plus a margin. The goodbye beacon is the fast path
|
|
72
|
+
// when the browser sends it, but a browser is not obliged to — measured on a
|
|
73
|
+
// programmatic tab close, it did not arrive at all — so this is the number that
|
|
74
|
+
// actually bounds how long a console can outlive its tab. Anything much shorter
|
|
75
|
+
// starts killing consoles whose tab is merely on a busy machine.
|
|
76
|
+
const HEARTBEAT_IDLE_MS = 45 * 1000;
|
|
77
|
+
const BYE_DELAY_MS = 4000;
|
|
78
|
+
/** How often the page says it is still there. Must stay well under `HEARTBEAT_IDLE_MS`. */
|
|
79
|
+
exports.HEARTBEAT_INTERVAL_MS = 15000;
|
|
80
|
+
/**
|
|
81
|
+
* Verbs the console may run, with the exact argv each one gets.
|
|
82
|
+
*
|
|
83
|
+
* `label` and `means` are written for someone who has never opened a terminal:
|
|
84
|
+
* the label says what it does to their app or their tests, and `means` says
|
|
85
|
+
* what just happened to their files once it has run. Neither names a flag —
|
|
86
|
+
* the flags are a constant here precisely so nobody has to know them.
|
|
87
|
+
*/
|
|
88
|
+
const ACTIONS = {
|
|
89
|
+
map: {
|
|
90
|
+
argv: ['map', '--screenshots'],
|
|
91
|
+
label: 'Look at the app again',
|
|
92
|
+
writes: false,
|
|
93
|
+
means: 'Your pages were read again, screenshots included. Everything on this page now describes the app as it is right now.',
|
|
94
|
+
},
|
|
95
|
+
ingest: {
|
|
96
|
+
argv: ['ingest'],
|
|
97
|
+
label: 'Read my test files again',
|
|
98
|
+
writes: false,
|
|
99
|
+
means: 'Your test files were re-read. The console now knows which buttons and links your tests rely on.',
|
|
100
|
+
},
|
|
101
|
+
diff: {
|
|
102
|
+
argv: ['diff'],
|
|
103
|
+
label: 'Check for changes',
|
|
104
|
+
writes: false,
|
|
105
|
+
means: 'This is the check itself — the app as it is now, against the reference you saved earlier. Nothing was modified.',
|
|
106
|
+
},
|
|
107
|
+
audit: {
|
|
108
|
+
argv: ['audit'],
|
|
109
|
+
label: 'Do my tests still match the app?',
|
|
110
|
+
writes: false,
|
|
111
|
+
means: 'This looked for buttons and links your tests name but that no longer exist. It is advice, not a gate — nothing was modified.',
|
|
112
|
+
},
|
|
113
|
+
check: {
|
|
114
|
+
argv: ['check'],
|
|
115
|
+
label: 'Is the app itself healthy?',
|
|
116
|
+
writes: false,
|
|
117
|
+
means: 'This looked for problems in the app, not in your tests: broken links, buttons with no name, two things sharing one name.',
|
|
118
|
+
},
|
|
119
|
+
'fix-dry': {
|
|
120
|
+
argv: ['fix', '--dry-run'],
|
|
121
|
+
label: 'Preview the repairs',
|
|
122
|
+
writes: false,
|
|
123
|
+
means: 'A preview only. Nothing in your files has changed — use “Repair my test files” when the plan looks right.',
|
|
124
|
+
},
|
|
125
|
+
'fix-apply': {
|
|
126
|
+
argv: ['fix'],
|
|
127
|
+
label: 'Repair my test files',
|
|
128
|
+
writes: true,
|
|
129
|
+
means: 'Your test files on disk were edited. Nothing was committed — review the changes before you push them.',
|
|
130
|
+
},
|
|
131
|
+
baseline: {
|
|
132
|
+
argv: ['baseline'],
|
|
133
|
+
label: 'Accept the app as it is now',
|
|
134
|
+
writes: true,
|
|
135
|
+
means: 'What the app looks like today is now the reference. Future checks compare against this.',
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
function actionCatalogue() {
|
|
139
|
+
return Object.entries(ACTIONS).map(([id, a]) => ({ id, label: a.label, writes: a.writes, means: a.means }));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Loopback check on the `Host` header — the defence a token cannot provide.
|
|
143
|
+
* An IPv6 literal arrives bracketed (`[::1]:7333`), which is why this is not a
|
|
144
|
+
* bare `startsWith`.
|
|
145
|
+
*/
|
|
146
|
+
function isLoopbackHost(host) {
|
|
147
|
+
if (!host)
|
|
148
|
+
return false;
|
|
149
|
+
const name = host.replace(/:\d+$/, '').replace(/^\[|\]$/g, '').toLowerCase();
|
|
150
|
+
return name === '127.0.0.1' || name === 'localhost' || name === '::1';
|
|
151
|
+
}
|
|
152
|
+
function cliEntry() {
|
|
153
|
+
// dist/ui/server.js → dist/cli/index.js. Spawned with the running Node binary
|
|
154
|
+
// so the console never depends on the package being on PATH.
|
|
155
|
+
return path.join(__dirname, '..', 'cli', 'index.js');
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Everything the page renders, computed fresh on each request.
|
|
159
|
+
*
|
|
160
|
+
* Deliberately not cached: the whole point of the console is that the user just
|
|
161
|
+
* ran something, and a stale panel that looks live is worse than a slow one.
|
|
162
|
+
*/
|
|
163
|
+
/**
|
|
164
|
+
* The project the console is currently showing.
|
|
165
|
+
*
|
|
166
|
+
* Module state rather than a parameter threaded everywhere, because `baseDir()`
|
|
167
|
+
* — which every path helper in this package reads — is itself global. Set once
|
|
168
|
+
* at the top of a request and used synchronously; Node runs one request's
|
|
169
|
+
* synchronous work to completion, so two requests cannot interleave a read of
|
|
170
|
+
* it. Child processes are never trusted to inherit it: they are handed
|
|
171
|
+
* `--config <dir>` explicitly.
|
|
172
|
+
*/
|
|
173
|
+
let activeDir = null;
|
|
174
|
+
function setActiveProject(dir) {
|
|
175
|
+
activeDir = dir;
|
|
176
|
+
(0, config_1.setBaseDir)(dir);
|
|
177
|
+
}
|
|
178
|
+
function getActiveProject() {
|
|
179
|
+
return activeDir ?? (0, config_1.baseDir)();
|
|
180
|
+
}
|
|
181
|
+
function buildState() {
|
|
182
|
+
if (activeDir)
|
|
183
|
+
(0, config_1.setBaseDir)(activeDir);
|
|
184
|
+
const base = (0, config_1.baselineDir)();
|
|
185
|
+
const current = (0, config_1.mappingDir)();
|
|
186
|
+
// Which project this console is about, stated rather than implied. A console
|
|
187
|
+
// is bound to the directory it was started in, and someone who opened it from
|
|
188
|
+
// a desktop icon has no other way to tell which app they are looking at —
|
|
189
|
+
// "localhost:3000" is every project they have.
|
|
190
|
+
let project = { baseUrl: (0, config_1.configuredBaseUrl)() };
|
|
191
|
+
try {
|
|
192
|
+
const cfg = (0, config_1.loadConfig)();
|
|
193
|
+
project = {
|
|
194
|
+
baseUrl: cfg.baseUrl,
|
|
195
|
+
pages: cfg.pages.length,
|
|
196
|
+
pageNames: cfg.pages.slice(0, 12).map((p) => p.name),
|
|
197
|
+
testCommand: cfg.testCommand ?? null,
|
|
198
|
+
testPaths: cfg.testPaths ?? [],
|
|
199
|
+
hasTestPaths: Boolean(cfg.testPaths?.length),
|
|
200
|
+
dir: (0, config_1.baseDir)(),
|
|
201
|
+
configFile: path.join((0, config_1.baseDir)(), config_1.CONFIG_DIR, 'config.json'),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
project.dir = (0, config_1.baseDir)();
|
|
206
|
+
project.error = 'No .ia-qa/config.json in this folder — run `ia-qa-heal init` here.';
|
|
207
|
+
}
|
|
208
|
+
// Which frameworks the suite is actually written in, read off the inventory
|
|
209
|
+
// rather than guessed from a folder name — `ingest` already recorded the call
|
|
210
|
+
// shape of every locator it found.
|
|
211
|
+
const inventory = (0, ingest_1.loadUsage)();
|
|
212
|
+
const frameworks = inventory
|
|
213
|
+
? [...new Set(Object.values(inventory.selectors).flat().map((s) => s.shape))].sort()
|
|
214
|
+
: [];
|
|
215
|
+
const history = (0, history_1.readHistory)();
|
|
216
|
+
const state = {
|
|
217
|
+
project: { ...project, frameworks, scannedFiles: inventory?.scanned ?? 0 },
|
|
218
|
+
// Only projects a console was opened in — see registry.ts. The client is
|
|
219
|
+
// shown the list; it can never propose a directory outside it.
|
|
220
|
+
projects: (0, registry_1.listProjects)().map((p) => ({ dir: p.dir, baseUrl: p.baseUrl, lastOpened: p.lastOpened })),
|
|
221
|
+
activeDir: getActiveProject(),
|
|
222
|
+
hasBaseline: fs.existsSync(base),
|
|
223
|
+
history: { entries: history, summary: (0, history_1.summarize)(history) },
|
|
224
|
+
actions: actionCatalogue(),
|
|
225
|
+
};
|
|
226
|
+
if (!fs.existsSync(base) || !fs.existsSync(current)) {
|
|
227
|
+
state.verdict = null;
|
|
228
|
+
state.decisions = [];
|
|
229
|
+
return state;
|
|
230
|
+
}
|
|
231
|
+
let collected;
|
|
232
|
+
try {
|
|
233
|
+
collected = (0, diff_1.collectDirDiff)(base, current);
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
state.verdict = null;
|
|
237
|
+
state.decisions = [];
|
|
238
|
+
return state;
|
|
239
|
+
}
|
|
240
|
+
const { reports, stale } = collected;
|
|
241
|
+
if (reports.length === 0) {
|
|
242
|
+
state.verdict = null;
|
|
243
|
+
state.staleExcluded = stale;
|
|
244
|
+
state.decisions = [];
|
|
245
|
+
return state;
|
|
246
|
+
}
|
|
247
|
+
const agg = (0, diff_1.aggregateReports)(reports);
|
|
248
|
+
if (stale.length > 0)
|
|
249
|
+
agg.staleExcluded = stale;
|
|
250
|
+
state.verdict = agg;
|
|
251
|
+
state.coverage = { measured: reports.filter((r) => !r.isLayout).length, stale: stale.length };
|
|
252
|
+
// The decision list: only the rows where the tool stopped and handed over.
|
|
253
|
+
const usage = (0, ingest_1.loadUsage)();
|
|
254
|
+
const decisions = [];
|
|
255
|
+
for (const { name, report, isLayout } of reports) {
|
|
256
|
+
if (isLayout)
|
|
257
|
+
continue;
|
|
258
|
+
const wanted = report.rows.filter((r) => r.status === 'ambiguous' || r.status === 'lost' || r.rebound === true);
|
|
259
|
+
if (wanted.length === 0)
|
|
260
|
+
continue;
|
|
261
|
+
const shot = (0, evidence_1.loadPageShot)(name);
|
|
262
|
+
let after = null;
|
|
263
|
+
try {
|
|
264
|
+
after = JSON.parse(fs.readFileSync(path.join(current, `${name}.json`), 'utf8'));
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
after = null;
|
|
268
|
+
}
|
|
269
|
+
for (const r of wanted) {
|
|
270
|
+
const ev = (0, evidence_1.rowEvidence)(r, after, shot);
|
|
271
|
+
decisions.push({
|
|
272
|
+
page: name,
|
|
273
|
+
selector: r.selector,
|
|
274
|
+
status: r.status,
|
|
275
|
+
label: r.name ? `${r.role} "${r.name}"` : r.hint ? `${r.role} ⋯${r.hint}` : `${r.role} "(no name)"`,
|
|
276
|
+
context: r.context,
|
|
277
|
+
rebound: r.rebound,
|
|
278
|
+
reboundTo: r.reboundTo,
|
|
279
|
+
sites: (usage?.selectors[r.selector] ?? []).map((s) => ({ file: s.file, line: s.line })),
|
|
280
|
+
nowAt: ev?.nowAt,
|
|
281
|
+
candidates: ev?.candidates ?? [],
|
|
282
|
+
note: ev?.note,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
state.decisions = decisions;
|
|
287
|
+
state.nameDrift = agg.nameDrift ?? [];
|
|
288
|
+
return state;
|
|
289
|
+
}
|
|
290
|
+
function send(res, code, type, body) {
|
|
291
|
+
res.writeHead(code, {
|
|
292
|
+
'Content-Type': type,
|
|
293
|
+
'Cache-Control': 'no-store',
|
|
294
|
+
// A console that renders contract data must not be framed by anything, and
|
|
295
|
+
// has no reason to load or reach anywhere off this machine.
|
|
296
|
+
'X-Content-Type-Options': 'nosniff',
|
|
297
|
+
'X-Frame-Options': 'DENY',
|
|
298
|
+
'Content-Security-Policy': "default-src 'none'; img-src 'self' data:; style-src 'unsafe-inline'; script-src 'unsafe-inline'; connect-src 'self'; form-action 'none'; frame-ancestors 'none'",
|
|
299
|
+
});
|
|
300
|
+
res.end(body);
|
|
301
|
+
}
|
|
302
|
+
function readBody(req, limit = 64 * 1024) {
|
|
303
|
+
return new Promise((resolve, reject) => {
|
|
304
|
+
let data = '';
|
|
305
|
+
req.on('data', (c) => {
|
|
306
|
+
data += c;
|
|
307
|
+
if (data.length > limit)
|
|
308
|
+
reject(new Error('body too large'));
|
|
309
|
+
});
|
|
310
|
+
req.on('end', () => resolve(data));
|
|
311
|
+
req.on('error', reject);
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
async function startUi(opts = {}) {
|
|
315
|
+
const token = crypto.randomBytes(24).toString('hex');
|
|
316
|
+
const startedAt = Date.now();
|
|
317
|
+
let lastSeen = 0;
|
|
318
|
+
let byeAt = 0;
|
|
319
|
+
let idleHandler = null;
|
|
320
|
+
const server = http.createServer((req, res) => {
|
|
321
|
+
lastSeen = Date.now();
|
|
322
|
+
byeAt = 0;
|
|
323
|
+
void handle(req, res, token, () => {
|
|
324
|
+
byeAt = Date.now();
|
|
325
|
+
}).catch(() => {
|
|
326
|
+
try {
|
|
327
|
+
send(res, 500, 'text/plain; charset=utf-8', 'internal error');
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
/* the socket is gone; nothing to report to */
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
// The watchdog. `unref` so it is never the reason the process stays alive —
|
|
335
|
+
// a timer that keeps a server up in order to decide whether to shut it down
|
|
336
|
+
// would be its own bug.
|
|
337
|
+
const watchdog = setInterval(() => {
|
|
338
|
+
if (opts.keepAlive)
|
|
339
|
+
return;
|
|
340
|
+
const now = Date.now();
|
|
341
|
+
const gone = (byeAt !== 0 && now - byeAt > BYE_DELAY_MS) ||
|
|
342
|
+
(lastSeen !== 0 && now - lastSeen > HEARTBEAT_IDLE_MS) ||
|
|
343
|
+
(lastSeen === 0 && now - startedAt > HEARTBEAT_GRACE_MS);
|
|
344
|
+
if (gone) {
|
|
345
|
+
clearInterval(watchdog);
|
|
346
|
+
idleHandler?.();
|
|
347
|
+
}
|
|
348
|
+
}, 5000);
|
|
349
|
+
watchdog.unref();
|
|
350
|
+
await new Promise((resolve, reject) => {
|
|
351
|
+
server.once('error', reject);
|
|
352
|
+
// 127.0.0.1, explicitly and always. `localhost` can resolve to a non-loopback
|
|
353
|
+
// interface on a misconfigured host, and `0.0.0.0` would publish the console.
|
|
354
|
+
server.listen(opts.port ?? 0, '127.0.0.1', resolve);
|
|
355
|
+
});
|
|
356
|
+
const addr = server.address();
|
|
357
|
+
const port = typeof addr === 'object' && addr ? addr.port : opts.port;
|
|
358
|
+
const url = `http://127.0.0.1:${port}/?t=${token}`;
|
|
359
|
+
return {
|
|
360
|
+
url,
|
|
361
|
+
close: () => {
|
|
362
|
+
clearInterval(watchdog);
|
|
363
|
+
server.close();
|
|
364
|
+
},
|
|
365
|
+
onIdle: (fn) => {
|
|
366
|
+
idleHandler = fn;
|
|
367
|
+
},
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
async function handle(req, res, token, onBye) {
|
|
371
|
+
if (!isLoopbackHost(req.headers.host)) {
|
|
372
|
+
send(res, 403, 'text/plain; charset=utf-8', 'refused: this console answers on loopback only');
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
const url = new URL(req.url ?? '/', 'http://127.0.0.1');
|
|
376
|
+
const given = url.searchParams.get('t') ?? req.headers['x-iaqa-token'] ?? '';
|
|
377
|
+
// Constant-time compare on equal-length buffers; a length mismatch is decided
|
|
378
|
+
// before that and is not a secret worth hiding.
|
|
379
|
+
const ok = given.length === token.length &&
|
|
380
|
+
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(token));
|
|
381
|
+
if (!ok) {
|
|
382
|
+
send(res, 401, 'text/plain; charset=utf-8', 'refused: missing or wrong session token');
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (req.method === 'GET' && url.pathname === '/') {
|
|
386
|
+
send(res, 200, 'text/html; charset=utf-8', (0, page_1.renderConsoleHtml)(token));
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
// "I am still here." Every authenticated request already refreshes the
|
|
390
|
+
// heartbeat; this is the one the open page sends when nothing else is
|
|
391
|
+
// happening. `/api/bye` is its counterpart, fired by the page as it unloads —
|
|
392
|
+
// a reload cancels it simply by arriving before the delay is up.
|
|
393
|
+
if (url.pathname === '/api/ping') {
|
|
394
|
+
send(res, 204, 'text/plain; charset=utf-8', '');
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (url.pathname === '/api/bye') {
|
|
398
|
+
onBye();
|
|
399
|
+
send(res, 204, 'text/plain; charset=utf-8', '');
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (req.method === 'GET' && url.pathname === '/api/state') {
|
|
403
|
+
send(res, 200, 'application/json; charset=utf-8', JSON.stringify(buildState()));
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
// Page screenshots are served as files rather than inlined as data: URIs — the
|
|
407
|
+
// one real advantage the console has over the static report, which has to
|
|
408
|
+
// carry its own bytes. The name is sanitized to a single path segment, so
|
|
409
|
+
// nothing here can address a file outside `_shots/`.
|
|
410
|
+
if (req.method === 'GET' && url.pathname.startsWith('/shot/')) {
|
|
411
|
+
if (activeDir)
|
|
412
|
+
(0, config_1.setBaseDir)(activeDir);
|
|
413
|
+
const raw = decodeURIComponent(url.pathname.slice('/shot/'.length));
|
|
414
|
+
const safe = path.basename(raw).replace(/[^a-zA-Z0-9._-]/g, '-');
|
|
415
|
+
const file = path.join((0, config_1.shotsDir)(), safe.endsWith('.jpg') ? safe : `${safe}.jpg`);
|
|
416
|
+
try {
|
|
417
|
+
send(res, 200, 'image/jpeg', fs.readFileSync(file));
|
|
418
|
+
}
|
|
419
|
+
catch {
|
|
420
|
+
send(res, 404, 'text/plain; charset=utf-8', 'no screenshot for this page');
|
|
421
|
+
}
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
// Switch which project the console is showing. The body names a directory,
|
|
425
|
+
// and `resolveRequestedProject` will only ever hand back one that is already
|
|
426
|
+
// in the registry — so an unknown or crafted path is not "rejected", it is
|
|
427
|
+
// unrepresentable.
|
|
428
|
+
if (req.method === 'POST' && url.pathname === '/api/project') {
|
|
429
|
+
let body;
|
|
430
|
+
try {
|
|
431
|
+
body = JSON.parse(await readBody(req));
|
|
432
|
+
}
|
|
433
|
+
catch {
|
|
434
|
+
send(res, 400, 'application/json', JSON.stringify({ error: 'bad request body' }));
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const dir = (0, registry_1.resolveRequestedProject)(body.dir);
|
|
438
|
+
if (!dir) {
|
|
439
|
+
send(res, 400, 'application/json', JSON.stringify({
|
|
440
|
+
error: 'unknown project — the console can only open folders you have started it in. Run `ia-qa-heal ui` there once.',
|
|
441
|
+
}));
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
setActiveProject(dir);
|
|
445
|
+
// Re-stamp it so the switcher orders by what you actually use.
|
|
446
|
+
let url2;
|
|
447
|
+
try {
|
|
448
|
+
url2 = (0, config_1.loadConfig)().baseUrl;
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
451
|
+
/* a project with a broken config can still be selected and shown as broken */
|
|
452
|
+
}
|
|
453
|
+
(0, registry_1.rememberProject)(dir, url2);
|
|
454
|
+
send(res, 200, 'application/json; charset=utf-8', JSON.stringify(buildState()));
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Add a project to the switcher, from the console itself.
|
|
459
|
+
*
|
|
460
|
+
* The registry started as "opening a console in a folder is the act of
|
|
461
|
+
* consent", which was over-tight measured against the rest of this surface:
|
|
462
|
+
* the same token already authorizes `fix-apply`, which edits the user's test
|
|
463
|
+
* files. The threat this list defends against is a *drive-by* — another page
|
|
464
|
+
* in the browser reaching localhost — and that is stopped by the token and
|
|
465
|
+
* the Host check, not by refusing a deliberate action from the person holding
|
|
466
|
+
* it. Making them go to a terminal to add a project also defeated the point:
|
|
467
|
+
* the console exists for people who do not have one.
|
|
468
|
+
*
|
|
469
|
+
* So consent can also be given here — but it is still consent, not discovery:
|
|
470
|
+
* a path is only accepted if it actually holds `.ia-qa/config.json`, and it is
|
|
471
|
+
* *registered*, which means `ui --forget` can take it back. Nothing scans.
|
|
472
|
+
*/
|
|
473
|
+
if (req.method === 'POST' && url.pathname === '/api/project/add') {
|
|
474
|
+
let body;
|
|
475
|
+
try {
|
|
476
|
+
body = JSON.parse(await readBody(req));
|
|
477
|
+
}
|
|
478
|
+
catch {
|
|
479
|
+
send(res, 400, 'application/json', JSON.stringify({ error: 'bad request body' }));
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const raw = typeof body.dir === 'string' ? body.dir.trim().replace(/^["']|["']$/g, '') : '';
|
|
483
|
+
if (raw === '') {
|
|
484
|
+
send(res, 400, 'application/json', JSON.stringify({ error: 'Give the folder that holds your .ia-qa directory.' }));
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const dir = path.resolve(raw);
|
|
488
|
+
if (!(0, registry_1.isProjectDir)(dir)) {
|
|
489
|
+
send(res, 400, 'application/json', JSON.stringify({
|
|
490
|
+
error: `No .ia-qa/config.json in ${dir}\n\n` +
|
|
491
|
+
`Pick the project's top folder — the one you would open in your editor, ` +
|
|
492
|
+
`not the .ia-qa folder itself. If that project has never been set up, run ` +
|
|
493
|
+
`\`ia-qa-heal init\` in it first.`,
|
|
494
|
+
}));
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
setActiveProject(dir);
|
|
498
|
+
let addedUrl;
|
|
499
|
+
try {
|
|
500
|
+
addedUrl = (0, config_1.loadConfig)().baseUrl;
|
|
501
|
+
}
|
|
502
|
+
catch {
|
|
503
|
+
/* a project whose config will not parse can still be selected, and shown as broken */
|
|
504
|
+
}
|
|
505
|
+
(0, registry_1.rememberProject)(dir, addedUrl);
|
|
506
|
+
send(res, 200, 'application/json; charset=utf-8', JSON.stringify(buildState()));
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (req.method === 'POST' && url.pathname === '/api/run') {
|
|
510
|
+
let body;
|
|
511
|
+
try {
|
|
512
|
+
body = JSON.parse(await readBody(req));
|
|
513
|
+
}
|
|
514
|
+
catch {
|
|
515
|
+
send(res, 400, 'application/json', JSON.stringify({ error: 'bad request body' }));
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const action = ACTIONS[String(body.action ?? '')];
|
|
519
|
+
if (!action) {
|
|
520
|
+
send(res, 400, 'application/json', JSON.stringify({ error: 'unknown action' }));
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
// The active project is passed explicitly, never inherited: the child must
|
|
524
|
+
// act on the project the user is looking at, and a global the parent
|
|
525
|
+
// happens to hold is not a promise about a process it spawns.
|
|
526
|
+
const result = await runCli([...action.argv, '--config', getActiveProject()]);
|
|
527
|
+
const read = interpret(result.output, result.code);
|
|
528
|
+
send(res, 200, 'application/json; charset=utf-8', JSON.stringify({ ...result, ...read, means: action.means }));
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
send(res, 404, 'text/plain; charset=utf-8', 'not found');
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Run one of this package's own verbs and return what it printed.
|
|
535
|
+
*
|
|
536
|
+
* `argv` comes from the allowlist above and never from the request, so there is
|
|
537
|
+
* no shell and no user-controlled argument: `spawn` is called with an argument
|
|
538
|
+
* array and `shell:false`. The console's authority is exactly the CLI's.
|
|
539
|
+
*/
|
|
540
|
+
/**
|
|
541
|
+
* Turn a finished command into something a manual QA can act on.
|
|
542
|
+
*
|
|
543
|
+
* Every verb signs off with one deliberately stable line —
|
|
544
|
+
* `<icon> ia-qa-heal <verb> — <headline> · <count> · <count>` — which exists so a
|
|
545
|
+
* CI log stays greppable. It is also the only sentence in the output already
|
|
546
|
+
* written for a person, so the console reads *that* rather than re-deriving a
|
|
547
|
+
* meaning from the exit code. An exit code is a fact about a process; "2" tells
|
|
548
|
+
* a human nothing, and "0" is actively misleading here (a FIX verdict exits 0).
|
|
549
|
+
*
|
|
550
|
+
* When no summary line is found the command did not get far enough to have an
|
|
551
|
+
* opinion, and saying so is better than inventing one.
|
|
552
|
+
*/
|
|
553
|
+
// The verb can carry flags — `ia-qa-heal fix --dir — …` — so the middle is
|
|
554
|
+
// lazy rather than a single token. Anchored on the em dash, which is the
|
|
555
|
+
// separator `summaryLine` guarantees.
|
|
556
|
+
const SUMMARY_RE = /^(\S+)\s+ia-qa-heal\s+(.+?)\s+—\s+(.+)$/u;
|
|
557
|
+
const TONE_BY_ICON = {
|
|
558
|
+
'✅': 'ok',
|
|
559
|
+
'🔧': 'fix',
|
|
560
|
+
'⛔': 'block',
|
|
561
|
+
'ℹ️': 'info',
|
|
562
|
+
'ℹ': 'info',
|
|
563
|
+
'⚠️': 'warn',
|
|
564
|
+
'⚠': 'warn',
|
|
565
|
+
};
|
|
566
|
+
function interpret(output, code) {
|
|
567
|
+
const lines = output.split('\n').map((l) => l.trim()).filter(Boolean);
|
|
568
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
569
|
+
const m = SUMMARY_RE.exec(lines[i]);
|
|
570
|
+
if (m)
|
|
571
|
+
return { tone: TONE_BY_ICON[m[1]] ?? 'info', headline: m[3] };
|
|
572
|
+
}
|
|
573
|
+
// No receipt: the verb refused before doing anything (no baseline yet, nothing
|
|
574
|
+
// to compare, no config). Those refusals are written as a headline line
|
|
575
|
+
// starting with ❌/⛔/⚠️ followed by an indented explanation, so the FIRST
|
|
576
|
+
// such line is the sentence — taking the last one hands back the tail of a
|
|
577
|
+
// wrapped paragraph ("a baseline against."), which is worse than saying
|
|
578
|
+
// nothing.
|
|
579
|
+
const headline = lines.find((l) => /^[❌⛔⚠]/u.test(l)) ?? lines[0] ?? '';
|
|
580
|
+
return {
|
|
581
|
+
tone: code === 0 ? 'info' : 'stopped',
|
|
582
|
+
headline: headline.replace(/^[❌⚠️⛔✅ℹ️🔧️\s]+/u, '').trim() ||
|
|
583
|
+
'It stopped without saying why — the detail below is all it printed.',
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
function runCli(argv) {
|
|
587
|
+
return new Promise((resolve) => {
|
|
588
|
+
const child = (0, child_process_1.spawn)(process.execPath, [cliEntry(), ...argv], {
|
|
589
|
+
shell: false,
|
|
590
|
+
env: { ...process.env, FORCE_COLOR: '0', CI: '1' },
|
|
591
|
+
});
|
|
592
|
+
let out = '';
|
|
593
|
+
const cap = (chunk) => {
|
|
594
|
+
out += chunk.toString();
|
|
595
|
+
if (out.length > 512 * 1024)
|
|
596
|
+
out = out.slice(-512 * 1024);
|
|
597
|
+
};
|
|
598
|
+
child.stdout.on('data', cap);
|
|
599
|
+
child.stderr.on('data', cap);
|
|
600
|
+
child.on('close', (code) => resolve({ code: code ?? 1, output: out }));
|
|
601
|
+
child.on('error', (e) => resolve({ code: 1, output: String(e) }));
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/ui/server.ts"],"names":[],"mappings":"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"}
|