@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,135 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ FAMILIES,
4
+ renderFamilyBrief
5
+ } from "./chunk-5IR2AZVK.js";
6
+ import {
7
+ runAgent
8
+ } from "./chunk-MGHJSERZ.js";
9
+ import {
10
+ FIRST_TURN_ADDENDUM
11
+ } from "./chunk-NT2HR4RD.js";
12
+
13
+ // src/variants/variants.ts
14
+ import { execFileSync } from "child_process";
15
+ import fs from "fs";
16
+ import path from "path";
17
+ var MAX_VARIANTS = 4;
18
+ function git(cwd, args) {
19
+ return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
20
+ }
21
+ function variantsRoot(cwd) {
22
+ return path.join(cwd, ".squint", "variants");
23
+ }
24
+ function pickFamilies(n) {
25
+ return FAMILIES.slice(0, Math.min(n, MAX_VARIANTS, FAMILIES.length));
26
+ }
27
+ function createVariantWorktree(cwd, family) {
28
+ const dir = path.join(variantsRoot(cwd), family.id);
29
+ fs.rmSync(dir, { recursive: true, force: true });
30
+ fs.mkdirSync(path.dirname(dir), { recursive: true });
31
+ git(cwd, ["worktree", "add", "--force", "--detach", dir, "HEAD"]);
32
+ const mainModules = path.join(cwd, "node_modules");
33
+ const variantModules = path.join(dir, "node_modules");
34
+ if (fs.existsSync(mainModules) && !fs.existsSync(variantModules)) {
35
+ fs.symlinkSync(mainModules, variantModules, "dir");
36
+ }
37
+ return { family, dir };
38
+ }
39
+ function variantPrompt(family, ask) {
40
+ return `${renderFamilyBrief(family)}
41
+
42
+ ${FIRST_TURN_ADDENDUM}
43
+
44
+ ## Task
45
+
46
+ ${ask}
47
+
48
+ Note: this is one of several parallel design explorations of the same task. Commit hard to the ${family.name} direction \u2014 differentiation between explorations is the point. Do not hedge toward a middle ground.`;
49
+ }
50
+ async function runVariants(cwd, ask, n, engine, model, onStatus) {
51
+ const families = pickFamilies(n);
52
+ const variants = families.map((family) => {
53
+ onStatus(family.id, "preparing worktree");
54
+ return createVariantWorktree(cwd, family);
55
+ });
56
+ return Promise.all(
57
+ variants.map(async (variant) => {
58
+ onStatus(variant.family.id, "engine running");
59
+ const result = await runAgent(
60
+ engine,
61
+ { prompt: variantPrompt(variant.family, ask), cwd: variant.dir, model },
62
+ (event) => {
63
+ if (event.type === "tool") onStatus(variant.family.id, `\u2699 ${event.name}`);
64
+ if (event.type === "error") onStatus(variant.family.id, `\u2717 ${event.text.split("\n")[0]}`);
65
+ }
66
+ );
67
+ onStatus(
68
+ variant.family.id,
69
+ result.ok ? `done${result.costUsd !== void 0 ? ` \xB7 $${result.costUsd.toFixed(2)}` : ""}` : `failed${result.error ? ` \xB7 ${result.error.split("\n")[0]}` : ""}`
70
+ );
71
+ return { variant, result };
72
+ })
73
+ );
74
+ }
75
+ function listVariants(cwd) {
76
+ try {
77
+ return fs.readdirSync(variantsRoot(cwd), { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
78
+ } catch {
79
+ return [];
80
+ }
81
+ }
82
+ function applyVariant(cwd, familyId) {
83
+ const dir = path.join(variantsRoot(cwd), familyId);
84
+ if (!fs.existsSync(dir)) {
85
+ return { ok: false, detail: `no variant "${familyId}" \u2014 run squint variants list` };
86
+ }
87
+ try {
88
+ git(dir, ["add", "-A"]);
89
+ const patch = git(dir, ["diff", "--binary", "--cached", "HEAD"]);
90
+ if (patch.length === 0) {
91
+ return { ok: false, detail: "variant made no changes" };
92
+ }
93
+ const patchFile = path.join(variantsRoot(cwd), `${familyId}.patch`);
94
+ fs.writeFileSync(patchFile, patch + "\n");
95
+ git(cwd, ["apply", "--whitespace=nowarn", patchFile]);
96
+ fs.rmSync(patchFile, { force: true });
97
+ return { ok: true };
98
+ } catch (err) {
99
+ return { ok: false, detail: err instanceof Error ? err.message.split("\n")[0] : String(err) };
100
+ }
101
+ }
102
+ function cleanVariants(cwd) {
103
+ const ids = listVariants(cwd);
104
+ for (const id of ids) {
105
+ const dir = path.join(variantsRoot(cwd), id);
106
+ try {
107
+ const link = path.join(dir, "node_modules");
108
+ if (fs.existsSync(link) && fs.lstatSync(link).isSymbolicLink()) fs.rmSync(link);
109
+ } catch {
110
+ }
111
+ try {
112
+ git(cwd, ["worktree", "remove", "--force", dir]);
113
+ } catch {
114
+ fs.rmSync(dir, { recursive: true, force: true });
115
+ }
116
+ }
117
+ try {
118
+ git(cwd, ["worktree", "prune"]);
119
+ } catch {
120
+ }
121
+ fs.rmSync(variantsRoot(cwd), { recursive: true, force: true });
122
+ return ids.length;
123
+ }
124
+
125
+ export {
126
+ MAX_VARIANTS,
127
+ variantsRoot,
128
+ pickFamilies,
129
+ createVariantWorktree,
130
+ variantPrompt,
131
+ runVariants,
132
+ listVariants,
133
+ applyVariant,
134
+ cleanVariants
135
+ };
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/tagger/source.ts
4
+ var TAGGER_FILENAME = "squint-tagger.mjs";
5
+ var TAGGER_SOURCE = `// squint element tagger \u2014 dev-only Vite plugin.
6
+ // Alt+S in the browser toggles the picker; clicking an element copies
7
+ // its JSX source location (file:line:col) to paste into squint.
8
+ const VIRTUAL_ID = '\\0squint-jsx-dev-runtime'
9
+
10
+ export default function squintTagger() {
11
+ let actualRuntime = null
12
+ return {
13
+ name: 'squint-tagger',
14
+ apply: 'serve',
15
+ enforce: 'pre',
16
+
17
+ async resolveId(id, importer) {
18
+ if (id === 'react/jsx-dev-runtime') {
19
+ const resolved = await this.resolve(id, importer, { skipSelf: true })
20
+ if (!resolved) return null
21
+ actualRuntime = resolved.id
22
+ return VIRTUAL_ID
23
+ }
24
+ return null
25
+ },
26
+
27
+ load(id) {
28
+ if (id !== VIRTUAL_ID || !actualRuntime) return null
29
+ return [
30
+ 'import * as runtime from ' + JSON.stringify(actualRuntime) + ';',
31
+ 'export const Fragment = runtime.Fragment;',
32
+ 'export const jsxDEV = (type, props, key, isStatic, source, self) => {',
33
+ ' if (source && props && typeof type === "string") {',
34
+ ' const info = { file: source.fileName, line: source.lineNumber, col: source.columnNumber, tag: type };',
35
+ ' const prevRef = props.ref;',
36
+ ' props = { ...props, ref: (node) => {',
37
+ ' if (node && node.nodeType === 1) node.__squintSource = info;',
38
+ ' if (typeof prevRef === "function") return prevRef(node);',
39
+ ' if (prevRef && typeof prevRef === "object") prevRef.current = node;',
40
+ ' } };',
41
+ ' }',
42
+ ' return runtime.jsxDEV(type, props, key, isStatic, source, self);',
43
+ '};',
44
+ ].join('\\n')
45
+ },
46
+
47
+ // NOTE: jsxDEV line numbers reflect the transformed module (dev
48
+ // preambles shift them), so the picker treats them as approximate
49
+ // and copies tag + class list + text alongside \u2014 self-locating for
50
+ // any agent regardless of build pipeline.
51
+
52
+ transformIndexHtml() {
53
+ return [{ tag: 'script', attrs: { type: 'module' }, children: PICKER, injectTo: 'body' }]
54
+ },
55
+ }
56
+ }
57
+
58
+ const PICKER = \`(() => {
59
+ if (window.__squintPicker) return; window.__squintPicker = true;
60
+ let active = false;
61
+ const box = document.createElement('div');
62
+ box.style.cssText = 'position:fixed;pointer-events:none;z-index:2147483646;border:2px solid #e8a33d;background:rgba(232,163,61,.08);display:none;font:12px ui-monospace,monospace;';
63
+ const tip = document.createElement('div');
64
+ tip.style.cssText = 'position:fixed;z-index:2147483647;background:#1b1b1b;color:#fff;padding:4px 8px;border-radius:3px;font:12px ui-monospace,monospace;display:none;pointer-events:none;max-width:70vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
65
+ document.documentElement.append(box, tip);
66
+ const find = (el) => { while (el && el !== document.body) { if (el.__squintSource) return el; el = el.parentElement; } return null; };
67
+ const rel = (file) => file.replace(location.origin, '').replace(/^.*?\\\\/(src\\\\/)/, '$1');
68
+ const describe = (el) => {
69
+ const s = el.__squintSource;
70
+ const cls = (el.getAttribute('class') || '').trim();
71
+ const text = (el.textContent || '').trim().replace(/\\\\s+/g, ' ').slice(0, 40);
72
+ return rel(s.file) + ' <' + s.tag + (cls ? ' class="' + cls + '"' : '') + '>' + (text ? ' "' + text + '"' : '');
73
+ };
74
+ const toast = (text) => {
75
+ tip.textContent = text; tip.style.display = 'block';
76
+ tip.style.left = '12px'; tip.style.top = '12px';
77
+ setTimeout(() => { if (!active) tip.style.display = 'none'; }, 2200);
78
+ };
79
+ addEventListener('keydown', (e) => {
80
+ if (e.altKey && (e.key === 's' || e.key === 'S' || e.code === 'KeyS')) {
81
+ active = !active;
82
+ if (!active) { box.style.display = 'none'; tip.style.display = 'none'; }
83
+ else toast('squint picker on \u2014 click an element (esc to cancel)');
84
+ } else if (e.key === 'Escape' && active) {
85
+ active = false; box.style.display = 'none'; tip.style.display = 'none';
86
+ }
87
+ });
88
+ addEventListener('mousemove', (e) => {
89
+ if (!active) return;
90
+ const el = find(e.target); if (!el) { box.style.display = 'none'; return; }
91
+ const r = el.getBoundingClientRect(); const s = el.__squintSource;
92
+ box.style.display = 'block';
93
+ box.style.left = r.left + 'px'; box.style.top = r.top + 'px';
94
+ box.style.width = r.width + 'px'; box.style.height = r.height + 'px';
95
+ tip.style.display = 'block';
96
+ tip.style.left = Math.min(r.left, innerWidth - 340) + 'px';
97
+ tip.style.top = Math.max(r.top - 26, 2) + 'px';
98
+ tip.textContent = '<' + s.tag + '> ' + rel(s.file);
99
+ }, true);
100
+ addEventListener('click', (e) => {
101
+ if (!active) return;
102
+ e.preventDefault(); e.stopPropagation();
103
+ const el = find(e.target); if (!el) return;
104
+ const ref = describe(el);
105
+ window.__squintLastPick = ref;
106
+ const done = () => toast('copied \u2014 paste into squint: ' + ref);
107
+ if (navigator.clipboard?.writeText) navigator.clipboard.writeText(ref).then(done, done);
108
+ else done();
109
+ active = false; box.style.display = 'none';
110
+ }, true);
111
+ })();\`
112
+ `;
113
+ function patchViteConfig(source) {
114
+ if (source.includes("squint-tagger") || source.includes("squintTagger")) return "already";
115
+ const pluginsMatch = /plugins:\s*\[/.exec(source);
116
+ if (!pluginsMatch) return null;
117
+ const withPlugin = source.slice(0, pluginsMatch.index) + pluginsMatch[0].replace("[", "[squintTagger(), ") + source.slice(pluginsMatch.index + pluginsMatch[0].length);
118
+ return `import squintTagger from './${TAGGER_FILENAME}'
119
+ ${withPlugin}`;
120
+ }
121
+
122
+ export {
123
+ TAGGER_FILENAME,
124
+ TAGGER_SOURCE,
125
+ patchViteConfig
126
+ };
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/vcs/snapshot.ts
4
+ import { execFileSync } from "child_process";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ function git(cwd, args) {
8
+ return execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
9
+ }
10
+ function isGitRepo(cwd) {
11
+ try {
12
+ return git(cwd, ["rev-parse", "--is-inside-work-tree"]) === "true";
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+ function listUntracked(cwd) {
18
+ const out = git(cwd, ["ls-files", "--others", "--exclude-standard"]);
19
+ return out.length > 0 ? out.split("\n") : [];
20
+ }
21
+ function takeSnapshot(cwd) {
22
+ try {
23
+ if (!isGitRepo(cwd)) return null;
24
+ git(cwd, ["rev-parse", "HEAD"]);
25
+ const stashHash = git(cwd, ["stash", "create"]) || null;
26
+ return { stashHash, untracked: listUntracked(cwd), at: Date.now() };
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+ function restoreSnapshot(cwd, snapshot) {
32
+ try {
33
+ const before = new Set(snapshot.untracked);
34
+ const created = listUntracked(cwd).filter((file) => !before.has(file));
35
+ for (const file of created) {
36
+ fs.rmSync(path.join(cwd, file), { force: true });
37
+ }
38
+ const source = snapshot.stashHash ?? "HEAD";
39
+ git(cwd, ["restore", "--source", source, "--worktree", "--", "."]);
40
+ return { restored: true, deletedFiles: created.length };
41
+ } catch (err) {
42
+ return {
43
+ restored: false,
44
+ deletedFiles: 0,
45
+ detail: err instanceof Error ? err.message.split("\n")[0] : String(err)
46
+ };
47
+ }
48
+ }
49
+
50
+ export {
51
+ isGitRepo,
52
+ takeSnapshot,
53
+ restoreSnapshot
54
+ };