@aayambansal/squint 0.2.3 → 0.2.5
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 +2 -0
- package/dist/background-J7OQTYEC.js +41 -0
- package/dist/{chrome-RD7XQ767.js → chrome-RV25VKUA.js} +2 -2
- package/dist/{chunk-DLCRYRWQ.js → chunk-62JNF5M2.js} +14 -0
- package/dist/{chunk-2LRIKWBU.js → chunk-CH4GNJCZ.js} +8 -5
- package/dist/{chunk-P3V5CWH5.js → chunk-CJXYSQNB.js} +1 -1
- package/dist/{chunk-SU6YRRMF.js → chunk-DKQ5KJD7.js} +33 -2
- package/dist/{chunk-2IW2MMCY.js → chunk-QNNT6FP4.js} +3 -3
- package/dist/{chunk-OTG4ZB4R.js → chunk-TI2R7QRL.js} +1 -1
- package/dist/{chunk-LCS47EAG.js → chunk-XLNTTZX4.js} +1 -1
- package/dist/cli.js +89 -25
- package/dist/{gates-I2GGQGMA.js → gates-ZC67NMW3.js} +1 -1
- package/dist/{preview-UX4VS4SX.js → preview-ZHUQT7TJ.js} +7 -3
- package/dist/{run-XHLCTF6V.js → run-TIGEZHMQ.js} +2 -2
- package/dist/shots-X3I6MRLX.js +12 -0
- package/dist/{variants-7A7723L7.js → variants-SM6NRX4U.js} +3 -3
- package/package.json +1 -1
- package/dist/shots-LRYYMTPK.js +0 -12
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
|
+
};
|
|
@@ -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") });
|
|
@@ -37,6 +37,7 @@ var aider = {
|
|
|
37
37
|
supportsResume: false,
|
|
38
38
|
buildArgs(opts) {
|
|
39
39
|
const args = ["--message", opts.prompt, "--yes-always", "--no-auto-commits"];
|
|
40
|
+
if (opts.mode === "plan") args.push("--dry-run");
|
|
40
41
|
if (opts.model) args.push("--model", opts.model);
|
|
41
42
|
return args;
|
|
42
43
|
}
|
|
@@ -123,10 +124,9 @@ var amp = {
|
|
|
123
124
|
install: "npm install -g @sourcegraph/amp",
|
|
124
125
|
supportsResume: true,
|
|
125
126
|
buildArgs(opts) {
|
|
126
|
-
|
|
127
|
-
|
|
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"
|
|
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
|
}
|
|
@@ -314,6 +315,8 @@ var opencode = {
|
|
|
314
315
|
supportsResume: true,
|
|
315
316
|
buildArgs(opts) {
|
|
316
317
|
const args = ["run", "--format", "json"];
|
|
318
|
+
if (opts.mode === "plan") args.push("--agent", "plan");
|
|
319
|
+
if (opts.mode === "yolo") args.push("--auto");
|
|
317
320
|
if (opts.model) args.push("--model", opts.model);
|
|
318
321
|
if (opts.sessionId) args.push("--session", opts.sessionId);
|
|
319
322
|
args.push(opts.prompt);
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
findChrome,
|
|
8
8
|
screenshot
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CJXYSQNB.js";
|
|
10
10
|
|
|
11
11
|
// src/preview/preview.ts
|
|
12
12
|
import fs2 from "fs";
|
|
@@ -62,6 +62,19 @@ var VIEWPORTS = [
|
|
|
62
62
|
{ name: "tablet", width: 768, height: 1024 },
|
|
63
63
|
{ name: "desktop", width: 1440, height: 900 }
|
|
64
64
|
];
|
|
65
|
+
function loadRoutes(cwd) {
|
|
66
|
+
let lines = [];
|
|
67
|
+
try {
|
|
68
|
+
lines = fs2.readFileSync(path2.join(cwd, ".squint", "routes"), "utf8").split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#"));
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
const routes = ["/", ...lines.filter((l) => l !== "/")];
|
|
72
|
+
return routes.slice(0, 6).map((r) => r.startsWith("/") ? r : `/${r}`);
|
|
73
|
+
}
|
|
74
|
+
function routeShotName(route) {
|
|
75
|
+
const clean = route.replace(/^\/+|\/+$/g, "").replace(/[^a-zA-Z0-9]+/g, "-");
|
|
76
|
+
return clean.length > 0 ? clean : "root";
|
|
77
|
+
}
|
|
65
78
|
function previewDir(cwd) {
|
|
66
79
|
const dir = path2.join(cwd, ".squint", "preview");
|
|
67
80
|
fs2.mkdirSync(dir, { recursive: true });
|
|
@@ -72,10 +85,26 @@ async function captureViewports(cwd, url) {
|
|
|
72
85
|
const chrome = findChrome();
|
|
73
86
|
if (!chrome) return null;
|
|
74
87
|
const dir = previewDir(cwd);
|
|
88
|
+
const routes = loadRoutes(cwd);
|
|
89
|
+
const base = url.replace(/\/+$/, "");
|
|
75
90
|
if (hasWebSocket()) {
|
|
76
91
|
try {
|
|
77
92
|
const { report, shots: shots2, a11y } = await cdpCapture(chrome, url, dir, VIEWPORTS, 2500, true);
|
|
78
|
-
|
|
93
|
+
const errors2 = [];
|
|
94
|
+
for (const route of routes.slice(1)) {
|
|
95
|
+
try {
|
|
96
|
+
const routeCapture = await cdpCapture(chrome, `${base}${route}`, dir, [
|
|
97
|
+
{ name: routeShotName(route), width: 1440, height: 900 }
|
|
98
|
+
]);
|
|
99
|
+
shots2.push(...routeCapture.shots);
|
|
100
|
+
for (const err of routeCapture.report.pageErrors.slice(0, 3)) {
|
|
101
|
+
errors2.push(`${route}: ${err.split("\n")[0]}`);
|
|
102
|
+
}
|
|
103
|
+
} catch {
|
|
104
|
+
errors2.push(`${route}: capture failed`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { shots: shots2, errors: errors2, runtime: report, a11y };
|
|
79
108
|
} catch {
|
|
80
109
|
}
|
|
81
110
|
}
|
|
@@ -178,6 +207,8 @@ export {
|
|
|
178
207
|
saveState,
|
|
179
208
|
clearState,
|
|
180
209
|
VIEWPORTS,
|
|
210
|
+
loadRoutes,
|
|
211
|
+
routeShotName,
|
|
181
212
|
previewDir,
|
|
182
213
|
captureViewports,
|
|
183
214
|
runtimeSummary,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
variantsRoot
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XLNTTZX4.js";
|
|
5
5
|
import {
|
|
6
6
|
findChrome,
|
|
7
7
|
screenshot
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-CJXYSQNB.js";
|
|
9
9
|
import {
|
|
10
10
|
lineSplitter
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-CH4GNJCZ.js";
|
|
12
12
|
|
|
13
13
|
// src/variants/shots.ts
|
|
14
14
|
import path2 from "path";
|
package/dist/cli.js
CHANGED
|
@@ -10,19 +10,19 @@ import {
|
|
|
10
10
|
buildFixPrompt,
|
|
11
11
|
detectDevCommand,
|
|
12
12
|
screenshotVariants
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QNNT6FP4.js";
|
|
14
14
|
import {
|
|
15
15
|
applyVariant,
|
|
16
16
|
cleanVariants,
|
|
17
17
|
listVariants,
|
|
18
18
|
runVariants
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-XLNTTZX4.js";
|
|
20
20
|
import {
|
|
21
21
|
composePrompt
|
|
22
22
|
} from "./chunk-P3H4N2EN.js";
|
|
23
23
|
import {
|
|
24
24
|
runAgent
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-TI2R7QRL.js";
|
|
26
26
|
import {
|
|
27
27
|
completeCommand
|
|
28
28
|
} from "./chunk-EECGXFRX.js";
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
detectFastGates,
|
|
32
32
|
detectGates,
|
|
33
33
|
runGates
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-62JNF5M2.js";
|
|
35
35
|
import {
|
|
36
36
|
buildReviewPrompt,
|
|
37
37
|
buildRuntimeFixPrompt,
|
|
@@ -42,15 +42,15 @@ import {
|
|
|
42
42
|
probeRuntime,
|
|
43
43
|
runtimeSummary,
|
|
44
44
|
saveState
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-DKQ5KJD7.js";
|
|
46
46
|
import "./chunk-OC6RU6XH.js";
|
|
47
47
|
import {
|
|
48
48
|
findChrome
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-CJXYSQNB.js";
|
|
50
50
|
import {
|
|
51
51
|
detectEngines,
|
|
52
52
|
getEngine
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-CH4GNJCZ.js";
|
|
54
54
|
import {
|
|
55
55
|
enrich
|
|
56
56
|
} from "./chunk-4LAU5TGK.js";
|
|
@@ -80,6 +80,8 @@ var ConfigSchema = z.object({
|
|
|
80
80
|
autoCheck: z.boolean().optional(),
|
|
81
81
|
/** Terminal bell when a turn finishes (default on). */
|
|
82
82
|
bell: z.boolean().optional(),
|
|
83
|
+
/** Session budget in USD; crossing it warns (never blocks). */
|
|
84
|
+
budgetUsd: z.number().positive().optional(),
|
|
83
85
|
/** TUI theme name (amber, ocean, moss, rose, mono). */
|
|
84
86
|
theme: z.string().optional()
|
|
85
87
|
});
|
|
@@ -129,13 +131,19 @@ function setConfigValue(file, key, value) {
|
|
|
129
131
|
throw new Error(`"${key}" must be true or false`);
|
|
130
132
|
}
|
|
131
133
|
next = { ...current, [key]: value === "true" };
|
|
134
|
+
} else if (key === "budgetUsd") {
|
|
135
|
+
const budget = Number.parseFloat(value);
|
|
136
|
+
if (!Number.isFinite(budget) || budget <= 0) {
|
|
137
|
+
throw new Error('"budgetUsd" must be a positive number');
|
|
138
|
+
}
|
|
139
|
+
next = { ...current, budgetUsd: budget };
|
|
132
140
|
} else if (key.startsWith("models.")) {
|
|
133
141
|
const engineId = key.slice("models.".length);
|
|
134
142
|
if (!engineId) throw new Error("Usage: squint config set models.<engineId> <model>");
|
|
135
143
|
next = { ...current, models: { ...current.models, [engineId]: value } };
|
|
136
144
|
} else {
|
|
137
145
|
throw new Error(
|
|
138
|
-
`Unknown config key "${key}". Supported: engine, theme, autoDev, autoFix, autoProbe, autoCheck, bell, models.<engineId>`
|
|
146
|
+
`Unknown config key "${key}". Supported: engine, theme, autoDev, autoFix, autoProbe, autoCheck, bell, budgetUsd, models.<engineId>`
|
|
139
147
|
);
|
|
140
148
|
}
|
|
141
149
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
@@ -347,16 +355,32 @@ var Session = class {
|
|
|
347
355
|
}
|
|
348
356
|
turnEdits = 0;
|
|
349
357
|
turnTools = 0;
|
|
358
|
+
toolStreak = 0;
|
|
359
|
+
collapsedTools = 0;
|
|
360
|
+
/**
|
|
361
|
+
* Long tool cascades collapse: the first three of a consecutive burst
|
|
362
|
+
* render, the rest fold into one "+N more" line pushed when the burst
|
|
363
|
+
* ends — append-only, so the Static transcript stays valid.
|
|
364
|
+
*/
|
|
365
|
+
flushToolCollapse() {
|
|
366
|
+
if (this.collapsedTools > 0) {
|
|
367
|
+
this.push("tool", `+${this.collapsedTools} more tool call${this.collapsedTools === 1 ? "" : "s"}`);
|
|
368
|
+
this.collapsedTools = 0;
|
|
369
|
+
}
|
|
370
|
+
this.toolStreak = 0;
|
|
371
|
+
}
|
|
350
372
|
handleEvent = (event) => {
|
|
351
373
|
switch (event.type) {
|
|
352
374
|
case "status":
|
|
353
375
|
this.commitLive();
|
|
376
|
+
this.flushToolCollapse();
|
|
354
377
|
this.push("status", event.text);
|
|
355
378
|
break;
|
|
356
379
|
case "delta":
|
|
357
380
|
this.setLive(this.live + event.text);
|
|
358
381
|
break;
|
|
359
382
|
case "text":
|
|
383
|
+
this.flushToolCollapse();
|
|
360
384
|
if (event.streamed) {
|
|
361
385
|
this.live = "";
|
|
362
386
|
this.state = { ...this.state, liveText: "" };
|
|
@@ -367,17 +391,24 @@ var Session = class {
|
|
|
367
391
|
break;
|
|
368
392
|
case "thinking":
|
|
369
393
|
this.commitLive();
|
|
394
|
+
this.flushToolCollapse();
|
|
370
395
|
this.push("thinking", event.text);
|
|
371
396
|
break;
|
|
372
397
|
case "tool": {
|
|
373
398
|
this.commitLive();
|
|
374
399
|
this.turnTools += 1;
|
|
400
|
+
this.toolStreak += 1;
|
|
375
401
|
if (/edit|write|patch|apply/i.test(event.name)) this.turnEdits += 1;
|
|
376
|
-
this.
|
|
402
|
+
if (this.toolStreak <= 3) {
|
|
403
|
+
this.push("tool", event.detail ? `${event.name} \xB7 ${event.detail}` : event.name);
|
|
404
|
+
} else {
|
|
405
|
+
this.collapsedTools += 1;
|
|
406
|
+
}
|
|
377
407
|
break;
|
|
378
408
|
}
|
|
379
409
|
case "error":
|
|
380
410
|
this.commitLive();
|
|
411
|
+
this.flushToolCollapse();
|
|
381
412
|
this.push("error", event.text);
|
|
382
413
|
break;
|
|
383
414
|
case "result":
|
|
@@ -410,6 +441,7 @@ var Session = class {
|
|
|
410
441
|
);
|
|
411
442
|
this.abort = null;
|
|
412
443
|
this.commitLive();
|
|
444
|
+
this.flushToolCollapse();
|
|
413
445
|
if (result.ok) {
|
|
414
446
|
const cost = result.costUsd !== void 0 ? ` \xB7 $${result.costUsd.toFixed(2)}` : "";
|
|
415
447
|
const secs = result.durationMs !== void 0 ? ` \xB7 ${(result.durationMs / 1e3).toFixed(0)}s` : "";
|
|
@@ -417,12 +449,20 @@ var Session = class {
|
|
|
417
449
|
const stat = checkpoint ? diffStatSince(this.opts.cwd, checkpoint.snapshot) : null;
|
|
418
450
|
const work = stat ? ` \xB7 ${stat}` : this.turnEdits > 0 ? ` \xB7 ${this.turnEdits} edit${this.turnEdits === 1 ? "" : "s"}` : this.turnTools > 0 ? ` \xB7 ${this.turnTools} tool call${this.turnTools === 1 ? "" : "s"}` : "";
|
|
419
451
|
this.push("status", `done${secs}${cost}${work}`);
|
|
452
|
+
const before = this.state.totals.costUsd;
|
|
420
453
|
this.notify({
|
|
421
454
|
totals: {
|
|
422
|
-
costUsd:
|
|
455
|
+
costUsd: before + (result.costUsd ?? 0),
|
|
423
456
|
turns: this.state.totals.turns + 1
|
|
424
457
|
}
|
|
425
458
|
});
|
|
459
|
+
const budget = this.opts.budgetUsd;
|
|
460
|
+
if (budget && before < budget && this.state.totals.costUsd >= budget) {
|
|
461
|
+
this.push(
|
|
462
|
+
"error",
|
|
463
|
+
`session cost $${this.state.totals.costUsd.toFixed(2)} crossed your $${budget.toFixed(2)} budget \u2014 squint keeps working, this is just the flag you asked for`
|
|
464
|
+
);
|
|
465
|
+
}
|
|
426
466
|
if (this.sessionId) {
|
|
427
467
|
saveState(this.opts.cwd, {
|
|
428
468
|
engine: this.state.engineId,
|
|
@@ -1011,6 +1051,15 @@ var THEMES = {
|
|
|
1011
1051
|
success: "#31748f",
|
|
1012
1052
|
tool: "#c4a7e7"
|
|
1013
1053
|
},
|
|
1054
|
+
light: {
|
|
1055
|
+
name: "light",
|
|
1056
|
+
accent: "#9a6b1f",
|
|
1057
|
+
dim: "#6b6f76",
|
|
1058
|
+
user: "#2a5db0",
|
|
1059
|
+
error: "#c4322e",
|
|
1060
|
+
success: "#3d7a37",
|
|
1061
|
+
tool: "#0f7b8a"
|
|
1062
|
+
},
|
|
1014
1063
|
mono: {
|
|
1015
1064
|
name: "mono",
|
|
1016
1065
|
accent: "white",
|
|
@@ -1227,6 +1276,7 @@ function App({
|
|
|
1227
1276
|
autoProbe,
|
|
1228
1277
|
autoCheck,
|
|
1229
1278
|
bell,
|
|
1279
|
+
budgetUsd,
|
|
1230
1280
|
initialTheme
|
|
1231
1281
|
}) {
|
|
1232
1282
|
const { exit } = useApp();
|
|
@@ -1242,6 +1292,7 @@ function App({
|
|
|
1242
1292
|
autoFix,
|
|
1243
1293
|
autoProbe,
|
|
1244
1294
|
autoCheck,
|
|
1295
|
+
budgetUsd,
|
|
1245
1296
|
// Delay lets the goodbye summary land in the Static scrollback.
|
|
1246
1297
|
onQuit: () => setTimeout(() => exit(), 60)
|
|
1247
1298
|
});
|
|
@@ -1431,12 +1482,18 @@ function App({
|
|
|
1431
1482
|
|
|
1432
1483
|
// src/cli.tsx
|
|
1433
1484
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1434
|
-
var VERSION = "0.2.
|
|
1485
|
+
var VERSION = "0.2.5";
|
|
1435
1486
|
var program = new Command();
|
|
1436
1487
|
program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
|
|
1437
|
-
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 (
|
|
1488
|
+
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(
|
|
1438
1489
|
async (promptWords, options) => {
|
|
1439
1490
|
const cwd = process.cwd();
|
|
1491
|
+
if (options.mode && !["plan", "safe", "yolo"].includes(options.mode)) {
|
|
1492
|
+
console.error(pc.red("\u2717 --mode must be plan, safe, or yolo"));
|
|
1493
|
+
process.exitCode = 1;
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
const mode = options.mode;
|
|
1440
1497
|
const config = loadConfig(defaultPaths(cwd));
|
|
1441
1498
|
const engineId = resolveEngineId(config, options.engine);
|
|
1442
1499
|
const engine = getEngine(engineId);
|
|
@@ -1446,8 +1503,9 @@ program.command("run").description("Run one prompt headlessly and stream the res
|
|
|
1446
1503
|
const onEvent = options.json ? (event) => {
|
|
1447
1504
|
if (event.type !== "delta") console.log(JSON.stringify(event));
|
|
1448
1505
|
} : createPrinter();
|
|
1449
|
-
if (!options.json)
|
|
1450
|
-
|
|
1506
|
+
if (!options.json)
|
|
1507
|
+
console.log(pc.dim(`squint \xB7 ${engine.id}${model ? ` \xB7 ${model}` : ""}${mode && mode !== "safe" ? ` \xB7 ${mode}` : ""}`));
|
|
1508
|
+
const result = await runAgent(engine, { prompt, cwd, model, mode }, onEvent);
|
|
1451
1509
|
if (options.json) {
|
|
1452
1510
|
console.log(JSON.stringify({ type: "summary", ...result }));
|
|
1453
1511
|
} else if (result.ok) {
|
|
@@ -1475,7 +1533,7 @@ program.command("doctor").description("Check squint prerequisites and engine ava
|
|
|
1475
1533
|
console.log(`${status} ${engine.name}${binaryPath ? "" : pc.dim(` \u2014 install: ${engine.install}`)}`);
|
|
1476
1534
|
}
|
|
1477
1535
|
if (options.probe) {
|
|
1478
|
-
const { runAgent: runAgent2 } = await import("./run-
|
|
1536
|
+
const { runAgent: runAgent2 } = await import("./run-TIGEZHMQ.js");
|
|
1479
1537
|
console.log(pc.dim("\nprobing engines with a one-word prompt (verifies auth end to end)\u2026"));
|
|
1480
1538
|
for (const { engine, path: binaryPath } of detected) {
|
|
1481
1539
|
if (!binaryPath) continue;
|
|
@@ -1497,7 +1555,7 @@ program.command("doctor").description("Check squint prerequisites and engine ava
|
|
|
1497
1555
|
);
|
|
1498
1556
|
}
|
|
1499
1557
|
}
|
|
1500
|
-
const { findChrome: findChrome2 } = await import("./chrome-
|
|
1558
|
+
const { findChrome: findChrome2 } = await import("./chrome-RV25VKUA.js");
|
|
1501
1559
|
const { hasWebSocket } = await import("./cdp-SFWNP7OA.js");
|
|
1502
1560
|
const chrome = findChrome2();
|
|
1503
1561
|
console.log(
|
|
@@ -1624,7 +1682,7 @@ variantsCommand.command("gen").description("Generate n variants of one ask in pa
|
|
|
1624
1682
|
process.exitCode = 1;
|
|
1625
1683
|
return;
|
|
1626
1684
|
}
|
|
1627
|
-
const { runVariants: runVariants2, cleanVariants: cleanVariants2 } = await import("./variants-
|
|
1685
|
+
const { runVariants: runVariants2, cleanVariants: cleanVariants2 } = await import("./variants-SM6NRX4U.js");
|
|
1628
1686
|
const config = loadConfig(defaultPaths(cwd));
|
|
1629
1687
|
const engineId = resolveEngineId(config, options.engine);
|
|
1630
1688
|
const engine = getEngine(engineId);
|
|
@@ -1642,7 +1700,7 @@ variantsCommand.command("gen").description("Generate n variants of one ask in pa
|
|
|
1642
1700
|
);
|
|
1643
1701
|
const succeeded = runs.filter((r) => r.result.ok);
|
|
1644
1702
|
if (options.shots && succeeded.length > 0) {
|
|
1645
|
-
const { screenshotVariants: screenshotVariants2 } = await import("./shots-
|
|
1703
|
+
const { screenshotVariants: screenshotVariants2 } = await import("./shots-X3I6MRLX.js");
|
|
1646
1704
|
console.log(pc.dim("capturing screenshots\u2026"));
|
|
1647
1705
|
const shots = await screenshotVariants2(cwd, succeeded.map((r) => r.variant));
|
|
1648
1706
|
for (const shot of shots) {
|
|
@@ -1657,7 +1715,7 @@ ${succeeded.length}/${runs.length} variants ready in .squint/variants/ \u2014 `
|
|
|
1657
1715
|
}
|
|
1658
1716
|
);
|
|
1659
1717
|
variantsCommand.command("list").description("List generated variants").action(async () => {
|
|
1660
|
-
const { listVariants: listVariants2 } = await import("./variants-
|
|
1718
|
+
const { listVariants: listVariants2 } = await import("./variants-SM6NRX4U.js");
|
|
1661
1719
|
const ids = listVariants2(process.cwd());
|
|
1662
1720
|
if (ids.length === 0) {
|
|
1663
1721
|
console.log(pc.dim('no variants \u2014 squint variants gen <n> "<ask>"'));
|
|
@@ -1666,7 +1724,7 @@ variantsCommand.command("list").description("List generated variants").action(as
|
|
|
1666
1724
|
for (const id of ids) console.log(id);
|
|
1667
1725
|
});
|
|
1668
1726
|
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) => {
|
|
1669
|
-
const { applyVariant: applyVariant2, cleanVariants: cleanVariants2 } = await import("./variants-
|
|
1727
|
+
const { applyVariant: applyVariant2, cleanVariants: cleanVariants2 } = await import("./variants-SM6NRX4U.js");
|
|
1670
1728
|
const cwd = process.cwd();
|
|
1671
1729
|
const result = applyVariant2(cwd, id);
|
|
1672
1730
|
if (!result.ok) {
|
|
@@ -1678,7 +1736,7 @@ variantsCommand.command("apply").description("Apply one variant\u2019s changes t
|
|
|
1678
1736
|
console.log(pc.green(`\u2713 applied ${id} to the working tree`) + pc.dim(" \u2014 review with git diff"));
|
|
1679
1737
|
});
|
|
1680
1738
|
variantsCommand.command("clean").description("Discard all variants").action(async () => {
|
|
1681
|
-
const { cleanVariants: cleanVariants2 } = await import("./variants-
|
|
1739
|
+
const { cleanVariants: cleanVariants2 } = await import("./variants-SM6NRX4U.js");
|
|
1682
1740
|
const count = cleanVariants2(process.cwd());
|
|
1683
1741
|
console.log(pc.dim(`removed ${count} variant(s)`));
|
|
1684
1742
|
});
|
|
@@ -1712,7 +1770,7 @@ program.command("brief").description("Set a committed design direction for this
|
|
|
1712
1770
|
console.log(pc.dim("every squint ask in this repo now holds this direction \u2014 edit the file to remix"));
|
|
1713
1771
|
});
|
|
1714
1772
|
program.command("check").description("Run this project\u2019s quality gates (typecheck, lint, test, build)").action(async () => {
|
|
1715
|
-
const { detectGates: detectGates2, runGates: runGates2 } = await import("./gates-
|
|
1773
|
+
const { detectGates: detectGates2, runGates: runGates2 } = await import("./gates-ZC67NMW3.js");
|
|
1716
1774
|
const cwd = process.cwd();
|
|
1717
1775
|
const gates = detectGates2(cwd);
|
|
1718
1776
|
if (gates.length === 0) {
|
|
@@ -1728,7 +1786,7 @@ program.command("check").description("Run this project\u2019s quality gates (typ
|
|
|
1728
1786
|
if (results.some((r) => !r.ok)) process.exitCode = 1;
|
|
1729
1787
|
});
|
|
1730
1788
|
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) => {
|
|
1731
|
-
const { captureViewports: captureViewports2 } = await import("./preview-
|
|
1789
|
+
const { captureViewports: captureViewports2 } = await import("./preview-ZHUQT7TJ.js");
|
|
1732
1790
|
const result = await captureViewports2(process.cwd(), url);
|
|
1733
1791
|
if (!result) {
|
|
1734
1792
|
console.error(pc.red("\u2717 no Chrome/Chromium found"));
|
|
@@ -1755,11 +1813,16 @@ configCommand.command("path").description("Show config file locations").action((
|
|
|
1755
1813
|
console.log(`global ${paths.globalFile}`);
|
|
1756
1814
|
console.log(`project ${paths.projectFile}`);
|
|
1757
1815
|
});
|
|
1758
|
-
program.action(() => {
|
|
1816
|
+
program.action(async () => {
|
|
1759
1817
|
const cwd = process.cwd();
|
|
1760
1818
|
const config = loadConfig(defaultPaths(cwd));
|
|
1761
1819
|
const engineId = resolveEngineId(config);
|
|
1762
1820
|
const model = resolveModel(config, engineId);
|
|
1821
|
+
let theme2 = config.theme;
|
|
1822
|
+
if (!theme2 && !process.env.NO_COLOR) {
|
|
1823
|
+
const { detectBackground } = await import("./background-J7OQTYEC.js");
|
|
1824
|
+
if (await detectBackground() === "light") theme2 = "light";
|
|
1825
|
+
}
|
|
1763
1826
|
render(
|
|
1764
1827
|
/* @__PURE__ */ jsx4(
|
|
1765
1828
|
App,
|
|
@@ -1772,7 +1835,8 @@ program.action(() => {
|
|
|
1772
1835
|
autoProbe: config.autoProbe,
|
|
1773
1836
|
autoCheck: config.autoCheck,
|
|
1774
1837
|
bell: config.bell,
|
|
1775
|
-
|
|
1838
|
+
budgetUsd: config.budgetUsd,
|
|
1839
|
+
initialTheme: theme2
|
|
1776
1840
|
}
|
|
1777
1841
|
)
|
|
1778
1842
|
);
|
|
@@ -5,20 +5,24 @@ import {
|
|
|
5
5
|
buildRuntimeFixPrompt,
|
|
6
6
|
captureViewports,
|
|
7
7
|
comparePulse,
|
|
8
|
+
loadRoutes,
|
|
8
9
|
previewDir,
|
|
9
10
|
probeRuntime,
|
|
11
|
+
routeShotName,
|
|
10
12
|
runtimeSummary
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-DKQ5KJD7.js";
|
|
12
14
|
import "./chunk-OC6RU6XH.js";
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
+
import "./chunk-CJXYSQNB.js";
|
|
16
|
+
import "./chunk-CH4GNJCZ.js";
|
|
15
17
|
export {
|
|
16
18
|
VIEWPORTS,
|
|
17
19
|
buildReviewPrompt,
|
|
18
20
|
buildRuntimeFixPrompt,
|
|
19
21
|
captureViewports,
|
|
20
22
|
comparePulse,
|
|
23
|
+
loadRoutes,
|
|
21
24
|
previewDir,
|
|
22
25
|
probeRuntime,
|
|
26
|
+
routeShotName,
|
|
23
27
|
runtimeSummary
|
|
24
28
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
screenshotVariants
|
|
4
|
+
} from "./chunk-QNNT6FP4.js";
|
|
5
|
+
import "./chunk-XLNTTZX4.js";
|
|
6
|
+
import "./chunk-P3H4N2EN.js";
|
|
7
|
+
import "./chunk-TI2R7QRL.js";
|
|
8
|
+
import "./chunk-CJXYSQNB.js";
|
|
9
|
+
import "./chunk-CH4GNJCZ.js";
|
|
10
|
+
export {
|
|
11
|
+
screenshotVariants
|
|
12
|
+
};
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
runVariants,
|
|
10
10
|
variantPrompt,
|
|
11
11
|
variantsRoot
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-XLNTTZX4.js";
|
|
13
13
|
import "./chunk-P3H4N2EN.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-TI2R7QRL.js";
|
|
15
|
+
import "./chunk-CH4GNJCZ.js";
|
|
16
16
|
export {
|
|
17
17
|
MAX_VARIANTS,
|
|
18
18
|
applyVariant,
|
package/package.json
CHANGED
package/dist/shots-LRYYMTPK.js
DELETED
|
@@ -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
|
-
};
|