storebound 0.8.3: prompts read stdin with rt.readLine (node:readline) instead of Bun-only for await (const line of console), which crashed npx storebound desktop on Node/Windows; node-compat test bans Bun-only stdin iteration; Node prompt smoke, also on the Windows release runner
This commit is contained in:
parent
c3fed8efa2
commit
3a27c78f49
8 changed files with 111 additions and 9 deletions
|
|
@ -1,11 +1,12 @@
|
|||
#!/usr/bin/env bun
|
||||
// Smoke test of the npm bundle (dist/storebound.mjs) with the real `node` binary: the CLI must run on Node 20+.
|
||||
// bun tools/node-smoke.ts [--bundle dist/storebound.mjs] [--node <path>]
|
||||
// bun tools/node-smoke.ts [--bundle dist/storebound.mjs] [--node <path>] [--only prompt]
|
||||
// --only prompt: just the stdin prompt steps (the Windows release job runs these on the runner).
|
||||
// Offline only: --version, help, check on examples/demo-game (same exit code and problems as under Bun), scan on the
|
||||
// teaser fixture, release plan --help, init + check in an empty folder (the TypeScript config the template writes),
|
||||
// and an MCP initialize handshake over stdio with tools/list and one tools/call (a child run through the bundle).
|
||||
// Every step has a timeout; on a failure the step's output is printed.
|
||||
import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { ROOT } from './build-sidecars';
|
||||
|
|
@ -45,6 +46,37 @@ const norm = (s: string) => s.replace(/^\d\d:\d\d:\d\d /gm, '').replace(/\/\S*\/
|
|||
const nodeVersion = run([node, '--version']).out.trim();
|
||||
console.log(`node-smoke: ${bundle.replace(ROOT + '/', '')} with node ${nodeVersion} (package engines: node ${pkg.engines?.node ?? '?'})`);
|
||||
|
||||
// ---- stdin prompts: `for await (const line of console)` is Bun-only and crashed `npx storebound desktop` at its
|
||||
// [Y/n] prompt on Node ("console is not async iterable", then a libuv assertion on Windows). The bundle must not
|
||||
// contain it, and rt.readLine (what every prompt uses) must read one piped line, see EOF, and exit cleanly.
|
||||
step('prompt: the bundle has no Bun-only stdin iteration', () => {
|
||||
const src = readFileSync(bundle, 'utf8');
|
||||
if (/\bof\s+console\b/.test(src)) throw new Error('dist bundle iterates `console` (Bun-only): use rt.readLine');
|
||||
if (!/readline/.test(src)) throw new Error('dist bundle has no node:readline (rt.readLine missing?)');
|
||||
});
|
||||
step('prompt: rt.readLine under node reads "n", EOF and CRLF, exits 0 without a crash', () => {
|
||||
const tmp = mkdtempSync(join(tmpdir(), 'storebound-prompt-smoke-'));
|
||||
try {
|
||||
const entry = join(tmp, 'entry.ts');
|
||||
writeFileSync(entry, `import { readLine } from ${JSON.stringify(join(ROOT, 'cli/lib/rt.ts'))};\nprocess.stdout.write('Install? [Y/n] ');\nconst a = await readLine();\nconst b = await readLine();\nconsole.log(JSON.stringify([a, b]));\n`);
|
||||
const built = Bun.spawnSync(['bun', 'build', entry, '--target', 'node', '--format', 'esm', '--outfile', join(tmp, 'p.mjs')], { stdout: 'pipe', stderr: 'pipe' });
|
||||
if (built.exitCode !== 0) throw new Error(`bun build: ${built.stderr.toString()}`);
|
||||
const notes: string[] = [];
|
||||
for (const [input, want] of [['n\n', '["n",null]'], ['', '[null,null]'], ['y\r\n', '["y",null]']] as const) {
|
||||
const r = run([node, join(tmp, 'p.mjs')], tmp, input, 20_000);
|
||||
const got = r.out.replace('Install? [Y/n] ', '').trim();
|
||||
if (r.code !== 0 || got !== want || /assert|not async iterable/i.test(r.err)) throw new Error(`stdin ${JSON.stringify(input)}: exit ${r.code}, printed ${JSON.stringify(got)} (want ${want})\n${r.err.slice(-1500)}`);
|
||||
notes.push(`${JSON.stringify(input)} -> ${got}`);
|
||||
}
|
||||
return notes.join(', ');
|
||||
} finally { rmSync(tmp, { recursive: true, force: true }); }
|
||||
});
|
||||
if (arg('--only') === 'prompt') {
|
||||
if (failed) { console.error(`node-smoke: ${failed} step(s) failed`); process.exit(1); }
|
||||
console.log('node-smoke: prompt steps passed');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
step('--version', () => {
|
||||
const r = sb(['--version']);
|
||||
expectOk(r, '--version');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue