fix: npx fails — loader creates workspace symlinks at runtime (#380)

npx runs with --ignore-scripts, skipping postinstall. The loader now
creates node_modules/@gsd/* symlinks pointing to packages/* before
importing cli.js, so @gsd/* packages resolve without postinstall.

Bumps to v2.10.12.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
TÂCHES 2026-03-14 11:38:33 -06:00 committed by GitHub
parent 8a64ac054c
commit c69be2078f
9 changed files with 32 additions and 10 deletions

View file

@ -12,6 +12,11 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Fallback `--backend=local` for offline faster-whisper on CPU
- Venv-aware Python detection (`~/.gsd/voice-venv/bin/python3`)
## [2.10.12] - 2026-03-14
### Fixed
- Fix `npx gsd-pi@latest` failing with `ERR_MODULE_NOT_FOUND: Cannot find package '@gsd/pi-coding-agent'`. The loader now creates workspace package symlinks at runtime before importing, so it works even when `npx` skips postinstall scripts.
## [2.10.11] - 2026-03-14
### Fixed
@ -496,7 +501,8 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Changed
- License updated to MIT
[Unreleased]: https://github.com/gsd-build/gsd-2/compare/v2.10.11...HEAD
[Unreleased]: https://github.com/gsd-build/gsd-2/compare/v2.10.12...HEAD
[2.10.12]: https://github.com/gsd-build/gsd-2/compare/v2.10.11...v2.10.12
[2.10.11]: https://github.com/gsd-build/gsd-2/compare/v2.10.10...v2.10.11
[2.10.10]: https://github.com/gsd-build/gsd-2/compare/v2.10.9...v2.10.10
[2.10.9]: https://github.com/gsd-build/gsd-2/compare/v2.10.8...v2.10.9

View file

@ -1,6 +1,6 @@
{
"name": "@gsd-build/engine-darwin-arm64",
"version": "2.10.11",
"version": "2.10.12",
"description": "GSD native engine binary for macOS ARM64",
"os": [
"darwin"

View file

@ -1,6 +1,6 @@
{
"name": "@gsd-build/engine-darwin-x64",
"version": "2.10.11",
"version": "2.10.12",
"description": "GSD native engine binary for macOS Intel",
"os": [
"darwin"

View file

@ -1,6 +1,6 @@
{
"name": "@gsd-build/engine-linux-arm64-gnu",
"version": "2.10.11",
"version": "2.10.12",
"description": "GSD native engine binary for Linux ARM64 (glibc)",
"os": [
"linux"

View file

@ -1,6 +1,6 @@
{
"name": "@gsd-build/engine-linux-x64-gnu",
"version": "2.10.11",
"version": "2.10.12",
"description": "GSD native engine binary for Linux x64 (glibc)",
"os": [
"linux"

View file

@ -1,6 +1,6 @@
{
"name": "@gsd-build/engine-win32-x64-msvc",
"version": "2.10.11",
"version": "2.10.12",
"description": "GSD native engine binary for Windows x64 (MSVC)",
"os": [
"win32"

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "gsd-pi",
"version": "2.10.11",
"version": "2.10.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gsd-pi",
"version": "2.10.11",
"version": "2.10.12",
"hasInstallScript": true,
"license": "MIT",
"workspaces": [

View file

@ -1,6 +1,6 @@
{
"name": "gsd-pi",
"version": "2.10.11",
"version": "2.10.12",
"description": "GSD — Get Shit Done coding agent",
"license": "MIT",
"repository": {

View file

@ -1,7 +1,7 @@
#!/usr/bin/env node
import { fileURLToPath } from 'url'
import { dirname, resolve, join } from 'path'
import { existsSync, readFileSync } from 'fs'
import { existsSync, readFileSync, mkdirSync, symlinkSync, lstatSync } from 'fs'
import { agentDir, appRoot } from './app-paths.js'
import { renderLogo } from './logo.js'
@ -101,5 +101,21 @@ process.env.GSD_BUNDLED_EXTENSION_PATHS = [
import { EnvHttpProxyAgent, setGlobalDispatcher } from 'undici'
setGlobalDispatcher(new EnvHttpProxyAgent())
// Ensure workspace packages are linked before importing cli.js (which imports @gsd/*).
// npm postinstall handles this normally, but npx --ignore-scripts skips postinstall.
const gsdScopeDir = join(gsdNodeModules, '@gsd')
const packagesDir = join(gsdRoot, 'packages')
const wsPackages = ['native', 'pi-agent-core', 'pi-ai', 'pi-coding-agent', 'pi-tui']
try {
if (!existsSync(gsdScopeDir)) mkdirSync(gsdScopeDir, { recursive: true })
for (const pkg of wsPackages) {
const target = join(gsdScopeDir, pkg)
const source = join(packagesDir, pkg)
if (existsSync(source) && !existsSync(target)) {
try { symlinkSync(source, target, 'junction') } catch { /* non-fatal */ }
}
}
} catch { /* non-fatal */ }
// Dynamic import defers ESM evaluation — config.js will see PI_PACKAGE_DIR above
await import('./cli.js')