diff --git a/package.json b/package.json index 6022bf409..6afa30f09 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "check:fixture-privacy": "scripts/check-fixture-privacy.sh", "check:conversation-parser": "bun src/cli.ts eval conversation-parser test/fixtures/conversation-formats/all.jsonl --no-llm", "check:source-scope-onboard": "scripts/check-source-scope-onboard.sh", - "postinstall": "command -v gbrain >/dev/null 2>&1 && gbrain apply-migrations --yes --non-interactive || echo '[gbrain] postinstall skipped. If installed via bun install -g github:...: run `gbrain doctor` and `gbrain apply-migrations --yes` manually. See https://github.com/garrytan/gbrain/issues/218' 1>&2", + "postinstall": "bun run scripts/postinstall.ts", "prepublish:clawhub": "bun run build:all", "publish:clawhub": "clawhub package publish . --family bundle-plugin" }, diff --git a/scripts/postinstall.ts b/scripts/postinstall.ts new file mode 100644 index 000000000..ca86829db --- /dev/null +++ b/scripts/postinstall.ts @@ -0,0 +1,49 @@ +#!/usr/bin/env bun +// scripts/postinstall.ts +// +// Postinstall hook: after `bun install`, apply any pending schema migrations so +// a freshly-installed gbrain is immediately usable. Wired via package.json +// ("postinstall": "bun run scripts/postinstall.ts") as a real Bun script rather +// than an inline `node -e` one-liner. +// +// Why a script file and not an inline command: +// Embedding a program inside the package.json postinstall string lets the +// lifecycle shell mangle it. Bun's Windows script-runner expands `\n` in the +// hint string into a REAL newline before node sees it, producing +// `SyntaxError: Invalid or unexpected token` and aborting the whole install. +// `node` is also not guaranteed present under a Bun install (bun is the +// guaranteed runtime), and `shell: win32` re-opens a quoting surface. A +// checked-in .ts run by `bun run` sidesteps all three. +// +// Uses Bun APIs only — `which()` for Windows-aware PATH resolution (finds +// gbrain.exe / gbrain.cmd) and an argv-array `Bun.spawnSync` (no shell, nothing +// to quote). It NEVER fails the install: every path exits 0. + +import { which } from 'bun'; + +const HINT = + '[gbrain] postinstall skipped. If installed via bun install -g github:...: ' + + 'run `gbrain doctor` and `gbrain apply-migrations --yes` manually. ' + + 'See https://github.com/garrytan/gbrain/issues/218'; + +// Windows-aware PATH resolution — finds gbrain, gbrain.exe or gbrain.cmd. +const bin = which('gbrain'); + +if (!bin) { + // Fresh clone / global install where gbrain isn't on PATH yet: skip cleanly. + console.error(HINT); + process.exit(0); +} + +try { + const r = Bun.spawnSync({ + cmd: [bin, 'apply-migrations', '--yes', '--non-interactive'], + stdout: 'inherit', + stderr: 'inherit', + }); + if (r.exitCode !== 0) console.error(HINT); +} catch { + console.error(HINT); +} + +process.exit(0); // never abort the install