mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-06 00:44:07 +01:00
fix(browse): refuse a runtime-root CLI and checkout server from different builds (#3026)
A Windows runtime root runs the source checkout's Node server bundle through .source-path. When the root's CLI and the checkout's bundle carry different browse/dist/.version builds (the checkout was rebuilt without refreshing the root), the CLI now refuses to start the server with both builds, the ./setup fix and its troubleshooting anchor. Unversioned dev builds are not called skew. Co-authored-by: ubay887 <ubay887@users.noreply.github.com>
This commit is contained in:
1 parent
c9766e3540
commit
e1ceb5fcf4
3 files changed
+67
-4
No files matched your search
+21
-4
@@ -121,18 +121,35 @@ function reachesPlaywright(script: string): boolean {
|
||||
* copies of browse/dist and no node_modules, so its server-node.mjs cannot
|
||||
* import playwright. setup records the source checkout in the root's
|
||||
* .source-path; run that checkout's bundle, which sits beside node_modules.
|
||||
* Refuses (throws) when the two builds differ.
|
||||
*/
|
||||
function sourceServerScript(execPath: string): string | null {
|
||||
const root = path.resolve(path.dirname(execPath), '..', '..');
|
||||
let source: string;
|
||||
try {
|
||||
const root = path.resolve(path.dirname(execPath), '..', '..');
|
||||
const source = fs.readFileSync(path.join(root, '.source-path'), 'utf8').trim();
|
||||
const script = path.join(source, 'browse', 'dist', 'server-node.mjs');
|
||||
return path.isAbsolute(source) && fs.existsSync(script) && reachesPlaywright(script) ? script : null;
|
||||
source = fs.readFileSync(path.join(root, '.source-path'), 'utf8').trim();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
const script = path.join(source, 'browse', 'dist', 'server-node.mjs');
|
||||
if (!path.isAbsolute(source) || !fs.existsSync(script) || !reachesPlaywright(script)) return null;
|
||||
// The CLI here and the checkout's server must come from the same build
|
||||
// (both write browse/dist/.version); a checkout rebuilt without refreshing
|
||||
// this root would otherwise run a server its CLI does not match.
|
||||
const cliVersion = readVersionHash(execPath);
|
||||
const serverVersion = readVersionHash(script);
|
||||
if (cliVersion && serverVersion && cliVersion !== serverVersion) {
|
||||
throw new Error(
|
||||
`this install's browse CLI (${root}, build ${cliVersion.slice(0, 12)}) and the gstack checkout's server bundle ` +
|
||||
`(${source}, build ${serverVersion.slice(0, 12)}) are from different builds, so the server was not started. ` +
|
||||
`Fix: cd "${source}" && ./setup (rebuilds and refreshes every runtime root). ${BROWSE_VERSION_SKEW_ANCHOR}`,
|
||||
);
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
export const BROWSE_VERSION_SKEW_ANCHOR = 'https://github.com/garrytan/gstack/blob/main/docs/troubleshooting.md#browse-runtime-version-skew';
|
||||
|
||||
/**
|
||||
* Which server to start, resolved only when a server is actually started
|
||||
* (#2439). Windows runs the Node bundle and never needs server.ts, which a
|
||||
|
||||
@@ -340,6 +340,36 @@ describe('#3026: a Windows runtime root without node_modules runs the source che
|
||||
}
|
||||
});
|
||||
|
||||
test('same build on both sides -> the checkout bundle; different builds -> refusal with the ./setup fix and anchor', () => {
|
||||
const { BROWSE_VERSION_SKEW_ANCHOR } = require('../src/cli');
|
||||
const l = layout({ runtimeModules: false, sourcePath: true, sourceModules: true });
|
||||
const version = (root: string, v: string) => fs.writeFileSync(path.join(root, 'browse', 'dist', '.version'), `${v}\n`);
|
||||
try {
|
||||
version(l.runtime, 'a'.repeat(40));
|
||||
version(l.source, 'a'.repeat(40));
|
||||
expect(resolveNodeServerScript('/$bunfs/root', l.exe)).toBe(path.join(l.source, 'browse', 'dist', 'server-node.mjs'));
|
||||
version(l.source, 'b'.repeat(40));
|
||||
let message = '';
|
||||
try { resolveNodeServerScript('/$bunfs/root', l.exe); } catch (err: any) { message = err.message; }
|
||||
expect(message).toContain(`build ${'a'.repeat(12)}`);
|
||||
expect(message).toContain(`build ${'b'.repeat(12)}`);
|
||||
expect(message).toContain('are from different builds, so the server was not started');
|
||||
expect(message).toContain(`Fix: cd "${l.source}" && ./setup`);
|
||||
expect(message).toContain(BROWSE_VERSION_SKEW_ANCHOR);
|
||||
expect(BROWSE_VERSION_SKEW_ANCHOR).toBe('https://github.com/garrytan/gstack/blob/main/docs/troubleshooting.md#browse-runtime-version-skew');
|
||||
// resolveServerLaunch surfaces the same refusal on Windows.
|
||||
expect(() => require('../src/cli').resolveServerLaunch('win32', {}, '/$bunfs/root', l.exe)).toThrow('different builds');
|
||||
} finally { fs.rmSync(l.base, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('an unversioned build on either side is not called skew', () => {
|
||||
const l = layout({ runtimeModules: false, sourcePath: true, sourceModules: true });
|
||||
try {
|
||||
fs.writeFileSync(path.join(l.runtime, 'browse', 'dist', '.version'), 'abc\n');
|
||||
expect(resolveNodeServerScript('/$bunfs/root', l.exe)).toBe(path.join(l.source, 'browse', 'dist', 'server-node.mjs'));
|
||||
} finally { fs.rmSync(l.base, { recursive: true, force: true }); }
|
||||
});
|
||||
|
||||
test('setup records the source checkout in every runtime root it links', () => {
|
||||
const setup = fs.readFileSync(path.resolve(__dirname, '../../setup'), 'utf8');
|
||||
const fn = setup.slice(setup.indexOf('_link_runtime_dists() {'), setup.indexOf('\n}\n', setup.indexOf('_link_runtime_dists() {')));
|
||||
|
||||
@@ -582,6 +582,22 @@ hooks stay.
|
||||
|
||||
## Browser
|
||||
|
||||
<a id="browse-runtime-version-skew"></a>
|
||||
### `[browse] this install's browse CLI (<root>, build <hash>) and the gstack checkout's server bundle (<checkout>, build <hash>) are from different builds, so the server was not started. ...`
|
||||
|
||||
**Meaning.** On Windows a host runtime root (`~/.codex/skills/gstack` and the
|
||||
other env-var hosts) holds a copy of browse with no `node_modules`, so its CLI
|
||||
starts the server bundle in the gstack checkout recorded in `.source-path`.
|
||||
The checkout was rebuilt (or updated) without refreshing this runtime root, so
|
||||
the two builds differ and browse refuses rather than run a mismatched server.
|
||||
|
||||
**Fix.** Re-run setup from the checkout named in the message; it rebuilds and
|
||||
refreshes every runtime root:
|
||||
|
||||
```bash
|
||||
cd <checkout> && ./setup
|
||||
```
|
||||
|
||||
<a id="browse-chain-no-flow"></a>
|
||||
### `[browse] chain: no flow to run (stdin was empty)` (or `stdin is a terminal`, `stdin could not be read (EAGAIN)`)
|
||||
|
||||
|
||||
Reference in new issue
Block a user