@aayambansal/squint 0.5.0 → 0.5.1
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/dist/{App-MC2XEM7K.js → App-KTNAMHY6.js} +7 -6
- package/dist/{cdp-WSWOSDEX.js → cdp-D2F4P7UQ.js} +1 -1
- package/dist/{chunk-EB4OSUB7.js → chunk-2NYNTVMX.js} +2 -2
- package/dist/{chunk-DCFNX2CQ.js → chunk-3YCG234A.js} +39 -0
- package/dist/{chunk-YK5DEB7T.js → chunk-AMA3F2Y2.js} +1 -1
- package/dist/{chunk-CRDRWTON.js → chunk-ERF2SPUW.js} +3 -3
- package/dist/{chunk-WASLLXEZ.js → chunk-G5NS2IFQ.js} +61 -10
- package/dist/chunk-IEQGTVWN.js +52 -0
- package/dist/{chunk-BKOGVFCO.js → chunk-LESZB7DT.js} +5 -3
- package/dist/{chunk-ARDV4XH6.js → chunk-UBADCBPT.js} +14 -59
- package/dist/{chunk-43NQNIJY.js → chunk-VJ2QKHYK.js} +2 -0
- package/dist/cli.js +19 -18
- package/dist/{commands-BY44HDQ6.js → commands-WC7V6EAE.js} +1 -1
- package/dist/{contextDoctor-3Y36YURE.js → contextDoctor-LHKGSIEM.js} +3 -2
- package/dist/designLog-S67J7SO2.js +11 -0
- package/dist/{preview-CDEMPHWV.js → preview-JN5PTWLX.js} +2 -2
- package/dist/{remote-C4BACCKX.js → remote-UOV4ZXWU.js} +6 -5
- package/dist/{sentinel-42NZRTTS.js → sentinel-4SKSSCXX.js} +0 -0
- package/dist/{server-ENT2OFNL.js → server-2WPGU3KQ.js} +6 -5
- package/dist/{skills-POB4ZZY5.js → skills-DQTE5Q77.js} +2 -1
- package/package.json +1 -1
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
App
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-2NYNTVMX.js";
|
|
5
|
+
import "./chunk-VJ2QKHYK.js";
|
|
6
|
+
import "./chunk-G5NS2IFQ.js";
|
|
7
|
+
import "./chunk-UBADCBPT.js";
|
|
8
|
+
import "./chunk-IEQGTVWN.js";
|
|
8
9
|
import "./chunk-AUJJGMZG.js";
|
|
9
10
|
import "./chunk-YHRAOBI2.js";
|
|
10
11
|
import "./chunk-2I3YHT6P.js";
|
|
@@ -13,9 +14,9 @@ import "./chunk-6NPUVPQD.js";
|
|
|
13
14
|
import "./chunk-K5QJMSJH.js";
|
|
14
15
|
import "./chunk-WAJXATCO.js";
|
|
15
16
|
import "./chunk-62JNF5M2.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-ERF2SPUW.js";
|
|
17
18
|
import "./chunk-7CAGWFAQ.js";
|
|
18
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-3YCG234A.js";
|
|
19
20
|
import "./chunk-PYC53J7D.js";
|
|
20
21
|
import "./chunk-GV2HAALP.js";
|
|
21
22
|
export {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
completeCommand
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VJ2QKHYK.js";
|
|
5
5
|
import {
|
|
6
6
|
Session
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-G5NS2IFQ.js";
|
|
8
8
|
|
|
9
9
|
// src/tui/App.tsx
|
|
10
10
|
import { Box as Box3, Static, Text as Text3, useApp, useInput } from "ink";
|
|
@@ -771,6 +771,44 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
|
|
|
771
771
|
if (checkFailures.length >= 15) break;
|
|
772
772
|
}
|
|
773
773
|
if (audit) {
|
|
774
|
+
const kbdFindings = [];
|
|
775
|
+
try {
|
|
776
|
+
const seen = [];
|
|
777
|
+
let trapped = null;
|
|
778
|
+
for (let i = 0; i < 12; i++) {
|
|
779
|
+
await connection.send("Input.dispatchKeyEvent", { type: "rawKeyDown", key: "Tab", code: "Tab", windowsVirtualKeyCode: 9 }, sessionId);
|
|
780
|
+
await connection.send("Input.dispatchKeyEvent", { type: "keyUp", key: "Tab", code: "Tab", windowsVirtualKeyCode: 9 }, sessionId);
|
|
781
|
+
const { result } = await connection.send(
|
|
782
|
+
"Runtime.evaluate",
|
|
783
|
+
{
|
|
784
|
+
expression: `(() => {
|
|
785
|
+
const el = document.activeElement;
|
|
786
|
+
if (!el || el === document.body || el === document.documentElement) return null;
|
|
787
|
+
let label = el.tagName.toLowerCase();
|
|
788
|
+
if (el.id) label += '#' + el.id;
|
|
789
|
+
else if (el.classList[0]) label += '.' + el.classList[0];
|
|
790
|
+
const cs = getComputedStyle(el);
|
|
791
|
+
const visible = (cs.outlineStyle !== 'none' && parseFloat(cs.outlineWidth) > 0) || cs.boxShadow !== 'none';
|
|
792
|
+
return { label, visible };
|
|
793
|
+
})()`,
|
|
794
|
+
returnByValue: true
|
|
795
|
+
},
|
|
796
|
+
sessionId
|
|
797
|
+
);
|
|
798
|
+
const stop = result?.value;
|
|
799
|
+
if (!stop) continue;
|
|
800
|
+
if (seen.length > 0 && seen[seen.length - 1] === stop.label && seen.filter((s) => s === stop.label).length >= 2) {
|
|
801
|
+
trapped = stop.label;
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
seen.push(stop.label);
|
|
805
|
+
if (!stop.visible) kbdFindings.push(`keyboard: focus invisible on <${stop.label}> (tab stop ${seen.length}) \u2014 outline and box-shadow both none`);
|
|
806
|
+
}
|
|
807
|
+
if (trapped) kbdFindings.push(`keyboard: focus trapped at <${trapped}> \u2014 Tab cannot leave it`);
|
|
808
|
+
if (seen.length === 0) kbdFindings.push("keyboard: no tabbable elements \u2014 the page is unreachable without a mouse");
|
|
809
|
+
await connection.send("Runtime.evaluate", { expression: "document.activeElement && document.activeElement.blur()" }, sessionId).catch(() => null);
|
|
810
|
+
} catch {
|
|
811
|
+
}
|
|
774
812
|
try {
|
|
775
813
|
const { result } = await connection.send(
|
|
776
814
|
"Runtime.evaluate",
|
|
@@ -778,6 +816,7 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
|
|
|
778
816
|
sessionId
|
|
779
817
|
);
|
|
780
818
|
if (Array.isArray(result?.value)) a11y = result.value.map(String);
|
|
819
|
+
a11y.push(...kbdFindings);
|
|
781
820
|
} catch {
|
|
782
821
|
}
|
|
783
822
|
try {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
cdpCapture,
|
|
7
7
|
hasWebSocket
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3YCG234A.js";
|
|
9
9
|
import {
|
|
10
10
|
findChrome,
|
|
11
11
|
screenshot
|
|
@@ -163,13 +163,13 @@ async function probeRuntime(url, cwd) {
|
|
|
163
163
|
async function comparePulse(previous, current) {
|
|
164
164
|
const chrome = findChrome();
|
|
165
165
|
if (!chrome || !hasWebSocket()) return null;
|
|
166
|
-
const { pixelDiffPct } = await import("./cdp-
|
|
166
|
+
const { pixelDiffPct } = await import("./cdp-D2F4P7UQ.js");
|
|
167
167
|
return pixelDiffPct(chrome, previous, current);
|
|
168
168
|
}
|
|
169
169
|
async function comparePulseAttributed(previous, current, url) {
|
|
170
170
|
const chrome = findChrome();
|
|
171
171
|
if (!chrome || !hasWebSocket()) return null;
|
|
172
|
-
const { pixelDiffAttributed } = await import("./cdp-
|
|
172
|
+
const { pixelDiffAttributed } = await import("./cdp-D2F4P7UQ.js");
|
|
173
173
|
return pixelDiffAttributed(chrome, previous, current, url);
|
|
174
174
|
}
|
|
175
175
|
function buildRuntimeFixPrompt(report) {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
appendDecision,
|
|
4
3
|
enrich
|
|
5
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UBADCBPT.js";
|
|
5
|
+
import {
|
|
6
|
+
appendDecision
|
|
7
|
+
} from "./chunk-IEQGTVWN.js";
|
|
6
8
|
import {
|
|
7
9
|
applySandbox,
|
|
8
10
|
discardSandbox,
|
|
@@ -49,7 +51,7 @@ import {
|
|
|
49
51
|
comparePulseAttributed,
|
|
50
52
|
probeRuntime,
|
|
51
53
|
runtimeSummary
|
|
52
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-ERF2SPUW.js";
|
|
53
55
|
import {
|
|
54
56
|
clearState,
|
|
55
57
|
loadState,
|
|
@@ -102,6 +104,7 @@ function prefixed(payload) {
|
|
|
102
104
|
|
|
103
105
|
// src/session/engine.ts
|
|
104
106
|
var MAX_AUTO_FIX_ATTEMPTS = 2;
|
|
107
|
+
var MAX_GOAL_FIX_ATTEMPTS = 6;
|
|
105
108
|
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
106
109
|
var Session = class {
|
|
107
110
|
constructor(opts) {
|
|
@@ -153,6 +156,7 @@ var Session = class {
|
|
|
153
156
|
fixAttempts = 0;
|
|
154
157
|
reviewTipShown = false;
|
|
155
158
|
pendingApproval = null;
|
|
159
|
+
goal = null;
|
|
156
160
|
lastPulse = null;
|
|
157
161
|
lastPerf = null;
|
|
158
162
|
autoReviewedThisAsk = false;
|
|
@@ -210,10 +214,11 @@ var Session = class {
|
|
|
210
214
|
}
|
|
211
215
|
/** Launch a capped auto-fix turn over all open problems. Returns true if launched. */
|
|
212
216
|
maybeAutoFix() {
|
|
213
|
-
|
|
217
|
+
const cap = this.goal ? MAX_GOAL_FIX_ATTEMPTS : MAX_AUTO_FIX_ATTEMPTS;
|
|
218
|
+
if (!this.opts.autoFix || this.fixAttempts >= cap) return false;
|
|
214
219
|
if (this.state.problems.length === 0) return false;
|
|
215
220
|
this.fixAttempts += 1;
|
|
216
|
-
this.push("status", `auto-fix attempt ${this.fixAttempts}/${
|
|
221
|
+
this.push("status", `auto-fix attempt ${this.fixAttempts}/${cap}${this.goal ? " (goal armed)" : ""}`);
|
|
217
222
|
this.notify({ running: false });
|
|
218
223
|
this.dispatchFix([...this.state.problems]);
|
|
219
224
|
return true;
|
|
@@ -510,7 +515,7 @@ ${driftSummary(drift)}`);
|
|
|
510
515
|
} catch {
|
|
511
516
|
}
|
|
512
517
|
try {
|
|
513
|
-
const { scanEvasion, sentinelSummary } = await import("./sentinel-
|
|
518
|
+
const { scanEvasion, sentinelSummary } = await import("./sentinel-4SKSSCXX.js");
|
|
514
519
|
const evasions = scanEvasion(this.execCwd(), checkpoint.snapshot.stashHash ?? "HEAD");
|
|
515
520
|
if (evasions.length > 0) {
|
|
516
521
|
this.push("error", `\u26A0 sentinel: ${evasions.length} gate-evasion pattern(s) this turn
|
|
@@ -694,6 +699,15 @@ ${probe.checkFailures.slice(0, 5).join("\n")}`);
|
|
|
694
699
|
this.push("status", `skills: ${enrichment.matchedSkills.join(", ")}`);
|
|
695
700
|
}
|
|
696
701
|
prompt += enrichment.sections;
|
|
702
|
+
if (this.goal) {
|
|
703
|
+
prompt += `
|
|
704
|
+
|
|
705
|
+
## Standing goal (machine-checked)
|
|
706
|
+
|
|
707
|
+
${this.goal}
|
|
708
|
+
|
|
709
|
+
squint verifies every turn \u2014 gates, runtime probe, page audits. Do not declare this done while any of its checks fail; squint will keep sending failures back until they are clean.`;
|
|
710
|
+
}
|
|
697
711
|
await this.runTurn(prompt, ask);
|
|
698
712
|
}
|
|
699
713
|
/** Restore files to the state before checkpoint `index`; drop it and everything after. */
|
|
@@ -947,8 +961,45 @@ They are objective defects, not style preferences.`
|
|
|
947
961
|
}
|
|
948
962
|
break;
|
|
949
963
|
}
|
|
964
|
+
case "distill": {
|
|
965
|
+
void (async () => {
|
|
966
|
+
const { loadDecisions } = await import("./designLog-S67J7SO2.js");
|
|
967
|
+
const decisions = loadDecisions(this.opts.cwd, 24);
|
|
968
|
+
if (decisions.length < 3) {
|
|
969
|
+
this.push("status", `only ${decisions.length} decision(s) on record \u2014 distillation needs a few more (/decide, variants, approvals, rollbacks all feed the ledger)`);
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
const ledger = decisions.map((d) => `- [${d.source}] ${d.decision}`).join("\n");
|
|
973
|
+
const prompt = `The design ledger below is every decision this project has recorded \u2014 approvals, rejections, chosen variants, rollbacks. Distill the accumulated taste into standing enforcement:
|
|
974
|
+
|
|
975
|
+
${ledger}
|
|
976
|
+
|
|
977
|
+
1. Append at most 3 SHORT always-on rules to .squint/rules.md capturing patterns that repeat across decisions (rejections matter most \u2014 "no gradient buttons" beats restating one-off choices). Create the file if missing; never delete existing rules.
|
|
978
|
+
2. Where a decision is mechanically checkable in the DOM, write a persistent check at .squint/checks/<name>.js \u2014 plain JS that evaluates IN THE PAGE to an array of failure strings (empty = pass). At most 2 new checks; skip anything that needs judgment rather than a selector.
|
|
979
|
+
3. Reply with exactly what you wrote and why, briefly.
|
|
980
|
+
|
|
981
|
+
Do not restyle anything \u2014 this task only writes rules and checks.`;
|
|
982
|
+
await this.runTurn(prompt, "/distill \u2014 compress the ledger into rules and checks", this.opts.fixModel);
|
|
983
|
+
})();
|
|
984
|
+
break;
|
|
985
|
+
}
|
|
986
|
+
case "goal": {
|
|
987
|
+
if (!arg || arg === "show") {
|
|
988
|
+
this.push("status", this.goal ? `standing goal: ${this.goal}` : "no standing goal \u2014 /goal <objective> arms one; /goal off clears");
|
|
989
|
+
break;
|
|
990
|
+
}
|
|
991
|
+
if (arg === "off") {
|
|
992
|
+
this.goal = null;
|
|
993
|
+
this.push("status", "goal cleared \u2014 auto-fix back to the normal cap");
|
|
994
|
+
break;
|
|
995
|
+
}
|
|
996
|
+
this.goal = arg;
|
|
997
|
+
this.push("status", `goal armed: ${arg}
|
|
998
|
+
every ask now carries it; auto-fix presses to ${MAX_GOAL_FIX_ATTEMPTS} attempts until squint's checks come back clean`);
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
950
1001
|
case "context": {
|
|
951
|
-
import("./contextDoctor-
|
|
1002
|
+
import("./contextDoctor-LHKGSIEM.js").then(({ contextReport, formatContextReport }) => {
|
|
952
1003
|
this.push("status", formatContextReport(contextReport(this.execCwd())));
|
|
953
1004
|
}).catch((error) => {
|
|
954
1005
|
this.push("status", `context report failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -1083,8 +1134,8 @@ They are objective defects, not style preferences.`
|
|
|
1083
1134
|
this.push("error", "no Chrome/Chromium found for flows");
|
|
1084
1135
|
return;
|
|
1085
1136
|
}
|
|
1086
|
-
const { runFlow } = await import("./cdp-
|
|
1087
|
-
const { previewDir } = await import("./preview-
|
|
1137
|
+
const { runFlow } = await import("./cdp-D2F4P7UQ.js");
|
|
1138
|
+
const { previewDir } = await import("./preview-JN5PTWLX.js");
|
|
1088
1139
|
this.push("status", `replaying ${flows.length} flow(s)\u2026`);
|
|
1089
1140
|
this.notify({ running: true, runStartedAt: Date.now() });
|
|
1090
1141
|
const failures = [];
|
|
@@ -1408,7 +1459,7 @@ ${sandboxFiles(this.opts.cwd).join("\n")}`);
|
|
|
1408
1459
|
this.notify({ items: [], totals: { costUsd: 0, turns: 0 } });
|
|
1409
1460
|
break;
|
|
1410
1461
|
case "help": {
|
|
1411
|
-
void import("./commands-
|
|
1462
|
+
void import("./commands-WC7V6EAE.js").then(({ commandHelp }) => this.push("status", commandHelp()));
|
|
1412
1463
|
break;
|
|
1413
1464
|
}
|
|
1414
1465
|
case "quit":
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/session/designLog.ts
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
function logFile(cwd) {
|
|
7
|
+
return path.join(cwd, ".squint", "design-log.jsonl");
|
|
8
|
+
}
|
|
9
|
+
function appendDecision(cwd, entry) {
|
|
10
|
+
try {
|
|
11
|
+
fs.mkdirSync(path.join(cwd, ".squint"), { recursive: true });
|
|
12
|
+
const record = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry };
|
|
13
|
+
fs.appendFileSync(logFile(cwd), JSON.stringify(record) + "\n");
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function loadDecisions(cwd, limit = 8) {
|
|
18
|
+
try {
|
|
19
|
+
const lines = fs.readFileSync(logFile(cwd), "utf8").trim().split("\n");
|
|
20
|
+
const decisions = [];
|
|
21
|
+
for (const line of lines.slice(-limit * 2)) {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = JSON.parse(line);
|
|
24
|
+
if (typeof parsed?.decision === "string" && typeof parsed?.ts === "string") decisions.push(parsed);
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return decisions.slice(-limit);
|
|
29
|
+
} catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function decisionsSection(cwd) {
|
|
34
|
+
const decisions = loadDecisions(cwd);
|
|
35
|
+
if (decisions.length === 0) return "";
|
|
36
|
+
const lines = decisions.map((d) => {
|
|
37
|
+
const days = Math.floor((Date.now() - Date.parse(d.ts)) / 864e5);
|
|
38
|
+
const age = days <= 0 ? "today" : `${days}d ago`;
|
|
39
|
+
return `- ${d.decision} (${d.source}, ${age}${d.screenshot ? `, evidence: ${d.screenshot}` : ""})`;
|
|
40
|
+
});
|
|
41
|
+
return `## Design decisions on record
|
|
42
|
+
|
|
43
|
+
${lines.join("\n")}
|
|
44
|
+
|
|
45
|
+
These were decided deliberately. Do not silently undo them; if a task genuinely requires reversing one, say so explicitly first.`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
appendDecision,
|
|
50
|
+
loadDecisions,
|
|
51
|
+
decisionsSection
|
|
52
|
+
};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
decisionsSection,
|
|
4
3
|
inventorySection,
|
|
5
4
|
loadComponentInventory,
|
|
6
|
-
loadDecisions,
|
|
7
5
|
loadLocks,
|
|
8
6
|
loadRules,
|
|
9
7
|
loadSkills
|
|
10
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-UBADCBPT.js";
|
|
9
|
+
import {
|
|
10
|
+
decisionsSection,
|
|
11
|
+
loadDecisions
|
|
12
|
+
} from "./chunk-IEQGTVWN.js";
|
|
11
13
|
import {
|
|
12
14
|
loadBrief
|
|
13
15
|
} from "./chunk-WAJXATCO.js";
|
|
@@ -1,70 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
decisionsSection
|
|
4
|
+
} from "./chunk-IEQGTVWN.js";
|
|
2
5
|
|
|
3
6
|
// src/prompt/skills.ts
|
|
4
|
-
import
|
|
5
|
-
import
|
|
7
|
+
import fs2 from "fs";
|
|
8
|
+
import path2 from "path";
|
|
6
9
|
|
|
7
|
-
// src/
|
|
10
|
+
// src/prompt/registry.ts
|
|
8
11
|
import fs from "fs";
|
|
9
12
|
import path from "path";
|
|
10
|
-
function logFile(cwd) {
|
|
11
|
-
return path.join(cwd, ".squint", "design-log.jsonl");
|
|
12
|
-
}
|
|
13
|
-
function appendDecision(cwd, entry) {
|
|
14
|
-
try {
|
|
15
|
-
fs.mkdirSync(path.join(cwd, ".squint"), { recursive: true });
|
|
16
|
-
const record = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry };
|
|
17
|
-
fs.appendFileSync(logFile(cwd), JSON.stringify(record) + "\n");
|
|
18
|
-
} catch {
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
function loadDecisions(cwd, limit = 8) {
|
|
22
|
-
try {
|
|
23
|
-
const lines = fs.readFileSync(logFile(cwd), "utf8").trim().split("\n");
|
|
24
|
-
const decisions = [];
|
|
25
|
-
for (const line of lines.slice(-limit * 2)) {
|
|
26
|
-
try {
|
|
27
|
-
const parsed = JSON.parse(line);
|
|
28
|
-
if (typeof parsed?.decision === "string" && typeof parsed?.ts === "string") decisions.push(parsed);
|
|
29
|
-
} catch {
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return decisions.slice(-limit);
|
|
33
|
-
} catch {
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
function decisionsSection(cwd) {
|
|
38
|
-
const decisions = loadDecisions(cwd);
|
|
39
|
-
if (decisions.length === 0) return "";
|
|
40
|
-
const lines = decisions.map((d) => {
|
|
41
|
-
const days = Math.floor((Date.now() - Date.parse(d.ts)) / 864e5);
|
|
42
|
-
const age = days <= 0 ? "today" : `${days}d ago`;
|
|
43
|
-
return `- ${d.decision} (${d.source}, ${age}${d.screenshot ? `, evidence: ${d.screenshot}` : ""})`;
|
|
44
|
-
});
|
|
45
|
-
return `## Design decisions on record
|
|
46
|
-
|
|
47
|
-
${lines.join("\n")}
|
|
48
|
-
|
|
49
|
-
These were decided deliberately. Do not silently undo them; if a task genuinely requires reversing one, say so explicitly first.`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// src/prompt/registry.ts
|
|
53
|
-
import fs2 from "fs";
|
|
54
|
-
import path2 from "path";
|
|
55
13
|
function loadComponentInventory(cwd) {
|
|
56
14
|
let config;
|
|
57
15
|
try {
|
|
58
|
-
config = JSON.parse(
|
|
16
|
+
config = JSON.parse(fs.readFileSync(path.join(cwd, "components.json"), "utf8"));
|
|
59
17
|
} catch {
|
|
60
18
|
return null;
|
|
61
19
|
}
|
|
62
20
|
const alias = config.aliases?.ui ?? (config.aliases?.components ? `${config.aliases.components}/ui` : "@/components/ui");
|
|
63
21
|
const relative = alias.replace(/^@\//, "src/").replace(/^~\//, "");
|
|
64
|
-
const uiDir =
|
|
22
|
+
const uiDir = path.join(cwd, relative);
|
|
65
23
|
let entries;
|
|
66
24
|
try {
|
|
67
|
-
entries =
|
|
25
|
+
entries = fs.readdirSync(uiDir);
|
|
68
26
|
} catch {
|
|
69
27
|
return null;
|
|
70
28
|
}
|
|
@@ -100,17 +58,17 @@ function parseSkill(name, raw) {
|
|
|
100
58
|
return { name, triggers, body };
|
|
101
59
|
}
|
|
102
60
|
function loadSkills(cwd) {
|
|
103
|
-
const dir =
|
|
61
|
+
const dir = path2.join(cwd, ".squint", "skills");
|
|
104
62
|
let entries;
|
|
105
63
|
try {
|
|
106
|
-
entries =
|
|
64
|
+
entries = fs2.readdirSync(dir).filter((f) => f.endsWith(".md"));
|
|
107
65
|
} catch {
|
|
108
66
|
return [];
|
|
109
67
|
}
|
|
110
68
|
const skills = [];
|
|
111
69
|
for (const entry of entries.sort()) {
|
|
112
70
|
try {
|
|
113
|
-
const skill = parseSkill(entry.replace(/\.md$/, ""),
|
|
71
|
+
const skill = parseSkill(entry.replace(/\.md$/, ""), fs2.readFileSync(path2.join(dir, entry), "utf8"));
|
|
114
72
|
if (skill) skills.push(skill);
|
|
115
73
|
} catch {
|
|
116
74
|
}
|
|
@@ -119,7 +77,7 @@ function loadSkills(cwd) {
|
|
|
119
77
|
}
|
|
120
78
|
function loadRules(cwd) {
|
|
121
79
|
try {
|
|
122
|
-
const text =
|
|
80
|
+
const text = fs2.readFileSync(path2.join(cwd, ".squint", "rules.md"), "utf8").trim();
|
|
123
81
|
return text.length > 0 ? text : null;
|
|
124
82
|
} catch {
|
|
125
83
|
return null;
|
|
@@ -131,7 +89,7 @@ function matchSkills(skills, ask) {
|
|
|
131
89
|
}
|
|
132
90
|
function loadLocks(cwd) {
|
|
133
91
|
try {
|
|
134
|
-
return
|
|
92
|
+
return fs2.readFileSync(path2.join(cwd, ".squint", "locks"), "utf8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
135
93
|
} catch {
|
|
136
94
|
return [];
|
|
137
95
|
}
|
|
@@ -180,9 +138,6 @@ ${parts.join("\n\n")}` : "",
|
|
|
180
138
|
}
|
|
181
139
|
|
|
182
140
|
export {
|
|
183
|
-
appendDecision,
|
|
184
|
-
loadDecisions,
|
|
185
|
-
decisionsSection,
|
|
186
141
|
loadComponentInventory,
|
|
187
142
|
inventorySection,
|
|
188
143
|
parseSkill,
|
|
@@ -27,6 +27,8 @@ var COMMANDS = [
|
|
|
27
27
|
{ name: "save", group: "session", description: "export the transcript to .squint/transcripts/" },
|
|
28
28
|
{ name: "find", args: "<term>", group: "session", description: "search this session and saved transcripts" },
|
|
29
29
|
{ name: "decide", args: "<text>", group: "session", description: "record a design decision; injected into every future ask" },
|
|
30
|
+
{ name: "goal", args: "[text|off]", group: "build", description: "arm a standing objective; auto-fix presses until checks are clean" },
|
|
31
|
+
{ name: "distill", group: "session", description: "compress the design ledger into rules.md lines and proposed checks" },
|
|
30
32
|
{ name: "context", group: "session", description: "what squint injects per ask, token-costed, with staleness warnings" },
|
|
31
33
|
{ name: "yes", args: "[note]", group: "build", description: "approve the engine's pending visual-approval request" },
|
|
32
34
|
{ name: "no", args: "[note]", group: "build", description: "reject the engine's pending visual-approval request" },
|
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
App
|
|
4
|
+
} from "./chunk-2NYNTVMX.js";
|
|
5
|
+
import "./chunk-VJ2QKHYK.js";
|
|
2
6
|
import {
|
|
3
7
|
connectDaemon,
|
|
4
8
|
socketPath,
|
|
5
9
|
startDaemon
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import "./chunk-43NQNIJY.js";
|
|
11
|
-
import "./chunk-WASLLXEZ.js";
|
|
12
|
-
import "./chunk-ARDV4XH6.js";
|
|
10
|
+
} from "./chunk-AMA3F2Y2.js";
|
|
11
|
+
import "./chunk-G5NS2IFQ.js";
|
|
12
|
+
import "./chunk-UBADCBPT.js";
|
|
13
|
+
import "./chunk-IEQGTVWN.js";
|
|
13
14
|
import "./chunk-AUJJGMZG.js";
|
|
14
15
|
import "./chunk-YHRAOBI2.js";
|
|
15
16
|
import "./chunk-2I3YHT6P.js";
|
|
@@ -22,9 +23,9 @@ import {
|
|
|
22
23
|
composePrompt
|
|
23
24
|
} from "./chunk-WAJXATCO.js";
|
|
24
25
|
import "./chunk-62JNF5M2.js";
|
|
25
|
-
import "./chunk-
|
|
26
|
+
import "./chunk-ERF2SPUW.js";
|
|
26
27
|
import "./chunk-7CAGWFAQ.js";
|
|
27
|
-
import "./chunk-
|
|
28
|
+
import "./chunk-3YCG234A.js";
|
|
28
29
|
import "./chunk-PYC53J7D.js";
|
|
29
30
|
import {
|
|
30
31
|
detectEngines,
|
|
@@ -186,18 +187,18 @@ function registerDaemon(program2) {
|
|
|
186
187
|
process.on("SIGTERM", stop);
|
|
187
188
|
});
|
|
188
189
|
program2.command("mcp").description("serve the gates as MCP tools over stdio (check, shot, flows, context)").action(async () => {
|
|
189
|
-
const { runMcpServer } = await import("./server-
|
|
190
|
+
const { runMcpServer } = await import("./server-2WPGU3KQ.js");
|
|
190
191
|
runMcpServer(process.cwd());
|
|
191
192
|
});
|
|
192
193
|
program2.command("attach").description("attach this terminal to a running squint daemon (full TUI; --plain for line mode)").option("--plain", "line-mode attach instead of the full TUI").action(async (opts) => {
|
|
193
194
|
const cwd = process.cwd();
|
|
194
195
|
if (!opts.plain) {
|
|
195
196
|
try {
|
|
196
|
-
const { RemoteSession } = await import("./remote-
|
|
197
|
+
const { RemoteSession } = await import("./remote-UOV4ZXWU.js");
|
|
197
198
|
const remote = await RemoteSession.connect(cwd);
|
|
198
199
|
const config = loadConfig(defaultPaths(cwd));
|
|
199
200
|
const { render: render2 } = await import("ink");
|
|
200
|
-
const { App: App2 } = await import("./App-
|
|
201
|
+
const { App: App2 } = await import("./App-KTNAMHY6.js");
|
|
201
202
|
const React = await import("react");
|
|
202
203
|
render2(
|
|
203
204
|
React.createElement(App2, {
|
|
@@ -314,7 +315,7 @@ function registerEnv(program2) {
|
|
|
314
315
|
}
|
|
315
316
|
}
|
|
316
317
|
const { findChrome } = await import("./chrome-EEXJCG6W.js");
|
|
317
|
-
const { hasWebSocket } = await import("./cdp-
|
|
318
|
+
const { hasWebSocket } = await import("./cdp-D2F4P7UQ.js");
|
|
318
319
|
const chrome = findChrome();
|
|
319
320
|
console.log(
|
|
320
321
|
chrome ? `${pc3.green("\u2713")} Chrome ${pc3.dim(chrome)}` : `${pc3.yellow("\u25CB")} Chrome ${pc3.dim("\u2014 screenshots and runtime probing disabled")}`
|
|
@@ -338,7 +339,7 @@ import pc4 from "picocolors";
|
|
|
338
339
|
function registerProject(program2) {
|
|
339
340
|
const skillsCommand = program2.command("skills").description("Project knowledge injected into asks (.squint/rules.md + .squint/skills/)");
|
|
340
341
|
skillsCommand.command("list").description("Show always-on rules and trigger-matched skills").action(async () => {
|
|
341
|
-
const { loadRules, loadSkills } = await import("./skills-
|
|
342
|
+
const { loadRules, loadSkills } = await import("./skills-DQTE5Q77.js");
|
|
342
343
|
const cwd = process.cwd();
|
|
343
344
|
const rules = loadRules(cwd);
|
|
344
345
|
console.log(
|
|
@@ -550,7 +551,7 @@ function registerQuality(program2) {
|
|
|
550
551
|
report.gates = gateResults.map((r) => ({ id: r.gate.id, ok: r.ok, durationMs: r.durationMs, outputTail: r.ok ? void 0 : r.outputTail }));
|
|
551
552
|
if (gateResults.some((r) => !r.ok)) failed = true;
|
|
552
553
|
if (opts.url) {
|
|
553
|
-
const { captureViewports, runtimeSummary, previewDir } = await import("./preview-
|
|
554
|
+
const { captureViewports, runtimeSummary, previewDir } = await import("./preview-JN5PTWLX.js");
|
|
554
555
|
const capture = await captureViewports(cwd, opts.url);
|
|
555
556
|
if (!capture) {
|
|
556
557
|
console.log(pc5.red("\u2717 audit: capture failed (Chrome missing or URL unreachable)"));
|
|
@@ -589,7 +590,7 @@ function registerQuality(program2) {
|
|
|
589
590
|
const chrome = findChrome();
|
|
590
591
|
const flowReport = [];
|
|
591
592
|
if (chrome) {
|
|
592
|
-
const { runFlow } = await import("./cdp-
|
|
593
|
+
const { runFlow } = await import("./cdp-D2F4P7UQ.js");
|
|
593
594
|
for (const flow of flows) {
|
|
594
595
|
const result = await runFlow(chrome, opts.url, flow, previewDir(cwd));
|
|
595
596
|
flowReport.push({ name: flow.name, ok: result.ok, detail: result.ok ? void 0 : `step ${result.failedStep}: ${result.detail}` });
|
|
@@ -610,7 +611,7 @@ function registerQuality(program2) {
|
|
|
610
611
|
if (failed) process.exitCode = 1;
|
|
611
612
|
});
|
|
612
613
|
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) => {
|
|
613
|
-
const { captureViewports } = await import("./preview-
|
|
614
|
+
const { captureViewports } = await import("./preview-JN5PTWLX.js");
|
|
614
615
|
const result = await captureViewports(process.cwd(), url);
|
|
615
616
|
if (!result) {
|
|
616
617
|
console.error(pc5.red("\u2717 no Chrome/Chromium found"));
|
|
@@ -797,7 +798,7 @@ function registerTui(program2) {
|
|
|
797
798
|
}
|
|
798
799
|
|
|
799
800
|
// src/cli.tsx
|
|
800
|
-
var VERSION = true ? "0.5.
|
|
801
|
+
var VERSION = true ? "0.5.1" : "0.0.0-dev";
|
|
801
802
|
var program = new Command();
|
|
802
803
|
program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
|
|
803
804
|
registerRun(program);
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
contextReport,
|
|
4
4
|
formatContextReport
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-LESZB7DT.js";
|
|
6
|
+
import "./chunk-UBADCBPT.js";
|
|
7
|
+
import "./chunk-IEQGTVWN.js";
|
|
7
8
|
import "./chunk-WAJXATCO.js";
|
|
8
9
|
export {
|
|
9
10
|
contextReport,
|
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
probeRuntime,
|
|
12
12
|
routeShotName,
|
|
13
13
|
runtimeSummary
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ERF2SPUW.js";
|
|
15
15
|
import "./chunk-7CAGWFAQ.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-3YCG234A.js";
|
|
17
17
|
import "./chunk-PYC53J7D.js";
|
|
18
18
|
import "./chunk-GV2HAALP.js";
|
|
19
19
|
export {
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
connectDaemon,
|
|
4
4
|
socketPath
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-AMA3F2Y2.js";
|
|
6
|
+
import "./chunk-G5NS2IFQ.js";
|
|
7
|
+
import "./chunk-UBADCBPT.js";
|
|
8
|
+
import "./chunk-IEQGTVWN.js";
|
|
8
9
|
import "./chunk-AUJJGMZG.js";
|
|
9
10
|
import "./chunk-YHRAOBI2.js";
|
|
10
11
|
import "./chunk-2I3YHT6P.js";
|
|
@@ -13,9 +14,9 @@ import "./chunk-6NPUVPQD.js";
|
|
|
13
14
|
import "./chunk-K5QJMSJH.js";
|
|
14
15
|
import "./chunk-WAJXATCO.js";
|
|
15
16
|
import "./chunk-62JNF5M2.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-ERF2SPUW.js";
|
|
17
18
|
import "./chunk-7CAGWFAQ.js";
|
|
18
|
-
import "./chunk-
|
|
19
|
+
import "./chunk-3YCG234A.js";
|
|
19
20
|
import "./chunk-PYC53J7D.js";
|
|
20
21
|
import "./chunk-GV2HAALP.js";
|
|
21
22
|
|
|
Binary file
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
contextReport,
|
|
4
4
|
formatContextReport
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-LESZB7DT.js";
|
|
6
|
+
import "./chunk-UBADCBPT.js";
|
|
7
|
+
import "./chunk-IEQGTVWN.js";
|
|
7
8
|
import "./chunk-WAJXATCO.js";
|
|
8
9
|
import {
|
|
9
10
|
detectGates,
|
|
@@ -16,9 +17,9 @@ import {
|
|
|
16
17
|
captureViewports,
|
|
17
18
|
previewDir,
|
|
18
19
|
runtimeSummary
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-ERF2SPUW.js";
|
|
20
21
|
import "./chunk-7CAGWFAQ.js";
|
|
21
|
-
import "./chunk-
|
|
22
|
+
import "./chunk-3YCG234A.js";
|
|
22
23
|
import {
|
|
23
24
|
findChrome
|
|
24
25
|
} from "./chunk-PYC53J7D.js";
|
|
@@ -74,7 +75,7 @@ ${list.join("\n")}`);
|
|
|
74
75
|
if (flows.length === 0) return "no flows declared \u2014 add .squint/flows/<name>.flow";
|
|
75
76
|
const chrome = findChrome();
|
|
76
77
|
if (!chrome) return "no Chrome/Chromium found";
|
|
77
|
-
const { runFlow } = await import("./cdp-
|
|
78
|
+
const { runFlow } = await import("./cdp-D2F4P7UQ.js");
|
|
78
79
|
const lines = [];
|
|
79
80
|
for (const flow of flows) {
|
|
80
81
|
const result = await runFlow(chrome, url, flow, previewDir(cwd));
|
package/package.json
CHANGED