feat(dev): detect package manager per project dir instead of hard-coding pnpm#92
Open
kaihaase wants to merge 1 commit into
Open
feat(dev): detect package manager per project dir instead of hard-coding pnpm#92kaihaase wants to merge 1 commit into
kaihaase wants to merge 1 commit into
Conversation
…ing pnpm
Every `lt dev` flow that spawned a package-manager call (api/app start
in dev up + test, build + dev-runner fallbacks in the test session,
worktree install on ticket start) hard-coded `pnpm` via the legacy
`LT_PNPM_BIN` env var. In an npm-only monorepo (e.g. document-analyzer,
where AGENTS.md explicitly forbids pnpm) the supervised processes died
on the first call: pnpm regenerated a foreign pnpm-lock.yaml, then exited
with ERR_PNPM_IGNORED_BUILDS on un-approved scripts (bcrypt, sharp,
esbuild). `lt dev status` reported the components as dead, the user saw
a white page behind Caddy.
Mechanics:
- New `src/lib/dev-package-manager.ts` exposes `pickPackageManager(cwd)`.
Detection chain: LT_PM_BIN env → legacy LT_PNPM_BIN env → pnpm-lock.yaml
→ yarn.lock → package-lock.json → fallback `pnpm` (preserves the
historical default for fresh scaffolds without a lockfile yet). Returns
a `PackageManagerCommand` with `bin`, `installArgs`, `runScript()` and
`exec()` so call sites can emit one argv regardless of which manager
was picked. `exec()` inserts `--` for npm so option flags
(`--shard=1/2`, `--reporter=line`) reach the binary instead of being
re-parsed as npm's own.
- Per-component detection — a monorepo with an npm api + pnpm app
drives each component with the correct manager.
- Migrated all five call sites:
1. commands/dev/up.ts — api start + app dev
2. commands/dev/test.ts — api test:e2e + app test:e2e + sharded
3. lib/dev-test-session.ts — api/app build, ts-node/dev fallbacks,
sharded playwright exec (now via pm.exec)
4. lib/dev-ticket.ts — worktree install (renamed pnpmInstall
→ installWorktreeDeps to match the
new behaviour)
5. commands/ticket/start.ts — calls the renamed helper
- `LT_PNPM_BIN` kept as a lower-precedence override so older CI configs
don't regress; `LT_PM_BIN` is the new generic override.
Tests:
- __tests__/dev-package-manager.test.ts — 14 unit tests covering
lockfile precedence, both env overrides, monorepo per-component
detection, the npm `exec --` separator, and the `runScript` /
`installArgs` portability contracts.
- 60 existing tests across dev-bootstrap, dev-test-session, dev-ticket,
dev-up-soft-migrate still green.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every
lt devflow that spawned a package-manager call (api/appstart indev up+dev test, build + dev-runner fallbacks in the test session, worktree install onticket start) used to hard-codepnpmvia the legacyLT_PNPM_BINenv var.In an npm-only monorepo (e.g.
document-analyzer, whereAGENTS.mdexplicitly forbids pnpm), the supervised processes died on the first call:pnpm-lock.yaml.ERR_PNPM_IGNORED_BUILDSon un-approved scripts (bcrypt, sharp, esbuild).lt dev statusreportedapi: dead+app: dead→ user sees a white page behind Caddy.Mechanics
New
src/lib/dev-package-manager.tsexposespickPackageManager(cwd)with the chain:LT_PM_BINenv (new generic override).LT_PNPM_BINenv (legacy alias — kept so older CI configs don't regress).pnpm-lock.yamlincwd→ pnpmyarn.lockincwd→ yarnpackage-lock.jsonincwd→ npmpnpm(historical default for fresh scaffolds without a lockfile).Returns a
PackageManagerCommandwithbin,installArgs,runScript()andexec()so call sites emit ONE argv regardless of manager.exec()inserts--for npm so option flags (--shard=1/2,--reporter=line) reach the binary instead of being re-parsed as npm's own.Per-component detection — a monorepo with an npm api + pnpm app drives each component correctly.
Files changed
src/lib/dev-package-manager.tsPackageManagerCommand.src/commands/dev/up.tsstart+ appdevnow per-dir resolved.src/commands/dev/test.tstest:e2e, shardedplaywrightcall now per-dir resolved.src/lib/dev-test-session.tsbuild, fallbackstart/dev, sharded exec now per-dir.src/lib/dev-ticket.tspnpmInstall→installWorktreeDeps, lockfile-aware.src/commands/ticket/start.ts__tests__/dev-package-manager.test.tsTest plan
npx jest __tests__/dev-package-manager.test.ts— 14 / 14 green.dev-bootstrap,dev-test-session,dev-ticket,dev-up-soft-migrate,dev-package-manager— 74 / 74 green.npm run compile— TypeScript clean.lt dev upagainst an npm-only monorepo (document-analyzer) now boots api + app cleanly; previously both died onpnpm installexit 1.lt ticket startagainst a yarn project (if any consumer has one).🤖 Generated with Claude Code