@aayambansal/squint 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/{cdp-VRGCGN5R.js → cdp-UGLMW5R5.js} +1 -1
- package/dist/{chunk-6FR4TRRQ.js → chunk-7YKO5MMN.js} +5 -1
- package/dist/{chunk-2EJWUBUP.js → chunk-UTBTLCUO.js} +2 -2
- package/dist/cli.js +9 -9
- package/dist/{flows-V5ZLVVSQ.js → flows-6LK7NGWS.js} +39 -0
- package/dist/{init-LSYB32NS.js → init-YB2IMA4N.js} +6 -0
- package/dist/{preview-X7EWTRCZ.js → preview-6MML2NEG.js} +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -148,7 +148,10 @@ squint doctor --probe # run every engine end to end, verify auth act
|
|
|
148
148
|
order; `/queue clear` drops them. `Esc` interrupts the current turn.
|
|
149
149
|
- **Editing**: a real line editor — arrows move, `alt+←/→` jump words, `ctrl+a/e/k/u/w`,
|
|
150
150
|
`↑/↓` history. `ctrl+c` twice exits with a session summary.
|
|
151
|
-
- **
|
|
151
|
+
- **Flows**: declare user journeys as six readable lines in `.squint/flows/`; `/flows`
|
|
152
|
+
replays them headlessly and failing steps join the fix loop. `/score` snapshots quality
|
|
153
|
+
deterministically.
|
|
154
|
+
- **Problems**: findings from gates, the dev server, the runtime probe, a11y sweeps, and flows
|
|
152
155
|
collect into a list — `/problems` shows it, `/fix` sends everything as one turn,
|
|
153
156
|
`/fix <n>` targets one. The footer counts what's open.
|
|
154
157
|
- **Sandbox**: `/sandbox on` and asks accumulate in a shadow worktree — the dev server,
|
|
@@ -179,7 +179,7 @@ var describe = (value) => {
|
|
|
179
179
|
return String(value);
|
|
180
180
|
};
|
|
181
181
|
async function runFlow(chromePath, baseUrl, flow, outDir) {
|
|
182
|
-
const { stepExpression } = await import("./flows-
|
|
182
|
+
const { stepExpression } = await import("./flows-6LK7NGWS.js");
|
|
183
183
|
const { child, wsUrl, profileDir } = await launchChrome(chromePath);
|
|
184
184
|
const shots = [];
|
|
185
185
|
let connection = null;
|
|
@@ -203,6 +203,10 @@ async function runFlow(chromePath, baseUrl, flow, outDir) {
|
|
|
203
203
|
await new Promise((resolve) => setTimeout(resolve, 1800));
|
|
204
204
|
continue;
|
|
205
205
|
}
|
|
206
|
+
if (step.kind === "wait") {
|
|
207
|
+
await new Promise((resolve) => setTimeout(resolve, step.ms));
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
206
210
|
if (step.kind === "shot") {
|
|
207
211
|
const { data } = await connection.send("Page.captureScreenshot", { format: "png" }, sessionId);
|
|
208
212
|
const outPath = path.join(outDir, `flow-${flow.name}-${step.name}.png`);
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
cdpCapture,
|
|
11
11
|
hasWebSocket
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7YKO5MMN.js";
|
|
13
13
|
|
|
14
14
|
// src/preview/preview.ts
|
|
15
15
|
import fs from "fs";
|
|
@@ -133,7 +133,7 @@ async function probeRuntime(url, cwd) {
|
|
|
133
133
|
async function comparePulse(previous, current) {
|
|
134
134
|
const chrome = findChrome();
|
|
135
135
|
if (!chrome || !hasWebSocket()) return null;
|
|
136
|
-
const { pixelDiffPct } = await import("./cdp-
|
|
136
|
+
const { pixelDiffPct } = await import("./cdp-UGLMW5R5.js");
|
|
137
137
|
return pixelDiffPct(chrome, previous, current);
|
|
138
138
|
}
|
|
139
139
|
function buildRuntimeFixPrompt(report) {
|
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-UTBTLCUO.js";
|
|
46
46
|
import {
|
|
47
47
|
clearState,
|
|
48
48
|
loadState,
|
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
detectEngines,
|
|
59
59
|
getEngine
|
|
60
60
|
} from "./chunk-KVYGPLWW.js";
|
|
61
|
-
import "./chunk-
|
|
61
|
+
import "./chunk-7YKO5MMN.js";
|
|
62
62
|
import {
|
|
63
63
|
enrich
|
|
64
64
|
} from "./chunk-H5K55LXY.js";
|
|
@@ -238,7 +238,7 @@ function registerEnv(program2) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
const { findChrome: findChrome2 } = await import("./chrome-SBV3H77F.js");
|
|
241
|
-
const { hasWebSocket } = await import("./cdp-
|
|
241
|
+
const { hasWebSocket } = await import("./cdp-UGLMW5R5.js");
|
|
242
242
|
const chrome = findChrome2();
|
|
243
243
|
console.log(
|
|
244
244
|
chrome ? `${pc2.green("\u2713")} Chrome ${pc2.dim(chrome)}` : `${pc2.yellow("\u25CB")} Chrome ${pc2.dim("\u2014 screenshots and runtime probing disabled")}`
|
|
@@ -461,7 +461,7 @@ function registerQuality(program2) {
|
|
|
461
461
|
if (results.some((r) => !r.ok)) process.exitCode = 1;
|
|
462
462
|
});
|
|
463
463
|
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) => {
|
|
464
|
-
const { captureViewports: captureViewports2 } = await import("./preview-
|
|
464
|
+
const { captureViewports: captureViewports2 } = await import("./preview-6MML2NEG.js");
|
|
465
465
|
const result = await captureViewports2(process.cwd(), url);
|
|
466
466
|
if (!result) {
|
|
467
467
|
console.error(pc4.red("\u2717 no Chrome/Chromium found"));
|
|
@@ -554,7 +554,7 @@ function registerRun(program2) {
|
|
|
554
554
|
import pc6 from "picocolors";
|
|
555
555
|
function registerScaffold(program2) {
|
|
556
556
|
program2.command("init").description("Scaffold a new Vite + React + TS + Tailwind app with token-first CSS").argument("[dir]", "target directory", ".").option("--force", "write into a non-empty directory").option("--no-install", "skip npm install").action(async (dir, options) => {
|
|
557
|
-
const { installDependencies, writeTemplate } = await import("./init-
|
|
557
|
+
const { installDependencies, writeTemplate } = await import("./init-YB2IMA4N.js");
|
|
558
558
|
let result;
|
|
559
559
|
try {
|
|
560
560
|
result = writeTemplate(dir, { force: options.force });
|
|
@@ -1480,7 +1480,7 @@ They are objective defects, not style preferences.`
|
|
|
1480
1480
|
break;
|
|
1481
1481
|
}
|
|
1482
1482
|
void (async () => {
|
|
1483
|
-
const { loadFlows } = await import("./flows-
|
|
1483
|
+
const { loadFlows } = await import("./flows-6LK7NGWS.js");
|
|
1484
1484
|
const flows = loadFlows(this.opts.cwd);
|
|
1485
1485
|
if (flows.length === 0) {
|
|
1486
1486
|
this.push("status", "no flows \u2014 add .squint/flows/<name>.flow (goto/click/fill/press/expect/shot lines), or ask the engine to write one");
|
|
@@ -1491,8 +1491,8 @@ They are objective defects, not style preferences.`
|
|
|
1491
1491
|
this.push("error", "no Chrome/Chromium found for flows");
|
|
1492
1492
|
return;
|
|
1493
1493
|
}
|
|
1494
|
-
const { runFlow } = await import("./cdp-
|
|
1495
|
-
const { previewDir } = await import("./preview-
|
|
1494
|
+
const { runFlow } = await import("./cdp-UGLMW5R5.js");
|
|
1495
|
+
const { previewDir } = await import("./preview-6MML2NEG.js");
|
|
1496
1496
|
this.push("status", `replaying ${flows.length} flow(s)\u2026`);
|
|
1497
1497
|
this.notify({ running: true, runStartedAt: Date.now() });
|
|
1498
1498
|
const failures = [];
|
|
@@ -2433,7 +2433,7 @@ function registerTui(program2) {
|
|
|
2433
2433
|
}
|
|
2434
2434
|
|
|
2435
2435
|
// src/cli.tsx
|
|
2436
|
-
var VERSION = true ? "0.4.
|
|
2436
|
+
var VERSION = true ? "0.4.1" : "0.0.0-dev";
|
|
2437
2437
|
var program = new Command();
|
|
2438
2438
|
program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
|
|
2439
2439
|
registerRun(program);
|
|
@@ -32,6 +32,18 @@ function parseFlow(name, text) {
|
|
|
32
32
|
case "shot":
|
|
33
33
|
steps.push({ kind: "shot", name: arg.replace(/[^a-zA-Z0-9-]/g, "-") });
|
|
34
34
|
break;
|
|
35
|
+
case "hover":
|
|
36
|
+
steps.push({ kind: "hover", target: arg });
|
|
37
|
+
break;
|
|
38
|
+
case "scroll":
|
|
39
|
+
steps.push({ kind: "scroll", target: arg || "bottom" });
|
|
40
|
+
break;
|
|
41
|
+
case "wait": {
|
|
42
|
+
const ms = Number.parseInt(arg, 10);
|
|
43
|
+
if (!Number.isInteger(ms) || ms < 0 || ms > 1e4) return null;
|
|
44
|
+
steps.push({ kind: "wait", ms });
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
35
47
|
default:
|
|
36
48
|
return null;
|
|
37
49
|
}
|
|
@@ -96,8 +108,35 @@ function stepExpression(step) {
|
|
|
96
108
|
}
|
|
97
109
|
return { ok: true };
|
|
98
110
|
})()`;
|
|
111
|
+
case "hover":
|
|
112
|
+
return `(() => {
|
|
113
|
+
const target = ${JSON.stringify(step.target)};
|
|
114
|
+
let el = null;
|
|
115
|
+
try { el = document.querySelector(target); } catch {}
|
|
116
|
+
if (!el) {
|
|
117
|
+
const all = [...document.querySelectorAll('*')];
|
|
118
|
+
el = all.find((e) => e.children.length === 0 && (e.textContent || '').trim().toLowerCase().includes(target.toLowerCase()));
|
|
119
|
+
}
|
|
120
|
+
if (!el) return { ok: false, detail: 'no element matching ' + target };
|
|
121
|
+
for (const type of ['pointerover', 'mouseover', 'mouseenter']) {
|
|
122
|
+
el.dispatchEvent(new MouseEvent(type, { bubbles: type !== 'mouseenter' }));
|
|
123
|
+
}
|
|
124
|
+
return { ok: true };
|
|
125
|
+
})()`;
|
|
126
|
+
case "scroll":
|
|
127
|
+
return `(() => {
|
|
128
|
+
const target = ${JSON.stringify(step.target)};
|
|
129
|
+
if (target === 'bottom') { window.scrollTo(0, document.body.scrollHeight); return { ok: true }; }
|
|
130
|
+
if (target === 'top') { window.scrollTo(0, 0); return { ok: true }; }
|
|
131
|
+
let el = null;
|
|
132
|
+
try { el = document.querySelector(target); } catch {}
|
|
133
|
+
if (!el) return { ok: false, detail: 'no element matching ' + target };
|
|
134
|
+
el.scrollIntoView({ block: 'center' });
|
|
135
|
+
return { ok: true };
|
|
136
|
+
})()`;
|
|
99
137
|
case "goto":
|
|
100
138
|
case "shot":
|
|
139
|
+
case "wait":
|
|
101
140
|
return null;
|
|
102
141
|
}
|
|
103
142
|
}
|
|
@@ -139,6 +139,12 @@ body {
|
|
|
139
139
|
dist/
|
|
140
140
|
*.log
|
|
141
141
|
.DS_Store
|
|
142
|
+
`,
|
|
143
|
+
".squint/flows/home.flow": `# The starter journey: replayed headlessly by /flows after every change.
|
|
144
|
+
# Grow this file as the app grows \u2014 or ask the engine to.
|
|
145
|
+
goto /
|
|
146
|
+
expect Ready
|
|
147
|
+
shot home
|
|
142
148
|
`
|
|
143
149
|
};
|
|
144
150
|
}
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
probeRuntime,
|
|
11
11
|
routeShotName,
|
|
12
12
|
runtimeSummary
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-UTBTLCUO.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-7YKO5MMN.js";
|
|
18
18
|
export {
|
|
19
19
|
VIEWPORTS,
|
|
20
20
|
buildReviewPrompt,
|
package/package.json
CHANGED