@jevitate/cli 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.
- package/LICENSE +21 -0
- package/dist/ai-cli.d.ts +31 -0
- package/dist/ai-cli.js +238 -0
- package/dist/ai-cli.js.map +1 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +50663 -0
- package/dist/bin.js.map +1 -0
- package/dist/data-dir.d.ts +9 -0
- package/dist/data-dir.js +13 -0
- package/dist/data-dir.js.map +1 -0
- package/dist/envelope.d.ts +11 -0
- package/dist/envelope.js +7 -0
- package/dist/envelope.js.map +1 -0
- package/dist/explore-api.d.ts +187 -0
- package/dist/explore-api.js +302 -0
- package/dist/explore-api.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/init-keys.d.ts +14 -0
- package/dist/init-keys.js +18 -0
- package/dist/init-keys.js.map +1 -0
- package/dist/init-mcp.d.ts +87 -0
- package/dist/init-mcp.js +198 -0
- package/dist/init-mcp.js.map +1 -0
- package/dist/init-skills.d.ts +80 -0
- package/dist/init-skills.js +256 -0
- package/dist/init-skills.js.map +1 -0
- package/dist/journey-api.d.ts +37 -0
- package/dist/journey-api.js +55 -0
- package/dist/journey-api.js.map +1 -0
- package/dist/load-api.d.ts +48 -0
- package/dist/load-api.js +84 -0
- package/dist/load-api.js.map +1 -0
- package/dist/mcp-api.d.ts +116 -0
- package/dist/mcp-api.js +359 -0
- package/dist/mcp-api.js.map +1 -0
- package/dist/mission-api.d.ts +56 -0
- package/dist/mission-api.js +65 -0
- package/dist/mission-api.js.map +1 -0
- package/dist/program.d.ts +77 -0
- package/dist/program.js +1938 -0
- package/dist/program.js.map +1 -0
- package/dist/record-api.d.ts +74 -0
- package/dist/record-api.js +93 -0
- package/dist/record-api.js.map +1 -0
- package/dist/regression-api.d.ts +17 -0
- package/dist/regression-api.js +16 -0
- package/dist/regression-api.js.map +1 -0
- package/dist/self-heal-adapter.d.ts +31 -0
- package/dist/self-heal-adapter.js +70 -0
- package/dist/self-heal-adapter.js.map +1 -0
- package/dist/source-api.d.ts +147 -0
- package/dist/source-api.js +208 -0
- package/dist/source-api.js.map +1 -0
- package/dist/source-run-api.d.ts +57 -0
- package/dist/source-run-api.js +91 -0
- package/dist/source-run-api.js.map +1 -0
- package/dist/ui-api.d.ts +35 -0
- package/dist/ui-api.js +369 -0
- package/dist/ui-api.js.map +1 -0
- package/dist/ux-api.d.ts +75 -0
- package/dist/ux-api.js +231 -0
- package/dist/ux-api.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +37 -0
- package/dist/version.js.map +1 -0
- package/package.json +85 -0
- package/skills/jevitate-explore/SKILL.md +108 -0
- package/skills/jevitate-load-test/SKILL.md +42 -0
- package/skills/jevitate-mission-scope/SKILL.md +107 -0
- package/skills/jevitate-record/SKILL.md +78 -0
- package/skills/jevitate-run-journey/SKILL.md +72 -0
- package/skills/jevitate-sources/SKILL.md +88 -0
- package/skills/jevitate-ux-review/SKILL.md +68 -0
- package/ui/app.js +538 -0
- package/ui/index.html +546 -0
package/dist/ui-api.js
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
import { readFile, realpath } from "node:fs/promises";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { join, sep } from "node:path";
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { FsInboxStore, InboxItemNotFoundError, InboxItemAlreadyResolvedError, IllegalTransitionError, SAFE_INBOX_ID_RE, } from "@jevitate/inbox";
|
|
8
|
+
const DEFAULT_PORT = 4180;
|
|
9
|
+
const MAX_PORT_ATTEMPTS = 20;
|
|
10
|
+
const MAX_BODY_BYTES = 1_000_000; // 1 MB cap — plenty for a human-typed input string.
|
|
11
|
+
const TOKEN_COOKIE = "jevitate_ui_token";
|
|
12
|
+
const SWEEP_INTERVAL_MS = 60_000;
|
|
13
|
+
const RESOLVE_ACTIONS = new Set(["approve", "reject", "resume"]);
|
|
14
|
+
function isPlainObject(value) {
|
|
15
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16
|
+
}
|
|
17
|
+
function isAddrInUse(err) {
|
|
18
|
+
return typeof err === "object" && err !== null && "code" in err && err.code === "EADDRINUSE";
|
|
19
|
+
}
|
|
20
|
+
function parseCookies(header) {
|
|
21
|
+
const out = {};
|
|
22
|
+
if (!header)
|
|
23
|
+
return out;
|
|
24
|
+
for (const part of header.split(";")) {
|
|
25
|
+
const idx = part.indexOf("=");
|
|
26
|
+
if (idx === -1)
|
|
27
|
+
continue;
|
|
28
|
+
const key = part.slice(0, idx).trim();
|
|
29
|
+
const value = part.slice(idx + 1).trim();
|
|
30
|
+
if (key)
|
|
31
|
+
out[key] = decodeURIComponent(value);
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/** Reads the request body up to `limit` bytes and JSON-parses it. An empty
|
|
36
|
+
* body parses to `undefined` (not an error — some actions take no body).
|
|
37
|
+
* Over-limit or malformed JSON both resolve `{ ok: false }`; the caller
|
|
38
|
+
* maps that to 400, never throws it up as an unhandled rejection. */
|
|
39
|
+
function readJsonBody(req, limit = MAX_BODY_BYTES) {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
let total = 0;
|
|
42
|
+
const chunks = [];
|
|
43
|
+
let settled = false;
|
|
44
|
+
const finish = (result) => {
|
|
45
|
+
if (settled)
|
|
46
|
+
return;
|
|
47
|
+
settled = true;
|
|
48
|
+
resolve(result);
|
|
49
|
+
};
|
|
50
|
+
req.on("data", (chunk) => {
|
|
51
|
+
total += chunk.length;
|
|
52
|
+
if (total > limit) {
|
|
53
|
+
finish({ ok: false });
|
|
54
|
+
req.destroy();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
chunks.push(chunk);
|
|
58
|
+
});
|
|
59
|
+
req.on("end", () => {
|
|
60
|
+
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
61
|
+
if (raw.length === 0) {
|
|
62
|
+
finish({ ok: true, data: undefined });
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
finish({ ok: true, data: JSON.parse(raw) });
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
finish({ ok: false });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
req.on("error", () => finish({ ok: false }));
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function listenOnce(server, host, port) {
|
|
76
|
+
return new Promise((resolve, reject) => {
|
|
77
|
+
const onError = (err) => {
|
|
78
|
+
server.removeListener("listening", onListening);
|
|
79
|
+
reject(err);
|
|
80
|
+
};
|
|
81
|
+
const onListening = () => {
|
|
82
|
+
server.removeListener("error", onError);
|
|
83
|
+
resolve();
|
|
84
|
+
};
|
|
85
|
+
server.once("error", onError);
|
|
86
|
+
server.once("listening", onListening);
|
|
87
|
+
server.listen(port, host);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/** Fire-and-forget browser open (S-D). A failed spawn (missing `xdg-open`
|
|
91
|
+
* under WSL, etc.) is swallowed — it must NEVER reject `startUiServer` or
|
|
92
|
+
* throw an unhandled rejection. */
|
|
93
|
+
function openInBrowser(url) {
|
|
94
|
+
try {
|
|
95
|
+
const platform = process.platform;
|
|
96
|
+
let cmd;
|
|
97
|
+
let args;
|
|
98
|
+
if (platform === "darwin") {
|
|
99
|
+
cmd = "open";
|
|
100
|
+
args = [url];
|
|
101
|
+
}
|
|
102
|
+
else if (platform === "win32") {
|
|
103
|
+
cmd = "cmd";
|
|
104
|
+
args = ["/c", "start", "", url];
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
cmd = "xdg-open";
|
|
108
|
+
args = [url];
|
|
109
|
+
}
|
|
110
|
+
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
111
|
+
child.on("error", () => {
|
|
112
|
+
// swallow — a failed opener must never surface (S-D)
|
|
113
|
+
});
|
|
114
|
+
child.unref();
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// swallow — same guarantee, for a synchronous spawn failure
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export async function startUiServer(deps) {
|
|
121
|
+
const store = new FsInboxStore(deps.inboxDir);
|
|
122
|
+
const token = randomBytes(32).toString("hex");
|
|
123
|
+
const logger = deps.logger ?? (() => { });
|
|
124
|
+
const shouldOpen = deps.open ?? true;
|
|
125
|
+
// Sibling of dist/ — same convention build.mjs uses for `skills`. NOT
|
|
126
|
+
// copied into dist; `ui/` ships via package.json "files" (Task 10).
|
|
127
|
+
const indexHtmlPath = fileURLToPath(new URL("../ui/index.html", import.meta.url));
|
|
128
|
+
const appJsPath = fileURLToPath(new URL("../ui/app.js", import.meta.url));
|
|
129
|
+
const screenshotsDir = join(deps.inboxDir, "screenshots");
|
|
130
|
+
const server = createServer();
|
|
131
|
+
let boundPort = 0;
|
|
132
|
+
function send(res, status, body, headers = {}) {
|
|
133
|
+
const payload = body === undefined ? undefined : JSON.stringify(body);
|
|
134
|
+
res.writeHead(status, { "Content-Type": "application/json", ...headers });
|
|
135
|
+
res.end(payload);
|
|
136
|
+
return status;
|
|
137
|
+
}
|
|
138
|
+
async function serveIndex(req, res) {
|
|
139
|
+
const reqUrl = new URL(req.url ?? "/", `http://127.0.0.1:${boundPort}`);
|
|
140
|
+
const t = reqUrl.searchParams.get("t");
|
|
141
|
+
const html = await readFile(indexHtmlPath, "utf8");
|
|
142
|
+
const headers = {
|
|
143
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
144
|
+
"Content-Security-Policy": "default-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'",
|
|
145
|
+
};
|
|
146
|
+
if (t) {
|
|
147
|
+
headers["Set-Cookie"] = `${TOKEN_COOKIE}=${encodeURIComponent(t)}; Path=/; HttpOnly; SameSite=Strict`;
|
|
148
|
+
}
|
|
149
|
+
res.writeHead(200, headers);
|
|
150
|
+
res.end(html);
|
|
151
|
+
return 200;
|
|
152
|
+
}
|
|
153
|
+
async function serveAppJs(res) {
|
|
154
|
+
const js = await readFile(appJsPath, "utf8");
|
|
155
|
+
res.writeHead(200, { "Content-Type": "text/javascript" });
|
|
156
|
+
res.end(js);
|
|
157
|
+
return 200;
|
|
158
|
+
}
|
|
159
|
+
/** `<inboxDir>/screenshots/<id>.png` only — never built from any item
|
|
160
|
+
* field, only from the URL id. Rejects an unsafe id BEFORE touching the
|
|
161
|
+
* filesystem, then re-checks the RESOLVED realpath is inside the
|
|
162
|
+
* screenshots dir via a trailing-separator prefix check (N-c). */
|
|
163
|
+
async function serveScreenshot(id, res) {
|
|
164
|
+
if (!SAFE_INBOX_ID_RE.test(id))
|
|
165
|
+
return send(res, 404, { error: "not_found" });
|
|
166
|
+
let resolvedDir;
|
|
167
|
+
try {
|
|
168
|
+
resolvedDir = await realpath(screenshotsDir);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return send(res, 404, { error: "not_found" });
|
|
172
|
+
}
|
|
173
|
+
const candidate = join(screenshotsDir, `${id}.png`);
|
|
174
|
+
let resolved;
|
|
175
|
+
try {
|
|
176
|
+
resolved = await realpath(candidate);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return send(res, 404, { error: "not_found" });
|
|
180
|
+
}
|
|
181
|
+
if (!(resolved === resolvedDir || resolved.startsWith(resolvedDir + sep))) {
|
|
182
|
+
return send(res, 404, { error: "not_found" });
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
const data = await readFile(resolved);
|
|
186
|
+
res.writeHead(200, { "Content-Type": "image/png" });
|
|
187
|
+
res.end(data);
|
|
188
|
+
return 200;
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
return send(res, 404, { error: "not_found" });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function handleAction(id, action, req, res) {
|
|
195
|
+
if (!SAFE_INBOX_ID_RE.test(id))
|
|
196
|
+
return send(res, 400, { error: "invalid_id" });
|
|
197
|
+
const bodyResult = await readJsonBody(req);
|
|
198
|
+
if (!bodyResult.ok)
|
|
199
|
+
return send(res, 400, { error: "invalid_body" });
|
|
200
|
+
const body = isPlainObject(bodyResult.data) ? bodyResult.data : {};
|
|
201
|
+
const input = typeof body.input === "string" ? body.input : undefined;
|
|
202
|
+
try {
|
|
203
|
+
let item;
|
|
204
|
+
if (action === "input") {
|
|
205
|
+
if (input === undefined)
|
|
206
|
+
return send(res, 400, { error: "invalid_body", message: "'input' must be a string" });
|
|
207
|
+
item = await store.appendThread(id, { author: "human", text: input, at: new Date().toISOString() });
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
const resolveAction = action;
|
|
211
|
+
item = await store.resolve(id, {
|
|
212
|
+
channel: "human",
|
|
213
|
+
action: resolveAction,
|
|
214
|
+
...(input !== undefined ? { input } : {}),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return send(res, 200, item);
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
if (err instanceof InboxItemNotFoundError)
|
|
221
|
+
return send(res, 404, { error: "not_found" });
|
|
222
|
+
if (err instanceof InboxItemAlreadyResolvedError)
|
|
223
|
+
return send(res, 409, { error: "already_resolved" });
|
|
224
|
+
if (err instanceof IllegalTransitionError)
|
|
225
|
+
return send(res, 409, { error: "illegal_transition" });
|
|
226
|
+
return send(res, 500, { error: "internal" });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
async function route(req, res, pathname) {
|
|
230
|
+
// (1) Host-header check — every path, before anything else.
|
|
231
|
+
const host = req.headers.host;
|
|
232
|
+
if (host !== `127.0.0.1:${boundPort}` && host !== `localhost:${boundPort}`) {
|
|
233
|
+
return send(res, 403, { error: "forbidden_host" });
|
|
234
|
+
}
|
|
235
|
+
// Defense-in-depth (fix for the token-gate bypass, security review round
|
|
236
|
+
// 1): reject any RAW pathname carrying an encoded path separator before
|
|
237
|
+
// it is ever decoded — an id/segment must never be able to smuggle a
|
|
238
|
+
// `/` or `\` past `decodeURIComponent` and confuse segment matching.
|
|
239
|
+
if (/%2f|%5c/i.test(pathname)) {
|
|
240
|
+
return send(res, 400, { error: "invalid_path" });
|
|
241
|
+
}
|
|
242
|
+
// Single source of truth: the gate and the router MUST parse the path
|
|
243
|
+
// IDENTICALLY, or a request can be shaped (`/%61pi/inbox`, `//api/inbox`,
|
|
244
|
+
// ...) so the token gate reads `isApi === false` while the router still
|
|
245
|
+
// matches an /api handler — the exact capability-token bypass fixed here.
|
|
246
|
+
// `segments` is computed ONCE, decoded, and used for BOTH the token gate
|
|
247
|
+
// and routing below.
|
|
248
|
+
const method = req.method ?? "GET";
|
|
249
|
+
const segments = pathname.split("/").filter(Boolean).map((s) => decodeURIComponent(s));
|
|
250
|
+
// (2) Capability-token check — every /api/* path, derived from the SAME
|
|
251
|
+
// decoded `segments` the router uses.
|
|
252
|
+
const isApi = segments[0] === "api";
|
|
253
|
+
if (isApi) {
|
|
254
|
+
const headerTokenRaw = req.headers["x-jevitate-token"];
|
|
255
|
+
const headerToken = Array.isArray(headerTokenRaw) ? headerTokenRaw[0] : headerTokenRaw;
|
|
256
|
+
const cookieToken = parseCookies(req.headers.cookie)[TOKEN_COOKIE];
|
|
257
|
+
// An empty-string header must be treated as ABSENT, not as "supplied
|
|
258
|
+
// the empty string" — `headerToken ?? cookieToken` only falls through
|
|
259
|
+
// to the cookie on `undefined`/`null`, so a client that sends
|
|
260
|
+
// `x-jevitate-token: ""` (e.g. after its in-memory token was cleared
|
|
261
|
+
// on a reload) would otherwise mask a perfectly valid auth cookie and
|
|
262
|
+
// 401 every request. This does NOT weaken the actual check below —
|
|
263
|
+
// `supplied` still must equal `token` exactly.
|
|
264
|
+
const supplied = typeof headerToken === "string" && headerToken.length > 0 ? headerToken : cookieToken;
|
|
265
|
+
if (supplied !== token)
|
|
266
|
+
return send(res, 401, { error: "unauthorized" });
|
|
267
|
+
}
|
|
268
|
+
// (3) Route.
|
|
269
|
+
if (method === "GET" && segments.length === 0)
|
|
270
|
+
return serveIndex(req, res);
|
|
271
|
+
if (method === "GET" && segments.length === 1 && segments[0] === "app.js")
|
|
272
|
+
return serveAppJs(res);
|
|
273
|
+
if (method === "GET" && segments.length === 2 && segments[0] === "api" && segments[1] === "inbox") {
|
|
274
|
+
const items = await store.getSummaries();
|
|
275
|
+
return send(res, 200, { items });
|
|
276
|
+
}
|
|
277
|
+
if (method === "GET" && segments.length === 2 && segments[0] === "api" && segments[1] === "health") {
|
|
278
|
+
const health = await store.health();
|
|
279
|
+
return send(res, 200, health);
|
|
280
|
+
}
|
|
281
|
+
if (segments.length === 3 && segments[0] === "api" && segments[1] === "inbox") {
|
|
282
|
+
const id = segments[2];
|
|
283
|
+
if (method === "GET") {
|
|
284
|
+
if (!SAFE_INBOX_ID_RE.test(id))
|
|
285
|
+
return send(res, 404, { error: "not_found" });
|
|
286
|
+
const item = await store.get(id);
|
|
287
|
+
if (!item)
|
|
288
|
+
return send(res, 404, { error: "not_found" });
|
|
289
|
+
return send(res, 200, item);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (segments.length === 4 && segments[0] === "api" && segments[1] === "inbox") {
|
|
293
|
+
const id = segments[2];
|
|
294
|
+
const sub = segments[3];
|
|
295
|
+
if (method === "GET" && sub === "screenshot")
|
|
296
|
+
return serveScreenshot(id, res);
|
|
297
|
+
if (method === "POST" && (RESOLVE_ACTIONS.has(sub) || sub === "input")) {
|
|
298
|
+
return handleAction(id, sub, req, res);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return send(res, 404, { error: "not_found" });
|
|
302
|
+
}
|
|
303
|
+
async function handleRequest(req, res) {
|
|
304
|
+
const pathname = new URL(req.url ?? "/", `http://127.0.0.1:${boundPort}`).pathname;
|
|
305
|
+
let status = 500;
|
|
306
|
+
try {
|
|
307
|
+
status = await route(req, res, pathname);
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
status = res.headersSent ? res.statusCode : send(res, 500, { error: "internal" });
|
|
311
|
+
}
|
|
312
|
+
finally {
|
|
313
|
+
// NEVER log req.url (carries `?t=<token>`) or the body/query string —
|
|
314
|
+
// only the derived pathname + status (S-C/N4).
|
|
315
|
+
logger(`${req.method ?? "GET"} ${pathname} ${status}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
server.on("request", (req, res) => {
|
|
319
|
+
void handleRequest(req, res);
|
|
320
|
+
});
|
|
321
|
+
async function bind() {
|
|
322
|
+
if (deps.port !== undefined) {
|
|
323
|
+
try {
|
|
324
|
+
await listenOnce(server, "127.0.0.1", deps.port);
|
|
325
|
+
}
|
|
326
|
+
catch (err) {
|
|
327
|
+
if (isAddrInUse(err)) {
|
|
328
|
+
throw new Error(`jevitate ui: port ${deps.port} is already in use`);
|
|
329
|
+
}
|
|
330
|
+
throw err;
|
|
331
|
+
}
|
|
332
|
+
return deps.port;
|
|
333
|
+
}
|
|
334
|
+
let port = DEFAULT_PORT;
|
|
335
|
+
for (let attempt = 0; attempt < MAX_PORT_ATTEMPTS; attempt++) {
|
|
336
|
+
try {
|
|
337
|
+
await listenOnce(server, "127.0.0.1", port);
|
|
338
|
+
return port;
|
|
339
|
+
}
|
|
340
|
+
catch (err) {
|
|
341
|
+
if (isAddrInUse(err) && attempt < MAX_PORT_ATTEMPTS - 1) {
|
|
342
|
+
port++;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
throw err;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
/* istanbul ignore next -- unreachable: loop always returns or throws */
|
|
349
|
+
throw new Error("jevitate ui: failed to bind after 20 attempts");
|
|
350
|
+
}
|
|
351
|
+
boundPort = await bind();
|
|
352
|
+
const sweepTimer = setInterval(() => {
|
|
353
|
+
void store.sweepExpired().catch(() => {
|
|
354
|
+
// best-effort background sweep; a failure here must not crash the server
|
|
355
|
+
});
|
|
356
|
+
}, SWEEP_INTERVAL_MS);
|
|
357
|
+
sweepTimer.unref();
|
|
358
|
+
const url = `http://127.0.0.1:${boundPort}/?t=${token}`;
|
|
359
|
+
if (shouldOpen)
|
|
360
|
+
openInBrowser(url);
|
|
361
|
+
async function close() {
|
|
362
|
+
clearInterval(sweepTimer);
|
|
363
|
+
await new Promise((resolve, reject) => {
|
|
364
|
+
server.close((err) => (err ? reject(err) : resolve()));
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return { url, token, port: boundPort, close };
|
|
368
|
+
}
|
|
369
|
+
//# sourceMappingURL=ui-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-api.js","sourceRoot":"","sources":["../src/ui-api.ts"],"names":[],"mappings":"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"}
|
package/dist/ux-api.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { JudgmentPort, GenerationPort } from "@jevitate/ai-core";
|
|
2
|
+
import { type BrowserPort } from "@jevitate/playwright";
|
|
3
|
+
import type { Recording } from "@jevitate/recording";
|
|
4
|
+
import { type Snapshot, type Bounds } from "@jevitate/explore";
|
|
5
|
+
import { type AppContext, type ScreenRef, type UxEvidence, type UxReport } from "@jevitate/ux";
|
|
6
|
+
/** A live Snapshot (+ extracted page text) → one screen's UxEvidence. */
|
|
7
|
+
export declare function snapshotToEvidence(snap: Snapshot, visibleText: string, appContext: AppContext, job: string | undefined, history: readonly ScreenRef[]): UxEvidence;
|
|
8
|
+
/**
|
|
9
|
+
* A saved Recording → per-page UxEvidence. A Recording is deterministic and
|
|
10
|
+
* thin: it carries the CONTROLS the user touched (via each step's descriptor)
|
|
11
|
+
* and the page url, but NOT the full visible text or a11y geometry. So offline
|
|
12
|
+
* analysis is honestly partial — items needing `visibleText`/`a11yFacts` Skip,
|
|
13
|
+
* and coverage reports it. (The live mode carries the rich per-screen snapshot.)
|
|
14
|
+
*/
|
|
15
|
+
export declare function recordingToEvidence(recording: Recording, appContext: AppContext, job?: string): UxEvidence[];
|
|
16
|
+
export interface RunUxReviewOptions {
|
|
17
|
+
readonly recording: Recording;
|
|
18
|
+
readonly appContext: AppContext;
|
|
19
|
+
readonly judge: JudgmentPort;
|
|
20
|
+
readonly secrets?: readonly string[];
|
|
21
|
+
readonly judgmentBudget?: number;
|
|
22
|
+
/** Where to write the report. Default `~/.jevitate/ux-reports`. */
|
|
23
|
+
readonly outDir?: string;
|
|
24
|
+
readonly nowIso?: () => string;
|
|
25
|
+
}
|
|
26
|
+
export interface RunUxReviewResult {
|
|
27
|
+
readonly report: UxReport;
|
|
28
|
+
readonly reportPath: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Offline UX review. FAIL-FAST: an analyzer `failed` outcome throws
|
|
32
|
+
* `UxAnalysisFailedError` (the CLI maps it to a non-zero fail envelope) — never
|
|
33
|
+
* a fabricated "clean" report.
|
|
34
|
+
*/
|
|
35
|
+
export declare function runUxReview(opts: RunUxReviewOptions): Promise<RunUxReviewResult>;
|
|
36
|
+
export declare class UxAnalysisFailedError extends Error {
|
|
37
|
+
readonly screenId?: string | undefined;
|
|
38
|
+
readonly rubricItemId?: string | undefined;
|
|
39
|
+
readonly code: "E_UX_ANALYSIS";
|
|
40
|
+
constructor(reason: string, screenId?: string | undefined, rubricItemId?: string | undefined);
|
|
41
|
+
}
|
|
42
|
+
export interface RunUsabilityMissionOptions {
|
|
43
|
+
readonly url: string;
|
|
44
|
+
readonly job: string;
|
|
45
|
+
readonly allowlist: readonly string[];
|
|
46
|
+
readonly appContext: AppContext;
|
|
47
|
+
readonly judge: JudgmentPort;
|
|
48
|
+
readonly gen: GenerationPort;
|
|
49
|
+
readonly bounds?: Partial<Bounds>;
|
|
50
|
+
readonly secrets?: readonly string[];
|
|
51
|
+
readonly judgmentBudget?: number;
|
|
52
|
+
readonly outDir?: string;
|
|
53
|
+
readonly browserPortFactory?: () => BrowserPort;
|
|
54
|
+
readonly nowIso?: () => string;
|
|
55
|
+
/** Test seam: extract a page's visible text. Default reads the live page. */
|
|
56
|
+
readonly extractText?: (session: {
|
|
57
|
+
page: {
|
|
58
|
+
evaluate: (fn: () => string) => Promise<string>;
|
|
59
|
+
};
|
|
60
|
+
}) => Promise<string>;
|
|
61
|
+
}
|
|
62
|
+
export interface RunUsabilityMissionResult {
|
|
63
|
+
readonly report: UxReport;
|
|
64
|
+
readonly reportPath: string;
|
|
65
|
+
readonly stop: string;
|
|
66
|
+
readonly screensObserved: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Live usability mission. Guardrail #1 authorizes BEFORE opening a browser.
|
|
70
|
+
* Reuses explore()'s loop (goal = the job) and, via the additive onSnapshot
|
|
71
|
+
* hook, collects one screen's evidence per observation — then analyzes ONCE
|
|
72
|
+
* after the run. A UX finding NEVER gates the loop (the hook's result is
|
|
73
|
+
* ignored by explore). The temp profile dir is always removed.
|
|
74
|
+
*/
|
|
75
|
+
export declare function runUsabilityMission(opts: RunUsabilityMissionOptions): Promise<RunUsabilityMissionResult>;
|