@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 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
- - **Problems**: findings from gates, the dev server, the runtime probe, and a11y sweeps
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,
@@ -4,7 +4,7 @@ import {
4
4
  hasWebSocket,
5
5
  pixelDiffPct,
6
6
  runFlow
7
- } from "./chunk-6FR4TRRQ.js";
7
+ } from "./chunk-7YKO5MMN.js";
8
8
  export {
9
9
  cdpCapture,
10
10
  hasWebSocket,
@@ -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-V5ZLVVSQ.js");
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-6FR4TRRQ.js";
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-VRGCGN5R.js");
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-2EJWUBUP.js";
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-6FR4TRRQ.js";
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-VRGCGN5R.js");
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-X7EWTRCZ.js");
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-LSYB32NS.js");
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-V5ZLVVSQ.js");
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-VRGCGN5R.js");
1495
- const { previewDir } = await import("./preview-X7EWTRCZ.js");
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.0" : "0.0.0-dev";
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-2EJWUBUP.js";
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-6FR4TRRQ.js";
17
+ import "./chunk-7YKO5MMN.js";
18
18
  export {
19
19
  VIEWPORTS,
20
20
  buildReviewPrompt,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aayambansal/squint",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Lovable for your terminal — a frontend harness on top of Claude Code, Codex, and other coding agents.",
5
5
  "type": "module",
6
6
  "license": "MIT",