Skip to content

fix(using-git-worktrees): lockfile-aware Step 3 (pnpm/yarn/bun + uv)#1562

Open
iKon85 wants to merge 1 commit into
obra:mainfrom
iKon85:fix/lockfile-aware-step-3-pnpm-yarn
Open

fix(using-git-worktrees): lockfile-aware Step 3 (pnpm/yarn/bun + uv)#1562
iKon85 wants to merge 1 commit into
obra:mainfrom
iKon85:fix/lockfile-aware-step-3-pnpm-yarn

Conversation

@iKon85
Copy link
Copy Markdown

@iKon85 iKon85 commented May 16, 2026

What problem are you trying to solve?

using-git-worktrees Step 3 ("Project Setup") is hardcoded to npm install whenever a package.json is present:

```bash

Node.js

if [ -f package.json ]; then npm install; fi
```

In pnpm or yarn workspaces this is wrong. npm install:

  • ignores the workspace:* protocol that pnpm/yarn lockfiles declare,
  • does not create node_modules/<pkg> symlinks for sibling workspace packages,
  • can write a package-lock.json next to an existing pnpm-lock.yaml / yarn.lock, leaving the tree in a hybrid state.

Failure mode is silent. Tools that resolve through node_modules (LSP, tsserver, ts-node, type-aware refactors) get a partial module graph and return partial results. A findReferences on a workspace-shared type comes back with fewer matches than reality. Nothing logs an error; the agent gets a wrong answer and proceeds.

Empirical repro (real pnpm workspace, two packages with one importing the other via package name, the other via tsconfig path alias):

Worktree state LSP findReferences
Main tree (warm, baseline) 94 refs / 29 files
Fresh worktree, no setup 54 refs / 19 files
Same worktree after pnpm install 94 refs / 29 files

The 40 missing refs were all in the package importing via the workspace package name (@scope/shared). With no node_modules/@scope/shared symlink, tsserver couldn't load that project into the reference search at all. npm install from the current Step 3 would have produced the same broken state plus a stray package-lock.json.

Initial prompt that led to this change: "Arbeite an #271 — using-git-worktrees-Skill pnpm/yarn-aware machen. #270 hat empirisch gezeigt, dass das in pnpm-Workspaces zu LSP-Bruch führt." (Tracking in the downstream project: iKon85/Testreporter#270, iKon85/Testreporter#271.)

What does this PR change?

Detects the package manager from the lockfile and runs the matching install. Falls back to npm when only package.json is present. Same lockfile-aware shape applied to the Python block (uv → poetry → poetry → pip), because the original ran both pip and poetry when requirements.txt and pyproject.toml coexisted.

Is this change appropriate for the core library?

Yes. The skill already commits to auto-detecting and running setup; this PR fixes the detection so it matches what the project actually uses. The change is not project-specific, team-specific, or tool-specific — it makes a generic skill correct in the common case of pnpm/yarn/bun workspaces, which the skill currently misbehaves on. No new third-party integration.

What alternatives did you consider?

  1. Project-local override only (no upstream change). Considered and shipped in parallel in the downstream project as a CLAUDE.md bridge rule, since the user-instruction layer outranks plugin skills. But that only helps one project — the skill is wrong for every pnpm/yarn user, so the bridge is not a substitute for fixing it here.
  2. Runtime detection via command -v pnpm / which yarn. Rejected: a developer can have pnpm installed globally and still use npm in a given repo; the lockfile is the authoritative signal for what this project uses.
  3. Per-corepack handling. Rejected as out of scope: corepack opt-in is a separate setup concern; lockfile detection works whether or not corepack is enabled.
  4. Leave Node.js alone and only touch Python. Rejected — Node.js is the documented failure case.

Does this PR contain multiple unrelated changes?

The Node.js block is the primary change. The Python block applies the same lockfile-aware pattern and fixes an adjacent bug (the original runs pip install and poetry install if both requirements.txt and pyproject.toml exist). If reviewers prefer to land Node.js alone, I'll happily split out Python into a follow-up — let me know.

Existing PRs

Environment tested

Harness Harness version Model Model version/ID
Claude Code latest CLI as of 2026-05-16 Opus 4.7 claude-opus-4-7 (1M context)

Evaluation

  • Initial prompt above produced the design (CLAUDE.md bridge + upstream PR split).
  • Eval sessions after the change: 1. I didn't run a formal adversarial-pressure-test suite (see Rigor below). The empirical evidence is the baseline: the failure mode was reproduced on a real pnpm monorepo before this PR was written. After the fix, the same setup script picks pnpm install, which we already know produces the correct node_modules state in that repo. The fix is mechanical (lockfile selector); the risk surface is narrow.
  • If reviewers want a synthetic A/B (subagent in a pnpm sandbox running old Step 3 vs. new Step 3), happy to add it.

Rigor

  • If this is a skills change: I used superpowers:writing-skills and completed adversarial pressure testing
  • This change was tested adversarially, not just on the happy path — but "adversarially" here means the production failure was the adversarial test, not a synthetic subagent run.
  • I did not modify carefully-tuned content (Red Flags table, rationalizations, "human partner" language)

Honest disclosure: superpowers:writing-skills was invoked, but the formal RED-GREEN-REFACTOR-with-subagent-pressure-tests workflow was deliberately skipped after user agreement, on the reasoning that #270 is the RED, the fix is a 5-line shell selector with no behavioral surface beyond "pick the right binary," and a synthetic pressure scenario wouldn't surface anything the production repro didn't already show. Re-test on request.

Human review

  • A human has reviewed the COMPLETE proposed diff before submission

Step 3 was hardcoded to `npm install` whenever `package.json` exists.
In pnpm/yarn workspaces this is wrong: `npm install`

- ignores `workspace:*` protocol declarations,
- won't create `node_modules/<pkg>` symlinks for workspace packages,
- can produce a `package-lock.json` alongside the existing `pnpm-lock.yaml` / `yarn.lock`.

The downstream effect is silent: tools that resolve imports through
`node_modules` (LSP, tsserver, ts-node, type checkers) see a partial
module graph. In a multi-package repo, references in one package may
resolve while the other package's resolution quietly breaks.

Empirical repro from a real pnpm workspace (testreporter): a freshly
created worktree without setup ran LSP findReferences on a shared
type and returned 54 refs across 19 files. After `pnpm install` in
the worktree, the same query returned 94 refs across 29 files — the
missing 40 refs were all in the workspace package importing via the
package name (`@scope/shared`) rather than a tsconfig path alias.

Fix:

- Detect the package manager from the lockfile and run the matching
  install: `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `bun.lockb` →
  bun, `package-lock.json` → npm, fall back to npm if only
  `package.json` is present.
- Same lockfile-aware logic for Python: prefer `uv.lock` (uv sync),
  then `poetry.lock`, then `pyproject.toml` (poetry install), then
  `requirements.txt` (pip).

No regression for npm-only projects (still hits `npm install` in the
fallback). No new tooling required by the skill itself.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant