From 193b2b32a5ae5d8d41e9fc744ce2c62d6705f4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=82CHES?= Date: Mon, 16 Mar 2026 21:35:04 -0600 Subject: [PATCH] fix: strip clack UI from postinstall, keep silent Playwright download (#783) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit npm ≥7 suppresses lifecycle script output by default, so the clack banner/spinner was invisible during `npm install -g`. The user-facing onboarding experience already lives at first `gsd` launch (onboarding.ts), making the postinstall UI redundant dead code. Co-authored-by: Claude Opus 4.6 (1M context) --- scripts/postinstall.js | 116 ++-------------------------------- src/tests/postinstall.test.ts | 5 -- 2 files changed, 7 insertions(+), 114 deletions(-) diff --git a/scripts/postinstall.js b/scripts/postinstall.js index 46c78cd96..a75953878 100644 --- a/scripts/postinstall.js +++ b/scripts/postinstall.js @@ -1,125 +1,23 @@ #!/usr/bin/env node import { exec as execCb } from 'child_process' -import { createRequire } from 'module' -import os from 'os' import { dirname, resolve } from 'path' import { fileURLToPath } from 'url' const __dirname = dirname(fileURLToPath(import.meta.url)) -const require = createRequire(import.meta.url) -const pkg = require(resolve(__dirname, '..', 'package.json')) const cwd = resolve(__dirname, '..') -const shouldSkipBrowserDownload = +const shouldSkip = process.env.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD === '1' || process.env.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD === 'true' -// --------------------------------------------------------------------------- -// Async exec helper — captures stdout+stderr, never inherits to terminal -// --------------------------------------------------------------------------- -function run(cmd, options = {}) { +function run(cmd) { return new Promise((resolve) => { - execCb(cmd, { cwd, ...options }, (error, stdout, stderr) => { - resolve({ ok: !error, stdout, stderr, error }) + execCb(cmd, { cwd }, (error, stdout, stderr) => { + resolve({ ok: !error, stdout, stderr }) }) }) } -// --------------------------------------------------------------------------- -// Redirect stdout → stderr so npm always shows postinstall output. -// npm ≥7 suppresses stdout from lifecycle scripts by default; stderr is -// always forwarded. Clack writes to process.stdout, so we reroute it. -// --------------------------------------------------------------------------- -process.stdout.write = process.stderr.write.bind(process.stderr) - -// --------------------------------------------------------------------------- -// ASCII banner — printed before clack UI for brand recognition -// --------------------------------------------------------------------------- -const cyan = '\x1b[36m' -const dim = '\x1b[2m' -const reset = '\x1b[0m' - -const banner = - '\n' + - cyan + - ' ██████╗ ███████╗██████╗ \n' + - ' ██╔════╝ ██╔════╝██╔══██╗\n' + - ' ██║ ███╗███████╗██║ ██║\n' + - ' ██║ ██║╚════██║██║ ██║\n' + - ' ╚██████╔╝███████║██████╔╝\n' + - ' ╚═════╝ ╚══════╝╚═════╝ ' + - reset + '\n' + - '\n' + - ` Get Shit Done ${dim}v${pkg.version}${reset}\n` - -// --------------------------------------------------------------------------- -// Main — wrapped in async IIFE, with graceful fallback if clack fails -// --------------------------------------------------------------------------- -;(async () => { - process.stderr.write(banner) - - let p, pc - - try { - p = await import('@clack/prompts') - pc = (await import('picocolors')).default - } catch { - // Clack or picocolors unavailable — fall back to minimal output - process.stderr.write(` Run gsd to get started.\n\n`) - if (!shouldSkipBrowserDownload) { - await run('npx playwright install chromium') - } - return - } - - // --- Branded intro ------------------------------------------------------- - p.intro('Setup') - - const results = [] - const s = p.spinner() - - // --- Playwright browser -------------------------------------------------- - // Avoid --with-deps: install scripts should not block on interactive sudo - // prompts. If Linux libs are missing, suggest the explicit follow-up. - s.start('Setting up browser tools…') - if (shouldSkipBrowserDownload) { - s.stop(pc.yellow('Browser tools skipped via PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD')) - results.push({ - label: 'Browser tools skipped — run ' + pc.cyan('npx playwright install chromium') + ' later if needed', - ok: false, - }) - } else { - const pwResult = await run('npx playwright install chromium') - if (pwResult.ok) { - s.stop('Browser tools ready') - results.push({ label: 'Browser tools ready', ok: true }) - } else { - const output = `${pwResult.stdout ?? ''}${pwResult.stderr ?? ''}` - if (os.platform() === 'linux' && output.includes('Host system is missing dependencies to run browsers.')) { - s.stop(pc.yellow('Browser downloaded, missing Linux deps')) - results.push({ - label: 'Run ' + pc.cyan('sudo npx playwright install-deps chromium') + ' to finish setup', - ok: false, - }) - } else { - s.stop(pc.yellow('Browser tools — skipped (non-fatal)')) - results.push({ - label: 'Browser tools unavailable — run ' + pc.cyan('npx playwright install chromium'), - ok: false, - }) - } - } - } - - // --- Summary note -------------------------------------------------------- - const lines = results.map( - (r) => (r.ok ? pc.green('✓') : pc.yellow('⚠')) + ' ' + r.label - ) - lines.push('') - lines.push('Run ' + pc.cyan('gsd') + ' to get started.') - - p.note(lines.join('\n'), 'Installed') - - // --- Outro --------------------------------------------------------------- - p.outro(pc.green('Done!')) -})() +if (!shouldSkip) { + await run('npx playwright install chromium') +} diff --git a/src/tests/postinstall.test.ts b/src/tests/postinstall.test.ts index b533084a1..88b8e0a47 100644 --- a/src/tests/postinstall.test.ts +++ b/src/tests/postinstall.test.ts @@ -14,9 +14,4 @@ test("postinstall respects PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD", () => { }); assert.equal(result.status, 0, `postinstall exits cleanly: ${result.stderr}`); - assert.match( - result.stderr, - /PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD|Browser tools skipped/, - "postinstall reports that browser download was skipped", - ); });