-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
fix: inject .npmrc ignore-workspace=true into worktrees to prevent monorepo corruption #2016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -834,6 +834,27 @@ async function createTerminalWorktree( | |
| debugLog('[TerminalWorktree] Created worktree in detached HEAD mode from', baseRef); | ||
| } | ||
|
|
||
| // Write .npmrc to prevent pnpm/npm from walking up to the parent | ||
| // workspace root (pnpm-workspace.yaml / package.json#workspaces). | ||
| // Without this, running `pnpm install` inside the worktree silently | ||
| // re-links the parent repo's node_modules into the worktree's pnpm | ||
| // store, corrupting the parent's dependency graph after cleanup. | ||
| // See: https://pnpm.io/npmrc#ignore-workspace | ||
| // If the host repo already commits a .npmrc (registry/auth config), we | ||
| // append the directive instead of skipping — otherwise the workspace | ||
| // fix gets bypassed silently for monorepos that need it most. | ||
| const npmrcPath = path.join(worktreePath, '.npmrc'); | ||
| try { | ||
| const existing = existsSync(npmrcPath) ? readFileSync(npmrcPath, 'utf-8') : ''; | ||
| if (!/^\s*ignore-workspace\s*=/m.test(existing)) { | ||
| const separator = !existing || existing.endsWith('\n') ? '' : '\n'; | ||
| writeFileSync(npmrcPath, existing + separator + 'ignore-workspace=true\n', 'utf-8'); | ||
| debugLog('[TerminalWorktree] Ensured ignore-workspace=true in .npmrc for worktree:', worktreePath); | ||
| } | ||
| } catch (npmrcError) { | ||
| debugError('[TerminalWorktree] Could not write .npmrc to worktree:', npmrcError); | ||
| } | ||
|
Comment on lines
+837
to
+856
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Duplicated logic across backend and frontend — extract a shared constant at minimum. This block is byte-for-byte equivalent (modulo language) to
🤖 Prompt for AI Agents
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| // Set up dependencies (node_modules, venvs, etc.) for tooling support | ||
| // This allows pre-commit hooks to run typecheck without npm install in worktree | ||
| const setupDeps = await setupWorktreeDependencies(projectPath, worktreePath); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Does pnpm npmrc settingignore-workspace=truealso affect npm or yarn workspace discovery?💡 Result:
No. pnpm’s .npmrc setting ignore-workspace=true only affects pnpm’s own workspace detection/resolution. It does not change how npm or Yarn discover their workspaces. Reason (grounded): 1) pnpm documents that .npmrc is used for pnpm configuration in the npmrc format primarily for authentication/registry-style settings; other workspace-related behavior is configured via pnpm-workspace.yaml or pnpm’s pnpm config/config.yaml. This implies pnpm-specific ignore-workspace behavior is implemented inside pnpm, not as a cross-tool npmrc workspace-discovery toggle. 2) pnpm provides its own CLI/workspace-ignore mechanism (e.g., --ignore-workspace), and pnpm issues/documentation describe it as “pnpm ignores any workspace configuration found in the current or parent directories,” indicating the option is scoped to pnpm’s workspace logic. Practical takeaway: - If you want npm or Yarn to ignore their workspaces, you must use whatever mechanism those tools provide (there isn’t an npmrc setting documented here that makes them ignore pnpm-style workspaces). - Setting ignore-workspace=true in .npmrc won’t prevent npm/yarn from detecting their own workspaces (e.g., via package.json workspaces, yarn workspaces, or npm workspaces rules).
Citations:
--ignore-workspaceoption undocumented pnpm/pnpm#7802🌐 Web query:
npm workspaces configuration how does npm detect workspaces💡 Result:
npm detects workspaces through the "workspaces" property in the root package.json file of a project. This property contains an array of glob patterns or direct paths pointing to directories containing package.json files that define the individual workspaces. When running npm commands like npm install, npm reads the "workspaces" field from the nearest ancestor package.json (walking up from the current working directory if necessary, with automatic workspace root detection). It then uses these patterns to traverse the filesystem, matching directories that contain valid package.json files. Valid workspaces are those nested packages explicitly defined by the workspaces configuration. Internally, npm uses the
@npmcli/map-workspacespackage to process the workspaces field: it expands globs (e.g., "packages/"), ignores patterns like "/node_modules/", reads package.json files in matching directories, extracts package names, and builds a map of package name to path. During installation, matching workspace dependencies are symlinked into node_modules instead of being fetched from the registry. Example configuration: { "name": "my-monorepo", "workspaces": ["packages/", "apps/*"] } This would detect all directories under packages/ and apps/ that have a package.json. The root package.json should typically have "private": true. Commands support --workspace=<name/path> or --workspaces flags to target specific or all workspaces.Citations:
🌐 Web query:
Yarn workspaces configuration how does Yarn detect workspaces💡 Result:
Yarn detects workspaces through a root package.json file containing a "workspaces" field with glob patterns, and individual workspace directories each containing their own package.json files. The process works as follows: 1. Yarn identifies the project root by starting from the current working directory and walking up parent directories until it finds a directory containing a package.json file. This becomes the project root (cwd). 2. It loads the manifest (package.json) from this root directory. 3. From the root manifest's workspaceDefinitions (derived from the "workspaces" field, which is an array of glob patterns like ["packages/*"]), it extracts the patterns. 4. Using fastGlob, it resolves these glob patterns relative to the root cwd, with options: onlyDirectories: true, ignore: ['/node_modules', '/.git', '/.yarn']. 5. For each matching directory, it checks if a package.json exists. 6. Valid directories (those with package.json) become child workspaces of the root workspace. This applies to Yarn Berry (2+). The root workspace is always present, and child workspaces are discovered via globs during the Workspace setup method, called as part of Project initialization.
Citations:
Narrow comment to "pnpm" —
ignore-workspacedoes not affect npm or Yarn.The setting
ignore-workspace=trueis pnpm-specific. npm detects workspaces via theworkspacesfield in package.json (not .npmrc), and Yarn similarly uses theworkspacesfield in package.json. The .npmrc file does not control workspace detection for npm or Yarn. The code fix is correct for pnpm, but the comment's "pnpm/npm" wording is misleading — change it to reference pnpm only. Addressing npm and Yarn workspace handling in a worktree should be tracked separately as part of theWORKTREE_ROOTacceptance criterion from#2013.🤖 Prompt for AI Agents