@aayambansal/squint 0.3.4 → 0.4.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/README.md +1 -0
- package/dist/{cdp-UOIP4ZQZ.js → cdp-VRGCGN5R.js} +5 -3
- package/dist/{chunk-SXF7CVRW.js → chunk-2EJWUBUP.js} +5 -5
- package/dist/{chunk-XOVOQJFL.js → chunk-6FR4TRRQ.js} +55 -0
- package/dist/{chunk-BNJGHNXB.js → chunk-SVKV77TO.js} +2 -0
- package/dist/cli.js +87 -12
- package/dist/{commands-3HHBHBQV.js → commands-DE5Q7VWY.js} +1 -1
- package/dist/flows-V5ZLVVSQ.js +108 -0
- package/dist/{preview-S6FOTRRR.js → preview-X7EWTRCZ.js} +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -133,6 +133,7 @@ squint config set autoDev true # dev server starts with the TUI
|
|
|
133
133
|
squint config set autoFix true # errors auto-route back (max 2 tries)
|
|
134
134
|
squint config set autoCheck false # skip the per-turn typecheck+lint pass
|
|
135
135
|
squint config set autoReview true # big visual change → automatic self-critique
|
|
136
|
+
squint config set fixModel haiku # mechanical fix turns run on the cheap tier
|
|
136
137
|
squint config set theme ocean # amber · ocean · moss · rose · mono
|
|
137
138
|
squint config set bell false # no bell on turn completion
|
|
138
139
|
squint doctor # engines + Chrome + WebSocket check
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ensureSquintIgnore
|
|
4
|
+
} from "./chunk-O2S6PAJE.js";
|
|
2
5
|
import {
|
|
3
6
|
findChrome,
|
|
4
7
|
screenshot
|
|
@@ -6,10 +9,7 @@ import {
|
|
|
6
9
|
import {
|
|
7
10
|
cdpCapture,
|
|
8
11
|
hasWebSocket
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import {
|
|
11
|
-
ensureSquintIgnore
|
|
12
|
-
} from "./chunk-O2S6PAJE.js";
|
|
12
|
+
} from "./chunk-6FR4TRRQ.js";
|
|
13
13
|
|
|
14
14
|
// src/preview/preview.ts
|
|
15
15
|
import fs from "fs";
|
|
@@ -133,7 +133,7 @@ async function probeRuntime(url, cwd) {
|
|
|
133
133
|
async function comparePulse(previous, current) {
|
|
134
134
|
const chrome = findChrome();
|
|
135
135
|
if (!chrome || !hasWebSocket()) return null;
|
|
136
|
-
const { pixelDiffPct } = await import("./cdp-
|
|
136
|
+
const { pixelDiffPct } = await import("./cdp-VRGCGN5R.js");
|
|
137
137
|
return pixelDiffPct(chrome, previous, current);
|
|
138
138
|
}
|
|
139
139
|
function buildRuntimeFixPrompt(report) {
|
|
@@ -178,6 +178,60 @@ var describe = (value) => {
|
|
|
178
178
|
}
|
|
179
179
|
return String(value);
|
|
180
180
|
};
|
|
181
|
+
async function runFlow(chromePath, baseUrl, flow, outDir) {
|
|
182
|
+
const { stepExpression } = await import("./flows-V5ZLVVSQ.js");
|
|
183
|
+
const { child, wsUrl, profileDir } = await launchChrome(chromePath);
|
|
184
|
+
const shots = [];
|
|
185
|
+
let connection = null;
|
|
186
|
+
try {
|
|
187
|
+
connection = await CdpConnection.connect(wsUrl, 1e4);
|
|
188
|
+
const { targetId } = await connection.send("Target.createTarget", { url: "about:blank" });
|
|
189
|
+
const { sessionId } = await connection.send("Target.attachToTarget", { targetId, flatten: true });
|
|
190
|
+
await connection.send("Page.enable", {}, sessionId);
|
|
191
|
+
await connection.send(
|
|
192
|
+
"Emulation.setDeviceMetricsOverride",
|
|
193
|
+
{ width: 1280, height: 800, deviceScaleFactor: 1, mobile: false },
|
|
194
|
+
sessionId
|
|
195
|
+
);
|
|
196
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
197
|
+
let stepNumber = 0;
|
|
198
|
+
for (const step of flow.steps) {
|
|
199
|
+
stepNumber += 1;
|
|
200
|
+
if (step.kind === "goto") {
|
|
201
|
+
const url = step.route === "/" ? base : `${base}${step.route}`;
|
|
202
|
+
await connection.send("Page.navigate", { url }, sessionId);
|
|
203
|
+
await new Promise((resolve) => setTimeout(resolve, 1800));
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (step.kind === "shot") {
|
|
207
|
+
const { data } = await connection.send("Page.captureScreenshot", { format: "png" }, sessionId);
|
|
208
|
+
const outPath = path.join(outDir, `flow-${flow.name}-${step.name}.png`);
|
|
209
|
+
fs.writeFileSync(outPath, Buffer.from(data, "base64"));
|
|
210
|
+
shots.push(outPath);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const expression = stepExpression(step);
|
|
214
|
+
if (!expression) continue;
|
|
215
|
+
const { result } = await connection.send(
|
|
216
|
+
"Runtime.evaluate",
|
|
217
|
+
{ expression, returnByValue: true },
|
|
218
|
+
sessionId
|
|
219
|
+
);
|
|
220
|
+
const value = result?.value;
|
|
221
|
+
if (!value?.ok) {
|
|
222
|
+
return { ok: false, failedStep: stepNumber, detail: value?.detail ?? "step failed", shots };
|
|
223
|
+
}
|
|
224
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
|
225
|
+
}
|
|
226
|
+
return { ok: true, shots };
|
|
227
|
+
} catch (err) {
|
|
228
|
+
return { ok: false, detail: err instanceof Error ? err.message : String(err), shots };
|
|
229
|
+
} finally {
|
|
230
|
+
connection?.close();
|
|
231
|
+
child.kill("SIGKILL");
|
|
232
|
+
setTimeout(() => fs.rmSync(profileDir, { recursive: true, force: true }), 500).unref?.();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
181
235
|
async function pixelDiffPct(chromePath, pngA, pngB) {
|
|
182
236
|
const { child, wsUrl, profileDir } = await launchChrome(chromePath);
|
|
183
237
|
let connection = null;
|
|
@@ -420,6 +474,7 @@ async function cdpCapture(chromePath, url, outDir, viewports, settleMs = 2500, a
|
|
|
420
474
|
|
|
421
475
|
export {
|
|
422
476
|
hasWebSocket,
|
|
477
|
+
runFlow,
|
|
423
478
|
pixelDiffPct,
|
|
424
479
|
cdpCapture
|
|
425
480
|
};
|
|
@@ -14,6 +14,8 @@ var COMMANDS = [
|
|
|
14
14
|
{ name: "shot", args: "[url]", group: "verify", description: "screenshot the app (or any url) at mobile/tablet/desktop" },
|
|
15
15
|
{ name: "review", args: "[focus]", group: "verify", description: "screenshots + the engine critiques its own rendered work" },
|
|
16
16
|
{ name: "polish", args: "[1-5]", group: "verify", description: "unattended rounds of review \u2192 fix (default 2)" },
|
|
17
|
+
{ name: "score", group: "verify", description: "deterministic quality snapshot (problems, a11y, tells, runtime, LCP)" },
|
|
18
|
+
{ name: "flows", args: "[name]", group: "verify", description: "replay declared .squint/flows/ journeys headlessly" },
|
|
17
19
|
{ name: "variants", args: "<2-4> <ask>", group: "explore", description: "parallel design explorations; apply/list/clean" },
|
|
18
20
|
{ name: "sandbox", args: "[on|diff|apply|discard]", group: "explore", description: "asks accumulate in a shadow worktree until you apply" },
|
|
19
21
|
{ name: "undo", group: "explore", description: "revert the last ask (files only)" },
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
completeCommand
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-SVKV77TO.js";
|
|
5
5
|
import {
|
|
6
6
|
applySandbox,
|
|
7
7
|
discardSandbox,
|
|
@@ -42,7 +42,12 @@ import {
|
|
|
42
42
|
comparePulse,
|
|
43
43
|
probeRuntime,
|
|
44
44
|
runtimeSummary
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-2EJWUBUP.js";
|
|
46
|
+
import {
|
|
47
|
+
clearState,
|
|
48
|
+
loadState,
|
|
49
|
+
saveState
|
|
50
|
+
} from "./chunk-O2S6PAJE.js";
|
|
46
51
|
import {
|
|
47
52
|
runAgent
|
|
48
53
|
} from "./chunk-VH7OOFQP.js";
|
|
@@ -53,18 +58,13 @@ import {
|
|
|
53
58
|
detectEngines,
|
|
54
59
|
getEngine
|
|
55
60
|
} from "./chunk-KVYGPLWW.js";
|
|
56
|
-
import "./chunk-
|
|
61
|
+
import "./chunk-6FR4TRRQ.js";
|
|
57
62
|
import {
|
|
58
63
|
enrich
|
|
59
64
|
} from "./chunk-H5K55LXY.js";
|
|
60
65
|
import {
|
|
61
66
|
composePrompt
|
|
62
67
|
} from "./chunk-P3H4N2EN.js";
|
|
63
|
-
import {
|
|
64
|
-
clearState,
|
|
65
|
-
loadState,
|
|
66
|
-
saveState
|
|
67
|
-
} from "./chunk-O2S6PAJE.js";
|
|
68
68
|
|
|
69
69
|
// src/cli.tsx
|
|
70
70
|
import { Command } from "commander";
|
|
@@ -238,7 +238,7 @@ function registerEnv(program2) {
|
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
const { findChrome: findChrome2 } = await import("./chrome-SBV3H77F.js");
|
|
241
|
-
const { hasWebSocket } = await import("./cdp-
|
|
241
|
+
const { hasWebSocket } = await import("./cdp-VRGCGN5R.js");
|
|
242
242
|
const chrome = findChrome2();
|
|
243
243
|
console.log(
|
|
244
244
|
chrome ? `${pc2.green("\u2713")} Chrome ${pc2.dim(chrome)}` : `${pc2.yellow("\u25CB")} Chrome ${pc2.dim("\u2014 screenshots and runtime probing disabled")}`
|
|
@@ -461,7 +461,7 @@ function registerQuality(program2) {
|
|
|
461
461
|
if (results.some((r) => !r.ok)) process.exitCode = 1;
|
|
462
462
|
});
|
|
463
463
|
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) => {
|
|
464
|
-
const { captureViewports: captureViewports2 } = await import("./preview-
|
|
464
|
+
const { captureViewports: captureViewports2 } = await import("./preview-X7EWTRCZ.js");
|
|
465
465
|
const result = await captureViewports2(process.cwd(), url);
|
|
466
466
|
if (!result) {
|
|
467
467
|
console.error(pc4.red("\u2717 no Chrome/Chromium found"));
|
|
@@ -1474,6 +1474,81 @@ They are objective defects, not style preferences.`
|
|
|
1474
1474
|
})();
|
|
1475
1475
|
break;
|
|
1476
1476
|
}
|
|
1477
|
+
case "flows": {
|
|
1478
|
+
if (!this.state.devUrl) {
|
|
1479
|
+
this.push("error", "dev server not running \u2014 /dev first");
|
|
1480
|
+
break;
|
|
1481
|
+
}
|
|
1482
|
+
void (async () => {
|
|
1483
|
+
const { loadFlows } = await import("./flows-V5ZLVVSQ.js");
|
|
1484
|
+
const flows = loadFlows(this.opts.cwd);
|
|
1485
|
+
if (flows.length === 0) {
|
|
1486
|
+
this.push("status", "no flows \u2014 add .squint/flows/<name>.flow (goto/click/fill/press/expect/shot lines), or ask the engine to write one");
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
const chrome = findChrome();
|
|
1490
|
+
if (!chrome) {
|
|
1491
|
+
this.push("error", "no Chrome/Chromium found for flows");
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
const { runFlow } = await import("./cdp-VRGCGN5R.js");
|
|
1495
|
+
const { previewDir } = await import("./preview-X7EWTRCZ.js");
|
|
1496
|
+
this.push("status", `replaying ${flows.length} flow(s)\u2026`);
|
|
1497
|
+
this.notify({ running: true, runStartedAt: Date.now() });
|
|
1498
|
+
const failures = [];
|
|
1499
|
+
for (const flow of flows) {
|
|
1500
|
+
const wanted = arg.trim();
|
|
1501
|
+
if (wanted && flow.name !== wanted) continue;
|
|
1502
|
+
const result = await runFlow(chrome, this.state.devUrl, flow, previewDir(this.opts.cwd));
|
|
1503
|
+
if (result.ok) {
|
|
1504
|
+
this.push("status", `\u2713 flow ${flow.name} \xB7 ${flow.steps.length} steps${result.shots.length > 0 ? ` \xB7 ${result.shots.length} shot(s)` : ""}`);
|
|
1505
|
+
for (const shot of result.shots) this.push("image", shot);
|
|
1506
|
+
} else {
|
|
1507
|
+
const where = result.failedStep ? ` at step ${result.failedStep}` : "";
|
|
1508
|
+
this.push("error", `\u2717 flow ${flow.name}${where}: ${result.detail}`);
|
|
1509
|
+
failures.push(`Flow "${flow.name}" fails${where}: ${result.detail}. The flow file is .squint/flows/${flow.name}.flow \u2014 fix the app (or the flow if the UI legitimately changed).`);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
this.notify({ running: false });
|
|
1513
|
+
if (failures.length > 0) {
|
|
1514
|
+
this.addProblem("flow", `${failures.length} flow(s) failing`, failures.join("\n\n"));
|
|
1515
|
+
this.push("status", "/fix sends open problems to the engine \xB7 /problems lists them");
|
|
1516
|
+
} else {
|
|
1517
|
+
this.clearProblems("flow");
|
|
1518
|
+
}
|
|
1519
|
+
this.drainQueue();
|
|
1520
|
+
})();
|
|
1521
|
+
break;
|
|
1522
|
+
}
|
|
1523
|
+
case "score": {
|
|
1524
|
+
if (!this.state.devUrl) {
|
|
1525
|
+
this.push("error", "dev server not running \u2014 /dev first");
|
|
1526
|
+
break;
|
|
1527
|
+
}
|
|
1528
|
+
void (async () => {
|
|
1529
|
+
const result = await this.capture();
|
|
1530
|
+
if (!result) return;
|
|
1531
|
+
const a11yCount = result.a11y?.length ?? 0;
|
|
1532
|
+
const slopCount = result.slop?.length ?? 0;
|
|
1533
|
+
const runtimeBad = result.runtime ? runtimeSummary(result.runtime) ? 1 : 0 : 0;
|
|
1534
|
+
const problems = this.state.problems.length;
|
|
1535
|
+
const score = Math.max(
|
|
1536
|
+
0,
|
|
1537
|
+
5 - problems * 0.75 - Math.min(a11yCount, 4) * 0.25 - Math.min(slopCount, 4) * 0.25 - runtimeBad
|
|
1538
|
+
);
|
|
1539
|
+
const lcp = this.lastPerf?.lcpMs !== void 0 ? ` \xB7 LCP ${this.lastPerf.lcpMs}ms` : "";
|
|
1540
|
+
this.push(
|
|
1541
|
+
"status",
|
|
1542
|
+
[
|
|
1543
|
+
`score: ${score.toFixed(2)}/5 (deterministic axes)`,
|
|
1544
|
+
` open problems: ${problems}${problems > 0 ? ` (${this.state.problems.map((p) => p.source).join(", ")})` : ""}`,
|
|
1545
|
+
` a11y findings: ${a11yCount} \xB7 distinctiveness tells: ${slopCount} \xB7 runtime ${runtimeBad ? "dirty" : "clean"}${lcp}`,
|
|
1546
|
+
" /review judges what numbers cannot \u2014 hierarchy, taste, coherence"
|
|
1547
|
+
].join("\n")
|
|
1548
|
+
);
|
|
1549
|
+
})();
|
|
1550
|
+
break;
|
|
1551
|
+
}
|
|
1477
1552
|
case "polish": {
|
|
1478
1553
|
const rounds = arg ? Number.parseInt(arg, 10) : 2;
|
|
1479
1554
|
if (!Number.isInteger(rounds) || rounds < 1 || rounds > 5) {
|
|
@@ -1739,7 +1814,7 @@ ${sandboxFiles(this.opts.cwd).join("\n")}`);
|
|
|
1739
1814
|
this.notify({ items: [], totals: { costUsd: 0, turns: 0 } });
|
|
1740
1815
|
break;
|
|
1741
1816
|
case "help": {
|
|
1742
|
-
void import("./commands-
|
|
1817
|
+
void import("./commands-DE5Q7VWY.js").then(({ commandHelp }) => this.push("status", commandHelp()));
|
|
1743
1818
|
break;
|
|
1744
1819
|
}
|
|
1745
1820
|
case "quit":
|
|
@@ -2358,7 +2433,7 @@ function registerTui(program2) {
|
|
|
2358
2433
|
}
|
|
2359
2434
|
|
|
2360
2435
|
// src/cli.tsx
|
|
2361
|
-
var VERSION = true ? "0.
|
|
2436
|
+
var VERSION = true ? "0.4.0" : "0.0.0-dev";
|
|
2362
2437
|
var program = new Command();
|
|
2363
2438
|
program.name("squint").description("Lovable for your terminal \u2014 a frontend harness on top of Claude Code, Codex, and friends.").version(VERSION);
|
|
2364
2439
|
registerRun(program);
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/preview/flows.ts
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
function parseFlow(name, text) {
|
|
7
|
+
const steps = [];
|
|
8
|
+
for (const rawLine of text.split("\n")) {
|
|
9
|
+
const line = rawLine.trim();
|
|
10
|
+
if (line.length === 0 || line.startsWith("#")) continue;
|
|
11
|
+
const [verb, ...rest] = line.split(/\s+/);
|
|
12
|
+
const arg = rest.join(" ");
|
|
13
|
+
switch (verb) {
|
|
14
|
+
case "goto":
|
|
15
|
+
steps.push({ kind: "goto", route: arg.startsWith("/") ? arg : `/${arg}` });
|
|
16
|
+
break;
|
|
17
|
+
case "click":
|
|
18
|
+
steps.push({ kind: "click", target: arg });
|
|
19
|
+
break;
|
|
20
|
+
case "fill": {
|
|
21
|
+
const [selector, ...valueParts] = rest;
|
|
22
|
+
if (!selector || valueParts.length === 0) return null;
|
|
23
|
+
steps.push({ kind: "fill", selector, value: valueParts.join(" ") });
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case "press":
|
|
27
|
+
steps.push({ kind: "press", key: arg });
|
|
28
|
+
break;
|
|
29
|
+
case "expect":
|
|
30
|
+
steps.push({ kind: "expect", text: arg });
|
|
31
|
+
break;
|
|
32
|
+
case "shot":
|
|
33
|
+
steps.push({ kind: "shot", name: arg.replace(/[^a-zA-Z0-9-]/g, "-") });
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return steps.length > 0 ? { name, steps } : null;
|
|
40
|
+
}
|
|
41
|
+
function loadFlows(cwd) {
|
|
42
|
+
const dir = path.join(cwd, ".squint", "flows");
|
|
43
|
+
let entries;
|
|
44
|
+
try {
|
|
45
|
+
entries = fs.readdirSync(dir).filter((f) => f.endsWith(".flow"));
|
|
46
|
+
} catch {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
const flows = [];
|
|
50
|
+
for (const entry of entries.sort()) {
|
|
51
|
+
try {
|
|
52
|
+
const flow = parseFlow(entry.replace(/\.flow$/, ""), fs.readFileSync(path.join(dir, entry), "utf8"));
|
|
53
|
+
if (flow) flows.push(flow);
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return flows;
|
|
58
|
+
}
|
|
59
|
+
function stepExpression(step) {
|
|
60
|
+
switch (step.kind) {
|
|
61
|
+
case "click":
|
|
62
|
+
return `(() => {
|
|
63
|
+
const target = ${JSON.stringify(step.target)};
|
|
64
|
+
let el = null;
|
|
65
|
+
try { el = document.querySelector(target); } catch {}
|
|
66
|
+
if (!el) {
|
|
67
|
+
const all = [...document.querySelectorAll('a, button, [role=button], input[type=submit], summary, label')];
|
|
68
|
+
el = all.find((e) => (e.textContent || '').trim().toLowerCase().includes(target.toLowerCase()));
|
|
69
|
+
}
|
|
70
|
+
if (!el) return { ok: false, detail: 'no element matching ' + target };
|
|
71
|
+
el.click();
|
|
72
|
+
return { ok: true };
|
|
73
|
+
})()`;
|
|
74
|
+
case "fill":
|
|
75
|
+
return `(() => {
|
|
76
|
+
const el = document.querySelector(${JSON.stringify(step.selector)});
|
|
77
|
+
if (!el) return { ok: false, detail: 'no element matching ${step.selector}' };
|
|
78
|
+
const setter = Object.getOwnPropertyDescriptor(el.constructor.prototype, 'value')?.set;
|
|
79
|
+
if (setter) setter.call(el, ${JSON.stringify(step.value)}); else el.value = ${JSON.stringify(step.value)};
|
|
80
|
+
el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
81
|
+
el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
82
|
+
return { ok: true };
|
|
83
|
+
})()`;
|
|
84
|
+
case "expect":
|
|
85
|
+
return `(() => {
|
|
86
|
+
const wanted = ${JSON.stringify(step.text)}.toLowerCase();
|
|
87
|
+
const ok = (document.body.innerText || '').toLowerCase().includes(wanted);
|
|
88
|
+
return ok ? { ok: true } : { ok: false, detail: 'page does not show: ' + ${JSON.stringify(step.text)} };
|
|
89
|
+
})()`;
|
|
90
|
+
case "press":
|
|
91
|
+
return `(() => {
|
|
92
|
+
const key = ${JSON.stringify(step.key)};
|
|
93
|
+
const el = document.activeElement || document.body;
|
|
94
|
+
for (const type of ['keydown', 'keypress', 'keyup']) {
|
|
95
|
+
el.dispatchEvent(new KeyboardEvent(type, { key, bubbles: true, cancelable: true }));
|
|
96
|
+
}
|
|
97
|
+
return { ok: true };
|
|
98
|
+
})()`;
|
|
99
|
+
case "goto":
|
|
100
|
+
case "shot":
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
loadFlows,
|
|
106
|
+
parseFlow,
|
|
107
|
+
stepExpression
|
|
108
|
+
};
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
probeRuntime,
|
|
11
11
|
routeShotName,
|
|
12
12
|
runtimeSummary
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-2EJWUBUP.js";
|
|
14
|
+
import "./chunk-O2S6PAJE.js";
|
|
14
15
|
import "./chunk-IMDRXXFU.js";
|
|
15
16
|
import "./chunk-KVYGPLWW.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-O2S6PAJE.js";
|
|
17
|
+
import "./chunk-6FR4TRRQ.js";
|
|
18
18
|
export {
|
|
19
19
|
VIEWPORTS,
|
|
20
20
|
buildReviewPrompt,
|
package/package.json
CHANGED