@slowcook-ai/cli 0.25.0 → 0.28.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/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/amend.d.ts +12 -0
- package/dist/commands/amend.d.ts.map +1 -0
- package/dist/commands/amend.js +99 -0
- package/dist/commands/amend.js.map +1 -0
- package/dist/commands/bench-browser.d.ts +2 -0
- package/dist/commands/bench-browser.d.ts.map +1 -0
- package/dist/commands/bench-browser.js +31 -0
- package/dist/commands/bench-browser.js.map +1 -0
- package/dist/commands/check/index.d.ts.map +1 -1
- package/dist/commands/check/index.js +13 -0
- package/dist/commands/check/index.js.map +1 -1
- package/dist/commands/check/style-drift.d.ts +18 -0
- package/dist/commands/check/style-drift.d.ts.map +1 -0
- package/dist/commands/check/style-drift.js +175 -0
- package/dist/commands/check/style-drift.js.map +1 -0
- package/dist/commands/check/surface-parity.d.ts +123 -0
- package/dist/commands/check/surface-parity.d.ts.map +1 -0
- package/dist/commands/check/surface-parity.js +328 -0
- package/dist/commands/check/surface-parity.js.map +1 -0
- package/dist/commands/chef/orchestrate.d.ts.map +1 -1
- package/dist/commands/chef/orchestrate.js +22 -2
- package/dist/commands/chef/orchestrate.js.map +1 -1
- package/dist/commands/extract/as-built-cli.d.ts +7 -0
- package/dist/commands/extract/as-built-cli.d.ts.map +1 -0
- package/dist/commands/extract/as-built-cli.js +67 -0
- package/dist/commands/extract/as-built-cli.js.map +1 -0
- package/dist/commands/extract/as-built.d.ts +21 -0
- package/dist/commands/extract/as-built.d.ts.map +1 -0
- package/dist/commands/extract/as-built.js +113 -0
- package/dist/commands/extract/as-built.js.map +1 -0
- package/dist/commands/extract/history-cli.d.ts +6 -0
- package/dist/commands/extract/history-cli.d.ts.map +1 -0
- package/dist/commands/extract/history-cli.js +58 -0
- package/dist/commands/extract/history-cli.js.map +1 -0
- package/dist/commands/extract/history.d.ts +42 -0
- package/dist/commands/extract/history.d.ts.map +1 -0
- package/dist/commands/extract/history.js +114 -0
- package/dist/commands/extract/history.js.map +1 -0
- package/dist/commands/extract/index.d.ts.map +1 -1
- package/dist/commands/extract/index.js +63 -3
- package/dist/commands/extract/index.js.map +1 -1
- package/dist/commands/extract/survey.d.ts +17 -0
- package/dist/commands/extract/survey.d.ts.map +1 -0
- package/dist/commands/extract/survey.js +176 -0
- package/dist/commands/extract/survey.js.map +1 -0
- package/dist/commands/eye/run.d.ts.map +1 -1
- package/dist/commands/eye/run.js +6 -0
- package/dist/commands/eye/run.js.map +1 -1
- package/dist/commands/guard.d.ts +4 -0
- package/dist/commands/guard.d.ts.map +1 -1
- package/dist/commands/guard.js +46 -2
- package/dist/commands/guard.js.map +1 -1
- package/dist/commands/init/templates.d.ts.map +1 -1
- package/dist/commands/init/templates.js +5 -3
- package/dist/commands/init/templates.js.map +1 -1
- package/dist/commands/recall/brief.d.ts +15 -0
- package/dist/commands/recall/brief.d.ts.map +1 -0
- package/dist/commands/recall/brief.js +32 -0
- package/dist/commands/recall/brief.js.map +1 -0
- package/dist/commands/recall/context.d.ts +18 -0
- package/dist/commands/recall/context.d.ts.map +1 -0
- package/dist/commands/recall/context.js +19 -0
- package/dist/commands/recall/context.js.map +1 -0
- package/dist/commands/recall/ctx.d.ts +31 -0
- package/dist/commands/recall/ctx.d.ts.map +1 -0
- package/dist/commands/recall/ctx.js +77 -0
- package/dist/commands/recall/ctx.js.map +1 -0
- package/dist/commands/recall/index.d.ts +2 -0
- package/dist/commands/recall/index.d.ts.map +1 -0
- package/dist/commands/recall/index.js +73 -0
- package/dist/commands/recall/index.js.map +1 -0
- package/dist/commands/vibe/app-gen.d.ts.map +1 -1
- package/dist/commands/vibe/app-gen.js +5 -3
- package/dist/commands/vibe/app-gen.js.map +1 -1
- package/dist/commands/vibe/as-built.d.ts +25 -0
- package/dist/commands/vibe/as-built.d.ts.map +1 -0
- package/dist/commands/vibe/as-built.js +115 -0
- package/dist/commands/vibe/as-built.js.map +1 -0
- package/dist/commands/vibe/index.d.ts.map +1 -1
- package/dist/commands/vibe/index.js +49 -1
- package/dist/commands/vibe/index.js.map +1 -1
- package/dist/commands.manifest.d.ts.map +1 -1
- package/dist/commands.manifest.js +22 -4
- package/dist/commands.manifest.js.map +1 -1
- package/dist/lib/browser/bench-worker.d.ts +2 -0
- package/dist/lib/browser/bench-worker.d.ts.map +1 -0
- package/dist/lib/browser/bench-worker.js +71 -0
- package/dist/lib/browser/bench-worker.js.map +1 -0
- package/dist/lib/browser/bench.d.ts +26 -0
- package/dist/lib/browser/bench.d.ts.map +1 -0
- package/dist/lib/browser/bench.js +68 -0
- package/dist/lib/browser/bench.js.map +1 -0
- package/dist/lib/browser/driver.d.ts +59 -0
- package/dist/lib/browser/driver.d.ts.map +1 -0
- package/dist/lib/browser/driver.js +19 -0
- package/dist/lib/browser/driver.js.map +1 -0
- package/dist/lib/browser/index.d.ts +8 -0
- package/dist/lib/browser/index.d.ts.map +1 -0
- package/dist/lib/browser/index.js +7 -0
- package/dist/lib/browser/index.js.map +1 -0
- package/dist/lib/browser/playwright-driver.d.ts +3 -0
- package/dist/lib/browser/playwright-driver.d.ts.map +1 -0
- package/dist/lib/browser/playwright-driver.js +44 -0
- package/dist/lib/browser/playwright-driver.js.map +1 -0
- package/dist/lib/browser/qa-replay.d.ts +47 -0
- package/dist/lib/browser/qa-replay.d.ts.map +1 -0
- package/dist/lib/browser/qa-replay.js +69 -0
- package/dist/lib/browser/qa-replay.js.map +1 -0
- package/dist/lib/browser/rustwright-driver.d.ts +5 -0
- package/dist/lib/browser/rustwright-driver.d.ts.map +1 -0
- package/dist/lib/browser/rustwright-driver.js +50 -0
- package/dist/lib/browser/rustwright-driver.js.map +1 -0
- package/dist/lib/browser/select.d.ts +21 -0
- package/dist/lib/browser/select.d.ts.map +1 -0
- package/dist/lib/browser/select.js +30 -0
- package/dist/lib/browser/select.js.map +1 -0
- package/package.json +9 -6
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { BrowserDriver, DriverNeed } from "./driver.js";
|
|
2
|
+
export interface QaStep {
|
|
3
|
+
action: "goto" | "click" | "fill" | "assert" | "screenshot" | "wait";
|
|
4
|
+
/** goto */ url?: string;
|
|
5
|
+
/** click/fill/assert */ selector?: string;
|
|
6
|
+
/** fill */ value?: string;
|
|
7
|
+
/** assert: a JS expression evaluated in the page; must be truthy (or === expect). */
|
|
8
|
+
expr?: string;
|
|
9
|
+
expect?: unknown;
|
|
10
|
+
/** screenshot */ path?: string;
|
|
11
|
+
/** wait */ ms?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface QaPlan {
|
|
14
|
+
name: string;
|
|
15
|
+
/** prepended to a step's `url` when it's a path, not absolute. */
|
|
16
|
+
baseUrl?: string;
|
|
17
|
+
steps: QaStep[];
|
|
18
|
+
}
|
|
19
|
+
export interface StepResult {
|
|
20
|
+
i: number;
|
|
21
|
+
action: string;
|
|
22
|
+
ok: boolean;
|
|
23
|
+
detail?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ReplayResult {
|
|
26
|
+
plan: string;
|
|
27
|
+
driver: string;
|
|
28
|
+
ok: boolean;
|
|
29
|
+
ms: number;
|
|
30
|
+
steps: StepResult[];
|
|
31
|
+
/** the step that failed, if any. */
|
|
32
|
+
failedAt?: number;
|
|
33
|
+
}
|
|
34
|
+
/** The capabilities a plan requires — only click+fill actions here, so "basic"
|
|
35
|
+
* suffices (rustwright fits); screenshots/evaluate are in both engines. */
|
|
36
|
+
export declare function planNeed(_plan: QaPlan): DriverNeed;
|
|
37
|
+
/** Replay a plan on a driver. Stops at the first failed step (like a real test),
|
|
38
|
+
* returns a per-step trace + total wall-time. */
|
|
39
|
+
export declare function replayPlan(driver: BrowserDriver, plan: QaPlan): Promise<ReplayResult>;
|
|
40
|
+
/** Replay a plan on the PROVEN-DEFAULT engine for QA replay: rustwright when it
|
|
41
|
+
* fits + is installed (the ~65%-lighter footprint that matters for a fleet),
|
|
42
|
+
* else Playwright (failover). Override with env SLOWCOOK_BROWSER. */
|
|
43
|
+
export declare function replayPlanAuto(plan: QaPlan, env?: NodeJS.ProcessEnv): Promise<ReplayResult & {
|
|
44
|
+
engine: string;
|
|
45
|
+
failover: boolean;
|
|
46
|
+
}>;
|
|
47
|
+
//# sourceMappingURL=qa-replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qa-replay.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/qa-replay.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG7D,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,MAAM,CAAC;IACrE,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3C,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAC3B,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE;AACvF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,OAAO,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;4EAC4E;AAC5E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAElD;AAKD;kDACkD;AAClD,wBAAsB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAoC3F;AAED;;sEAEsE;AACtE,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,YAAY,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAIzI"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { selectDriver } from "./select.js";
|
|
2
|
+
/** The capabilities a plan requires — only click+fill actions here, so "basic"
|
|
3
|
+
* suffices (rustwright fits); screenshots/evaluate are in both engines. */
|
|
4
|
+
export function planNeed(_plan) {
|
|
5
|
+
return { actions: "basic" };
|
|
6
|
+
}
|
|
7
|
+
const abs = (base, url) => /^[a-z]+:\/\//i.test(url) || url.startsWith("data:") ? url : `${(base ?? "").replace(/\/$/, "")}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
8
|
+
/** Replay a plan on a driver. Stops at the first failed step (like a real test),
|
|
9
|
+
* returns a per-step trace + total wall-time. */
|
|
10
|
+
export async function replayPlan(driver, plan) {
|
|
11
|
+
const t0 = Date.now();
|
|
12
|
+
const steps = [];
|
|
13
|
+
const session = await driver.launch();
|
|
14
|
+
const page = await session.newPage();
|
|
15
|
+
let ok = true;
|
|
16
|
+
let failedAt;
|
|
17
|
+
try {
|
|
18
|
+
for (let i = 0; i < plan.steps.length; i++) {
|
|
19
|
+
const s = plan.steps[i];
|
|
20
|
+
try {
|
|
21
|
+
switch (s.action) {
|
|
22
|
+
case "goto":
|
|
23
|
+
await page.goto(abs(plan.baseUrl, s.url ?? ""), { waitUntil: "load" });
|
|
24
|
+
break;
|
|
25
|
+
case "click":
|
|
26
|
+
await page.click(s.selector ?? "");
|
|
27
|
+
break;
|
|
28
|
+
case "fill":
|
|
29
|
+
await page.fill(s.selector ?? "", s.value ?? "");
|
|
30
|
+
break;
|
|
31
|
+
case "wait":
|
|
32
|
+
await page.waitFor(s.ms ?? 100);
|
|
33
|
+
break;
|
|
34
|
+
case "screenshot":
|
|
35
|
+
await page.screenshot({ path: s.path, fullPage: true });
|
|
36
|
+
break;
|
|
37
|
+
case "assert": {
|
|
38
|
+
const got = await page.evaluate(s.expr ?? "false");
|
|
39
|
+
const pass = "expect" in s ? JSON.stringify(got) === JSON.stringify(s.expect) : !!got;
|
|
40
|
+
if (!pass)
|
|
41
|
+
throw new Error(`assert failed: ${s.expr} → ${JSON.stringify(got)}${"expect" in s ? ` (expected ${JSON.stringify(s.expect)})` : ""}`);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
steps.push({ i, action: s.action, ok: true });
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
ok = false;
|
|
49
|
+
failedAt = i;
|
|
50
|
+
steps.push({ i, action: s.action, ok: false, detail: e instanceof Error ? e.message : String(e) });
|
|
51
|
+
break; // stop at first failure
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await page.close().catch(() => { });
|
|
57
|
+
await session.close().catch(() => { });
|
|
58
|
+
}
|
|
59
|
+
return { plan: plan.name, driver: driver.name, ok, ms: Date.now() - t0, steps, failedAt };
|
|
60
|
+
}
|
|
61
|
+
/** Replay a plan on the PROVEN-DEFAULT engine for QA replay: rustwright when it
|
|
62
|
+
* fits + is installed (the ~65%-lighter footprint that matters for a fleet),
|
|
63
|
+
* else Playwright (failover). Override with env SLOWCOOK_BROWSER. */
|
|
64
|
+
export async function replayPlanAuto(plan, env) {
|
|
65
|
+
const sel = await selectDriver({ need: planNeed(plan), prefer: "rustwright", env });
|
|
66
|
+
const r = await replayPlan(sel.driver, plan);
|
|
67
|
+
return { ...r, engine: sel.driver.name, failover: !sel.usedPreferred };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=qa-replay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qa-replay.js","sourceRoot":"","sources":["../../../src/lib/browser/qa-replay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { BrowserDriver } from "./driver.js";
|
|
2
|
+
/** true if the rustwright package is installed AND loads on this platform. */
|
|
3
|
+
export declare function rustwrightAvailable(): Promise<boolean>;
|
|
4
|
+
export declare function rustwrightDriver(): BrowserDriver;
|
|
5
|
+
//# sourceMappingURL=rustwright-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rustwright-driver.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/rustwright-driver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAqD,MAAM,aAAa,CAAC;AAoBpG,8EAA8E;AAC9E,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC,CAE5D;AAoBD,wBAAgB,gBAAgB,IAAI,aAAa,CAmBhD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// rustwright can't emulate (newPage takes no options) and has no contexts; its
|
|
2
|
+
// action surface is click + fill only.
|
|
3
|
+
const CAPS = { emulation: false, contexts: false, actions: "basic" };
|
|
4
|
+
/** true if the rustwright package is installed AND loads on this platform. */
|
|
5
|
+
export async function rustwrightAvailable() {
|
|
6
|
+
try {
|
|
7
|
+
await import("rustwright");
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
15
|
+
function wrapPage(page, onClose) {
|
|
16
|
+
return {
|
|
17
|
+
goto: async (url, opts) => { await page.goto(url, { waitUntil: opts?.waitUntil ?? "load" }); },
|
|
18
|
+
evaluate: (expr) => page.evaluate(expr),
|
|
19
|
+
screenshot: (opts) => page.screenshot({ path: opts.path, fullPage: opts.fullPage ?? false }),
|
|
20
|
+
click: (sel) => page.click(sel),
|
|
21
|
+
fill: (sel, v) => page.fill(sel, v),
|
|
22
|
+
textContent: (sel) => page.textContent(sel),
|
|
23
|
+
title: () => page.title(),
|
|
24
|
+
// rustwright has no waitForTimeout — a plain sleep is equivalent for
|
|
25
|
+
// "let styles settle" waits.
|
|
26
|
+
waitFor: (ms) => sleep(ms),
|
|
27
|
+
close: onClose,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export function rustwrightDriver() {
|
|
31
|
+
return {
|
|
32
|
+
name: "rustwright",
|
|
33
|
+
caps: CAPS,
|
|
34
|
+
async launch() {
|
|
35
|
+
const rw = (await import("rustwright"));
|
|
36
|
+
const browser = await rw.chromium.launch();
|
|
37
|
+
return {
|
|
38
|
+
// no contexts: each page is a bare newPage on the shared browser. `emu`
|
|
39
|
+
// is IGNORED by design — the selector never routes an emulation-needing
|
|
40
|
+
// workload here, so this only runs for needs that don't require it.
|
|
41
|
+
async newPage(_emu) {
|
|
42
|
+
const page = await browser.newPage();
|
|
43
|
+
return wrapPage(page, async () => { });
|
|
44
|
+
},
|
|
45
|
+
close: () => browser.close(),
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=rustwright-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rustwright-driver.js","sourceRoot":"","sources":["../../../src/lib/browser/rustwright-driver.ts"],"names":[],"mappings":"AAOA,+EAA+E;AAC/E,uCAAuC;AACvC,MAAM,IAAI,GAAe,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAgBjF,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,IAAI,CAAC;QAAC,MAAM,MAAM,CAAC,YAAsB,CAAC,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;AACpF,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAE1E,SAAS,QAAQ,CAAC,IAAY,EAAE,OAA4B;IAC1D,OAAO;QACL,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9F,QAAQ,EAAE,CAAI,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAe;QAChE,UAAU,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK,EAAE,CAAC;QAC5F,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/B,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACnC,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;QAC3C,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE;QACzB,qEAAqE;QACrE,6BAA6B;QAC7B,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,KAAK,EAAE,OAAO;KACf,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,IAAI;QACV,KAAK,CAAC,MAAM;YACV,MAAM,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,YAAsB,CAAC,CAAwB,CAAC;YACzE,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3C,OAAO;gBACL,wEAAwE;gBACxE,wEAAwE;gBACxE,oEAAoE;gBACpE,KAAK,CAAC,OAAO,CAAC,IAAiB;oBAC7B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;oBACrC,OAAO,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,GAAiD,CAAC,CAAC,CAAC;gBACvF,CAAC;gBACD,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE;aAC7B,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type BrowserDriver, type DriverNeed } from "./driver.js";
|
|
2
|
+
export interface SelectOptions {
|
|
3
|
+
/** what the workload requires; an engine is only picked if it satisfies all. */
|
|
4
|
+
need?: DriverNeed;
|
|
5
|
+
/** caller's preference; overridden by env SLOWCOOK_BROWSER. Default: playwright. */
|
|
6
|
+
prefer?: "playwright" | "rustwright";
|
|
7
|
+
/** override the env lookup (tests). */
|
|
8
|
+
env?: NodeJS.ProcessEnv;
|
|
9
|
+
}
|
|
10
|
+
export interface Selection {
|
|
11
|
+
driver: BrowserDriver;
|
|
12
|
+
/** true when the preferred engine was used; false when we failed over. */
|
|
13
|
+
usedPreferred: boolean;
|
|
14
|
+
/** human-readable why, for logs. */
|
|
15
|
+
reason: string;
|
|
16
|
+
}
|
|
17
|
+
/** Resolve which engine to use. env SLOWCOOK_BROWSER (playwright|rustwright) wins
|
|
18
|
+
* over `prefer`; the result is Playwright unless rustwright is preferred, fits,
|
|
19
|
+
* and is installed. NEVER throws for a missing rustwright — it fails over. */
|
|
20
|
+
export declare function selectDriver(opts?: SelectOptions): Promise<Selection>;
|
|
21
|
+
//# sourceMappingURL=select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/lib/browser/select.ts"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE7E,MAAM,WAAW,aAAa;IAC5B,gFAAgF;IAChF,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,oFAAoF;IACpF,MAAM,CAAC,EAAE,YAAY,GAAG,YAAY,CAAC;IACrC,uCAAuC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,aAAa,CAAC;IACtB,0EAA0E;IAC1E,aAAa,EAAE,OAAO,CAAC;IACvB,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;+EAE+E;AAC/E,wBAAsB,YAAY,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,SAAS,CAAC,CAqB/E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Driver selection (2026-07-16) — Playwright is the default + failover; rustwright
|
|
2
|
+
// is chosen only when explicitly preferred AND its capabilities fit the workload
|
|
3
|
+
// AND it's installed. Anything else falls back to Playwright, with a reason.
|
|
4
|
+
import { playwrightDriver } from "./playwright-driver.js";
|
|
5
|
+
import { rustwrightDriver, rustwrightAvailable } from "./rustwright-driver.js";
|
|
6
|
+
import { satisfies } from "./driver.js";
|
|
7
|
+
/** Resolve which engine to use. env SLOWCOOK_BROWSER (playwright|rustwright) wins
|
|
8
|
+
* over `prefer`; the result is Playwright unless rustwright is preferred, fits,
|
|
9
|
+
* and is installed. NEVER throws for a missing rustwright — it fails over. */
|
|
10
|
+
export async function selectDriver(opts = {}) {
|
|
11
|
+
const env = opts.env ?? process.env;
|
|
12
|
+
const envChoice = env["SLOWCOOK_BROWSER"]?.trim().toLowerCase();
|
|
13
|
+
const requested = envChoice === "rustwright" || envChoice === "playwright"
|
|
14
|
+
? envChoice
|
|
15
|
+
: (opts.prefer ?? "playwright");
|
|
16
|
+
const need = opts.need ?? {};
|
|
17
|
+
if (requested !== "rustwright") {
|
|
18
|
+
return { driver: playwrightDriver(), usedPreferred: true, reason: "playwright (default)" };
|
|
19
|
+
}
|
|
20
|
+
// rustwright requested — only if it fits the need AND is installed.
|
|
21
|
+
const rw = rustwrightDriver();
|
|
22
|
+
if (!satisfies(rw.caps, need)) {
|
|
23
|
+
return { driver: playwrightDriver(), usedPreferred: false, reason: `rustwright can't satisfy ${JSON.stringify(need)} — using playwright` };
|
|
24
|
+
}
|
|
25
|
+
if (!(await rustwrightAvailable())) {
|
|
26
|
+
return { driver: playwrightDriver(), usedPreferred: false, reason: "rustwright not installed — using playwright" };
|
|
27
|
+
}
|
|
28
|
+
return { driver: rw, usedPreferred: true, reason: "rustwright (preferred, fits)" };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../../src/lib/browser/select.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,iFAAiF;AACjF,6EAA6E;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAuC,MAAM,aAAa,CAAC;AAmB7E;;+EAE+E;AAC/E,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAsB,EAAE;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,SAAS,GAAG,GAAG,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAChE,MAAM,SAAS,GAAG,SAAS,KAAK,YAAY,IAAI,SAAS,KAAK,YAAY;QACxE,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,YAAY,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IAE7B,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;QAC/B,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IAC7F,CAAC;IAED,oEAAoE;IACpE,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAC9B,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,4BAA4B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC7I,CAAC;IACD,IAAI,CAAC,CAAC,MAAM,mBAAmB,EAAE,CAAC,EAAE,CAAC;QACnC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;IACrH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,8BAA8B,EAAE,CAAC;AACrF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slowcook-ai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "CLI for the slowcook brewing harness",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "aminazar",
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"ts-morph": "^28.0.0",
|
|
42
42
|
"yaml": "^2.9.0",
|
|
43
43
|
"zod": "^4.4.3",
|
|
44
|
-
"@slowcook-ai/core": "^0.17.0",
|
|
45
|
-
"@slowcook-ai/stack-ts": "^0.9.9",
|
|
46
44
|
"@slowcook-ai/forge-github": "^0.14.0",
|
|
45
|
+
"@slowcook-ai/stack-ts": "^0.9.9",
|
|
46
|
+
"@slowcook-ai/core": "^0.17.0",
|
|
47
47
|
"@slowcook-ai/llm-anthropic": "^0.21.0",
|
|
48
|
-
"@slowcook-ai/
|
|
49
|
-
"@slowcook-ai/review-overlay": "^0.
|
|
50
|
-
"@slowcook-ai/
|
|
48
|
+
"@slowcook-ai/recorder": "^0.9.1",
|
|
49
|
+
"@slowcook-ai/review-overlay": "^0.14.0",
|
|
50
|
+
"@slowcook-ai/gates": "^0.11.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "^26.0.1"
|
|
@@ -58,6 +58,9 @@
|
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=20"
|
|
60
60
|
},
|
|
61
|
+
"optionalDependencies": {
|
|
62
|
+
"rustwright": "^0.1.1"
|
|
63
|
+
},
|
|
61
64
|
"scripts": {
|
|
62
65
|
"build": "tsc -b",
|
|
63
66
|
"test": "vitest run --passWithNoTests",
|