@aayambansal/squint 0.2.2 → 0.2.3
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 +6 -3
- package/dist/{chunk-XZKQZKEE.js → chunk-4LAU5TGK.js} +18 -0
- package/dist/chunk-EECGXFRX.js +39 -0
- package/dist/{chunk-73ULM6HF.js → chunk-SU6YRRMF.js} +1 -1
- package/dist/cli.js +66 -16
- package/dist/commands-6XDXUVO6.js +11 -0
- package/dist/{preview-JJJLDF7H.js → preview-UX4VS4SX.js} +1 -1
- package/dist/{skills-UGHU22BS.js → skills-DNBHZAAU.js} +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -151,9 +151,12 @@ squint doctor --probe # run every engine end to end, verify auth act
|
|
|
151
151
|
`/fix <n>` targets one. The footer counts what's open.
|
|
152
152
|
- **Variants without leaving**: `/variants 3 <ask>` runs parallel explorations with
|
|
153
153
|
streaming per-family status; `/variants apply <id>` keeps the winner.
|
|
154
|
-
- **Commands**:
|
|
155
|
-
`/
|
|
156
|
-
`/
|
|
154
|
+
- **Commands**: type `/` and matching commands appear with descriptions; tab completes.
|
|
155
|
+
`/dev` `/check` `/problems` `/fix [n]` `/shot` `/review [focus]` `/variants` `/undo`
|
|
156
|
+
`/checkpoints` `/restore <n>` `/mode` `/theme` `/copy` `/save` `/resume` `/clear`.
|
|
157
|
+
- **Visual pulse**: every clean turn is screenshotted and pixel-compared with the last —
|
|
158
|
+
drift shows up as a number, not a surprise. `.squint/locks` lists paths the engine must
|
|
159
|
+
never touch; `/save` exports the transcript as markdown.
|
|
157
160
|
- Assistant output renders as markdown; the done line measures real work via git
|
|
158
161
|
(`3 files +42 −7`); the footer tracks session turns and cost; a bell rings when a
|
|
159
162
|
turn finishes.
|
|
@@ -51,12 +51,29 @@ function matchSkills(skills, ask) {
|
|
|
51
51
|
const haystack = ask.toLowerCase();
|
|
52
52
|
return skills.filter((skill) => skill.triggers.some((t) => haystack.includes(t)));
|
|
53
53
|
}
|
|
54
|
+
function loadLocks(cwd) {
|
|
55
|
+
try {
|
|
56
|
+
return fs.readFileSync(path.join(cwd, ".squint", "locks"), "utf8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
57
|
+
} catch {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
54
61
|
function enrich(cwd, ask) {
|
|
55
62
|
const parts = [];
|
|
56
63
|
const rules = loadRules(cwd);
|
|
57
64
|
if (rules) parts.push(`## Project rules (always apply)
|
|
58
65
|
|
|
59
66
|
${rules}`);
|
|
67
|
+
const locks = loadLocks(cwd);
|
|
68
|
+
if (locks.length > 0) {
|
|
69
|
+
parts.push(
|
|
70
|
+
`## Locked files (hard constraint)
|
|
71
|
+
|
|
72
|
+
Never modify these paths, no matter what the task seems to need:
|
|
73
|
+
${locks.map((l) => `- ${l}`).join("\n")}
|
|
74
|
+
If the task appears to require changing them, stop and explain instead.`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
60
77
|
const matched = matchSkills(loadSkills(cwd), ask);
|
|
61
78
|
for (const skill of matched) {
|
|
62
79
|
parts.push(`## Project notes: ${skill.name}
|
|
@@ -76,5 +93,6 @@ export {
|
|
|
76
93
|
loadSkills,
|
|
77
94
|
loadRules,
|
|
78
95
|
matchSkills,
|
|
96
|
+
loadLocks,
|
|
79
97
|
enrich
|
|
80
98
|
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/session/commands.ts
|
|
4
|
+
var COMMANDS = [
|
|
5
|
+
{ name: "dev", description: "start/stop the project dev server" },
|
|
6
|
+
{ name: "check", description: "run all quality gates (typecheck, lint, test, build)" },
|
|
7
|
+
{ name: "problems", description: "list open findings from gates, dev server, runtime, a11y" },
|
|
8
|
+
{ name: "fix", args: "[n]", description: "send all open problems to the engine, or just problem n" },
|
|
9
|
+
{ name: "shot", description: "screenshot the app at mobile/tablet/desktop" },
|
|
10
|
+
{ name: "review", args: "[focus]", description: "screenshots + the engine critiques its own rendered work" },
|
|
11
|
+
{ name: "variants", args: "<2-4> <ask>", description: "parallel design explorations; apply/list/clean" },
|
|
12
|
+
{ name: "undo", description: "revert the last ask (files only)" },
|
|
13
|
+
{ name: "checkpoints", description: "list per-ask checkpoints" },
|
|
14
|
+
{ name: "restore", args: "<n>", description: "rewind files to before ask n" },
|
|
15
|
+
{ name: "mode", args: "plan|safe|yolo", description: "how much the engine may do (shift+tab cycles)" },
|
|
16
|
+
{ name: "engine", args: "<id>", description: "switch backend (new session)" },
|
|
17
|
+
{ name: "model", args: "[name]", description: "model override for the engine" },
|
|
18
|
+
{ name: "theme", args: "[name]", description: "switch the TUI theme", viewLevel: true },
|
|
19
|
+
{ name: "copy", description: "copy the last reply to the clipboard" },
|
|
20
|
+
{ name: "save", description: "export the transcript to .squint/transcripts/" },
|
|
21
|
+
{ name: "queue", args: "clear", description: "drop queued asks" },
|
|
22
|
+
{ name: "resume", description: "pick up the previous session for this repo" },
|
|
23
|
+
{ name: "clear", description: "new session (transcript, totals, persisted state)" },
|
|
24
|
+
{ name: "help", description: "list commands" },
|
|
25
|
+
{ name: "quit", description: "exit with a session summary" }
|
|
26
|
+
];
|
|
27
|
+
function completeCommand(partial) {
|
|
28
|
+
const query = partial.toLowerCase();
|
|
29
|
+
return COMMANDS.filter((c) => c.name.startsWith(query));
|
|
30
|
+
}
|
|
31
|
+
function commandHelp() {
|
|
32
|
+
return COMMANDS.map((c) => `/${c.name}${c.args ? ` ${c.args}` : ""} \u2014 ${c.description}`).join("\n");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export {
|
|
36
|
+
COMMANDS,
|
|
37
|
+
completeCommand,
|
|
38
|
+
commandHelp
|
|
39
|
+
};
|
|
@@ -16,7 +16,7 @@ import path2 from "path";
|
|
|
16
16
|
// src/state/state.ts
|
|
17
17
|
import fs from "fs";
|
|
18
18
|
import path from "path";
|
|
19
|
-
var IGNORED = ["preview/", "state.json", "variants/"];
|
|
19
|
+
var IGNORED = ["preview/", "state.json", "variants/", "transcripts/"];
|
|
20
20
|
function ensureSquintIgnore(cwd) {
|
|
21
21
|
const dir = path.join(cwd, ".squint");
|
|
22
22
|
fs.mkdirSync(dir, { recursive: true });
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
diffStatSince,
|
|
4
|
+
isGitRepo,
|
|
5
|
+
restoreSnapshot,
|
|
6
|
+
takeSnapshot
|
|
7
|
+
} from "./chunk-YHRAOBI2.js";
|
|
2
8
|
import {
|
|
3
9
|
DevServer,
|
|
4
10
|
buildFixPrompt,
|
|
@@ -17,6 +23,9 @@ import {
|
|
|
17
23
|
import {
|
|
18
24
|
runAgent
|
|
19
25
|
} from "./chunk-OTG4ZB4R.js";
|
|
26
|
+
import {
|
|
27
|
+
completeCommand
|
|
28
|
+
} from "./chunk-EECGXFRX.js";
|
|
20
29
|
import {
|
|
21
30
|
buildGatePrompt,
|
|
22
31
|
detectFastGates,
|
|
@@ -33,7 +42,7 @@ import {
|
|
|
33
42
|
probeRuntime,
|
|
34
43
|
runtimeSummary,
|
|
35
44
|
saveState
|
|
36
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-SU6YRRMF.js";
|
|
37
46
|
import "./chunk-OC6RU6XH.js";
|
|
38
47
|
import {
|
|
39
48
|
findChrome
|
|
@@ -44,13 +53,7 @@ import {
|
|
|
44
53
|
} from "./chunk-2LRIKWBU.js";
|
|
45
54
|
import {
|
|
46
55
|
enrich
|
|
47
|
-
} from "./chunk-
|
|
48
|
-
import {
|
|
49
|
-
diffStatSince,
|
|
50
|
-
isGitRepo,
|
|
51
|
-
restoreSnapshot,
|
|
52
|
-
takeSnapshot
|
|
53
|
-
} from "./chunk-YHRAOBI2.js";
|
|
56
|
+
} from "./chunk-4LAU5TGK.js";
|
|
54
57
|
|
|
55
58
|
// src/cli.tsx
|
|
56
59
|
import { Command } from "commander";
|
|
@@ -669,6 +672,38 @@ They are objective defects, not style preferences.`
|
|
|
669
672
|
}
|
|
670
673
|
break;
|
|
671
674
|
}
|
|
675
|
+
case "save": {
|
|
676
|
+
void (async () => {
|
|
677
|
+
const fs2 = await import("fs");
|
|
678
|
+
const path4 = await import("path");
|
|
679
|
+
const dir = path4.join(this.opts.cwd, ".squint", "transcripts");
|
|
680
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
681
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
682
|
+
const file = path4.join(dir, `${stamp}.md`);
|
|
683
|
+
const lines = [`# squint session \u2014 ${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16)}`, ""];
|
|
684
|
+
for (const item of this.state.items) {
|
|
685
|
+
switch (item.role) {
|
|
686
|
+
case "user":
|
|
687
|
+
lines.push(`## \u276F ${item.text}`, "");
|
|
688
|
+
break;
|
|
689
|
+
case "assistant":
|
|
690
|
+
lines.push(item.text, "");
|
|
691
|
+
break;
|
|
692
|
+
case "tool":
|
|
693
|
+
lines.push(`- \u2699 ${item.text}`);
|
|
694
|
+
break;
|
|
695
|
+
case "thinking":
|
|
696
|
+
break;
|
|
697
|
+
default:
|
|
698
|
+
lines.push(`> ${item.role === "error" ? "\u2717 " : ""}${item.text.split("\n").join("\n> ")}`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
lines.push("", `> ${this.summary()}`);
|
|
702
|
+
fs2.writeFileSync(file, lines.join("\n") + "\n");
|
|
703
|
+
this.push("status", `saved transcript \u2192 ${path4.relative(this.opts.cwd, file)}`);
|
|
704
|
+
})();
|
|
705
|
+
break;
|
|
706
|
+
}
|
|
672
707
|
case "copy": {
|
|
673
708
|
const last = this.state.items.findLast((i) => i.role === "assistant");
|
|
674
709
|
if (!last) {
|
|
@@ -857,12 +892,10 @@ They are objective defects, not style preferences.`
|
|
|
857
892
|
clearState(this.opts.cwd);
|
|
858
893
|
this.notify({ items: [], totals: { costUsd: 0, turns: 0 } });
|
|
859
894
|
break;
|
|
860
|
-
case "help":
|
|
861
|
-
this.push(
|
|
862
|
-
"status",
|
|
863
|
-
"/engine <id> \xB7 /model <name> \xB7 /mode plan|safe|yolo \xB7 /dev \xB7 /check (gates) \xB7 /problems \xB7 /fix [n] \xB7 /shot \xB7 /review [focus] \xB7 /variants <2-4> <ask> \xB7 /undo \xB7 /checkpoints \xB7 /restore <n> \xB7 /copy (last reply) \xB7 /resume \xB7 /clear \xB7 /quit"
|
|
864
|
-
);
|
|
895
|
+
case "help": {
|
|
896
|
+
void import("./commands-6XDXUVO6.js").then(({ commandHelp }) => this.push("status", commandHelp()));
|
|
865
897
|
break;
|
|
898
|
+
}
|
|
866
899
|
case "quit":
|
|
867
900
|
case "exit":
|
|
868
901
|
this.push("status", this.summary());
|
|
@@ -1248,6 +1281,13 @@ function App({
|
|
|
1248
1281
|
session.cycleMode();
|
|
1249
1282
|
return;
|
|
1250
1283
|
}
|
|
1284
|
+
if (key.tab && line.text.startsWith("/") && !line.text.includes(" ")) {
|
|
1285
|
+
const matches = completeCommand(line.text.slice(1));
|
|
1286
|
+
if (matches.length > 0) {
|
|
1287
|
+
setLine(fromText(`/${matches[0].name}${matches[0].args ? " " : ""}`));
|
|
1288
|
+
}
|
|
1289
|
+
return;
|
|
1290
|
+
}
|
|
1251
1291
|
if (key.return) {
|
|
1252
1292
|
const value = line.text.trim();
|
|
1253
1293
|
setLine(emptyLine);
|
|
@@ -1341,6 +1381,16 @@ function App({
|
|
|
1341
1381
|
"\u22EF queued: ",
|
|
1342
1382
|
queued
|
|
1343
1383
|
] }) }, index)),
|
|
1384
|
+
line.text.startsWith("/") && !line.text.includes(" ") && /* @__PURE__ */ jsx3(Box2, { flexDirection: "column", children: completeCommand(line.text.slice(1)).slice(0, 5).map((command, index) => /* @__PURE__ */ jsxs3(Text3, { color: index === 0 ? theme2.accent : theme2.dim, children: [
|
|
1385
|
+
"/",
|
|
1386
|
+
command.name,
|
|
1387
|
+
command.args ? ` ${command.args}` : "",
|
|
1388
|
+
" ",
|
|
1389
|
+
/* @__PURE__ */ jsxs3(Text3, { color: theme2.dim, children: [
|
|
1390
|
+
"\u2014 ",
|
|
1391
|
+
command.description
|
|
1392
|
+
] })
|
|
1393
|
+
] }, command.name)) }),
|
|
1344
1394
|
/* @__PURE__ */ jsx3(Box2, { marginTop: state.running ? 0 : 1, children: /* @__PURE__ */ jsxs3(Text3, { children: [
|
|
1345
1395
|
/* @__PURE__ */ jsx3(Text3, { color: theme2.accent, children: "\u276F " }),
|
|
1346
1396
|
line.text.slice(0, line.cursor),
|
|
@@ -1381,7 +1431,7 @@ function App({
|
|
|
1381
1431
|
|
|
1382
1432
|
// src/cli.tsx
|
|
1383
1433
|
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1384
|
-
var VERSION = "0.2.
|
|
1434
|
+
var VERSION = "0.2.3";
|
|
1385
1435
|
var program = new Command();
|
|
1386
1436
|
program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
|
|
1387
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 (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(
|
|
@@ -1492,7 +1542,7 @@ Next: ${pc.bold(`${cd}${options.install ? "" : "npm install && "}squint`)}`);
|
|
|
1492
1542
|
});
|
|
1493
1543
|
var skillsCommand = program.command("skills").description("Project knowledge injected into asks (.squint/rules.md + .squint/skills/)");
|
|
1494
1544
|
skillsCommand.command("list").description("Show always-on rules and trigger-matched skills").action(async () => {
|
|
1495
|
-
const { loadRules, loadSkills } = await import("./skills-
|
|
1545
|
+
const { loadRules, loadSkills } = await import("./skills-DNBHZAAU.js");
|
|
1496
1546
|
const cwd = process.cwd();
|
|
1497
1547
|
const rules = loadRules(cwd);
|
|
1498
1548
|
console.log(rules ? `${pc.green("\u2713")} rules.md ${pc.dim(`(${rules.split("\n").length} lines, always on)`)}` : pc.dim("\u25CB no .squint/rules.md"));
|
|
@@ -1678,7 +1728,7 @@ program.command("check").description("Run this project\u2019s quality gates (typ
|
|
|
1678
1728
|
if (results.some((r) => !r.ok)) process.exitCode = 1;
|
|
1679
1729
|
});
|
|
1680
1730
|
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) => {
|
|
1681
|
-
const { captureViewports: captureViewports2 } = await import("./preview-
|
|
1731
|
+
const { captureViewports: captureViewports2 } = await import("./preview-UX4VS4SX.js");
|
|
1682
1732
|
const result = await captureViewports2(process.cwd(), url);
|
|
1683
1733
|
if (!result) {
|
|
1684
1734
|
console.error(pc.red("\u2717 no Chrome/Chromium found"));
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
enrich,
|
|
4
|
+
loadLocks,
|
|
4
5
|
loadRules,
|
|
5
6
|
loadSkills,
|
|
6
7
|
matchSkills,
|
|
7
8
|
parseSkill
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-4LAU5TGK.js";
|
|
9
10
|
export {
|
|
10
11
|
enrich,
|
|
12
|
+
loadLocks,
|
|
11
13
|
loadRules,
|
|
12
14
|
loadSkills,
|
|
13
15
|
matchSkills,
|
package/package.json
CHANGED