diff --git a/browse/src/cli.ts b/browse/src/cli.ts index e6e470fd5..995503e64 100644 --- a/browse/src/cli.ts +++ b/browse/src/cli.ts @@ -2,19 +2,38 @@ * gstack CLI — thin wrapper that talks to the persistent server * * Flow: - * 1. Read .gstack/browse.json for port + token - * 2. If missing or stale PID → start server in background - * 3. Health check + version mismatch detection - * 4. Send command via HTTP POST - * 5. Print response to stdout (or stderr for errors) + * 1. If invoked with --server, run in server mode (bundled server.ts) + * 2. Read .gstack/browse.json for port + token + * 3. If missing or stale PID → start server in background + * 4. Health check + version mismatch detection + * 5. Send command via HTTP POST + * 6. Print response to stdout (or stderr for errors) */ import * as fs from 'fs'; import * as path from 'path'; import { resolveConfig, ensureStateDir, readVersionHash } from './config'; +// ─── Server Mode Gate ───────────────────────────────────────── +// When the compiled binary is invoked with --server, it runs as the +// persistent Chromium daemon instead of the CLI. This eliminates the +// fragile resolveServerScript() fallback chain for finding server.ts +// on disk — server code is bundled into the same binary via +// bun build --compile. +const IS_SERVER_MODE = process.argv.includes('--server'); + +if (IS_SERVER_MODE) { + // Dynamic import triggers server.ts's top-level start() call. + // The server keeps the process alive via Bun.serve() — the CLI + // code below initializes but main() is gated on !IS_SERVER_MODE. + import('./server'); +} + +// ─── CLI Mode ───────────────────────────────────────────────── + const config = resolveConfig(); const IS_WINDOWS = process.platform === 'win32'; +const IS_COMPILED = import.meta.dir.includes('$bunfs'); const MAX_START_WAIT = IS_WINDOWS ? 15000 : (process.env.CI ? 30000 : 8000); // Node+Chromium takes longer on Windows export function resolveServerScript( @@ -49,7 +68,14 @@ export function resolveServerScript( ); } -const SERVER_SCRIPT = resolveServerScript(); +// Lazy resolution: only needed in dev mode (compiled mode uses --server flag) +let _serverScript: string | null = null; +function getServerScript(): string { + if (_serverScript === null) { + _serverScript = resolveServerScript(); + } + return _serverScript; +} /** * On Windows, resolve the Node.js-compatible server bundle. @@ -196,7 +222,7 @@ function cleanupLegacyState(): void { stdout: 'pipe', stderr: 'pipe', timeout: 2000, }); const cmd = check.stdout.toString().trim(); - if (cmd.includes('bun') || cmd.includes('server.ts')) { + if (cmd.includes('bun') || cmd.includes('server.ts') || cmd.includes('browse')) { try { process.kill(data.pid, 'SIGTERM'); } catch {} } } @@ -238,9 +264,18 @@ async function startServer(extraEnv?: Record): Promise { console.error(`[browse] ${err.message}`); process.exit(1); diff --git a/package.json b/package.json index 90d129376..ccd616322 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "browse": "./browse/dist/browse" }, "scripts": { - "build": "bun run gen:skill-docs --host all; bun build --compile browse/src/cli.ts --outfile browse/dist/browse && bun build --compile browse/src/find-browse.ts --outfile browse/dist/find-browse && bun build --compile design/src/cli.ts --outfile design/dist/design && bun build --compile bin/gstack-global-discover.ts --outfile bin/gstack-global-discover && bash browse/scripts/build-node-server.sh && git rev-parse HEAD > browse/dist/.version && git rev-parse HEAD > design/dist/.version && rm -f .*.bun-build || true", + "build": "bun run gen:skill-docs --host all; bun build --compile browse/src/cli.ts --outfile browse/dist/browse --external electron && bun build --compile browse/src/find-browse.ts --outfile browse/dist/find-browse && bun build --compile design/src/cli.ts --outfile design/dist/design && bun build --compile bin/gstack-global-discover.ts --outfile bin/gstack-global-discover && bash browse/scripts/build-node-server.sh && git rev-parse HEAD > browse/dist/.version && git rev-parse HEAD > design/dist/.version && rm -f .*.bun-build || true", "dev:design": "bun run design/src/cli.ts", "gen:skill-docs": "bun run scripts/gen-skill-docs.ts", "dev": "bun run browse/src/cli.ts",