@aayambansal/squint 0.4.5 → 0.4.6
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 +3 -0
- package/dist/{cdp-Q4H6ZHPT.js → cdp-OYRHOPVP.js} +1 -1
- package/dist/{chunk-ZLEP2TWF.js → chunk-ARDV4XH6.js} +5 -1
- package/dist/{chunk-CV5WVKHU.js → chunk-D7Q3M6PA.js} +54 -14
- package/dist/{chunk-RQHOE5MV.js → chunk-X2RZJT4L.js} +44 -2
- package/dist/cli.js +28 -13
- package/dist/{contextDoctor-U3YTDFVG.js → contextDoctor-A26C2ZDN.js} +1 -1
- package/dist/{preview-ZUCVWGZG.js → preview-XREFPMHX.js} +2 -2
- package/dist/{skills-6NZP67QT.js → skills-POB4ZZY5.js} +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -174,6 +174,9 @@ squint doctor --probe # run every engine end to end, verify auth act
|
|
|
174
174
|
flagged from the live page, and on Next 16+ the framework's own `/_next/mcp`
|
|
175
175
|
channel feeds structured errors straight into the fix loop. `/context` itemizes
|
|
176
176
|
the injected-context bill per source, with staleness warnings.
|
|
177
|
+
- **Persistent checks**: assertions the engine verifies once persist as
|
|
178
|
+
`.squint/checks/*.js` and replay against the live page every turn — one-off
|
|
179
|
+
verifications compound into repo-versioned regression checks.
|
|
177
180
|
- **Visual approval**: engines ask before contested changes — the request renders
|
|
178
181
|
with its screenshot, `/yes` / `/no` answer it, the ledger remembers.
|
|
179
182
|
- **The design ledger**: `/decide` (plus chosen variants, rollbacks, accepted
|
|
@@ -159,7 +159,11 @@ If the task appears to require changing them, stop and explain instead.`
|
|
|
159
159
|
parts.push(
|
|
160
160
|
`## Requesting visual approval
|
|
161
161
|
|
|
162
|
-
For a visual decision you should not make alone (a redesign direction, removing something deliberate, reversing a design decision on record): write .squint/approval-request.json containing {"summary": "<one line>", "screenshot": "<path, optional>"} and end your turn immediately without making the change. The user's verdict arrives as the next message
|
|
162
|
+
For a visual decision you should not make alone (a redesign direction, removing something deliberate, reversing a design decision on record): write .squint/approval-request.json containing {"summary": "<one line>", "screenshot": "<path, optional>"} and end your turn immediately without making the change. The user's verdict arrives as the next message.
|
|
163
|
+
|
|
164
|
+
## Persistent checks
|
|
165
|
+
|
|
166
|
+
When you verify something about the page that should stay true (an element exists, a state renders, a metric holds), persist it as .squint/checks/<name>.js \u2014 plain JS that evaluates IN THE PAGE to an array of failure strings (empty array = pass). squint replays every check against the live page after each turn.`
|
|
163
167
|
);
|
|
164
168
|
const matched = matchSkills(loadSkills(cwd), ask);
|
|
165
169
|
for (const skill of matched) {
|
|
@@ -9,12 +9,39 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
cdpCapture,
|
|
11
11
|
hasWebSocket
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-X2RZJT4L.js";
|
|
13
13
|
|
|
14
14
|
// src/preview/preview.ts
|
|
15
|
-
import
|
|
15
|
+
import fs2 from "fs";
|
|
16
16
|
import os from "os";
|
|
17
|
+
import path2 from "path";
|
|
18
|
+
|
|
19
|
+
// src/preview/checks.ts
|
|
20
|
+
import fs from "fs";
|
|
17
21
|
import path from "path";
|
|
22
|
+
var MAX_CHECKS = 20;
|
|
23
|
+
var MAX_BYTES = 1e4;
|
|
24
|
+
function loadChecks(cwd) {
|
|
25
|
+
const dir = path.join(cwd, ".squint", "checks");
|
|
26
|
+
let entries;
|
|
27
|
+
try {
|
|
28
|
+
entries = fs.readdirSync(dir).filter((f) => f.endsWith(".js"));
|
|
29
|
+
} catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const checks = [];
|
|
33
|
+
for (const entry of entries.sort().slice(0, MAX_CHECKS)) {
|
|
34
|
+
try {
|
|
35
|
+
const source = fs.readFileSync(path.join(dir, entry), "utf8");
|
|
36
|
+
if (source.trim().length === 0 || Buffer.byteLength(source) > MAX_BYTES) continue;
|
|
37
|
+
checks.push({ name: entry.replace(/\.js$/, ""), source });
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return checks;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/preview/preview.ts
|
|
18
45
|
var VIEWPORTS = [
|
|
19
46
|
{ name: "mobile", width: 390, height: 844 },
|
|
20
47
|
{ name: "tablet", width: 768, height: 1024 },
|
|
@@ -23,7 +50,7 @@ var VIEWPORTS = [
|
|
|
23
50
|
function loadRoutes(cwd) {
|
|
24
51
|
let lines = [];
|
|
25
52
|
try {
|
|
26
|
-
lines =
|
|
53
|
+
lines = fs2.readFileSync(path2.join(cwd, ".squint", "routes"), "utf8").split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#"));
|
|
27
54
|
} catch {
|
|
28
55
|
}
|
|
29
56
|
const routes = ["/", ...lines.filter((l) => l !== "/")];
|
|
@@ -34,8 +61,8 @@ function routeShotName(route) {
|
|
|
34
61
|
return clean.length > 0 ? clean : "root";
|
|
35
62
|
}
|
|
36
63
|
function previewDir(cwd) {
|
|
37
|
-
const dir =
|
|
38
|
-
|
|
64
|
+
const dir = path2.join(cwd, ".squint", "preview");
|
|
65
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
39
66
|
ensureSquintIgnore(cwd);
|
|
40
67
|
return dir;
|
|
41
68
|
}
|
|
@@ -47,7 +74,8 @@ async function captureViewports(cwd, url) {
|
|
|
47
74
|
const base = url.replace(/\/+$/, "");
|
|
48
75
|
if (hasWebSocket()) {
|
|
49
76
|
try {
|
|
50
|
-
const
|
|
77
|
+
const checks = loadChecks(cwd);
|
|
78
|
+
const { report, shots: shots2, a11y, slop, narration, phantoms, viewTransitions, components, checkFailures, webmcp } = await cdpCapture(chrome, url, dir, VIEWPORTS, 2500, true, checks);
|
|
51
79
|
const errors2 = [];
|
|
52
80
|
for (const route of routes.slice(1)) {
|
|
53
81
|
try {
|
|
@@ -62,14 +90,14 @@ async function captureViewports(cwd, url) {
|
|
|
62
90
|
errors2.push(`${route}: capture failed`);
|
|
63
91
|
}
|
|
64
92
|
}
|
|
65
|
-
return { shots: shots2, errors: errors2, runtime: report, a11y, slop, narration, phantoms, viewTransitions, components };
|
|
93
|
+
return { shots: shots2, errors: errors2, runtime: report, a11y, slop, narration, phantoms, viewTransitions, components, checkFailures, webmcp };
|
|
66
94
|
} catch {
|
|
67
95
|
}
|
|
68
96
|
}
|
|
69
97
|
const shots = [];
|
|
70
98
|
const errors = [];
|
|
71
99
|
for (const viewport of VIEWPORTS) {
|
|
72
|
-
const outPath =
|
|
100
|
+
const outPath = path2.join(dir, `${viewport.name}.png`);
|
|
73
101
|
const result = await screenshot(chrome, url, outPath, {
|
|
74
102
|
width: viewport.width,
|
|
75
103
|
height: viewport.height
|
|
@@ -118,14 +146,16 @@ async function probeRuntime(url, cwd) {
|
|
|
118
146
|
if (!chrome || !hasWebSocket()) return null;
|
|
119
147
|
try {
|
|
120
148
|
const dir = cwd ? previewDir(cwd) : os.tmpdir();
|
|
121
|
-
const { report, shots, perf } = await cdpCapture(
|
|
149
|
+
const { report, shots, perf, checkFailures } = await cdpCapture(
|
|
122
150
|
chrome,
|
|
123
151
|
url,
|
|
124
152
|
dir,
|
|
125
153
|
cwd ? [{ name: "pulse", width: 1280, height: 800 }] : [],
|
|
126
|
-
1500
|
|
154
|
+
1500,
|
|
155
|
+
false,
|
|
156
|
+
cwd ? loadChecks(cwd) : []
|
|
127
157
|
);
|
|
128
|
-
return { report, pulsePath: shots[0]?.path, perf };
|
|
158
|
+
return { report, pulsePath: shots[0]?.path, perf, checkFailures };
|
|
129
159
|
} catch {
|
|
130
160
|
return null;
|
|
131
161
|
}
|
|
@@ -133,7 +163,7 @@ async function probeRuntime(url, cwd) {
|
|
|
133
163
|
async function comparePulse(previous, current) {
|
|
134
164
|
const chrome = findChrome();
|
|
135
165
|
if (!chrome || !hasWebSocket()) return null;
|
|
136
|
-
const { pixelDiffPct } = await import("./cdp-
|
|
166
|
+
const { pixelDiffPct } = await import("./cdp-OYRHOPVP.js");
|
|
137
167
|
return pixelDiffPct(chrome, previous, current);
|
|
138
168
|
}
|
|
139
169
|
function buildRuntimeFixPrompt(report) {
|
|
@@ -161,6 +191,16 @@ ${narration.join("\n")}
|
|
|
161
191
|
|
|
162
192
|
Judge this narration as an experience: does the reading order make sense? do names actually describe their targets? is anything announced as "(no accessible name)"? Fix real incoherence \u2014 this is how non-visual users meet the page.`;
|
|
163
193
|
}
|
|
194
|
+
function webmcpSection(webmcp) {
|
|
195
|
+
if (!webmcp || webmcp.length === 0) return "";
|
|
196
|
+
return `
|
|
197
|
+
|
|
198
|
+
## Page-declared WebMCP tools
|
|
199
|
+
|
|
200
|
+
${webmcp.join("\n")}
|
|
201
|
+
|
|
202
|
+
The page registers these for agents via navigator.modelContext \u2014 keep them working, and prefer extending them over inventing parallel affordances.`;
|
|
203
|
+
}
|
|
164
204
|
function componentSection(components) {
|
|
165
205
|
if (!components || components.length === 0) return "";
|
|
166
206
|
return `
|
|
@@ -201,13 +241,13 @@ ${findings.join("\n")}
|
|
|
201
241
|
|
|
202
242
|
These patterns make the page read as template output. Rework them within the committed design direction \u2014 this is style debt, not a defect list.`;
|
|
203
243
|
}
|
|
204
|
-
function buildReviewPrompt(shots, extra, runtime, a11y, slop, narration, phantoms, viewTransitions, components) {
|
|
244
|
+
function buildReviewPrompt(shots, extra, runtime, a11y, slop, narration, phantoms, viewTransitions, components, webmcp) {
|
|
205
245
|
const list = shots.map((s) => `- ${s.name}: ${s.path}`).join("\n");
|
|
206
246
|
return `Screenshots of the running app were just captured:
|
|
207
247
|
|
|
208
248
|
${list}
|
|
209
249
|
|
|
210
|
-
Read each screenshot and review the rendered UI against the design standards you were given. Check: visual hierarchy and spacing rhythm, typography, color and contrast, alignment, empty-looking or broken regions, and whether the mobile capture shows horizontal overflow or cramped layout. List the concrete issues you can SEE (not hypothetical ones), ranked by visual impact${extra ? `, with special attention to: ${extra}` : ""}. Then fix them and verify the app still builds.${runtimeSection(runtime)}${a11ySection(a11y)}${slopSection(slop)}${narrationSection(narration)}${phantomSection(phantoms)}${vtSection(viewTransitions)}${componentSection(components)}`;
|
|
250
|
+
Read each screenshot and review the rendered UI against the design standards you were given. Check: visual hierarchy and spacing rhythm, typography, color and contrast, alignment, empty-looking or broken regions, and whether the mobile capture shows horizontal overflow or cramped layout. List the concrete issues you can SEE (not hypothetical ones), ranked by visual impact${extra ? `, with special attention to: ${extra}` : ""}. Then fix them and verify the app still builds.${runtimeSection(runtime)}${a11ySection(a11y)}${slopSection(slop)}${narrationSection(narration)}${phantomSection(phantoms)}${vtSection(viewTransitions)}${componentSection(components)}${webmcpSection(webmcp)}`;
|
|
211
251
|
}
|
|
212
252
|
|
|
213
253
|
export {
|
|
@@ -188,6 +188,7 @@ async function runFlow(chromePath, baseUrl, flow, outDir) {
|
|
|
188
188
|
const { targetId } = await connection.send("Target.createTarget", { url: "about:blank" });
|
|
189
189
|
const { sessionId } = await connection.send("Target.attachToTarget", { targetId, flatten: true });
|
|
190
190
|
await connection.send("Page.enable", {}, sessionId);
|
|
191
|
+
await connection.send("Page.addScriptToEvaluateOnNewDocument", { source: WEBMCP_SHIM }, sessionId).catch(() => null);
|
|
191
192
|
await connection.send(
|
|
192
193
|
"Emulation.setDeviceMetricsOverride",
|
|
193
194
|
{ width: 1280, height: 800, deviceScaleFactor: 1, mobile: false },
|
|
@@ -437,7 +438,20 @@ var FIBER_AUDIT = `(() => {
|
|
|
437
438
|
}
|
|
438
439
|
return out;
|
|
439
440
|
})()`;
|
|
440
|
-
|
|
441
|
+
var WEBMCP_SHIM = `(() => {
|
|
442
|
+
window.__squintWebMcp = [];
|
|
443
|
+
const record = (tools) => {
|
|
444
|
+
for (const t of tools || []) {
|
|
445
|
+
if (t && t.name) window.__squintWebMcp.push(t.name + (t.description ? ' \u2014 ' + t.description : ''));
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
const target = navigator.modelContext || (navigator.modelContext = {});
|
|
449
|
+
const provide = target.provideContext && target.provideContext.bind(target);
|
|
450
|
+
target.provideContext = (params) => { record(params && params.tools); return provide ? provide(params) : undefined; };
|
|
451
|
+
const register = target.registerTool && target.registerTool.bind(target);
|
|
452
|
+
target.registerTool = (tool) => { record([tool]); return register ? register(tool) : undefined; };
|
|
453
|
+
})()`;
|
|
454
|
+
async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, audit = false, checks = []) {
|
|
441
455
|
const { child, wsUrl, profileDir } = await launchChrome(chromePath);
|
|
442
456
|
const report = { consoleErrors: [], pageErrors: [], failedRequests: [] };
|
|
443
457
|
const shots = [];
|
|
@@ -448,6 +462,8 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
|
|
|
448
462
|
let phantoms = [];
|
|
449
463
|
let viewTransitions = [];
|
|
450
464
|
let components = [];
|
|
465
|
+
const checkFailures = [];
|
|
466
|
+
let webmcp = [];
|
|
451
467
|
const requests = /* @__PURE__ */ new Map();
|
|
452
468
|
let connection = null;
|
|
453
469
|
try {
|
|
@@ -486,6 +502,7 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
|
|
|
486
502
|
await connection.send("Runtime.enable", {}, sessionId);
|
|
487
503
|
await connection.send("Network.enable", {}, sessionId);
|
|
488
504
|
await connection.send("Page.enable", {}, sessionId);
|
|
505
|
+
await connection.send("Page.addScriptToEvaluateOnNewDocument", { source: WEBMCP_SHIM }, sessionId).catch(() => null);
|
|
489
506
|
await connection.send("Page.navigate", { url }, sessionId);
|
|
490
507
|
const deadline = Date.now() + 12e3;
|
|
491
508
|
while (!loaded && Date.now() < deadline) {
|
|
@@ -501,6 +518,31 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
|
|
|
501
518
|
if (result?.value && typeof result.value === "object") perf = result.value;
|
|
502
519
|
} catch {
|
|
503
520
|
}
|
|
521
|
+
try {
|
|
522
|
+
const { result } = await connection.send(
|
|
523
|
+
"Runtime.evaluate",
|
|
524
|
+
{ expression: "window.__squintWebMcp || []", returnByValue: true },
|
|
525
|
+
sessionId
|
|
526
|
+
);
|
|
527
|
+
if (Array.isArray(result?.value)) webmcp = result.value.map(String).slice(0, 12);
|
|
528
|
+
} catch {
|
|
529
|
+
}
|
|
530
|
+
for (const check of checks) {
|
|
531
|
+
try {
|
|
532
|
+
const { result, exceptionDetails } = await connection.send(
|
|
533
|
+
"Runtime.evaluate",
|
|
534
|
+
{ expression: check.source, returnByValue: true, timeout: 2e3 },
|
|
535
|
+
sessionId
|
|
536
|
+
);
|
|
537
|
+
if (exceptionDetails) {
|
|
538
|
+
checkFailures.push(`${check.name}: threw ${exceptionDetails.exception?.description?.split("\n")[0] ?? exceptionDetails.text ?? "an error"}`);
|
|
539
|
+
} else if (Array.isArray(result?.value)) {
|
|
540
|
+
for (const finding of result.value.slice(0, 5)) checkFailures.push(`${check.name}: ${String(finding)}`);
|
|
541
|
+
}
|
|
542
|
+
} catch {
|
|
543
|
+
}
|
|
544
|
+
if (checkFailures.length >= 15) break;
|
|
545
|
+
}
|
|
504
546
|
if (audit) {
|
|
505
547
|
try {
|
|
506
548
|
const { result } = await connection.send(
|
|
@@ -611,7 +653,7 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
|
|
|
611
653
|
child.kill("SIGKILL");
|
|
612
654
|
setTimeout(() => fs.rmSync(profileDir, { recursive: true, force: true }), 500).unref?.();
|
|
613
655
|
}
|
|
614
|
-
return { report, shots, a11y, slop, perf, narration, phantoms, viewTransitions, components };
|
|
656
|
+
return { report, shots, a11y, slop, perf, narration, phantoms, viewTransitions, components, checkFailures, webmcp };
|
|
615
657
|
}
|
|
616
658
|
|
|
617
659
|
export {
|
package/dist/cli.js
CHANGED
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
comparePulse,
|
|
43
43
|
probeRuntime,
|
|
44
44
|
runtimeSummary
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-D7Q3M6PA.js";
|
|
46
46
|
import {
|
|
47
47
|
clearState,
|
|
48
48
|
loadState,
|
|
@@ -58,11 +58,11 @@ import {
|
|
|
58
58
|
detectEngines,
|
|
59
59
|
getEngine
|
|
60
60
|
} from "./chunk-KVYGPLWW.js";
|
|
61
|
-
import "./chunk-
|
|
61
|
+
import "./chunk-X2RZJT4L.js";
|
|
62
62
|
import {
|
|
63
63
|
appendDecision,
|
|
64
64
|
enrich
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-ARDV4XH6.js";
|
|
66
66
|
import "./chunk-K5QJMSJH.js";
|
|
67
67
|
import {
|
|
68
68
|
composePrompt
|
|
@@ -240,7 +240,7 @@ function registerEnv(program2) {
|
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
242
|
const { findChrome: findChrome2 } = await import("./chrome-SBV3H77F.js");
|
|
243
|
-
const { hasWebSocket } = await import("./cdp-
|
|
243
|
+
const { hasWebSocket } = await import("./cdp-OYRHOPVP.js");
|
|
244
244
|
const chrome = findChrome2();
|
|
245
245
|
console.log(
|
|
246
246
|
chrome ? `${pc2.green("\u2713")} Chrome ${pc2.dim(chrome)}` : `${pc2.yellow("\u25CB")} Chrome ${pc2.dim("\u2014 screenshots and runtime probing disabled")}`
|
|
@@ -264,7 +264,7 @@ import pc3 from "picocolors";
|
|
|
264
264
|
function registerProject(program2) {
|
|
265
265
|
const skillsCommand = program2.command("skills").description("Project knowledge injected into asks (.squint/rules.md + .squint/skills/)");
|
|
266
266
|
skillsCommand.command("list").description("Show always-on rules and trigger-matched skills").action(async () => {
|
|
267
|
-
const { loadRules, loadSkills } = await import("./skills-
|
|
267
|
+
const { loadRules, loadSkills } = await import("./skills-POB4ZZY5.js");
|
|
268
268
|
const cwd = process.cwd();
|
|
269
269
|
const rules = loadRules(cwd);
|
|
270
270
|
console.log(
|
|
@@ -463,7 +463,7 @@ function registerQuality(program2) {
|
|
|
463
463
|
if (results.some((r) => !r.ok)) process.exitCode = 1;
|
|
464
464
|
});
|
|
465
465
|
program2.command("shot").description("Screenshot a running app at mobile/tablet/desktop viewports (+ .squint/routes)").argument("<url>", "URL of the running app (e.g. http://localhost:5173)").action(async (url) => {
|
|
466
|
-
const { captureViewports: captureViewports2 } = await import("./preview-
|
|
466
|
+
const { captureViewports: captureViewports2 } = await import("./preview-XREFPMHX.js");
|
|
467
467
|
const result = await captureViewports2(process.cwd(), url);
|
|
468
468
|
if (!result) {
|
|
469
469
|
console.error(pc4.red("\u2717 no Chrome/Chromium found"));
|
|
@@ -827,7 +827,7 @@ ${question}`,
|
|
|
827
827
|
return;
|
|
828
828
|
}
|
|
829
829
|
await this.runTurn(
|
|
830
|
-
buildReviewPrompt(result.shots, void 0, result.runtime, result.a11y, result.slop, result.narration, result.phantoms, result.viewTransitions, result.components),
|
|
830
|
+
buildReviewPrompt(result.shots, void 0, result.runtime, result.a11y, result.slop, result.narration, result.phantoms, result.viewTransitions, result.components, result.webmcp),
|
|
831
831
|
`\u{1F441} polish round ${round}/${rounds}`
|
|
832
832
|
);
|
|
833
833
|
}
|
|
@@ -1175,6 +1175,21 @@ ${errors.slice(-5).join("\n")}`);
|
|
|
1175
1175
|
this.clearProblems("dev");
|
|
1176
1176
|
if (this.opts.autoProbe !== false && this.state.devUrl) {
|
|
1177
1177
|
const probe = await probeRuntime(this.state.devUrl, this.opts.cwd);
|
|
1178
|
+
if (probe?.checkFailures && probe.checkFailures.length > 0) {
|
|
1179
|
+
this.addProblem(
|
|
1180
|
+
"check",
|
|
1181
|
+
`${probe.checkFailures.length} persistent check failure(s)`,
|
|
1182
|
+
`Repo checks in .squint/checks/ failed against the live page. Each line is <check>: <failure>:
|
|
1183
|
+
|
|
1184
|
+
${probe.checkFailures.join("\n")}
|
|
1185
|
+
|
|
1186
|
+
Fix the page (or, only if the assertion itself is genuinely outdated, update that check file and say so).`
|
|
1187
|
+
);
|
|
1188
|
+
this.push("error", `checks: ${probe.checkFailures.length} failure(s)
|
|
1189
|
+
${probe.checkFailures.slice(0, 5).join("\n")}`);
|
|
1190
|
+
} else {
|
|
1191
|
+
this.clearProblems("check");
|
|
1192
|
+
}
|
|
1178
1193
|
const summary = probe ? runtimeSummary(probe.report) : null;
|
|
1179
1194
|
if (probe && summary) {
|
|
1180
1195
|
this.addProblem("runtime", summary, buildRuntimeFixPrompt(probe.report));
|
|
@@ -1192,7 +1207,7 @@ ${errors.slice(-5).join("\n")}`);
|
|
|
1192
1207
|
const captureResult = await this.capture();
|
|
1193
1208
|
if (captureResult) {
|
|
1194
1209
|
await this.runTurn(
|
|
1195
|
-
buildReviewPrompt(captureResult.shots, void 0, captureResult.runtime, captureResult.a11y, captureResult.slop, captureResult.narration, captureResult.phantoms, captureResult.viewTransitions, captureResult.components),
|
|
1210
|
+
buildReviewPrompt(captureResult.shots, void 0, captureResult.runtime, captureResult.a11y, captureResult.slop, captureResult.narration, captureResult.phantoms, captureResult.viewTransitions, captureResult.components, captureResult.webmcp),
|
|
1196
1211
|
"\u{1F441} auto-review rendered UI"
|
|
1197
1212
|
);
|
|
1198
1213
|
}
|
|
@@ -1480,7 +1495,7 @@ They are objective defects, not style preferences.`
|
|
|
1480
1495
|
break;
|
|
1481
1496
|
}
|
|
1482
1497
|
case "context": {
|
|
1483
|
-
import("./contextDoctor-
|
|
1498
|
+
import("./contextDoctor-A26C2ZDN.js").then(({ contextReport, formatContextReport }) => {
|
|
1484
1499
|
this.push("status", formatContextReport(contextReport(this.execCwd())));
|
|
1485
1500
|
}).catch((error) => {
|
|
1486
1501
|
this.push("status", `context report failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -1615,8 +1630,8 @@ They are objective defects, not style preferences.`
|
|
|
1615
1630
|
this.push("error", "no Chrome/Chromium found for flows");
|
|
1616
1631
|
return;
|
|
1617
1632
|
}
|
|
1618
|
-
const { runFlow } = await import("./cdp-
|
|
1619
|
-
const { previewDir } = await import("./preview-
|
|
1633
|
+
const { runFlow } = await import("./cdp-OYRHOPVP.js");
|
|
1634
|
+
const { previewDir } = await import("./preview-XREFPMHX.js");
|
|
1620
1635
|
this.push("status", `replaying ${flows.length} flow(s)\u2026`);
|
|
1621
1636
|
this.notify({ running: true, runStartedAt: Date.now() });
|
|
1622
1637
|
const failures = [];
|
|
@@ -1754,7 +1769,7 @@ They are objective defects, not style preferences.`
|
|
|
1754
1769
|
const result = await this.capture();
|
|
1755
1770
|
if (result) {
|
|
1756
1771
|
await this.runTurn(
|
|
1757
|
-
buildReviewPrompt(result.shots, arg || void 0, result.runtime, result.a11y, result.slop, result.narration, result.phantoms, result.viewTransitions, result.components),
|
|
1772
|
+
buildReviewPrompt(result.shots, arg || void 0, result.runtime, result.a11y, result.slop, result.narration, result.phantoms, result.viewTransitions, result.components, result.webmcp),
|
|
1758
1773
|
`\u{1F441} review rendered UI${arg ? ` \xB7 ${arg}` : ""}`
|
|
1759
1774
|
);
|
|
1760
1775
|
}
|
|
@@ -2559,7 +2574,7 @@ function registerTui(program2) {
|
|
|
2559
2574
|
}
|
|
2560
2575
|
|
|
2561
2576
|
// src/cli.tsx
|
|
2562
|
-
var VERSION = true ? "0.4.
|
|
2577
|
+
var VERSION = true ? "0.4.6" : "0.0.0-dev";
|
|
2563
2578
|
var program = new Command();
|
|
2564
2579
|
program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
|
|
2565
2580
|
registerRun(program);
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
probeRuntime,
|
|
11
11
|
routeShotName,
|
|
12
12
|
runtimeSummary
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-D7Q3M6PA.js";
|
|
14
14
|
import "./chunk-O2S6PAJE.js";
|
|
15
15
|
import "./chunk-IMDRXXFU.js";
|
|
16
16
|
import "./chunk-KVYGPLWW.js";
|
|
17
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-X2RZJT4L.js";
|
|
18
18
|
export {
|
|
19
19
|
VIEWPORTS,
|
|
20
20
|
buildReviewPrompt,
|
package/package.json
CHANGED