@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.
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ FAMILIES,
4
+ getFamily,
5
+ renderFamilyBrief
6
+ } from "./chunk-5IR2AZVK.js";
7
+ import "./chunk-NT2HR4RD.js";
8
+ export {
9
+ FAMILIES,
10
+ getFamily,
11
+ renderFamilyBrief
12
+ };
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ buildGatePrompt,
4
+ detectGates,
5
+ runGate,
6
+ runGates
7
+ } from "./chunk-43VZK47W.js";
8
+ export {
9
+ buildGatePrompt,
10
+ detectGates,
11
+ runGate,
12
+ runGates
13
+ };
@@ -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,11 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ isGitRepo,
4
+ restoreSnapshot,
5
+ takeSnapshot
6
+ } from "./chunk-WTA6YYBY.js";
7
+ export {
8
+ isGitRepo,
9
+ restoreSnapshot,
10
+ takeSnapshot
11
+ };
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ TAGGER_FILENAME,
4
+ TAGGER_SOURCE,
5
+ patchViteConfig
6
+ } from "./chunk-W6MYXQIU.js";
7
+ export {
8
+ TAGGER_FILENAME,
9
+ TAGGER_SOURCE,
10
+ patchViteConfig
11
+ };
@@ -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
+ }