@aayambansal/squint 0.4.1 → 0.4.2

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.
@@ -4,7 +4,7 @@ import {
4
4
  hasWebSocket,
5
5
  pixelDiffPct,
6
6
  runFlow
7
- } from "./chunk-7YKO5MMN.js";
7
+ } from "./chunk-Y47X4ENN.js";
8
8
  export {
9
9
  cdpCapture,
10
10
  hasWebSocket,
@@ -1,25 +1,70 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/prompt/skills.ts
4
- import fs2 from "fs";
5
- import path2 from "path";
4
+ import fs3 from "fs";
5
+ import path3 from "path";
6
6
 
7
- // src/prompt/registry.ts
7
+ // src/session/designLog.ts
8
8
  import fs from "fs";
9
9
  import path from "path";
10
+ function logFile(cwd) {
11
+ return path.join(cwd, ".squint", "design-log.jsonl");
12
+ }
13
+ function appendDecision(cwd, entry) {
14
+ try {
15
+ fs.mkdirSync(path.join(cwd, ".squint"), { recursive: true });
16
+ const record = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry };
17
+ fs.appendFileSync(logFile(cwd), JSON.stringify(record) + "\n");
18
+ } catch {
19
+ }
20
+ }
21
+ function loadDecisions(cwd, limit = 8) {
22
+ try {
23
+ const lines = fs.readFileSync(logFile(cwd), "utf8").trim().split("\n");
24
+ const decisions = [];
25
+ for (const line of lines.slice(-limit * 2)) {
26
+ try {
27
+ const parsed = JSON.parse(line);
28
+ if (typeof parsed?.decision === "string" && typeof parsed?.ts === "string") decisions.push(parsed);
29
+ } catch {
30
+ }
31
+ }
32
+ return decisions.slice(-limit);
33
+ } catch {
34
+ return [];
35
+ }
36
+ }
37
+ function decisionsSection(cwd) {
38
+ const decisions = loadDecisions(cwd);
39
+ if (decisions.length === 0) return "";
40
+ const lines = decisions.map((d) => {
41
+ const days = Math.floor((Date.now() - Date.parse(d.ts)) / 864e5);
42
+ const age = days <= 0 ? "today" : `${days}d ago`;
43
+ return `- ${d.decision} (${d.source}, ${age}${d.screenshot ? `, evidence: ${d.screenshot}` : ""})`;
44
+ });
45
+ return `## Design decisions on record
46
+
47
+ ${lines.join("\n")}
48
+
49
+ These were decided deliberately. Do not silently undo them; if a task genuinely requires reversing one, say so explicitly first.`;
50
+ }
51
+
52
+ // src/prompt/registry.ts
53
+ import fs2 from "fs";
54
+ import path2 from "path";
10
55
  function loadComponentInventory(cwd) {
11
56
  let config;
12
57
  try {
13
- config = JSON.parse(fs.readFileSync(path.join(cwd, "components.json"), "utf8"));
58
+ config = JSON.parse(fs2.readFileSync(path2.join(cwd, "components.json"), "utf8"));
14
59
  } catch {
15
60
  return null;
16
61
  }
17
62
  const alias = config.aliases?.ui ?? (config.aliases?.components ? `${config.aliases.components}/ui` : "@/components/ui");
18
63
  const relative = alias.replace(/^@\//, "src/").replace(/^~\//, "");
19
- const uiDir = path.join(cwd, relative);
64
+ const uiDir = path2.join(cwd, relative);
20
65
  let entries;
21
66
  try {
22
- entries = fs.readdirSync(uiDir);
67
+ entries = fs2.readdirSync(uiDir);
23
68
  } catch {
24
69
  return null;
25
70
  }
@@ -55,17 +100,17 @@ function parseSkill(name, raw) {
55
100
  return { name, triggers, body };
56
101
  }
57
102
  function loadSkills(cwd) {
58
- const dir = path2.join(cwd, ".squint", "skills");
103
+ const dir = path3.join(cwd, ".squint", "skills");
59
104
  let entries;
60
105
  try {
61
- entries = fs2.readdirSync(dir).filter((f) => f.endsWith(".md"));
106
+ entries = fs3.readdirSync(dir).filter((f) => f.endsWith(".md"));
62
107
  } catch {
63
108
  return [];
64
109
  }
65
110
  const skills = [];
66
111
  for (const entry of entries.sort()) {
67
112
  try {
68
- const skill = parseSkill(entry.replace(/\.md$/, ""), fs2.readFileSync(path2.join(dir, entry), "utf8"));
113
+ const skill = parseSkill(entry.replace(/\.md$/, ""), fs3.readFileSync(path3.join(dir, entry), "utf8"));
69
114
  if (skill) skills.push(skill);
70
115
  } catch {
71
116
  }
@@ -74,7 +119,7 @@ function loadSkills(cwd) {
74
119
  }
75
120
  function loadRules(cwd) {
76
121
  try {
77
- const text = fs2.readFileSync(path2.join(cwd, ".squint", "rules.md"), "utf8").trim();
122
+ const text = fs3.readFileSync(path3.join(cwd, ".squint", "rules.md"), "utf8").trim();
78
123
  return text.length > 0 ? text : null;
79
124
  } catch {
80
125
  return null;
@@ -86,7 +131,7 @@ function matchSkills(skills, ask) {
86
131
  }
87
132
  function loadLocks(cwd) {
88
133
  try {
89
- return fs2.readFileSync(path2.join(cwd, ".squint", "locks"), "utf8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
134
+ return fs3.readFileSync(path3.join(cwd, ".squint", "locks"), "utf8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
90
135
  } catch {
91
136
  return [];
92
137
  }
@@ -97,6 +142,8 @@ function enrich(cwd, ask) {
97
142
  if (rules) parts.push(`## Project rules (always apply)
98
143
 
99
144
  ${rules}`);
145
+ const decisions = decisionsSection(cwd);
146
+ if (decisions) parts.push(decisions);
100
147
  const inventory = loadComponentInventory(cwd);
101
148
  if (inventory) parts.push(inventorySection(inventory));
102
149
  const locks = loadLocks(cwd);
@@ -124,6 +171,7 @@ ${parts.join("\n\n")}` : "",
124
171
  }
125
172
 
126
173
  export {
174
+ appendDecision,
127
175
  parseSkill,
128
176
  loadSkills,
129
177
  loadRules,
@@ -26,6 +26,7 @@ var COMMANDS = [
26
26
  { name: "copy", group: "session", description: "copy the last reply to the clipboard" },
27
27
  { name: "save", group: "session", description: "export the transcript to .squint/transcripts/" },
28
28
  { name: "find", args: "<term>", group: "session", description: "search this session and saved transcripts" },
29
+ { name: "decide", args: "<text>", group: "session", description: "record a design decision; injected into every future ask" },
29
30
  { name: "resume", group: "session", description: "pick up the previous session for this repo" },
30
31
  { name: "clear", group: "session", description: "new session (transcript, totals, persisted state)" },
31
32
  { name: "help", group: "session", description: "list commands" },
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  cdpCapture,
11
11
  hasWebSocket
12
- } from "./chunk-7YKO5MMN.js";
12
+ } from "./chunk-Y47X4ENN.js";
13
13
 
14
14
  // src/preview/preview.ts
15
15
  import fs from "fs";
@@ -47,7 +47,7 @@ async function captureViewports(cwd, url) {
47
47
  const base = url.replace(/\/+$/, "");
48
48
  if (hasWebSocket()) {
49
49
  try {
50
- const { report, shots: shots2, a11y, slop, narration } = await cdpCapture(chrome, url, dir, VIEWPORTS, 2500, true);
50
+ const { report, shots: shots2, a11y, slop, narration, phantoms } = await cdpCapture(chrome, url, dir, VIEWPORTS, 2500, true);
51
51
  const errors2 = [];
52
52
  for (const route of routes.slice(1)) {
53
53
  try {
@@ -62,7 +62,7 @@ async function captureViewports(cwd, url) {
62
62
  errors2.push(`${route}: capture failed`);
63
63
  }
64
64
  }
65
- return { shots: shots2, errors: errors2, runtime: report, a11y, slop, narration };
65
+ return { shots: shots2, errors: errors2, runtime: report, a11y, slop, narration, phantoms };
66
66
  } catch {
67
67
  }
68
68
  }
@@ -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-UGLMW5R5.js");
136
+ const { pixelDiffPct } = await import("./cdp-TPP2RGSR.js");
137
137
  return pixelDiffPct(chrome, previous, current);
138
138
  }
139
139
  function buildRuntimeFixPrompt(report) {
@@ -161,6 +161,16 @@ ${narration.join("\n")}
161
161
 
162
162
  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
163
  }
164
+ function phantomSection(phantoms) {
165
+ if (!phantoms || phantoms.length === 0) return "";
166
+ return `
167
+
168
+ ## Phantom classes (in the DOM, absent from the CSS)
169
+
170
+ ${phantoms.join("\n")}
171
+
172
+ Each of these is an element silently unstyled \u2014 usually a misspelled or version-mismatched utility (Tailwind v3 spellings in a v4 project) or a concatenated class the scanner never compiled. Fix the class names or define the styles.`;
173
+ }
164
174
  function slopSection(findings) {
165
175
  if (!findings || findings.length === 0) return "";
166
176
  return `
@@ -171,13 +181,13 @@ ${findings.join("\n")}
171
181
 
172
182
  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.`;
173
183
  }
174
- function buildReviewPrompt(shots, extra, runtime, a11y, slop, narration) {
184
+ function buildReviewPrompt(shots, extra, runtime, a11y, slop, narration, phantoms) {
175
185
  const list = shots.map((s) => `- ${s.name}: ${s.path}`).join("\n");
176
186
  return `Screenshots of the running app were just captured:
177
187
 
178
188
  ${list}
179
189
 
180
- 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)}`;
190
+ 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)}`;
181
191
  }
182
192
 
183
193
  export {
@@ -329,6 +329,37 @@ var SLOP_AUDIT = `(() => {
329
329
  }
330
330
  return out.slice(0, 8);
331
331
  })()`;
332
+ var PHANTOM_AUDIT = `(() => {
333
+ const defined = new Set();
334
+ for (const sheet of document.styleSheets) {
335
+ let rules; try { rules = sheet.cssRules; } catch { continue; }
336
+ const walk = (list) => {
337
+ for (const rule of list) {
338
+ if (rule.selectorText) {
339
+ for (const m of rule.selectorText.matchAll(/\\.((?:[\\w-]|\\\\.)+)/g)) {
340
+ defined.add(m[1].replace(/\\\\(.)/g, '$1'));
341
+ }
342
+ }
343
+ if (rule.cssRules) walk(rule.cssRules);
344
+ }
345
+ };
346
+ walk(rules);
347
+ }
348
+ if (defined.size < 10) return []; // no CSSOM visibility \u2014 stay silent
349
+ const seen = new Map();
350
+ for (const el of document.querySelectorAll('[class]')) {
351
+ for (const cls of el.classList) {
352
+ if (cls.length < 3) continue;
353
+ if (!defined.has(cls) && !seen.has(cls)) seen.set(cls, el.tagName.toLowerCase());
354
+ }
355
+ }
356
+ const out = [];
357
+ for (const [cls, tag] of seen) {
358
+ out.push(cls + ' (on <' + tag + '>)');
359
+ if (out.length >= 12) break;
360
+ }
361
+ return out;
362
+ })()`;
332
363
  async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, audit = false) {
333
364
  const { child, wsUrl, profileDir } = await launchChrome(chromePath);
334
365
  const report = { consoleErrors: [], pageErrors: [], failedRequests: [] };
@@ -337,6 +368,7 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
337
368
  let slop = [];
338
369
  let perf = {};
339
370
  let narration = [];
371
+ let phantoms = [];
340
372
  const requests = /* @__PURE__ */ new Map();
341
373
  let connection = null;
342
374
  try {
@@ -409,6 +441,15 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
409
441
  if (Array.isArray(result?.value)) slop = result.value.map(String);
410
442
  } catch {
411
443
  }
444
+ try {
445
+ const { result } = await connection.send(
446
+ "Runtime.evaluate",
447
+ { expression: PHANTOM_AUDIT, returnByValue: true },
448
+ sessionId
449
+ );
450
+ if (Array.isArray(result?.value)) phantoms = result.value.map(String);
451
+ } catch {
452
+ }
412
453
  try {
413
454
  await connection.send("Accessibility.enable", {}, sessionId);
414
455
  const { nodes } = await connection.send("Accessibility.getFullAXTree", {}, sessionId);
@@ -473,7 +514,7 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
473
514
  child.kill("SIGKILL");
474
515
  setTimeout(() => fs.rmSync(profileDir, { recursive: true, force: true }), 500).unref?.();
475
516
  }
476
- return { report, shots, a11y, slop, perf, narration };
517
+ return { report, shots, a11y, slop, perf, narration, phantoms };
477
518
  }
478
519
 
479
520
  export {
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  completeCommand
4
- } from "./chunk-SVKV77TO.js";
4
+ } from "./chunk-S3WV5C3X.js";
5
5
  import {
6
6
  applySandbox,
7
7
  discardSandbox,
@@ -42,7 +42,7 @@ import {
42
42
  comparePulse,
43
43
  probeRuntime,
44
44
  runtimeSummary
45
- } from "./chunk-UTBTLCUO.js";
45
+ } from "./chunk-WCLQZFOR.js";
46
46
  import {
47
47
  clearState,
48
48
  loadState,
@@ -58,10 +58,11 @@ import {
58
58
  detectEngines,
59
59
  getEngine
60
60
  } from "./chunk-KVYGPLWW.js";
61
- import "./chunk-7YKO5MMN.js";
61
+ import "./chunk-Y47X4ENN.js";
62
62
  import {
63
+ appendDecision,
63
64
  enrich
64
- } from "./chunk-H5K55LXY.js";
65
+ } from "./chunk-KGZILC3S.js";
65
66
  import {
66
67
  composePrompt
67
68
  } from "./chunk-P3H4N2EN.js";
@@ -238,7 +239,7 @@ function registerEnv(program2) {
238
239
  }
239
240
  }
240
241
  const { findChrome: findChrome2 } = await import("./chrome-SBV3H77F.js");
241
- const { hasWebSocket } = await import("./cdp-UGLMW5R5.js");
242
+ const { hasWebSocket } = await import("./cdp-TPP2RGSR.js");
242
243
  const chrome = findChrome2();
243
244
  console.log(
244
245
  chrome ? `${pc2.green("\u2713")} Chrome ${pc2.dim(chrome)}` : `${pc2.yellow("\u25CB")} Chrome ${pc2.dim("\u2014 screenshots and runtime probing disabled")}`
@@ -262,7 +263,7 @@ import pc3 from "picocolors";
262
263
  function registerProject(program2) {
263
264
  const skillsCommand = program2.command("skills").description("Project knowledge injected into asks (.squint/rules.md + .squint/skills/)");
264
265
  skillsCommand.command("list").description("Show always-on rules and trigger-matched skills").action(async () => {
265
- const { loadRules, loadSkills } = await import("./skills-ODOVNE6E.js");
266
+ const { loadRules, loadSkills } = await import("./skills-U2J7Z3B2.js");
266
267
  const cwd = process.cwd();
267
268
  const rules = loadRules(cwd);
268
269
  console.log(
@@ -461,7 +462,7 @@ function registerQuality(program2) {
461
462
  if (results.some((r) => !r.ok)) process.exitCode = 1;
462
463
  });
463
464
  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-6MML2NEG.js");
465
+ const { captureViewports: captureViewports2 } = await import("./preview-SKHIXVCE.js");
465
466
  const result = await captureViewports2(process.cwd(), url);
466
467
  if (!result) {
467
468
  console.error(pc4.red("\u2717 no Chrome/Chromium found"));
@@ -823,7 +824,7 @@ ${question}`,
823
824
  return;
824
825
  }
825
826
  await this.runTurn(
826
- buildReviewPrompt(result.shots, void 0, result.runtime, result.a11y, result.slop, result.narration),
827
+ buildReviewPrompt(result.shots, void 0, result.runtime, result.a11y, result.slop, result.narration, result.phantoms),
827
828
  `\u{1F441} polish round ${round}/${rounds}`
828
829
  );
829
830
  }
@@ -1141,7 +1142,7 @@ ${errors.slice(-5).join("\n")}`);
1141
1142
  const captureResult = await this.capture();
1142
1143
  if (captureResult) {
1143
1144
  await this.runTurn(
1144
- buildReviewPrompt(captureResult.shots, void 0, captureResult.runtime, captureResult.a11y, captureResult.slop, captureResult.narration),
1145
+ buildReviewPrompt(captureResult.shots, void 0, captureResult.runtime, captureResult.a11y, captureResult.slop, captureResult.narration, captureResult.phantoms),
1145
1146
  "\u{1F441} auto-review rendered UI"
1146
1147
  );
1147
1148
  }
@@ -1189,6 +1190,7 @@ ${errors.slice(-5).join("\n")}`);
1189
1190
  const result = restoreSnapshot(this.opts.cwd, checkpoint.snapshot);
1190
1191
  if (result.restored) {
1191
1192
  const dropped = this.checkpoints.length - index;
1193
+ appendDecision(this.opts.cwd, { decision: `rejected and rolled back: "${checkpoint.label}"`, source: "restore" });
1192
1194
  this.checkpoints = this.checkpoints.slice(0, index);
1193
1195
  this.push(
1194
1196
  "status",
@@ -1280,6 +1282,20 @@ ${errors.slice(-5).join("\n")}`);
1280
1282
  this.push("status", "runtime clean \u2014 no console errors, exceptions, or failed requests");
1281
1283
  }
1282
1284
  }
1285
+ if (result.phantoms && result.phantoms.length > 0) {
1286
+ this.push("error", `phantom classes: ${result.phantoms.length} (in the DOM, absent from CSS)
1287
+ ${result.phantoms.slice(0, 5).join("\n")}`);
1288
+ this.addProblem(
1289
+ "runtime",
1290
+ `${result.phantoms.length} phantom class(es) \u2014 elements silently unstyled`,
1291
+ `These class tokens appear in the DOM but match no CSS rule, so the elements are silently unstyled. Usually a misspelled or version-mismatched utility (e.g. Tailwind v3 spellings in a v4 project) or a concatenated class the scanner never compiled:
1292
+
1293
+ ${result.phantoms.join("\n")}
1294
+
1295
+ Fix the class names or define the styles, then confirm visually.`
1296
+ );
1297
+ this.push("status", "/fix sends open problems to the engine");
1298
+ }
1283
1299
  if (result.slop && result.slop.length > 0) {
1284
1300
  this.push("status", `distinctiveness: ${result.slop.length} tell(s)
1285
1301
  ${result.slop.join("\n")}`);
@@ -1395,6 +1411,19 @@ They are objective defects, not style preferences.`
1395
1411
  }
1396
1412
  break;
1397
1413
  }
1414
+ case "decide": {
1415
+ if (!arg) {
1416
+ this.push("status", "usage: /decide <the decision> \u2014 recorded in .squint/design-log.jsonl and injected into every future ask");
1417
+ break;
1418
+ }
1419
+ appendDecision(this.opts.cwd, {
1420
+ decision: arg,
1421
+ source: "decide",
1422
+ screenshot: this.lastPulse ? ".squint/preview/pulse.png" : void 0
1423
+ });
1424
+ this.push("status", `decision recorded: ${arg}`);
1425
+ break;
1426
+ }
1398
1427
  case "find": {
1399
1428
  if (!arg) {
1400
1429
  this.push("status", "usage: /find <term> \u2014 searches this session and saved transcripts");
@@ -1491,8 +1520,8 @@ They are objective defects, not style preferences.`
1491
1520
  this.push("error", "no Chrome/Chromium found for flows");
1492
1521
  return;
1493
1522
  }
1494
- const { runFlow } = await import("./cdp-UGLMW5R5.js");
1495
- const { previewDir } = await import("./preview-6MML2NEG.js");
1523
+ const { runFlow } = await import("./cdp-TPP2RGSR.js");
1524
+ const { previewDir } = await import("./preview-SKHIXVCE.js");
1496
1525
  this.push("status", `replaying ${flows.length} flow(s)\u2026`);
1497
1526
  this.notify({ running: true, runStartedAt: Date.now() });
1498
1527
  const failures = [];
@@ -1630,7 +1659,7 @@ They are objective defects, not style preferences.`
1630
1659
  const result = await this.capture();
1631
1660
  if (result) {
1632
1661
  await this.runTurn(
1633
- buildReviewPrompt(result.shots, arg || void 0, result.runtime, result.a11y, result.slop, result.narration),
1662
+ buildReviewPrompt(result.shots, arg || void 0, result.runtime, result.a11y, result.slop, result.narration, result.phantoms),
1634
1663
  `\u{1F441} review rendered UI${arg ? ` \xB7 ${arg}` : ""}`
1635
1664
  );
1636
1665
  }
@@ -1709,6 +1738,7 @@ ${sandboxFiles(this.opts.cwd).join("\n")}`);
1709
1738
  discardSandbox(this.opts.cwd);
1710
1739
  this.notify({ sandbox: false });
1711
1740
  this.resetDevServer();
1741
+ appendDecision(this.opts.cwd, { decision: "accepted the sandboxed session onto the real tree", source: "sandbox" });
1712
1742
  this.push("status", "sandbox applied to the real tree \u2014 review with git diff");
1713
1743
  } else {
1714
1744
  this.push("error", applied.detail ?? "apply failed");
@@ -1750,6 +1780,7 @@ ${sandboxFiles(this.opts.cwd).join("\n")}`);
1750
1780
  const applied = applyVariant(this.opts.cwd, id);
1751
1781
  if (applied.ok) {
1752
1782
  cleanVariants(this.opts.cwd);
1783
+ appendDecision(this.opts.cwd, { decision: `chose the ${id} direction over the other variants`, source: "variant" });
1753
1784
  this.push("status", `applied ${id} to the working tree \u2014 review with git diff`);
1754
1785
  } else {
1755
1786
  this.push("error", applied.detail ?? "apply failed");
@@ -1814,7 +1845,7 @@ ${sandboxFiles(this.opts.cwd).join("\n")}`);
1814
1845
  this.notify({ items: [], totals: { costUsd: 0, turns: 0 } });
1815
1846
  break;
1816
1847
  case "help": {
1817
- void import("./commands-DE5Q7VWY.js").then(({ commandHelp }) => this.push("status", commandHelp()));
1848
+ void import("./commands-B6I6C5LP.js").then(({ commandHelp }) => this.push("status", commandHelp()));
1818
1849
  break;
1819
1850
  }
1820
1851
  case "quit":
@@ -2433,7 +2464,7 @@ function registerTui(program2) {
2433
2464
  }
2434
2465
 
2435
2466
  // src/cli.tsx
2436
- var VERSION = true ? "0.4.1" : "0.0.0-dev";
2467
+ var VERSION = true ? "0.4.2" : "0.0.0-dev";
2437
2468
  var program = new Command();
2438
2469
  program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
2439
2470
  registerRun(program);
@@ -3,7 +3,7 @@ import {
3
3
  COMMANDS,
4
4
  commandHelp,
5
5
  completeCommand
6
- } from "./chunk-SVKV77TO.js";
6
+ } from "./chunk-S3WV5C3X.js";
7
7
  export {
8
8
  COMMANDS,
9
9
  commandHelp,
@@ -10,11 +10,11 @@ import {
10
10
  probeRuntime,
11
11
  routeShotName,
12
12
  runtimeSummary
13
- } from "./chunk-UTBTLCUO.js";
13
+ } from "./chunk-WCLQZFOR.js";
14
14
  import "./chunk-O2S6PAJE.js";
15
15
  import "./chunk-IMDRXXFU.js";
16
16
  import "./chunk-KVYGPLWW.js";
17
- import "./chunk-7YKO5MMN.js";
17
+ import "./chunk-Y47X4ENN.js";
18
18
  export {
19
19
  VIEWPORTS,
20
20
  buildReviewPrompt,
@@ -6,7 +6,7 @@ import {
6
6
  loadSkills,
7
7
  matchSkills,
8
8
  parseSkill
9
- } from "./chunk-H5K55LXY.js";
9
+ } from "./chunk-KGZILC3S.js";
10
10
  export {
11
11
  enrich,
12
12
  loadLocks,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aayambansal/squint",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
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",