@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,402 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/engines/registry.ts
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
// src/engines/aider.ts
|
|
8
|
+
var aider = {
|
|
9
|
+
id: "aider",
|
|
10
|
+
name: "Aider",
|
|
11
|
+
binary: "aider",
|
|
12
|
+
install: "python -m pip install aider-install && aider-install",
|
|
13
|
+
supportsResume: false,
|
|
14
|
+
buildArgs(opts) {
|
|
15
|
+
const args = ["--message", opts.prompt, "--yes-always", "--no-auto-commits"];
|
|
16
|
+
if (opts.model) args.push("--model", opts.model);
|
|
17
|
+
return args;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// src/util/stream.ts
|
|
22
|
+
function lineSplitter(onLine) {
|
|
23
|
+
let buffer = "";
|
|
24
|
+
return {
|
|
25
|
+
push(chunk) {
|
|
26
|
+
buffer += chunk;
|
|
27
|
+
let index;
|
|
28
|
+
while ((index = buffer.indexOf("\n")) >= 0) {
|
|
29
|
+
const line = buffer.slice(0, index).replace(/\r$/, "");
|
|
30
|
+
buffer = buffer.slice(index + 1);
|
|
31
|
+
if (line.trim().length > 0) onLine(line);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
flush() {
|
|
35
|
+
if (buffer.trim().length > 0) onLine(buffer);
|
|
36
|
+
buffer = "";
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function truncate(text, max) {
|
|
41
|
+
if (text.length <= max) return text;
|
|
42
|
+
return text.slice(0, max - 1) + "\u2026";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/engines/claudeProtocol.ts
|
|
46
|
+
function createClaudeStreamParser(readyLabel) {
|
|
47
|
+
let sawTextDelta = false;
|
|
48
|
+
return (line) => {
|
|
49
|
+
let data;
|
|
50
|
+
try {
|
|
51
|
+
data = JSON.parse(line);
|
|
52
|
+
} catch {
|
|
53
|
+
return [{ type: "text", text: line }];
|
|
54
|
+
}
|
|
55
|
+
switch (data?.type) {
|
|
56
|
+
case "system":
|
|
57
|
+
if (data.subtype === "init") {
|
|
58
|
+
const model = data.model ? ` \xB7 ${data.model}` : "";
|
|
59
|
+
return [{ type: "status", text: `${readyLabel} ready${model}` }];
|
|
60
|
+
}
|
|
61
|
+
return [];
|
|
62
|
+
case "stream_event": {
|
|
63
|
+
const delta = data.event?.delta;
|
|
64
|
+
if (data.event?.type === "content_block_delta" && delta?.type === "text_delta" && delta.text) {
|
|
65
|
+
sawTextDelta = true;
|
|
66
|
+
return [{ type: "delta", text: delta.text }];
|
|
67
|
+
}
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
case "assistant": {
|
|
71
|
+
if (data.parent_tool_use_id) return [];
|
|
72
|
+
const events = [];
|
|
73
|
+
for (const block of data.message?.content ?? []) {
|
|
74
|
+
if (block.type === "text" && block.text) {
|
|
75
|
+
events.push({ type: "text", text: block.text, streamed: sawTextDelta || void 0 });
|
|
76
|
+
} else if (block.type === "thinking" && block.thinking) {
|
|
77
|
+
events.push({ type: "thinking", text: block.thinking });
|
|
78
|
+
} else if (block.type === "tool_use") {
|
|
79
|
+
events.push({
|
|
80
|
+
type: "tool",
|
|
81
|
+
name: block.name ?? "tool",
|
|
82
|
+
detail: summarizeToolInput(block.input)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
sawTextDelta = false;
|
|
87
|
+
return events;
|
|
88
|
+
}
|
|
89
|
+
case "result":
|
|
90
|
+
return [
|
|
91
|
+
{
|
|
92
|
+
type: "result",
|
|
93
|
+
ok: data.subtype === "success" && data.is_error !== true,
|
|
94
|
+
summary: typeof data.result === "string" ? data.result : void 0,
|
|
95
|
+
sessionId: data.session_id,
|
|
96
|
+
costUsd: data.total_cost_usd,
|
|
97
|
+
durationMs: data.duration_ms
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
case "user":
|
|
101
|
+
return [];
|
|
102
|
+
case "rate_limit_event":
|
|
103
|
+
return [];
|
|
104
|
+
default:
|
|
105
|
+
return [{ type: "raw", data }];
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function summarizeToolInput(input) {
|
|
110
|
+
if (!input || typeof input !== "object") return void 0;
|
|
111
|
+
const obj = input;
|
|
112
|
+
const key = typeof obj.file_path === "string" ? obj.file_path : typeof obj.command === "string" ? obj.command : typeof obj.pattern === "string" ? obj.pattern : typeof obj.description === "string" ? obj.description : void 0;
|
|
113
|
+
if (key) return truncate(key, 80);
|
|
114
|
+
const json = JSON.stringify(obj);
|
|
115
|
+
return json === "{}" ? void 0 : truncate(json, 80);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/engines/amp.ts
|
|
119
|
+
var amp = {
|
|
120
|
+
id: "amp",
|
|
121
|
+
name: "Amp",
|
|
122
|
+
binary: "amp",
|
|
123
|
+
install: "npm install -g @sourcegraph/amp",
|
|
124
|
+
supportsResume: true,
|
|
125
|
+
buildArgs(opts) {
|
|
126
|
+
if (opts.sessionId) {
|
|
127
|
+
return ["threads", "continue", "--execute", opts.prompt, "--stream-json"];
|
|
128
|
+
}
|
|
129
|
+
return ["-x", opts.prompt, "--stream-json"];
|
|
130
|
+
},
|
|
131
|
+
createParser: () => createClaudeStreamParser("amp")
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// src/engines/claude.ts
|
|
135
|
+
var claude = {
|
|
136
|
+
id: "claude",
|
|
137
|
+
name: "Claude Code",
|
|
138
|
+
binary: "claude",
|
|
139
|
+
install: "npm install -g @anthropic-ai/claude-code",
|
|
140
|
+
supportsResume: true,
|
|
141
|
+
buildArgs(opts) {
|
|
142
|
+
const args = [
|
|
143
|
+
"-p",
|
|
144
|
+
opts.prompt,
|
|
145
|
+
"--output-format",
|
|
146
|
+
"stream-json",
|
|
147
|
+
"--verbose",
|
|
148
|
+
"--include-partial-messages",
|
|
149
|
+
"--permission-mode",
|
|
150
|
+
"acceptEdits"
|
|
151
|
+
];
|
|
152
|
+
if (opts.model) args.push("--model", opts.model);
|
|
153
|
+
if (opts.sessionId) args.push("--resume", opts.sessionId);
|
|
154
|
+
return args;
|
|
155
|
+
},
|
|
156
|
+
createParser: () => createClaudeStreamParser("claude")
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/engines/codex.ts
|
|
160
|
+
var codex = {
|
|
161
|
+
id: "codex",
|
|
162
|
+
name: "Codex CLI",
|
|
163
|
+
binary: "codex",
|
|
164
|
+
install: "npm install -g @openai/codex",
|
|
165
|
+
supportsResume: true,
|
|
166
|
+
buildArgs(opts) {
|
|
167
|
+
const args = ["exec"];
|
|
168
|
+
if (opts.sessionId) args.push("resume", opts.sessionId);
|
|
169
|
+
args.push("--json", "--sandbox", "workspace-write", "--skip-git-repo-check");
|
|
170
|
+
if (opts.model) args.push("--model", opts.model);
|
|
171
|
+
args.push(opts.prompt);
|
|
172
|
+
return args;
|
|
173
|
+
},
|
|
174
|
+
createParser() {
|
|
175
|
+
let threadId;
|
|
176
|
+
return (line) => {
|
|
177
|
+
let data;
|
|
178
|
+
try {
|
|
179
|
+
data = JSON.parse(line);
|
|
180
|
+
} catch {
|
|
181
|
+
return [{ type: "text", text: line }];
|
|
182
|
+
}
|
|
183
|
+
if (typeof data?.type === "string") {
|
|
184
|
+
switch (data.type) {
|
|
185
|
+
case "thread.started":
|
|
186
|
+
threadId = data.thread_id;
|
|
187
|
+
return [{ type: "status", text: "codex ready" }];
|
|
188
|
+
case "item.started":
|
|
189
|
+
return itemToEvents(data.item, "started");
|
|
190
|
+
case "item.completed":
|
|
191
|
+
return itemToEvents(data.item, "completed");
|
|
192
|
+
case "turn.completed":
|
|
193
|
+
return [{ type: "result", ok: true, sessionId: threadId }];
|
|
194
|
+
case "turn.failed":
|
|
195
|
+
case "error":
|
|
196
|
+
return [
|
|
197
|
+
{
|
|
198
|
+
type: "result",
|
|
199
|
+
ok: false,
|
|
200
|
+
summary: data.error?.message ?? data.message ?? "turn failed",
|
|
201
|
+
sessionId: threadId
|
|
202
|
+
}
|
|
203
|
+
];
|
|
204
|
+
default:
|
|
205
|
+
if (data.type.startsWith("item.") || data.type.startsWith("turn.")) return [];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const msg = data?.msg;
|
|
209
|
+
if (msg && typeof msg.type === "string") {
|
|
210
|
+
switch (msg.type) {
|
|
211
|
+
case "agent_message":
|
|
212
|
+
return msg.message ? [{ type: "text", text: msg.message }] : [];
|
|
213
|
+
case "agent_reasoning":
|
|
214
|
+
return [];
|
|
215
|
+
case "exec_command_begin":
|
|
216
|
+
return [
|
|
217
|
+
{
|
|
218
|
+
type: "tool",
|
|
219
|
+
name: "shell",
|
|
220
|
+
detail: Array.isArray(msg.command) ? truncate(msg.command.join(" "), 80) : void 0
|
|
221
|
+
}
|
|
222
|
+
];
|
|
223
|
+
case "patch_apply_begin":
|
|
224
|
+
return [{ type: "tool", name: "edit" }];
|
|
225
|
+
case "task_complete":
|
|
226
|
+
return [{ type: "result", ok: true, summary: msg.last_agent_message }];
|
|
227
|
+
case "error":
|
|
228
|
+
return [{ type: "error", text: msg.message ?? "codex error" }];
|
|
229
|
+
default:
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return [{ type: "raw", data }];
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
function itemToEvents(item, phase) {
|
|
238
|
+
if (!item) return [];
|
|
239
|
+
switch (item.type) {
|
|
240
|
+
case "agent_message":
|
|
241
|
+
return phase === "completed" && item.text ? [{ type: "text", text: item.text }] : [];
|
|
242
|
+
case "command_execution":
|
|
243
|
+
return phase === "started" ? [{ type: "tool", name: "shell", detail: item.command ? truncate(item.command, 80) : void 0 }] : [];
|
|
244
|
+
case "file_change": {
|
|
245
|
+
if (phase !== "completed") return [];
|
|
246
|
+
const changes = Array.isArray(item.changes) ? item.changes.map((c) => c.path).filter(Boolean).join(", ") : void 0;
|
|
247
|
+
return [{ type: "tool", name: "edit", detail: changes ? truncate(changes, 80) : void 0 }];
|
|
248
|
+
}
|
|
249
|
+
case "reasoning":
|
|
250
|
+
return phase === "completed" && item.text ? [{ type: "thinking", text: item.text }] : [];
|
|
251
|
+
case "todo_list":
|
|
252
|
+
return [];
|
|
253
|
+
default:
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/engines/copilot.ts
|
|
259
|
+
var copilot = {
|
|
260
|
+
id: "copilot",
|
|
261
|
+
name: "Copilot CLI",
|
|
262
|
+
binary: "copilot",
|
|
263
|
+
install: "npm install -g @github/copilot",
|
|
264
|
+
supportsResume: false,
|
|
265
|
+
buildArgs(opts) {
|
|
266
|
+
const args = ["-p", opts.prompt, "-s", "--allow-all-tools"];
|
|
267
|
+
if (opts.model) args.push("--model", opts.model);
|
|
268
|
+
return args;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// src/engines/cursor.ts
|
|
273
|
+
var cursor = {
|
|
274
|
+
id: "cursor",
|
|
275
|
+
name: "Cursor CLI",
|
|
276
|
+
binary: "cursor-agent",
|
|
277
|
+
altBinaries: ["agent"],
|
|
278
|
+
install: "curl https://cursor.com/install -fsS | bash",
|
|
279
|
+
supportsResume: true,
|
|
280
|
+
buildArgs(opts) {
|
|
281
|
+
const args = ["-p", opts.prompt, "--output-format", "stream-json", "--force"];
|
|
282
|
+
if (opts.model) args.push("--model", opts.model);
|
|
283
|
+
if (opts.sessionId) args.push(`--resume=${opts.sessionId}`);
|
|
284
|
+
return args;
|
|
285
|
+
},
|
|
286
|
+
createParser: () => createClaudeStreamParser("cursor")
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
// src/engines/gemini.ts
|
|
290
|
+
var gemini = {
|
|
291
|
+
id: "gemini",
|
|
292
|
+
name: "Gemini CLI",
|
|
293
|
+
binary: "gemini",
|
|
294
|
+
install: "npm install -g @google/gemini-cli",
|
|
295
|
+
supportsResume: false,
|
|
296
|
+
buildArgs(opts) {
|
|
297
|
+
const args = ["-p", opts.prompt, "--yolo"];
|
|
298
|
+
if (opts.model) args.push("-m", opts.model);
|
|
299
|
+
return args;
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// src/engines/opencode.ts
|
|
304
|
+
var opencode = {
|
|
305
|
+
id: "opencode",
|
|
306
|
+
name: "OpenCode",
|
|
307
|
+
binary: "opencode",
|
|
308
|
+
install: "npm install -g opencode-ai",
|
|
309
|
+
supportsResume: true,
|
|
310
|
+
buildArgs(opts) {
|
|
311
|
+
const args = ["run", "--format", "json"];
|
|
312
|
+
if (opts.model) args.push("--model", opts.model);
|
|
313
|
+
if (opts.sessionId) args.push("--session", opts.sessionId);
|
|
314
|
+
args.push(opts.prompt);
|
|
315
|
+
return args;
|
|
316
|
+
},
|
|
317
|
+
createParser() {
|
|
318
|
+
let sessionId;
|
|
319
|
+
return (line) => {
|
|
320
|
+
let data;
|
|
321
|
+
try {
|
|
322
|
+
data = JSON.parse(line);
|
|
323
|
+
} catch {
|
|
324
|
+
return [{ type: "text", text: line }];
|
|
325
|
+
}
|
|
326
|
+
if (data?.sessionID && !sessionId) sessionId = data.sessionID;
|
|
327
|
+
switch (data?.type) {
|
|
328
|
+
case "step_start":
|
|
329
|
+
return [];
|
|
330
|
+
case "text":
|
|
331
|
+
return data.part?.text ? [{ type: "text", text: data.part.text }] : [];
|
|
332
|
+
case "reasoning":
|
|
333
|
+
return data.part?.text ? [{ type: "thinking", text: data.part.text }] : [];
|
|
334
|
+
case "tool_use": {
|
|
335
|
+
const name = data.part?.tool ?? "tool";
|
|
336
|
+
const input = data.part?.state?.input;
|
|
337
|
+
const detail = input && typeof input === "object" ? truncate(
|
|
338
|
+
typeof input.command === "string" ? input.command : typeof input.filePath === "string" ? input.filePath : JSON.stringify(input),
|
|
339
|
+
80
|
|
340
|
+
) : void 0;
|
|
341
|
+
if (data.part?.state?.status === "completed" || data.part?.state?.status === "running") {
|
|
342
|
+
return [{ type: "tool", name, detail }];
|
|
343
|
+
}
|
|
344
|
+
return [];
|
|
345
|
+
}
|
|
346
|
+
case "step_finish":
|
|
347
|
+
if (data.part?.reason === "stop" || data.reason === "stop") {
|
|
348
|
+
return [{ type: "result", ok: true, sessionId }];
|
|
349
|
+
}
|
|
350
|
+
return [];
|
|
351
|
+
case "error":
|
|
352
|
+
return [{ type: "error", text: data.message ?? "opencode error" }];
|
|
353
|
+
default:
|
|
354
|
+
return [{ type: "raw", data }];
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
// src/engines/registry.ts
|
|
361
|
+
var engines = [claude, codex, gemini, opencode, amp, cursor, copilot, aider];
|
|
362
|
+
function getEngine(id) {
|
|
363
|
+
const engine = engines.find((e) => e.id === id);
|
|
364
|
+
if (!engine) {
|
|
365
|
+
const known = engines.map((e) => e.id).join(", ");
|
|
366
|
+
throw new Error(`Unknown engine "${id}". Available: ${known}`);
|
|
367
|
+
}
|
|
368
|
+
return engine;
|
|
369
|
+
}
|
|
370
|
+
function findBinary(binary) {
|
|
371
|
+
const dirs = (process.env.PATH ?? "").split(path.delimiter);
|
|
372
|
+
for (const dir of dirs) {
|
|
373
|
+
if (!dir) continue;
|
|
374
|
+
const full = path.join(dir, binary);
|
|
375
|
+
try {
|
|
376
|
+
fs.accessSync(full, fs.constants.X_OK);
|
|
377
|
+
return full;
|
|
378
|
+
} catch {
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
function findEngineBinary(engine) {
|
|
384
|
+
for (const name of [engine.binary, ...engine.altBinaries ?? []]) {
|
|
385
|
+
const found = findBinary(name);
|
|
386
|
+
if (found) return found;
|
|
387
|
+
}
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
function detectEngines() {
|
|
391
|
+
return engines.map((engine) => ({ engine, path: findEngineBinary(engine) }));
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export {
|
|
395
|
+
lineSplitter,
|
|
396
|
+
truncate,
|
|
397
|
+
engines,
|
|
398
|
+
getEngine,
|
|
399
|
+
findBinary,
|
|
400
|
+
findEngineBinary,
|
|
401
|
+
detectEngines
|
|
402
|
+
};
|