@aayambansal/squint 0.3.2 → 0.3.4

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.
@@ -3,7 +3,7 @@ import {
3
3
  cdpCapture,
4
4
  hasWebSocket,
5
5
  pixelDiffPct
6
- } from "./chunk-DAETGO2M.js";
6
+ } from "./chunk-XOVOQJFL.js";
7
7
  export {
8
8
  cdpCapture,
9
9
  hasWebSocket,
@@ -23,6 +23,7 @@ var COMMANDS = [
23
23
  { name: "btw", args: "<question>", group: "session", description: "read-only side question; the main thread is untouched" },
24
24
  { name: "copy", group: "session", description: "copy the last reply to the clipboard" },
25
25
  { name: "save", group: "session", description: "export the transcript to .squint/transcripts/" },
26
+ { name: "find", args: "<term>", group: "session", description: "search this session and saved transcripts" },
26
27
  { name: "resume", group: "session", description: "pick up the previous session for this repo" },
27
28
  { name: "clear", group: "session", description: "new session (transcript, totals, persisted state)" },
28
29
  { name: "help", group: "session", description: "list commands" },
@@ -1,8 +1,41 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/prompt/skills.ts
4
+ import fs2 from "fs";
5
+ import path2 from "path";
6
+
7
+ // src/prompt/registry.ts
4
8
  import fs from "fs";
5
9
  import path from "path";
10
+ function loadComponentInventory(cwd) {
11
+ let config;
12
+ try {
13
+ config = JSON.parse(fs.readFileSync(path.join(cwd, "components.json"), "utf8"));
14
+ } catch {
15
+ return null;
16
+ }
17
+ const alias = config.aliases?.ui ?? (config.aliases?.components ? `${config.aliases.components}/ui` : "@/components/ui");
18
+ const relative = alias.replace(/^@\//, "src/").replace(/^~\//, "");
19
+ const uiDir = path.join(cwd, relative);
20
+ let entries;
21
+ try {
22
+ entries = fs.readdirSync(uiDir);
23
+ } catch {
24
+ return null;
25
+ }
26
+ const components = entries.filter((f) => /\.(tsx|jsx|vue|svelte)$/.test(f)).map((f) => f.replace(/\.[^.]+$/, "")).sort();
27
+ if (components.length === 0) return null;
28
+ return { components, uiDir: relative };
29
+ }
30
+ function inventorySection(inventory) {
31
+ return `## Installed UI components (${inventory.uiDir})
32
+
33
+ ${inventory.components.join(" \xB7 ")}
34
+
35
+ Compose from these before writing new primitives. More are one command away: \`npx shadcn@latest add <name>\`. Never invent props for these components \u2014 read the file when unsure.`;
36
+ }
37
+
38
+ // src/prompt/skills.ts
6
39
  var FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?/;
7
40
  function parseSkill(name, raw) {
8
41
  const match = FRONTMATTER_RE.exec(raw);
@@ -22,17 +55,17 @@ function parseSkill(name, raw) {
22
55
  return { name, triggers, body };
23
56
  }
24
57
  function loadSkills(cwd) {
25
- const dir = path.join(cwd, ".squint", "skills");
58
+ const dir = path2.join(cwd, ".squint", "skills");
26
59
  let entries;
27
60
  try {
28
- entries = fs.readdirSync(dir).filter((f) => f.endsWith(".md"));
61
+ entries = fs2.readdirSync(dir).filter((f) => f.endsWith(".md"));
29
62
  } catch {
30
63
  return [];
31
64
  }
32
65
  const skills = [];
33
66
  for (const entry of entries.sort()) {
34
67
  try {
35
- const skill = parseSkill(entry.replace(/\.md$/, ""), fs.readFileSync(path.join(dir, entry), "utf8"));
68
+ const skill = parseSkill(entry.replace(/\.md$/, ""), fs2.readFileSync(path2.join(dir, entry), "utf8"));
36
69
  if (skill) skills.push(skill);
37
70
  } catch {
38
71
  }
@@ -41,7 +74,7 @@ function loadSkills(cwd) {
41
74
  }
42
75
  function loadRules(cwd) {
43
76
  try {
44
- const text = fs.readFileSync(path.join(cwd, ".squint", "rules.md"), "utf8").trim();
77
+ const text = fs2.readFileSync(path2.join(cwd, ".squint", "rules.md"), "utf8").trim();
45
78
  return text.length > 0 ? text : null;
46
79
  } catch {
47
80
  return null;
@@ -53,7 +86,7 @@ function matchSkills(skills, ask) {
53
86
  }
54
87
  function loadLocks(cwd) {
55
88
  try {
56
- return fs.readFileSync(path.join(cwd, ".squint", "locks"), "utf8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
89
+ return fs2.readFileSync(path2.join(cwd, ".squint", "locks"), "utf8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
57
90
  } catch {
58
91
  return [];
59
92
  }
@@ -64,6 +97,8 @@ function enrich(cwd, ask) {
64
97
  if (rules) parts.push(`## Project rules (always apply)
65
98
 
66
99
  ${rules}`);
100
+ const inventory = loadComponentInventory(cwd);
101
+ if (inventory) parts.push(inventorySection(inventory));
67
102
  const locks = loadLocks(cwd);
68
103
  if (locks.length > 0) {
69
104
  parts.push(
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  cdpCapture,
8
8
  hasWebSocket
9
- } from "./chunk-DAETGO2M.js";
9
+ } from "./chunk-XOVOQJFL.js";
10
10
  import {
11
11
  ensureSquintIgnore
12
12
  } from "./chunk-O2S6PAJE.js";
@@ -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 } = await cdpCapture(chrome, url, dir, VIEWPORTS, 2500, true);
50
+ const { report, shots: shots2, a11y, slop, narration } = 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 };
65
+ return { shots: shots2, errors: errors2, runtime: report, a11y, slop, narration };
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-2XAU5MEA.js");
136
+ const { pixelDiffPct } = await import("./cdp-UOIP4ZQZ.js");
137
137
  return pixelDiffPct(chrome, previous, current);
138
138
  }
139
139
  function buildRuntimeFixPrompt(report) {
@@ -151,6 +151,16 @@ ${findings.join("\n")}
151
151
 
152
152
  Fix these as part of the pass \u2014 they are objective defects, not style preferences.`;
153
153
  }
154
+ function narrationSection(narration) {
155
+ if (!narration || narration.length === 0) return "";
156
+ return `
157
+
158
+ ## What a screen reader would say (accessibility tree, in order)
159
+
160
+ ${narration.join("\n")}
161
+
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
+ }
154
164
  function slopSection(findings) {
155
165
  if (!findings || findings.length === 0) return "";
156
166
  return `
@@ -161,13 +171,13 @@ ${findings.join("\n")}
161
171
 
162
172
  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.`;
163
173
  }
164
- function buildReviewPrompt(shots, extra, runtime, a11y, slop) {
174
+ function buildReviewPrompt(shots, extra, runtime, a11y, slop, narration) {
165
175
  const list = shots.map((s) => `- ${s.name}: ${s.path}`).join("\n");
166
176
  return `Screenshots of the running app were just captured:
167
177
 
168
178
  ${list}
169
179
 
170
- 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)}`;
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)}`;
171
181
  }
172
182
 
173
183
  export {
@@ -278,6 +278,7 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
278
278
  let a11y = [];
279
279
  let slop = [];
280
280
  let perf = {};
281
+ let narration = [];
281
282
  const requests = /* @__PURE__ */ new Map();
282
283
  let connection = null;
283
284
  try {
@@ -350,6 +351,47 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
350
351
  if (Array.isArray(result?.value)) slop = result.value.map(String);
351
352
  } catch {
352
353
  }
354
+ try {
355
+ await connection.send("Accessibility.enable", {}, sessionId);
356
+ const { nodes } = await connection.send("Accessibility.getFullAXTree", {}, sessionId);
357
+ const interesting = /* @__PURE__ */ new Set([
358
+ "heading",
359
+ "link",
360
+ "button",
361
+ "textbox",
362
+ "checkbox",
363
+ "radio",
364
+ "combobox",
365
+ "listbox",
366
+ "img",
367
+ "image",
368
+ "navigation",
369
+ "main",
370
+ "banner",
371
+ "contentinfo",
372
+ "form",
373
+ "search",
374
+ "tab",
375
+ "menuitem",
376
+ "switch",
377
+ "slider",
378
+ "alert",
379
+ "dialog",
380
+ "list"
381
+ ]);
382
+ if (Array.isArray(nodes)) {
383
+ for (const node of nodes) {
384
+ if (node.ignored) continue;
385
+ const role = node.role?.value;
386
+ if (!role || !interesting.has(role)) continue;
387
+ const name = (node.name?.value ?? "").toString().trim().replace(/\s+/g, " ").slice(0, 80);
388
+ const level = node.properties?.find((p) => p.name === "level")?.value?.value;
389
+ narration.push(`${role}${level ? ` ${level}` : ""}${name ? `: "${name}"` : " (no accessible name)"}`);
390
+ if (narration.length >= 80) break;
391
+ }
392
+ }
393
+ } catch {
394
+ }
353
395
  }
354
396
  for (const viewport of viewports) {
355
397
  await connection.send(
@@ -373,7 +415,7 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
373
415
  child.kill("SIGKILL");
374
416
  setTimeout(() => fs.rmSync(profileDir, { recursive: true, force: true }), 500).unref?.();
375
417
  }
376
- return { report, shots, a11y, slop, perf };
418
+ return { report, shots, a11y, slop, perf, narration };
377
419
  }
378
420
 
379
421
  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-S2ODU4MN.js";
4
+ } from "./chunk-BNJGHNXB.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-OTCH66M7.js";
45
+ } from "./chunk-SXF7CVRW.js";
46
46
  import {
47
47
  runAgent
48
48
  } from "./chunk-VH7OOFQP.js";
@@ -53,10 +53,10 @@ import {
53
53
  detectEngines,
54
54
  getEngine
55
55
  } from "./chunk-KVYGPLWW.js";
56
- import "./chunk-DAETGO2M.js";
56
+ import "./chunk-XOVOQJFL.js";
57
57
  import {
58
58
  enrich
59
- } from "./chunk-4LAU5TGK.js";
59
+ } from "./chunk-H5K55LXY.js";
60
60
  import {
61
61
  composePrompt
62
62
  } from "./chunk-P3H4N2EN.js";
@@ -96,6 +96,8 @@ var ConfigSchema = z.object({
96
96
  budgetUsd: z.number().positive().optional(),
97
97
  /** Auto-run /review when the visual pulse shows a big change (default off). */
98
98
  autoReview: z.boolean().optional(),
99
+ /** Cheaper model used for auto-fix and /fix turns (mechanical work). */
100
+ fixModel: z.string().optional(),
99
101
  /** TUI theme name (amber, ocean, moss, rose, mono). */
100
102
  theme: z.string().optional()
101
103
  });
@@ -138,7 +140,7 @@ function resolveModel(config, engineId, override) {
138
140
  function setConfigValue(file, key, value) {
139
141
  const current = readConfigFile(file);
140
142
  let next;
141
- if (key === "engine" || key === "theme") {
143
+ if (key === "engine" || key === "theme" || key === "fixModel") {
142
144
  next = { ...current, [key]: value };
143
145
  } else if (key === "autoDev" || key === "autoFix" || key === "autoProbe" || key === "autoCheck" || key === "autoReview" || key === "bell") {
144
146
  if (value !== "true" && value !== "false") {
@@ -157,7 +159,7 @@ function setConfigValue(file, key, value) {
157
159
  next = { ...current, models: { ...current.models, [engineId]: value } };
158
160
  } else {
159
161
  throw new Error(
160
- `Unknown config key "${key}". Supported: engine, theme, autoDev, autoFix, autoProbe, autoCheck, autoReview, bell, budgetUsd, models.<engineId>`
162
+ `Unknown config key "${key}". Supported: engine, theme, autoDev, autoFix, autoProbe, autoCheck, autoReview, bell, budgetUsd, fixModel, models.<engineId>`
161
163
  );
162
164
  }
163
165
  fs.mkdirSync(path.dirname(file), { recursive: true });
@@ -236,7 +238,7 @@ function registerEnv(program2) {
236
238
  }
237
239
  }
238
240
  const { findChrome: findChrome2 } = await import("./chrome-SBV3H77F.js");
239
- const { hasWebSocket } = await import("./cdp-2XAU5MEA.js");
241
+ const { hasWebSocket } = await import("./cdp-UOIP4ZQZ.js");
240
242
  const chrome = findChrome2();
241
243
  console.log(
242
244
  chrome ? `${pc2.green("\u2713")} Chrome ${pc2.dim(chrome)}` : `${pc2.yellow("\u25CB")} Chrome ${pc2.dim("\u2014 screenshots and runtime probing disabled")}`
@@ -260,7 +262,7 @@ import pc3 from "picocolors";
260
262
  function registerProject(program2) {
261
263
  const skillsCommand = program2.command("skills").description("Project knowledge injected into asks (.squint/rules.md + .squint/skills/)");
262
264
  skillsCommand.command("list").description("Show always-on rules and trigger-matched skills").action(async () => {
263
- const { loadRules, loadSkills } = await import("./skills-DNBHZAAU.js");
265
+ const { loadRules, loadSkills } = await import("./skills-ODOVNE6E.js");
264
266
  const cwd = process.cwd();
265
267
  const rules = loadRules(cwd);
266
268
  console.log(
@@ -459,7 +461,7 @@ function registerQuality(program2) {
459
461
  if (results.some((r) => !r.ok)) process.exitCode = 1;
460
462
  });
461
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) => {
462
- const { captureViewports: captureViewports2 } = await import("./preview-PS7WJ2KO.js");
464
+ const { captureViewports: captureViewports2 } = await import("./preview-S6FOTRRR.js");
463
465
  const result = await captureViewports2(process.cwd(), url);
464
466
  if (!result) {
465
467
  console.error(pc4.red("\u2717 no Chrome/Chromium found"));
@@ -756,10 +758,11 @@ var Session = class {
756
758
  dispatchFix(problems) {
757
759
  if (problems.length === 0) return;
758
760
  const prompt = this.combinedFixPrompt(problems);
759
- const display = `\u26D1 fix: ${problems.map((p) => p.source).join(" + ")}`;
761
+ const fixModel = this.opts.fixModel;
762
+ const display = `\u26D1 fix: ${problems.map((p) => p.source).join(" + ")}${fixModel ? ` \xB7 ${fixModel}` : ""}`;
760
763
  for (const problem of problems) this.problemPrompts.delete(problem.id);
761
764
  this.notify({ problems: this.state.problems.filter((p) => !problems.includes(p)) });
762
- void this.runTurn(prompt, display);
765
+ void this.runTurn(prompt, display, fixModel);
763
766
  }
764
767
  /** Launch a capped auto-fix turn over all open problems. Returns true if launched. */
765
768
  maybeAutoFix() {
@@ -820,7 +823,7 @@ ${question}`,
820
823
  return;
821
824
  }
822
825
  await this.runTurn(
823
- buildReviewPrompt(result.shots, void 0, result.runtime, result.a11y, result.slop),
826
+ buildReviewPrompt(result.shots, void 0, result.runtime, result.a11y, result.slop, result.narration),
824
827
  `\u{1F441} polish round ${round}/${rounds}`
825
828
  );
826
829
  }
@@ -1006,7 +1009,7 @@ ${question}`,
1006
1009
  }
1007
1010
  };
1008
1011
  /** Run one engine turn. `display` is what the transcript shows as the ask. */
1009
- async runTurn(prompt, display) {
1012
+ async runTurn(prompt, display, modelOverride) {
1010
1013
  this.push("user", display);
1011
1014
  this.turnEdits = 0;
1012
1015
  this.turnTools = 0;
@@ -1019,7 +1022,7 @@ ${question}`,
1019
1022
  {
1020
1023
  prompt,
1021
1024
  cwd: this.execCwd(),
1022
- model: this.state.model,
1025
+ model: modelOverride ?? this.state.model,
1023
1026
  mode: this.state.mode,
1024
1027
  sessionId: engine.supportsResume ? this.sessionId : void 0
1025
1028
  },
@@ -1138,7 +1141,7 @@ ${errors.slice(-5).join("\n")}`);
1138
1141
  const captureResult = await this.capture();
1139
1142
  if (captureResult) {
1140
1143
  await this.runTurn(
1141
- buildReviewPrompt(captureResult.shots, void 0, captureResult.runtime, captureResult.a11y, captureResult.slop),
1144
+ buildReviewPrompt(captureResult.shots, void 0, captureResult.runtime, captureResult.a11y, captureResult.slop, captureResult.narration),
1142
1145
  "\u{1F441} auto-review rendered UI"
1143
1146
  );
1144
1147
  }
@@ -1392,6 +1395,50 @@ They are objective defects, not style preferences.`
1392
1395
  }
1393
1396
  break;
1394
1397
  }
1398
+ case "find": {
1399
+ if (!arg) {
1400
+ this.push("status", "usage: /find <term> \u2014 searches this session and saved transcripts");
1401
+ break;
1402
+ }
1403
+ const needle = arg.toLowerCase();
1404
+ const matches = [];
1405
+ for (const item of this.state.items) {
1406
+ if ((item.role === "user" || item.role === "assistant") && item.text.toLowerCase().includes(needle)) {
1407
+ const line = item.text.split("\n").find((l) => l.toLowerCase().includes(needle)) ?? item.text;
1408
+ matches.push(`[live] ${item.role === "user" ? "\u276F " : ""}${line.trim().slice(0, 90)}`);
1409
+ if (matches.length >= 8) break;
1410
+ }
1411
+ }
1412
+ if (matches.length < 8) {
1413
+ void (async () => {
1414
+ try {
1415
+ const fs3 = await import("fs");
1416
+ const path5 = await import("path");
1417
+ const dir = path5.join(this.opts.cwd, ".squint", "transcripts");
1418
+ const files = fs3.readdirSync(dir).filter((f) => f.endsWith(".md")).sort().reverse().slice(0, 20);
1419
+ for (const file of files) {
1420
+ if (matches.length >= 8) break;
1421
+ const text = fs3.readFileSync(path5.join(dir, file), "utf8");
1422
+ for (const line of text.split("\n")) {
1423
+ if (line.toLowerCase().includes(needle)) {
1424
+ matches.push(`[${file.replace(/\.md$/, "")}] ${line.trim().slice(0, 90)}`);
1425
+ break;
1426
+ }
1427
+ }
1428
+ }
1429
+ } catch {
1430
+ }
1431
+ this.push(
1432
+ "status",
1433
+ matches.length > 0 ? `${matches.join("\n")}
1434
+ /checkpoints can rewind \xB7 /save archives this session` : `no matches for "${arg}"`
1435
+ );
1436
+ })();
1437
+ } else {
1438
+ this.push("status", matches.join("\n"));
1439
+ }
1440
+ break;
1441
+ }
1395
1442
  case "save": {
1396
1443
  void (async () => {
1397
1444
  const fs3 = await import("fs");
@@ -1508,7 +1555,7 @@ They are objective defects, not style preferences.`
1508
1555
  const result = await this.capture();
1509
1556
  if (result) {
1510
1557
  await this.runTurn(
1511
- buildReviewPrompt(result.shots, arg || void 0, result.runtime, result.a11y, result.slop),
1558
+ buildReviewPrompt(result.shots, arg || void 0, result.runtime, result.a11y, result.slop, result.narration),
1512
1559
  `\u{1F441} review rendered UI${arg ? ` \xB7 ${arg}` : ""}`
1513
1560
  );
1514
1561
  }
@@ -1692,7 +1739,7 @@ ${sandboxFiles(this.opts.cwd).join("\n")}`);
1692
1739
  this.notify({ items: [], totals: { costUsd: 0, turns: 0 } });
1693
1740
  break;
1694
1741
  case "help": {
1695
- void import("./commands-Y5RUKBPS.js").then(({ commandHelp }) => this.push("status", commandHelp()));
1742
+ void import("./commands-3HHBHBQV.js").then(({ commandHelp }) => this.push("status", commandHelp()));
1696
1743
  break;
1697
1744
  }
1698
1745
  case "quit":
@@ -2063,6 +2110,7 @@ function App({
2063
2110
  autoProbe,
2064
2111
  autoCheck,
2065
2112
  autoReview,
2113
+ fixModel,
2066
2114
  bell,
2067
2115
  budgetUsd,
2068
2116
  initialTheme
@@ -2081,6 +2129,7 @@ function App({
2081
2129
  autoProbe,
2082
2130
  autoCheck,
2083
2131
  autoReview,
2132
+ fixModel,
2084
2133
  budgetUsd,
2085
2134
  // Delay lets the goodbye summary land in the Static scrollback.
2086
2135
  onQuit: () => setTimeout(() => exit(), 60)
@@ -2298,6 +2347,7 @@ function registerTui(program2) {
2298
2347
  autoProbe: config.autoProbe,
2299
2348
  autoCheck: config.autoCheck,
2300
2349
  autoReview: config.autoReview,
2350
+ fixModel: config.fixModel,
2301
2351
  bell: config.bell,
2302
2352
  budgetUsd: config.budgetUsd,
2303
2353
  initialTheme: theme2
@@ -2308,7 +2358,7 @@ function registerTui(program2) {
2308
2358
  }
2309
2359
 
2310
2360
  // src/cli.tsx
2311
- var VERSION = true ? "0.3.2" : "0.0.0-dev";
2361
+ var VERSION = true ? "0.3.4" : "0.0.0-dev";
2312
2362
  var program = new Command();
2313
2363
  program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
2314
2364
  registerRun(program);
@@ -3,7 +3,7 @@ import {
3
3
  COMMANDS,
4
4
  commandHelp,
5
5
  completeCommand
6
- } from "./chunk-S2ODU4MN.js";
6
+ } from "./chunk-BNJGHNXB.js";
7
7
  export {
8
8
  COMMANDS,
9
9
  commandHelp,
@@ -10,10 +10,10 @@ import {
10
10
  probeRuntime,
11
11
  routeShotName,
12
12
  runtimeSummary
13
- } from "./chunk-OTCH66M7.js";
13
+ } from "./chunk-SXF7CVRW.js";
14
14
  import "./chunk-IMDRXXFU.js";
15
15
  import "./chunk-KVYGPLWW.js";
16
- import "./chunk-DAETGO2M.js";
16
+ import "./chunk-XOVOQJFL.js";
17
17
  import "./chunk-O2S6PAJE.js";
18
18
  export {
19
19
  VIEWPORTS,
@@ -6,7 +6,7 @@ import {
6
6
  loadSkills,
7
7
  matchSkills,
8
8
  parseSkill
9
- } from "./chunk-4LAU5TGK.js";
9
+ } from "./chunk-H5K55LXY.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.3.2",
3
+ "version": "0.3.4",
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",