@aayambansal/squint 0.2.4 → 0.2.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 CHANGED
@@ -225,6 +225,8 @@ All product behavior lives in the harness, so a new engine is ~80 lines.
225
225
 
226
226
  ## Docs
227
227
 
228
+ - [Engine setup guide](./docs/engines.md) — install + auth for all eight, and how to choose
229
+ - [Configuration](./docs/configuration.md) — every key, every `.squint/` file
228
230
  - [Architecture](./docs/design/2026-07-25-architecture.md)
229
231
  - [How Lovable works under the hood](./docs/research/lovable.md)
230
232
  - [Making agents produce excellent frontend work](./docs/research/frontend-quality.md)
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/tui/background.ts
4
+ function parseOsc11(reply) {
5
+ const match = /rgb:([0-9a-fA-F]{2,4})\/([0-9a-fA-F]{2,4})\/([0-9a-fA-F]{2,4})/.exec(reply);
6
+ if (!match) return "unknown";
7
+ const channel = (hex) => Number.parseInt(hex.slice(0, 2), 16);
8
+ const [r, g, b] = [channel(match[1]), channel(match[2]), channel(match[3])];
9
+ const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
10
+ return luminance > 140 ? "light" : "dark";
11
+ }
12
+ function detectBackground(timeoutMs = 300) {
13
+ return new Promise((resolve) => {
14
+ const { stdin, stdout } = process;
15
+ if (!stdin.isTTY || !stdout.isTTY) return resolve("unknown");
16
+ let buffer = "";
17
+ const finish = (result) => {
18
+ clearTimeout(timer);
19
+ stdin.off("data", onData);
20
+ resolve(result);
21
+ };
22
+ const onData = (chunk) => {
23
+ buffer += chunk.toString("utf8");
24
+ if (buffer.includes("rgb:")) {
25
+ const parsed = parseOsc11(buffer);
26
+ if (parsed !== "unknown") finish(parsed);
27
+ }
28
+ };
29
+ const timer = setTimeout(() => finish("unknown"), timeoutMs);
30
+ stdin.on("data", onData);
31
+ try {
32
+ stdout.write("\x1B]11;?\x07");
33
+ } catch {
34
+ finish("unknown");
35
+ }
36
+ });
37
+ }
38
+ export {
39
+ detectBackground,
40
+ parseOsc11
41
+ };
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  findChrome,
4
4
  screenshot
5
- } from "./chunk-P3V5CWH5.js";
6
- import "./chunk-2LRIKWBU.js";
5
+ } from "./chunk-B7LOERSP.js";
6
+ import "./chunk-BWZFACBT.js";
7
7
  export {
8
8
  findChrome,
9
9
  screenshot
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  variantsRoot
4
- } from "./chunk-LCS47EAG.js";
4
+ } from "./chunk-LVA2OQSR.js";
5
5
  import {
6
6
  findChrome,
7
7
  screenshot
8
- } from "./chunk-P3V5CWH5.js";
8
+ } from "./chunk-B7LOERSP.js";
9
9
  import {
10
10
  lineSplitter
11
- } from "./chunk-2LRIKWBU.js";
11
+ } from "./chunk-BWZFACBT.js";
12
12
 
13
13
  // src/variants/shots.ts
14
14
  import path2 from "path";
@@ -79,12 +79,19 @@ var DevServer = class {
79
79
  callbacks;
80
80
  child = null;
81
81
  lines = [];
82
+ lastCommand = null;
83
+ restarts = 0;
82
84
  state = "stopped";
83
85
  url = null;
84
86
  start(command) {
87
+ this.restarts = 0;
88
+ return this.launch(command);
89
+ }
90
+ launch(command) {
85
91
  if (this.child) return true;
86
92
  const cmd = command ?? detectDevCommand(this.cwd);
87
93
  if (!cmd) return false;
94
+ this.lastCommand = cmd;
88
95
  this.setState("starting");
89
96
  this.lines = [];
90
97
  this.url = null;
@@ -118,7 +125,14 @@ var DevServer = class {
118
125
  });
119
126
  child.on("close", () => {
120
127
  this.child = null;
121
- if (this.state !== "stopped") this.setState("crashed");
128
+ if (this.state === "stopped") return;
129
+ this.setState("crashed");
130
+ if (this.restarts < 1 && this.lastCommand) {
131
+ this.restarts += 1;
132
+ setTimeout(() => {
133
+ if (this.state === "crashed") this.launch(this.lastCommand);
134
+ }, 1e3);
135
+ }
122
136
  });
123
137
  return true;
124
138
  }
@@ -39,6 +39,20 @@ function detectGates(cwd) {
39
39
  } else if (hasEslintConfig) {
40
40
  gates.push({ id: "lint", command: "npx", args: ["eslint", ".", "--max-warnings", "0"], display: "eslint ." });
41
41
  }
42
+ const hasPrettier = [
43
+ ".prettierrc",
44
+ ".prettierrc.json",
45
+ ".prettierrc.js",
46
+ ".prettierrc.yaml",
47
+ ".prettierrc.yml",
48
+ "prettier.config.js",
49
+ "prettier.config.mjs"
50
+ ].some((file) => fs.existsSync(path.join(cwd, file)));
51
+ if (scripts.format && /--check|-c\b/.test(scripts.format)) {
52
+ gates.push({ id: "format", ...npmRun("format") });
53
+ } else if (hasPrettier) {
54
+ gates.push({ id: "format", command: "npx", args: ["prettier", "--check", "."], display: "prettier --check ." });
55
+ }
42
56
  const testScript = scripts.test;
43
57
  if (testScript && !/no test specified/i.test(testScript)) {
44
58
  gates.push({ id: "test", ...npmRun("test") });
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  findBinary
4
- } from "./chunk-2LRIKWBU.js";
4
+ } from "./chunk-BWZFACBT.js";
5
5
 
6
6
  // src/preview/chrome.ts
7
7
  import { spawn } from "child_process";
@@ -1,5 +1,24 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/engines/registry.ts
4
+ import fs from "fs";
5
+ import path from "path";
6
+
7
+ // src/engines/aider.ts
8
+ var aider = {
9
+ id: "aider",
10
+ name: "Aider",
11
+ binary: "aider",
12
+ install: "python -m pip install aider-install && aider-install",
13
+ supportsResume: false,
14
+ buildArgs(opts) {
15
+ const args = ["--message", opts.prompt, "--yes-always", "--no-auto-commits"];
16
+ if (opts.mode === "plan") args.push("--dry-run");
17
+ if (opts.model) args.push("--model", opts.model);
18
+ return args;
19
+ }
20
+ };
21
+
3
22
  // src/util/stream.ts
4
23
  function lineSplitter(onLine) {
5
24
  let buffer = "";
@@ -24,24 +43,6 @@ function truncate(text, max) {
24
43
  return text.slice(0, max - 1) + "\u2026";
25
44
  }
26
45
 
27
- // src/engines/registry.ts
28
- import fs from "fs";
29
- import path from "path";
30
-
31
- // src/engines/aider.ts
32
- var aider = {
33
- id: "aider",
34
- name: "Aider",
35
- binary: "aider",
36
- install: "python -m pip install aider-install && aider-install",
37
- supportsResume: false,
38
- buildArgs(opts) {
39
- const args = ["--message", opts.prompt, "--yes-always", "--no-auto-commits"];
40
- if (opts.model) args.push("--model", opts.model);
41
- return args;
42
- }
43
- };
44
-
45
46
  // src/engines/claudeProtocol.ts
46
47
  function createClaudeStreamParser(readyLabel) {
47
48
  let sawTextDelta = false;
@@ -123,10 +124,9 @@ var amp = {
123
124
  install: "npm install -g @sourcegraph/amp",
124
125
  supportsResume: true,
125
126
  buildArgs(opts) {
126
- if (opts.sessionId) {
127
- return ["threads", "continue", "--execute", opts.prompt, "--stream-json"];
128
- }
129
- return ["-x", opts.prompt, "--stream-json"];
127
+ const args = opts.sessionId ? ["threads", "continue", "--execute", opts.prompt, "--stream-json"] : ["-x", opts.prompt, "--stream-json"];
128
+ if (opts.mode === "yolo") args.push("--dangerously-allow-all");
129
+ return args;
130
130
  },
131
131
  createParser: () => createClaudeStreamParser("amp")
132
132
  };
@@ -265,7 +265,8 @@ var copilot = {
265
265
  install: "npm install -g @github/copilot",
266
266
  supportsResume: false,
267
267
  buildArgs(opts) {
268
- const args = ["-p", opts.prompt, "-s", "--allow-all-tools"];
268
+ const args = ["-p", opts.prompt, "-s"];
269
+ if (opts.mode !== "plan") args.push("--allow-all-tools");
269
270
  if (opts.model) args.push("--model", opts.model);
270
271
  return args;
271
272
  }
@@ -299,9 +300,48 @@ var gemini = {
299
300
  supportsResume: false,
300
301
  buildArgs(opts) {
301
302
  const approval = opts.mode === "plan" ? "plan" : opts.mode === "yolo" ? "yolo" : "auto_edit";
302
- const args = ["-p", opts.prompt, "--approval-mode", approval];
303
+ const args = ["-p", opts.prompt, "--output-format", "stream-json", "--approval-mode", approval];
303
304
  if (opts.model) args.push("-m", opts.model);
304
305
  return args;
306
+ },
307
+ createParser() {
308
+ return (line) => {
309
+ let data;
310
+ try {
311
+ data = JSON.parse(line);
312
+ } catch {
313
+ return [{ type: "text", text: line }];
314
+ }
315
+ switch (data?.type) {
316
+ case "init":
317
+ return [{ type: "status", text: `gemini ready${data.model ? ` \xB7 ${data.model}` : ""}` }];
318
+ case "message": {
319
+ if (data.role && data.role !== "assistant" && data.role !== "model") return [];
320
+ const text = data.content ?? data.text ?? data.delta;
321
+ return typeof text === "string" && text.length > 0 ? [{ type: "text", text }] : [];
322
+ }
323
+ case "tool_use": {
324
+ const name = data.name ?? data.tool_name ?? "tool";
325
+ const input = data.args ?? data.input;
326
+ const detail = input && typeof input === "object" ? truncate(JSON.stringify(input), 80) : void 0;
327
+ return [{ type: "tool", name, detail }];
328
+ }
329
+ case "tool_result":
330
+ return [];
331
+ case "error":
332
+ return data.fatal === false ? [] : [{ type: "error", text: data.message ?? "gemini error" }];
333
+ case "result":
334
+ return [
335
+ {
336
+ type: "result",
337
+ ok: !data.error,
338
+ summary: typeof data.response === "string" ? data.response : void 0
339
+ }
340
+ ];
341
+ default:
342
+ return [{ type: "raw", data }];
343
+ }
344
+ };
305
345
  }
306
346
  };
307
347
 
@@ -314,6 +354,8 @@ var opencode = {
314
354
  supportsResume: true,
315
355
  buildArgs(opts) {
316
356
  const args = ["run", "--format", "json"];
357
+ if (opts.mode === "plan") args.push("--agent", "plan");
358
+ if (opts.mode === "yolo") args.push("--auto");
317
359
  if (opts.model) args.push("--model", opts.model);
318
360
  if (opts.sessionId) args.push("--session", opts.sessionId);
319
361
  args.push(opts.prompt);
@@ -399,6 +441,7 @@ function detectEngines() {
399
441
  export {
400
442
  lineSplitter,
401
443
  truncate,
444
+ engines,
402
445
  getEngine,
403
446
  findBinary,
404
447
  findEngineBinary,
@@ -3,7 +3,7 @@ import {
3
3
  findEngineBinary,
4
4
  lineSplitter,
5
5
  truncate
6
- } from "./chunk-2LRIKWBU.js";
6
+ } from "./chunk-BWZFACBT.js";
7
7
 
8
8
  // src/runner/run.ts
9
9
  import { spawn } from "child_process";
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-P3H4N2EN.js";
7
7
  import {
8
8
  runAgent
9
- } from "./chunk-OTG4ZB4R.js";
9
+ } from "./chunk-C7WKNJG6.js";
10
10
 
11
11
  // src/variants/variants.ts
12
12
  import { execFileSync } from "child_process";
@@ -14,6 +14,7 @@ var COMMANDS = [
14
14
  { name: "restore", args: "<n>", description: "rewind files to before ask n" },
15
15
  { name: "mode", args: "plan|safe|yolo", description: "how much the engine may do (shift+tab cycles)" },
16
16
  { name: "engine", args: "<id>", description: "switch backend (new session)" },
17
+ { name: "engines", description: "list installed engines with streaming/resume support" },
17
18
  { name: "model", args: "[name]", description: "model override for the engine" },
18
19
  { name: "theme", args: "[name]", description: "switch the TUI theme", viewLevel: true },
19
20
  { name: "copy", description: "copy the last reply to the clipboard" },
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  findChrome,
8
8
  screenshot
9
- } from "./chunk-P3V5CWH5.js";
9
+ } from "./chunk-B7LOERSP.js";
10
10
 
11
11
  // src/preview/preview.ts
12
12
  import fs2 from "fs";
package/dist/cli.js CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ enrich
4
+ } from "./chunk-4LAU5TGK.js";
2
5
  import {
3
6
  diffStatSince,
4
7
  isGitRepo,
@@ -10,28 +13,28 @@ import {
10
13
  buildFixPrompt,
11
14
  detectDevCommand,
12
15
  screenshotVariants
13
- } from "./chunk-2IW2MMCY.js";
16
+ } from "./chunk-43L4QXCM.js";
14
17
  import {
15
18
  applyVariant,
16
19
  cleanVariants,
17
20
  listVariants,
18
21
  runVariants
19
- } from "./chunk-LCS47EAG.js";
22
+ } from "./chunk-LVA2OQSR.js";
20
23
  import {
21
24
  composePrompt
22
25
  } from "./chunk-P3H4N2EN.js";
23
26
  import {
24
27
  runAgent
25
- } from "./chunk-OTG4ZB4R.js";
28
+ } from "./chunk-C7WKNJG6.js";
26
29
  import {
27
30
  completeCommand
28
- } from "./chunk-EECGXFRX.js";
31
+ } from "./chunk-V3M4WQLH.js";
29
32
  import {
30
33
  buildGatePrompt,
31
34
  detectFastGates,
32
35
  detectGates,
33
36
  runGates
34
- } from "./chunk-DLCRYRWQ.js";
37
+ } from "./chunk-62JNF5M2.js";
35
38
  import {
36
39
  buildReviewPrompt,
37
40
  buildRuntimeFixPrompt,
@@ -42,18 +45,15 @@ import {
42
45
  probeRuntime,
43
46
  runtimeSummary,
44
47
  saveState
45
- } from "./chunk-CIQ3OUAF.js";
48
+ } from "./chunk-YZEFBPBJ.js";
46
49
  import "./chunk-OC6RU6XH.js";
47
50
  import {
48
51
  findChrome
49
- } from "./chunk-P3V5CWH5.js";
52
+ } from "./chunk-B7LOERSP.js";
50
53
  import {
51
54
  detectEngines,
52
55
  getEngine
53
- } from "./chunk-2LRIKWBU.js";
54
- import {
55
- enrich
56
- } from "./chunk-4LAU5TGK.js";
56
+ } from "./chunk-BWZFACBT.js";
57
57
 
58
58
  // src/cli.tsx
59
59
  import { Command } from "commander";
@@ -652,9 +652,21 @@ They are objective defects, not style preferences.`
652
652
  const [name, ...rest] = commandLine.slice(1).split(/\s+/);
653
653
  const arg = rest.join(" ").trim();
654
654
  switch (name) {
655
+ case "engines": {
656
+ void import("./registry-S3PCXJVF.js").then(({ detectEngines: detectEngines2 }) => {
657
+ const lines = detectEngines2().map(({ engine, path: binaryPath }) => {
658
+ const mark = binaryPath ? "\u2713" : "\u2717";
659
+ const traits = [engine.createParser ? "stream" : "text", engine.supportsResume ? "resume" : null].filter(Boolean).join(" \xB7 ");
660
+ return `${mark} ${engine.id} \u2014 ${traits}${binaryPath ? "" : ` \xB7 install: ${engine.install}`}`;
661
+ });
662
+ this.push("status", `${lines.join("\n")}
663
+ /engine <id> switches (new session)`);
664
+ });
665
+ break;
666
+ }
655
667
  case "engine":
656
668
  if (!arg) {
657
- this.push("status", "usage: /engine <id> \u2014 see squint engines");
669
+ this.command("/engines");
658
670
  } else {
659
671
  try {
660
672
  getEngine(arg);
@@ -933,7 +945,7 @@ They are objective defects, not style preferences.`
933
945
  this.notify({ items: [], totals: { costUsd: 0, turns: 0 } });
934
946
  break;
935
947
  case "help": {
936
- void import("./commands-6XDXUVO6.js").then(({ commandHelp }) => this.push("status", commandHelp()));
948
+ void import("./commands-7DTZB4JE.js").then(({ commandHelp }) => this.push("status", commandHelp()));
937
949
  break;
938
950
  }
939
951
  case "quit":
@@ -1051,6 +1063,15 @@ var THEMES = {
1051
1063
  success: "#31748f",
1052
1064
  tool: "#c4a7e7"
1053
1065
  },
1066
+ light: {
1067
+ name: "light",
1068
+ accent: "#9a6b1f",
1069
+ dim: "#6b6f76",
1070
+ user: "#2a5db0",
1071
+ error: "#c4322e",
1072
+ success: "#3d7a37",
1073
+ tool: "#0f7b8a"
1074
+ },
1054
1075
  mono: {
1055
1076
  name: "mono",
1056
1077
  accent: "white",
@@ -1473,12 +1494,18 @@ function App({
1473
1494
 
1474
1495
  // src/cli.tsx
1475
1496
  import { jsx as jsx4 } from "react/jsx-runtime";
1476
- var VERSION = "0.2.4";
1497
+ var VERSION = "0.2.6";
1477
1498
  var program = new Command();
1478
1499
  program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
1479
- program.command("run").description("Run one prompt headlessly and stream the result").argument("<prompt...>", "what to build or change").option("-e, --engine <id>", "engine to use (claude, codex, gemini, opencode)").option("-m, --model <name>", "model override for the engine").option("--no-brief", "send the prompt without the squint design brief").option("--json", "emit normalized agent events as ndjson").action(
1500
+ program.command("run").description("Run one prompt headlessly and stream the result").argument("<prompt...>", "what to build or change").option("-e, --engine <id>", "engine to use (see squint engines)").option("-m, --model <name>", "model override for the engine").option("--mode <mode>", "plan (read-only) \xB7 safe (default) \xB7 yolo (no friction)").option("--no-brief", "send the prompt without the squint design brief").option("--json", "emit normalized agent events as ndjson").action(
1480
1501
  async (promptWords, options) => {
1481
1502
  const cwd = process.cwd();
1503
+ if (options.mode && !["plan", "safe", "yolo"].includes(options.mode)) {
1504
+ console.error(pc.red("\u2717 --mode must be plan, safe, or yolo"));
1505
+ process.exitCode = 1;
1506
+ return;
1507
+ }
1508
+ const mode = options.mode;
1482
1509
  const config = loadConfig(defaultPaths(cwd));
1483
1510
  const engineId = resolveEngineId(config, options.engine);
1484
1511
  const engine = getEngine(engineId);
@@ -1488,8 +1515,9 @@ program.command("run").description("Run one prompt headlessly and stream the res
1488
1515
  const onEvent = options.json ? (event) => {
1489
1516
  if (event.type !== "delta") console.log(JSON.stringify(event));
1490
1517
  } : createPrinter();
1491
- if (!options.json) console.log(pc.dim(`squint \xB7 ${engine.id}${model ? ` \xB7 ${model}` : ""}`));
1492
- const result = await runAgent(engine, { prompt, cwd, model }, onEvent);
1518
+ if (!options.json)
1519
+ console.log(pc.dim(`squint \xB7 ${engine.id}${model ? ` \xB7 ${model}` : ""}${mode && mode !== "safe" ? ` \xB7 ${mode}` : ""}`));
1520
+ const result = await runAgent(engine, { prompt, cwd, model, mode }, onEvent);
1493
1521
  if (options.json) {
1494
1522
  console.log(JSON.stringify({ type: "summary", ...result }));
1495
1523
  } else if (result.ok) {
@@ -1500,12 +1528,18 @@ program.command("run").description("Run one prompt headlessly and stream the res
1500
1528
  if (!result.ok) process.exitCode = 1;
1501
1529
  }
1502
1530
  );
1503
- program.command("engines").description("List engines and whether they are installed").action(() => {
1531
+ program.command("engines").description("List engines: installed, streaming, session resume").action(() => {
1532
+ console.log(pc.dim(" id name stream resume where"));
1504
1533
  for (const { engine, path: binaryPath } of detectEngines()) {
1505
1534
  const status = binaryPath ? pc.green("\u2713") : pc.red("\u2717");
1535
+ const stream = engine.createParser ? pc.green("yes") : pc.dim("text");
1536
+ const resume = engine.supportsResume ? pc.green("yes") : pc.dim("no");
1506
1537
  const location = binaryPath ?? pc.dim(`not found \u2014 ${engine.install}`);
1507
- console.log(`${status} ${engine.id.padEnd(10)} ${engine.name.padEnd(14)} ${location}`);
1538
+ console.log(
1539
+ `${status} ${engine.id.padEnd(10)} ${engine.name.padEnd(14)} ${stream.padEnd(15)} ${resume.padEnd(14)} ${location}`
1540
+ );
1508
1541
  }
1542
+ console.log(pc.dim("\nplan/safe/yolo modes map onto every engine \xB7 squint doctor --probe verifies auth"));
1509
1543
  });
1510
1544
  program.command("doctor").description("Check squint prerequisites and engine availability").option("--probe", "run each detected engine with a one-word prompt to verify auth works").action(async (options) => {
1511
1545
  const [major] = process.versions.node.split(".");
@@ -1517,7 +1551,7 @@ program.command("doctor").description("Check squint prerequisites and engine ava
1517
1551
  console.log(`${status} ${engine.name}${binaryPath ? "" : pc.dim(` \u2014 install: ${engine.install}`)}`);
1518
1552
  }
1519
1553
  if (options.probe) {
1520
- const { runAgent: runAgent2 } = await import("./run-XHLCTF6V.js");
1554
+ const { runAgent: runAgent2 } = await import("./run-S772BPMZ.js");
1521
1555
  console.log(pc.dim("\nprobing engines with a one-word prompt (verifies auth end to end)\u2026"));
1522
1556
  for (const { engine, path: binaryPath } of detected) {
1523
1557
  if (!binaryPath) continue;
@@ -1539,7 +1573,7 @@ program.command("doctor").description("Check squint prerequisites and engine ava
1539
1573
  );
1540
1574
  }
1541
1575
  }
1542
- const { findChrome: findChrome2 } = await import("./chrome-RD7XQ767.js");
1576
+ const { findChrome: findChrome2 } = await import("./chrome-NVU47PLK.js");
1543
1577
  const { hasWebSocket } = await import("./cdp-SFWNP7OA.js");
1544
1578
  const chrome = findChrome2();
1545
1579
  console.log(
@@ -1666,7 +1700,7 @@ variantsCommand.command("gen").description("Generate n variants of one ask in pa
1666
1700
  process.exitCode = 1;
1667
1701
  return;
1668
1702
  }
1669
- const { runVariants: runVariants2, cleanVariants: cleanVariants2 } = await import("./variants-7A7723L7.js");
1703
+ const { runVariants: runVariants2, cleanVariants: cleanVariants2 } = await import("./variants-2IM274AL.js");
1670
1704
  const config = loadConfig(defaultPaths(cwd));
1671
1705
  const engineId = resolveEngineId(config, options.engine);
1672
1706
  const engine = getEngine(engineId);
@@ -1684,7 +1718,7 @@ variantsCommand.command("gen").description("Generate n variants of one ask in pa
1684
1718
  );
1685
1719
  const succeeded = runs.filter((r) => r.result.ok);
1686
1720
  if (options.shots && succeeded.length > 0) {
1687
- const { screenshotVariants: screenshotVariants2 } = await import("./shots-LRYYMTPK.js");
1721
+ const { screenshotVariants: screenshotVariants2 } = await import("./shots-J7JG2FC4.js");
1688
1722
  console.log(pc.dim("capturing screenshots\u2026"));
1689
1723
  const shots = await screenshotVariants2(cwd, succeeded.map((r) => r.variant));
1690
1724
  for (const shot of shots) {
@@ -1699,7 +1733,7 @@ ${succeeded.length}/${runs.length} variants ready in .squint/variants/ \u2014 `
1699
1733
  }
1700
1734
  );
1701
1735
  variantsCommand.command("list").description("List generated variants").action(async () => {
1702
- const { listVariants: listVariants2 } = await import("./variants-7A7723L7.js");
1736
+ const { listVariants: listVariants2 } = await import("./variants-2IM274AL.js");
1703
1737
  const ids = listVariants2(process.cwd());
1704
1738
  if (ids.length === 0) {
1705
1739
  console.log(pc.dim('no variants \u2014 squint variants gen <n> "<ask>"'));
@@ -1708,7 +1742,7 @@ variantsCommand.command("list").description("List generated variants").action(as
1708
1742
  for (const id of ids) console.log(id);
1709
1743
  });
1710
1744
  variantsCommand.command("apply").description("Apply one variant\u2019s changes to the main tree and discard the rest").argument("<id>", "family id of the winning variant").action(async (id) => {
1711
- const { applyVariant: applyVariant2, cleanVariants: cleanVariants2 } = await import("./variants-7A7723L7.js");
1745
+ const { applyVariant: applyVariant2, cleanVariants: cleanVariants2 } = await import("./variants-2IM274AL.js");
1712
1746
  const cwd = process.cwd();
1713
1747
  const result = applyVariant2(cwd, id);
1714
1748
  if (!result.ok) {
@@ -1720,7 +1754,7 @@ variantsCommand.command("apply").description("Apply one variant\u2019s changes t
1720
1754
  console.log(pc.green(`\u2713 applied ${id} to the working tree`) + pc.dim(" \u2014 review with git diff"));
1721
1755
  });
1722
1756
  variantsCommand.command("clean").description("Discard all variants").action(async () => {
1723
- const { cleanVariants: cleanVariants2 } = await import("./variants-7A7723L7.js");
1757
+ const { cleanVariants: cleanVariants2 } = await import("./variants-2IM274AL.js");
1724
1758
  const count = cleanVariants2(process.cwd());
1725
1759
  console.log(pc.dim(`removed ${count} variant(s)`));
1726
1760
  });
@@ -1754,7 +1788,7 @@ program.command("brief").description("Set a committed design direction for this
1754
1788
  console.log(pc.dim("every squint ask in this repo now holds this direction \u2014 edit the file to remix"));
1755
1789
  });
1756
1790
  program.command("check").description("Run this project\u2019s quality gates (typecheck, lint, test, build)").action(async () => {
1757
- const { detectGates: detectGates2, runGates: runGates2 } = await import("./gates-I2GGQGMA.js");
1791
+ const { detectGates: detectGates2, runGates: runGates2 } = await import("./gates-ZC67NMW3.js");
1758
1792
  const cwd = process.cwd();
1759
1793
  const gates = detectGates2(cwd);
1760
1794
  if (gates.length === 0) {
@@ -1770,7 +1804,7 @@ program.command("check").description("Run this project\u2019s quality gates (typ
1770
1804
  if (results.some((r) => !r.ok)) process.exitCode = 1;
1771
1805
  });
1772
1806
  program.command("shot").description("Screenshot a running app at mobile/tablet/desktop viewports").argument("<url>", "URL of the running app (e.g. http://localhost:5173)").action(async (url) => {
1773
- const { captureViewports: captureViewports2 } = await import("./preview-LZDH65ID.js");
1807
+ const { captureViewports: captureViewports2 } = await import("./preview-UCH7H5R5.js");
1774
1808
  const result = await captureViewports2(process.cwd(), url);
1775
1809
  if (!result) {
1776
1810
  console.error(pc.red("\u2717 no Chrome/Chromium found"));
@@ -1797,11 +1831,16 @@ configCommand.command("path").description("Show config file locations").action((
1797
1831
  console.log(`global ${paths.globalFile}`);
1798
1832
  console.log(`project ${paths.projectFile}`);
1799
1833
  });
1800
- program.action(() => {
1834
+ program.action(async () => {
1801
1835
  const cwd = process.cwd();
1802
1836
  const config = loadConfig(defaultPaths(cwd));
1803
1837
  const engineId = resolveEngineId(config);
1804
1838
  const model = resolveModel(config, engineId);
1839
+ let theme2 = config.theme;
1840
+ if (!theme2 && !process.env.NO_COLOR) {
1841
+ const { detectBackground } = await import("./background-J7OQTYEC.js");
1842
+ if (await detectBackground() === "light") theme2 = "light";
1843
+ }
1805
1844
  render(
1806
1845
  /* @__PURE__ */ jsx4(
1807
1846
  App,
@@ -1815,7 +1854,7 @@ program.action(() => {
1815
1854
  autoCheck: config.autoCheck,
1816
1855
  bell: config.bell,
1817
1856
  budgetUsd: config.budgetUsd,
1818
- initialTheme: config.theme
1857
+ initialTheme: theme2
1819
1858
  }
1820
1859
  )
1821
1860
  );
@@ -3,7 +3,7 @@ import {
3
3
  COMMANDS,
4
4
  commandHelp,
5
5
  completeCommand
6
- } from "./chunk-EECGXFRX.js";
6
+ } from "./chunk-V3M4WQLH.js";
7
7
  export {
8
8
  COMMANDS,
9
9
  commandHelp,
@@ -5,7 +5,7 @@ import {
5
5
  detectGates,
6
6
  runGate,
7
7
  runGates
8
- } from "./chunk-DLCRYRWQ.js";
8
+ } from "./chunk-62JNF5M2.js";
9
9
  export {
10
10
  buildGatePrompt,
11
11
  detectFastGates,
@@ -10,10 +10,10 @@ import {
10
10
  probeRuntime,
11
11
  routeShotName,
12
12
  runtimeSummary
13
- } from "./chunk-CIQ3OUAF.js";
13
+ } from "./chunk-YZEFBPBJ.js";
14
14
  import "./chunk-OC6RU6XH.js";
15
- import "./chunk-P3V5CWH5.js";
16
- import "./chunk-2LRIKWBU.js";
15
+ import "./chunk-B7LOERSP.js";
16
+ import "./chunk-BWZFACBT.js";
17
17
  export {
18
18
  VIEWPORTS,
19
19
  buildReviewPrompt,
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ detectEngines,
4
+ engines,
5
+ findBinary,
6
+ findEngineBinary,
7
+ getEngine
8
+ } from "./chunk-BWZFACBT.js";
9
+ export {
10
+ detectEngines,
11
+ engines,
12
+ findBinary,
13
+ findEngineBinary,
14
+ getEngine
15
+ };
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runAgent
4
- } from "./chunk-OTG4ZB4R.js";
5
- import "./chunk-2LRIKWBU.js";
4
+ } from "./chunk-C7WKNJG6.js";
5
+ import "./chunk-BWZFACBT.js";
6
6
  export {
7
7
  runAgent
8
8
  };
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ screenshotVariants
4
+ } from "./chunk-43L4QXCM.js";
5
+ import "./chunk-LVA2OQSR.js";
6
+ import "./chunk-P3H4N2EN.js";
7
+ import "./chunk-C7WKNJG6.js";
8
+ import "./chunk-B7LOERSP.js";
9
+ import "./chunk-BWZFACBT.js";
10
+ export {
11
+ screenshotVariants
12
+ };
@@ -9,10 +9,10 @@ import {
9
9
  runVariants,
10
10
  variantPrompt,
11
11
  variantsRoot
12
- } from "./chunk-LCS47EAG.js";
12
+ } from "./chunk-LVA2OQSR.js";
13
13
  import "./chunk-P3H4N2EN.js";
14
- import "./chunk-OTG4ZB4R.js";
15
- import "./chunk-2LRIKWBU.js";
14
+ import "./chunk-C7WKNJG6.js";
15
+ import "./chunk-BWZFACBT.js";
16
16
  export {
17
17
  MAX_VARIANTS,
18
18
  applyVariant,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aayambansal/squint",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
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",
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- screenshotVariants
4
- } from "./chunk-2IW2MMCY.js";
5
- import "./chunk-LCS47EAG.js";
6
- import "./chunk-P3H4N2EN.js";
7
- import "./chunk-OTG4ZB4R.js";
8
- import "./chunk-P3V5CWH5.js";
9
- import "./chunk-2LRIKWBU.js";
10
- export {
11
- screenshotVariants
12
- };