CLI runs on Node 20+: npx storebound (bunx keeps working)
- cli/lib/rt.ts: the runtime layer on node: modules (spawn / spawnSync with Bun's defaults, exit codes and "Executable not found", which with PATHEXT, sleep, serve, Glob, hasher, gunzip, stdin, SQLite, packageRoot, config imports with a type-stripping fallback for Node 20); every Bun.* use in cli/ goes through it - tools/gen-embedded.ts -> cli/lib/embedded.ts: templates/, cli/shots/*.html and Play's Data safety form embedded (replaces Bun text imports; the bundle and the compiled sidecar carry them), checked fresh by bun run ci - package.json: bin dist/storebound.mjs (Node ESM bundle, tools/build-node.ts, prepack), engines node >=20 - bun run ci: node bundle + node smoke (real node: --version, help, check same as Bun, scan, release plan --help, init, MCP handshake + tool call); Forgejo CI sets up Node 20; tests/node-compat.test.ts guards cli/ - install writes npx MCP commands when run with Node; bin/storebound falls back to Node - docs: npx storebound init (Node 20+) or bunx storebound init
This commit is contained in:
parent
614c32bcba
commit
36a8bf9625
73 changed files with 1195 additions and 251 deletions
|
|
@ -37,6 +37,7 @@ import { adbAppLocaleArgs, adbDemoExitArgs, adbDemoModeArgs, adbForceStopArgs, a
|
|||
import { type CopyFile, copyText, type FrameDims, frameDims } from './lib';
|
||||
import { captureWeb, defaultConcurrency, hashPaths, hashServed, planWeb, readCache, selectJobs, summaryLines, writeCaptureState } from './capture-web';
|
||||
import { imageInfo } from './spec';
|
||||
import * as rt from '../lib/rt';
|
||||
|
||||
type Device = 'phone' | 'tablet';
|
||||
|
||||
|
|
@ -56,7 +57,7 @@ export function adbPath(): string {
|
|||
|
||||
/** Throws the install hint when a tool is neither a path that exists nor on PATH. */
|
||||
export function requireTool(cmd: string, name = cmd): void {
|
||||
if (existsSync(cmd) || Bun.which(cmd)) return;
|
||||
if (existsSync(cmd) || rt.which(cmd)) return;
|
||||
throw new Error(TOOL_HINTS[name] ?? `${name} not found on PATH`);
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +151,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (source === 'ios-sim') {
|
||||
const ios = need(cap.ios, 'shots.capture.ios');
|
||||
if (!dry) { requireTool('xcrun'); requireTool('ffmpeg'); }
|
||||
const list = dry && !Bun.which('xcrun') ? '{"devices":{}}' : sh('xcrun', ['simctl', 'list', 'devices', '-j']).out.toString();
|
||||
const list = dry && !rt.which('xcrun') ? '{"devices":{}}' : sh('xcrun', ['simctl', 'list', 'devices', '-j']).out.toString();
|
||||
for (const device of devices) {
|
||||
const want = simTarget(ios, device);
|
||||
const todo = shotsFor(cap, device, only);
|
||||
|
|
@ -171,16 +172,16 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (bootedByUs && warmup > 0) {
|
||||
log('shots', `warming up ${ios.bundleId} (first launch after boot, ${warmup} ms; shots.capture.ios.warmupMs)`);
|
||||
exec('xcrun', simLaunchArgs(sim.udid, ios.bundleId, { lang: langs[0]!, locale: localeOf(config, langs[0]!, 'ios-sim'), shot: '', baseArgs: ios.args }));
|
||||
if (!dry) await Bun.sleep(warmup);
|
||||
if (!dry) await rt.sleep(warmup);
|
||||
}
|
||||
for (const lang of langs) for (const [name, s] of todo) {
|
||||
try {
|
||||
const locale = localeOf(config, lang, 'ios-sim');
|
||||
exec('xcrun', simLaunchArgs(sim.udid, ios.bundleId, { lang, locale, shot: name, baseArgs: ios.args, args: s.args }));
|
||||
if (s.url) { if (!dry) await Bun.sleep(1500); exec('xcrun', simOpenUrlArgs(sim.udid, fill(s.url, { lang, locale, shot: name }))); }
|
||||
if (s.url) { if (!dry) await rt.sleep(1500); exec('xcrun', simOpenUrlArgs(sim.udid, fill(s.url, { lang, locale, shot: name }))); }
|
||||
const out = target(lang, device, name);
|
||||
if (dry) { progress(`${lang}/${device}/${name}.png (${sim.name}, would wait ${s.delayMs ?? 2500} ms)`); continue; }
|
||||
await Bun.sleep(s.delayMs ?? 2500);
|
||||
await rt.sleep(s.delayMs ?? 2500);
|
||||
const tmp = join(tmpDir, `sim-${name}.png`);
|
||||
sh('xcrun', simScreenshotArgs(sim.udid, tmp));
|
||||
storeFrame(tmp, out, cap.cropTop, device, dims[device]);
|
||||
|
|
@ -221,7 +222,7 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
exec(adb, adbStartArgs(and.package, { lang, locale, shot: name, url: s.url, activity: and.activity, extras: s.extras }, serial));
|
||||
const out = target(lang, device, name);
|
||||
if (dry) { progress(`${lang}/${device}/${name}.png (would wait ${s.delayMs ?? 2500} ms, screencap)`); continue; }
|
||||
await Bun.sleep(s.delayMs ?? 2500);
|
||||
await rt.sleep(s.delayMs ?? 2500);
|
||||
const tmp = join(tmpDir, `adb-${name}.png`);
|
||||
writeFileSync(tmp, sh(adb, adbScreencapArgs(serial)).out);
|
||||
storeFrame(tmp, out, cap.cropTop, device, dims[device]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue