@aayambansal/squint 0.1.0
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/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/cdp-5OHNGQXV.js +9 -0
- package/dist/chrome-4WNYZZ42.js +10 -0
- package/dist/chunk-43VZK47W.js +118 -0
- package/dist/chunk-4XHTAWTH.js +164 -0
- package/dist/chunk-5IR2AZVK.js +127 -0
- package/dist/chunk-FQDSJRTY.js +156 -0
- package/dist/chunk-MGHJSERZ.js +86 -0
- package/dist/chunk-MURKQ7SI.js +74 -0
- package/dist/chunk-NT2HR4RD.js +63 -0
- package/dist/chunk-OJTW5SYY.js +197 -0
- package/dist/chunk-UHVE42IQ.js +135 -0
- package/dist/chunk-W6MYXQIU.js +126 -0
- package/dist/chunk-WTA6YYBY.js +54 -0
- package/dist/chunk-YIVPCWSG.js +402 -0
- package/dist/cli.js +968 -0
- package/dist/families-RVP5BWQD.js +12 -0
- package/dist/gates-G5DABJWQ.js +13 -0
- package/dist/init-7AYGAKOS.js +176 -0
- package/dist/preview-5PCHDJL7.js +22 -0
- package/dist/shots-ADBOBALL.js +66 -0
- package/dist/snapshot-KKUY5RR6.js +11 -0
- package/dist/source-MEXHWVP4.js +11 -0
- package/dist/variants-VVIYT7WI.js +27 -0
- package/package.json +63 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
TAGGER_FILENAME,
|
|
4
|
+
TAGGER_SOURCE
|
|
5
|
+
} from "./chunk-W6MYXQIU.js";
|
|
6
|
+
|
|
7
|
+
// src/scaffold/init.ts
|
|
8
|
+
import { spawn } from "child_process";
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path from "path";
|
|
11
|
+
|
|
12
|
+
// src/scaffold/template.ts
|
|
13
|
+
function templateFiles(name) {
|
|
14
|
+
return {
|
|
15
|
+
[TAGGER_FILENAME]: TAGGER_SOURCE,
|
|
16
|
+
"package.json": `${JSON.stringify(
|
|
17
|
+
{
|
|
18
|
+
name,
|
|
19
|
+
private: true,
|
|
20
|
+
version: "0.0.0",
|
|
21
|
+
type: "module",
|
|
22
|
+
scripts: {
|
|
23
|
+
dev: "vite",
|
|
24
|
+
build: "tsc --noEmit && vite build",
|
|
25
|
+
preview: "vite preview",
|
|
26
|
+
typecheck: "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
dependencies: {
|
|
29
|
+
react: "^19.1.0",
|
|
30
|
+
"react-dom": "^19.1.0"
|
|
31
|
+
},
|
|
32
|
+
devDependencies: {
|
|
33
|
+
"@tailwindcss/vite": "^4.1.0",
|
|
34
|
+
"@types/react": "^19.1.0",
|
|
35
|
+
"@types/react-dom": "^19.1.0",
|
|
36
|
+
"@vitejs/plugin-react": "^4.4.0",
|
|
37
|
+
tailwindcss: "^4.1.0",
|
|
38
|
+
typescript: "~5.8.0",
|
|
39
|
+
vite: "^6.3.0"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
null,
|
|
43
|
+
2
|
|
44
|
+
)}
|
|
45
|
+
`,
|
|
46
|
+
"index.html": `<!doctype html>
|
|
47
|
+
<html lang="en">
|
|
48
|
+
<head>
|
|
49
|
+
<meta charset="UTF-8" />
|
|
50
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
51
|
+
<title>${name}</title>
|
|
52
|
+
</head>
|
|
53
|
+
<body>
|
|
54
|
+
<div id="root"></div>
|
|
55
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
58
|
+
`,
|
|
59
|
+
"vite.config.ts": `import tailwindcss from '@tailwindcss/vite'
|
|
60
|
+
import react from '@vitejs/plugin-react'
|
|
61
|
+
import { defineConfig } from 'vite'
|
|
62
|
+
import squintTagger from './squint-tagger.mjs'
|
|
63
|
+
|
|
64
|
+
export default defineConfig({
|
|
65
|
+
plugins: [react(), tailwindcss(), squintTagger()],
|
|
66
|
+
})
|
|
67
|
+
`,
|
|
68
|
+
"tsconfig.json": `${JSON.stringify(
|
|
69
|
+
{
|
|
70
|
+
compilerOptions: {
|
|
71
|
+
target: "ES2022",
|
|
72
|
+
lib: ["ES2022", "DOM", "DOM.Iterable"],
|
|
73
|
+
module: "ESNext",
|
|
74
|
+
moduleResolution: "bundler",
|
|
75
|
+
jsx: "react-jsx",
|
|
76
|
+
strict: true,
|
|
77
|
+
noEmit: true,
|
|
78
|
+
allowImportingTsExtensions: true,
|
|
79
|
+
skipLibCheck: true,
|
|
80
|
+
isolatedModules: true,
|
|
81
|
+
useDefineForClassFields: true,
|
|
82
|
+
noUncheckedIndexedAccess: true
|
|
83
|
+
},
|
|
84
|
+
include: ["src"]
|
|
85
|
+
},
|
|
86
|
+
null,
|
|
87
|
+
2
|
|
88
|
+
)}
|
|
89
|
+
`,
|
|
90
|
+
"src/main.tsx": `import { StrictMode } from 'react'
|
|
91
|
+
import { createRoot } from 'react-dom/client'
|
|
92
|
+
import App from './App.tsx'
|
|
93
|
+
import './index.css'
|
|
94
|
+
|
|
95
|
+
createRoot(document.getElementById('root')!).render(
|
|
96
|
+
<StrictMode>
|
|
97
|
+
<App />
|
|
98
|
+
</StrictMode>,
|
|
99
|
+
)
|
|
100
|
+
`,
|
|
101
|
+
"src/App.tsx": `export default function App() {
|
|
102
|
+
return (
|
|
103
|
+
<main className="grid min-h-dvh place-items-center bg-paper text-ink">
|
|
104
|
+
<div className="text-center">
|
|
105
|
+
<h1 className="font-display text-2xl font-semibold tracking-tight">Ready.</h1>
|
|
106
|
+
<p className="mt-2 text-sm text-muted">Open squint and describe what to build.</p>
|
|
107
|
+
</div>
|
|
108
|
+
</main>
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
`,
|
|
112
|
+
"src/index.css": `@import "tailwindcss";
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* Design tokens live here \u2014 this file IS the design system.
|
|
116
|
+
* Commit to a visual direction before building components:
|
|
117
|
+
* set real display/body fonts, a deliberate palette, then compose
|
|
118
|
+
* every component from these tokens (bg-paper, text-ink, text-accent\u2026).
|
|
119
|
+
* Never scatter literal colors through components.
|
|
120
|
+
*/
|
|
121
|
+
@theme {
|
|
122
|
+
/* Type \u2014 replace with a committed pairing on the first design pass */
|
|
123
|
+
--font-display: ui-sans-serif, system-ui, sans-serif;
|
|
124
|
+
--font-body: ui-sans-serif, system-ui, sans-serif;
|
|
125
|
+
|
|
126
|
+
/* Palette \u2014 neutral canvas + one accent until a direction is chosen */
|
|
127
|
+
--color-ink: oklch(0.22 0.01 260);
|
|
128
|
+
--color-paper: oklch(0.985 0.002 90);
|
|
129
|
+
--color-muted: oklch(0.55 0.01 260);
|
|
130
|
+
--color-accent: oklch(0.55 0.15 155);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
body {
|
|
134
|
+
font-family: var(--font-body);
|
|
135
|
+
-webkit-font-smoothing: antialiased;
|
|
136
|
+
}
|
|
137
|
+
`,
|
|
138
|
+
".gitignore": `node_modules/
|
|
139
|
+
dist/
|
|
140
|
+
*.log
|
|
141
|
+
.DS_Store
|
|
142
|
+
`
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// src/scaffold/init.ts
|
|
147
|
+
function writeTemplate(dir, opts = {}) {
|
|
148
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
149
|
+
const existing = fs.readdirSync(dir).filter((entry) => !entry.startsWith("."));
|
|
150
|
+
if (existing.length > 0 && !opts.force) {
|
|
151
|
+
throw new Error(`${dir} is not empty (${existing.slice(0, 3).join(", ")}\u2026). Use --force to write anyway.`);
|
|
152
|
+
}
|
|
153
|
+
const name = sanitizeName(path.basename(path.resolve(dir)));
|
|
154
|
+
const files = templateFiles(name);
|
|
155
|
+
for (const [relative, content] of Object.entries(files)) {
|
|
156
|
+
const target = path.join(dir, relative);
|
|
157
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
158
|
+
fs.writeFileSync(target, content);
|
|
159
|
+
}
|
|
160
|
+
return { dir, files: Object.keys(files) };
|
|
161
|
+
}
|
|
162
|
+
function sanitizeName(raw) {
|
|
163
|
+
const name = raw.toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/^-+|-+$/g, "");
|
|
164
|
+
return name.length > 0 ? name : "squint-app";
|
|
165
|
+
}
|
|
166
|
+
function installDependencies(dir) {
|
|
167
|
+
return new Promise((resolve) => {
|
|
168
|
+
const child = spawn("npm", ["install"], { cwd: dir, stdio: "inherit" });
|
|
169
|
+
child.on("error", () => resolve(false));
|
|
170
|
+
child.on("close", (code) => resolve(code === 0));
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
export {
|
|
174
|
+
installDependencies,
|
|
175
|
+
writeTemplate
|
|
176
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
VIEWPORTS,
|
|
4
|
+
buildReviewPrompt,
|
|
5
|
+
buildRuntimeFixPrompt,
|
|
6
|
+
captureViewports,
|
|
7
|
+
previewDir,
|
|
8
|
+
probeRuntime,
|
|
9
|
+
runtimeSummary
|
|
10
|
+
} from "./chunk-4XHTAWTH.js";
|
|
11
|
+
import "./chunk-OJTW5SYY.js";
|
|
12
|
+
import "./chunk-MURKQ7SI.js";
|
|
13
|
+
import "./chunk-YIVPCWSG.js";
|
|
14
|
+
export {
|
|
15
|
+
VIEWPORTS,
|
|
16
|
+
buildReviewPrompt,
|
|
17
|
+
buildRuntimeFixPrompt,
|
|
18
|
+
captureViewports,
|
|
19
|
+
previewDir,
|
|
20
|
+
probeRuntime,
|
|
21
|
+
runtimeSummary
|
|
22
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
variantsRoot
|
|
4
|
+
} from "./chunk-UHVE42IQ.js";
|
|
5
|
+
import "./chunk-5IR2AZVK.js";
|
|
6
|
+
import {
|
|
7
|
+
DevServer,
|
|
8
|
+
detectDevCommand
|
|
9
|
+
} from "./chunk-FQDSJRTY.js";
|
|
10
|
+
import "./chunk-MGHJSERZ.js";
|
|
11
|
+
import "./chunk-NT2HR4RD.js";
|
|
12
|
+
import {
|
|
13
|
+
findChrome,
|
|
14
|
+
screenshot
|
|
15
|
+
} from "./chunk-MURKQ7SI.js";
|
|
16
|
+
import "./chunk-YIVPCWSG.js";
|
|
17
|
+
|
|
18
|
+
// src/variants/shots.ts
|
|
19
|
+
import path from "path";
|
|
20
|
+
var URL_TIMEOUT_MS = 45e3;
|
|
21
|
+
function waitForUrl(server) {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
const startedAt = Date.now();
|
|
24
|
+
const poll = setInterval(() => {
|
|
25
|
+
if (server.url) {
|
|
26
|
+
clearInterval(poll);
|
|
27
|
+
resolve(server.url);
|
|
28
|
+
} else if (Date.now() - startedAt > URL_TIMEOUT_MS || server.state === "crashed") {
|
|
29
|
+
clearInterval(poll);
|
|
30
|
+
resolve(null);
|
|
31
|
+
}
|
|
32
|
+
}, 200);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async function screenshotVariants(cwd, variants) {
|
|
36
|
+
const chrome = findChrome();
|
|
37
|
+
if (!chrome) {
|
|
38
|
+
return variants.map((v) => ({ familyId: v.family.id, error: "no Chrome found" }));
|
|
39
|
+
}
|
|
40
|
+
const shots = [];
|
|
41
|
+
for (const variant of variants) {
|
|
42
|
+
const command = detectDevCommand(variant.dir);
|
|
43
|
+
if (!command) {
|
|
44
|
+
shots.push({ familyId: variant.family.id, error: "no dev script" });
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const server = new DevServer(variant.dir);
|
|
48
|
+
server.start(command);
|
|
49
|
+
const url = await waitForUrl(server);
|
|
50
|
+
if (!url) {
|
|
51
|
+
server.stop();
|
|
52
|
+
shots.push({ familyId: variant.family.id, error: "dev server did not announce a URL" });
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const outPath = path.join(variantsRoot(cwd), `${variant.family.id}.png`);
|
|
56
|
+
const result = await screenshot(chrome, url, outPath, { width: 1440, height: 900 });
|
|
57
|
+
server.stop();
|
|
58
|
+
shots.push(
|
|
59
|
+
result.ok ? { familyId: variant.family.id, path: outPath } : { familyId: variant.family.id, error: result.error }
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return shots;
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
screenshotVariants
|
|
66
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
MAX_VARIANTS,
|
|
4
|
+
applyVariant,
|
|
5
|
+
cleanVariants,
|
|
6
|
+
createVariantWorktree,
|
|
7
|
+
listVariants,
|
|
8
|
+
pickFamilies,
|
|
9
|
+
runVariants,
|
|
10
|
+
variantPrompt,
|
|
11
|
+
variantsRoot
|
|
12
|
+
} from "./chunk-UHVE42IQ.js";
|
|
13
|
+
import "./chunk-5IR2AZVK.js";
|
|
14
|
+
import "./chunk-MGHJSERZ.js";
|
|
15
|
+
import "./chunk-NT2HR4RD.js";
|
|
16
|
+
import "./chunk-YIVPCWSG.js";
|
|
17
|
+
export {
|
|
18
|
+
MAX_VARIANTS,
|
|
19
|
+
applyVariant,
|
|
20
|
+
cleanVariants,
|
|
21
|
+
createVariantWorktree,
|
|
22
|
+
listVariants,
|
|
23
|
+
pickFamilies,
|
|
24
|
+
runVariants,
|
|
25
|
+
variantPrompt,
|
|
26
|
+
variantsRoot
|
|
27
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aayambansal/squint",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lovable for your terminal — a frontend harness on top of Claude Code, Codex, and other coding agents.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Aayam Bansal <aayambansal@gmail.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/aayambansal/squint.git"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/aayambansal/squint#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/aayambansal/squint/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"ai",
|
|
18
|
+
"agent",
|
|
19
|
+
"frontend",
|
|
20
|
+
"harness",
|
|
21
|
+
"tui",
|
|
22
|
+
"cli",
|
|
23
|
+
"claude-code",
|
|
24
|
+
"codex",
|
|
25
|
+
"lovable",
|
|
26
|
+
"vite",
|
|
27
|
+
"design"
|
|
28
|
+
],
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
},
|
|
32
|
+
"bin": {
|
|
33
|
+
"squint": "dist/cli.js"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=20"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsup",
|
|
43
|
+
"dev": "tsup --watch",
|
|
44
|
+
"typecheck": "tsc --noEmit",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"check": "npm run typecheck && npm run test && npm run build",
|
|
47
|
+
"prepublishOnly": "npm run check"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"commander": "^13.1.0",
|
|
51
|
+
"ink": "^6.0.0",
|
|
52
|
+
"picocolors": "^1.1.1",
|
|
53
|
+
"react": "^19.1.0",
|
|
54
|
+
"zod": "^3.25.0"
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^22.15.0",
|
|
58
|
+
"@types/react": "^19.1.0",
|
|
59
|
+
"tsup": "^8.4.0",
|
|
60
|
+
"typescript": "^5.8.0",
|
|
61
|
+
"vitest": "^3.1.0"
|
|
62
|
+
}
|
|
63
|
+
}
|