Skip to content

feat(workspace): workspace-root component (rootDir ".") and the trackAllFiles flag - #10698

Open
davidfirst wants to merge 58 commits into
masterfrom
feat/workspace-root-component-nesting
Open

davidfirst wants to merge 58 commits into
masterfrom
feat/workspace-root-component-nesting

Conversation

@davidfirst

@davidfirst davidfirst commented Sep 10, 2026

Copy link
Copy Markdown
Member

Context: the Bit side of pnpm/rfcs#33, Bit version control for pnpm workspaces: each pnpm project is a component and the unclaimed files belong to a root component. This PR lands that root-component model in bit; the adoption command and the pnpm-specific pieces follow, based on #10675.

Lets a single component own the workspace root (rootDir: "."), and adds a workspace flag that tracks the files bit normally treats as generated. Together they make a git-free workspace restorable from its scope: the root component carries the repository-level files and .bitmap, and the flag keeps package.json and friends.

Workspace-root component

On the name: "root component" already means the dependency-resolver's rootComponents (envs and apps installed as roots under node_modules/.bit_roots), and "workspace component" is every component loaded from a workspace (WorkspaceComponent). "Workspace-root component" is what rootDir: "." says, clashes with neither, and pairs with "nested components" for the ones inside it. Code uses the WORKSPACE_ROOT_DIR constant and the workspaceRoot prefix.

  • rootDir: "." is valid and is the only root-dir allowed to contain other components. Its file-set is everything under the root minus the nested components' root-dirs, re-scanned like any other component, so files added later are picked up. .bit/, .git/ and node_modules are never claimed.
  • It tracks .bitmap, with versions normalized on load so it converges after a snap. The writer never writes .bitmap back, so an imported root cannot create a phantom nested workspace.
  • bit add . tracks it with teambit.harmony/empty-env as explicit config (so env resolution and the dependency policy agree), and it is excluded from install and link. Its files are not parsed for dependencies either: nothing installs, links or builds the root, and repo scripts may require anything, so detection would only produce blocking issues with no consumer for the result. Its main file defaults to workspace.jsonc, the root has no entry point of its own; --main still overrides. bit remove and bit eject do not delete the workspace. Re-adding it is a no-op; a second root component is rejected at add time.
  • New core aspect teambit.workspace/workspace-root owns the concept. The root marks itself in its aspect data ({ "isRoot": true }), and that marker, not the files it carries, is what tells a root apart, e.g. on import onto .. On snap, every member of the workspace records the root it was snapped in, at the root's version after that snap: { "root": "scope/root@version" }. A new or modified root joins every bit tag and bit snap of its members, so the recorded version always has the files the member was made with; a root tagged along gets a patch bump of its own, whatever --ver the members got, and the command output says so. Both are data, not config, so they never make a component modified and the root moving on does not touch its members. The record tells a CI or a clone which root files (lockfile, tsconfig, scripts) a version was made with, and bit show prints it as "workspace root".
  • bit clone <root-id> [dir] makes a workspace out of it, the way git clone makes a working tree out of a repository. It runs outside a workspace, in an empty or absent directory (default: the component name), needs no bit init, lands the root files at the root (workspace.jsonc included; nothing bit init generates is added), imports every component the root's versioned .bitmap lists into the directory it records, then installs and compiles (-x to skip). The versioned .bitmap has no versions, so the components come at their heads on main; --lane <scope>/<name> clones the workspace as it is on a lane and comes out on it. A version on the root id pins the root files only. A component the root lists that its remote does not have is reported and skipped. --remote <url> registers a self-hosted scope in the new workspace first. bit import <root> --path . stays as the low-level primitive.
  • Importing the root component onto . without --override is accepted only in a fresh workspace (nothing else tracked), which is the restore flow; an established workspace gets the usual conflict error listing the root files that would be overwritten.

trackAllFiles

"trackAllFiles": true under teambit.workspace/workspace stops bit from dropping package.json, a root-level tsconfig.json and lint configs, and the npm/yarn lockfiles. Only git-ignored files and the hard exclusions stay out. Meant for workspaces adopted from an existing monorepo, where those files are the source of truth. Import writes the model's files regardless, so a component with a tracked package.json shows as modified in a workspace without the flag.

Tests

  • unit: bit-map.spec.ts (nesting rules, getNestedRootDirs, .bitmap normalization and the versioned-map reader), component-map.spec.ts (ignore logic with and without the flag) and determine-main-file.spec.ts (the root's main-file default), workspace-root-data.spec.ts (the root marker and the snapped-in root record).
  • e2e: add-harmony.e2e.ts covers root tracking, .bitmap convergence, a modified root joining a member's snap and tag, remove, re-add, checkout, import into another workspace and onto ., env defaults, adopt → export → bit clone with the flag, and bit clone --lane.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Allow components to own the workspace root

✨ Enhancement 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Permit one component to use the workspace root while preserving nesting restrictions elsewhere.
• Exclude nested components and Bit internals from the root component’s dynamic file set.
• Cover root ownership, rescanning, exclusion, and nesting behavior with unit and end-to-end tests.
Diagram

graph TD
  A["bit add ."] --> B["AddComponents"] --> C{"Root path?"}
  C -->|"Yes"| D["rootDir ."] --> F["BitMap exclusions"] --> G["Directory scan"] --> H["Owned files"]
  C -->|"No"| E["Component root"] --> F
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Explicit repository-file manifest
  • ➕ Avoids scanning the entire workspace root
  • ➕ Makes ownership immediately visible in configuration
  • ➖ New root files would require manual registration
  • ➖ Conflicts with normal component rescanning behavior
2. Resolve overlaps after scanning
  • ➕ Keeps the scanner API unchanged
  • ➕ Centralizes ownership conflict resolution
  • ➖ Scans nested component trees unnecessarily
  • ➖ Temporarily creates duplicate claims and increases memory usage

Recommendation: Keep the PR’s exclusion-based scanning approach. It preserves dynamic component discovery, prevents duplicate ownership at the source, and reuses the existing rescan lifecycle; explicit manifests would freeze membership, while post-scan reconciliation would add avoidable work and ambiguity.

Files changed (7) +181 / -22

Enhancement (5) +111 / -22
bit-map.tsSupport root ownership in BitMap nesting rules +28/-3

Support root ownership in BitMap nesting rules

• Exempts the workspace-root component from parent-directory conflicts and adds 'getNestedRootDirs()' to calculate exclusion boundaries. Both bitmap file loading and rescanning now pass those exclusions to the directory scanner.

components/legacy/bit-map/bit-map.ts

component-map.tsScan workspace-root components without overlapping files +54/-12

Scan workspace-root components without overlapping files

• Defines '.' as the canonical workspace-root directory and permits it during validation. Extends directory rescanning to exclude nested component roots, Bit metadata, Git metadata, and all nested 'node_modules' paths while retaining workspace-relative file paths.

components/legacy/bit-map/component-map.ts

index.tsExport the workspace-root directory constant +1/-0

Export the workspace-root directory constant

• Exports 'WORKSPACE_ROOT_DIR' from the bit-map package for consistent root-path handling across consumers.

components/legacy/bit-map/index.ts

consumer-component.tsExclude nested roots during component loading +5/-1

Exclude nested roots during component loading

• Passes BitMap-derived nested root directories into component file rescanning so loaded root components cannot claim nested component files.

components/legacy/consumer-component/consumer-component.ts

add-components.tsNormalize and track the workspace root safely +23/-6

Normalize and track the workspace root safely

• Normalizes an empty workspace-relative path to '.' and exempts the root owner from ordinary parent-directory conflicts. Initial file discovery subtracts existing nested component roots and accepts all remaining workspace files as being inside the tracked root.

scopes/component/tracker/add-components.ts

Tests (2) +70 / -0
bit-map.spec.tsTest workspace-root nesting and exclusion discovery +44/-0

Test workspace-root nesting and exclusion discovery

• Adds unit coverage proving that a '.' root component can coexist with nested components regardless of add order. It also verifies that non-root nesting remains invalid and nested root directories are calculated correctly.

components/legacy/bit-map/bit-map.spec.ts

add-harmony.e2e.tsVerify workspace-root tracking end to end +26/-0

Verify workspace-root tracking end to end

• Tests that 'bit add .' persists 'rootDir' as '.', discovers root files added after tracking, and excludes nested component files and Bit internals.

e2e/harmony/add-harmony.e2e.ts

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 10, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (2) 📜 Skill insights (0)

⚠️ 3 lower-priority findings omitted to fit the comment size limit; re-run the review or view the findings in the Qodo portal.

Grey Divider


Action required

1. Root validation adds avoidable test cost 📘 Rule violation ➹ Performance
Description
The new adding a nested component that holds the main file E2E block runs two full
addComponent() commands solely to exercise the deterministic
throwForTakingWorkspaceRootMainFile() path check. Both ordinary and ignored-main-file variants
stop at the same validation before any map write or link, so they add Harmony setup and command
overhead for branches that can be covered beside the tracker.
Code

e2e/harmony/add-harmony.e2e.ts[R263-265]

+    it('should refuse, because the root would fail to load without its main file', () => {
+      const cmd = () => helper.command.addComponent('packages/comp1', { i: 'comp1' });
+      expect(cmd).to.throw('main file of the workspace-root component');
Evidence
Rule 2 reserves E2E tests for behavior requiring real workspace or multi-command flows. The added
tests invoke the command only to assert the error produced by a pure path-prefix check, including a
second variation that reaches the same branch even when the file is ignored.

CLAUDE.md: Prefer Co-Located Unit Tests and Minimize E2E Test Overhead: CLAUDE.md: Prefer Co-Located Unit Tests and Minimize E2E Test Overhead
e2e/harmony/add-harmony.e2e.ts[263-271]
scopes/component/tracker/add-components.ts[918-929]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Two new Harmony E2E cases exercise only the deterministic workspace-root main-file path validation, adding unnecessary command and workspace setup overhead.
## Fix Focus Areas
- e2e/harmony/add-harmony.e2e.ts[263-271]
- scopes/component/tracker/add-components.ts[918-929]
## Recommended Fix
Extract or export the workspace-root main-file validation helper as needed, cover its ordinary and ignored-file-equivalent path branches in a co-located tracker `.spec.ts`, and remove the two redundant E2E cases.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Members keep stale root provenance 🐞 Bug ≡ Correctness
Description
recordWorkspaceRoot() returns when findWorkspaceRootMap() finds no current root, leaving any
existing workspace-root aspect root value untouched. When a component imported from a rooted
workspace is tagged or snapped in a rootless one, its new version still identifies the old root, so
provenance consumers report workspace files that were not used for that version.
Code

scopes/component/snapping/version-maker.ts[779]

+    if (!rootMap) return;
Evidence
Workspace-root data is merged from the model into loaded components, while the component-load
callback returns no replacement data for ordinary components and the loader does not delete existing
data on an undefined callback result. The newly added versioning method then exits when the current
bitmap has no root, despite the runtime contract stating that components snapped without a root have
no root association.

scopes/component/snapping/version-maker.ts[775-789]
scopes/workspace/workspace-root/workspace-root-data.ts[31-60]
scopes/workspace/workspace-root/workspace-root.main.runtime.ts[73-80]
scopes/workspace/workspace/workspace-component/workspace-component-loader.ts[1198-1222]
scopes/workspace/workspace/aspects-merger.ts[164-180]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Components retain an old workspace-root association when tagged or snapped in a workspace that has no workspace-root component because `recordWorkspaceRoot()` returns without clearing existing aspect data.
## Fix Focus Areas
- scopes/component/snapping/version-maker.ts[775-789]
- scopes/workspace/workspace-root/workspace-root-data.ts[42-61]
- scopes/workspace/workspace-root/workspace-root-data.spec.ts[48-68]
## Recommended Fix
Add a workspace-root data helper that removes the existing `root` association, or removes the aspect entry when it has no other data. Invoke it for every versioned workspace member when no current root map exists, while preserving the root marker where applicable, and add coverage for re-versioning a component from a rooted workspace in a rootless workspace.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Root scans crash on nested ignores 🐞 Bug ☼ Reliability
Description
filterByIgnoreFiles() passes the gitIgnore instance into ignore().add(), whose argument must
be pattern strings or an array rather than another ignore object. Any workspace-root scan that
discovers a nested .gitignore or .bitignore reaches this branch, affecting root loading and `bit
add .`.
Code

components/legacy/bit-map/component-map.ts[127]

+  const filteredByUserRules: PathLinux[] = ignore().add(gitIgnore).add(nestedPatterns).filter(relativePaths);
Evidence
The helper treats gitIgnore as an ignore instance by calling its filter() method, but then
supplies that same object to a new instance's add() call. Nested ignore discovery makes the branch
reachable in the newly added workspace-root scan tests, while getGitIgnoreHarmony() confirms that
callers receive an ignore instance built from the workspace patterns.

components/legacy/bit-map/component-map.ts[116-130]
components/legacy/bit-map/component-map.ts[160-184]
components/legacy/bit-map/component-map.ts[590-596]
components/legacy/bit-map/component-map.spec.ts[141-169]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`filterByIgnoreFiles()` passes an existing ignore instance to `ignore().add()`, causing workspace-root scans with nested ignore files to throw.
## Fix Focus Areas
- components/legacy/bit-map/component-map.ts[116-130]
- components/legacy/bit-map/component-map.ts[590-616]
## Recommended Fix
Retain or obtain the root user-ignore pattern list and construct a new ignore instance from those pattern strings plus the rebased nested patterns. Apply Bit's generated and hard exclusions afterward so nested negations cannot override them, without passing an ignore object to `.add()`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View action required (3)
4. Workspace files are built as components 🐞 Bug ≡ Correctness
Description
configForWorkspaceRoot() preserves an existing or caller-supplied environment instead of forcing
the empty environment for a workspace-root component. When that environment provides build tasks,
bit build and tag/snap pass the root through their ordinary build batches, so repository-level
files are compiled or tested as component source.
Code

scopes/component/tracker/add-components.ts[R849-857]

+export function configForWorkspaceRoot(existingConfig?: Config, addedConfig?: Config): Config {
+  const configuredEnv = addedConfig?.[Extensions.envs] ?? existingConfig?.[Extensions.envs];
+  if (configuredEnv) return { ...existingConfig, ...addedConfig };
+  // the same two entries "bit env set" writes: the env aspect itself, and the env selection
+  return {
+    ...existingConfig,
+    ...addedConfig,
+    [WORKSPACE_ROOT_ENV]: {},
+    [Extensions.envs]: { env: WORKSPACE_ROOT_ENV },
Evidence
The added root configuration intentionally allows a configured env to replace empty-env; builder
entry points do not exclude root components, so those configured tasks execute for the
workspace-root component.

scopes/component/tracker/add-components.ts[849-857]
scopes/component/snapping/snapping.main.runtime.ts[269-275]
scopes/component/snapping/version-maker.ts[379-388]
scopes/pipelines/builder/builder.main.runtime.ts[416-436]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Workspace-root components may retain an explicit environment with build tasks, but they are still included in normal `bit build` and tag/snap build batches. Keep their versioning behavior while preventing workspace-root components from entering builder task execution.
## Fix Focus Areas
- scopes/component/tracker/add-components.ts[849-857]
- scopes/component/snapping/version-maker.ts[379-388]
- scopes/pipelines/builder/builder.main.runtime.ts[416-436]
## Recommended Fix
Add a shared workspace-root predicate based on the component's root-dir or persisted root marker, and filter workspace-root components before invoking builder services for explicit builds and tag/snap builds. Do not filter them from snap/tag version creation; they must still be versioned and recorded with members.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Main-file coverage is duplicated 📘 Rule violation ⚙ Maintainability
Description
adding the workspace root as a component repeats the workspace.jsonc default assertion already
exercised directly by determine-main-file.spec.ts. The extra E2E case places the same local
expectation in the full Harmony suite, requiring future changes to maintain identical coverage in
both layers.
Code

e2e/harmony/add-harmony.e2e.ts[R56-57]

+    it('should default the main file to workspace.jsonc, the root has no entry point of its own', () => {
+      expect(helper.bitMap.read()['ws-root'].mainFile).to.equal('workspace.jsonc');
Evidence
Compliance rule 2 requires component-local behavior to use focused unit coverage rather than
redundant E2E tests. The added Harmony test asserts the same workspace-root default already covered
directly by the colocated unit test.

CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage: CLAUDE.md: Prefer Focused Unit Tests and Minimize Necessary E2E Coverage
e2e/harmony/add-harmony.e2e.ts[56-57]
scopes/component/tracker/determine-main-file.spec.ts[19-25]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workspace-root main-file default is local component logic already covered by a focused unit test, but the PR repeats the same expectation in the Harmony E2E suite.
## Fix Focus Areas
- e2e/harmony/add-harmony.e2e.ts[56-57]
## Recommended Fix
Remove the duplicate E2E test while retaining the focused `determineMainFile` unit coverage in `determine-main-file.spec.ts`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Tracked generated files vanish after add ✓ Resolved 🐞 Bug ≡ Correctness
Description
AddComponents.addOrUpdateComponentInBitMap() filters a file with the auto-generated banner unless
it is the workspace-root .bitmap, without checking trackAllFiles. When that flag is enabled and
such a file is present, the initial add omits it while getFilesByDir() retains it on the next
load, leaving the component immediately modified.
Code

scopes/component/tracker/add-components.ts[R267-270]

const isAutoGenerated = await isAutoGeneratedFile(filePath);
-      if (isAutoGenerated) {
+      if (isAutoGenerated && !(isWorkspaceRoot && isWorkspaceMapFile(file.relativePath))) {
 return null;
}
Evidence
The changed add-time condition rejects auto-generated files independently of the new flag. The
rescan path has no equivalent banner check and selects its generated-file exclusions from the
trackAllFiles setting, so the two paths produce different file sets for the same component.

scopes/component/tracker/add-components.ts[262-270]
components/legacy/bit-map/component-map.ts[573-581]
components/legacy/bit-map/component-map.ts[604-615]
components/legacy/constants/constants.ts[273-284]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`bit add` drops banner-marked generated files even when the workspace enables `trackAllFiles`, while subsequent rescans retain them. This makes the bitmap's initial file set diverge from the rescan file set and immediately marks the component modified.
## Fix Focus Areas
- scopes/component/tracker/add-components.ts[262-270]
- components/legacy/bit-map/component-map.ts[573-581]
## Recommended Fix
Make the add-time auto-generated-file filter conditional on `!this.consumer.config.trackAllFiles`, while preserving the workspace-root `.bitmap` exception. Ensure the initial add uses the same inclusion policy as `getFilesByDir()` when all-files tracking is enabled.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: 🧠 Deep: This is a broad, high-blast-radius feature spanning workspace tracking, component nesting, persistence, import/clone, snapping, installation, and legacy map behavior, with many independent logic paths where a redundant review is likely to catch subtle defects.

Grey Divider

Tip of the day
💡 Did you know, you can group findings by type and pick your Finding display, from Minimal to Full

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread scopes/component/tracker/add-components.ts
Comment thread scopes/component/tracker/add-components.ts
Comment thread components/legacy/bit-map/component-map.ts Outdated
Comment thread scopes/component/tracker/add-components.ts Outdated
Comment thread components/legacy/bit-map/bit-map.ts Outdated
Comment thread components/legacy/bit-map/component-map.ts Outdated
@davidfirst

Copy link
Copy Markdown
Member Author

Follow-up: the root component now tracks .bitmap as well.

Tracking it verbatim does not converge — snapping rewrites every entry's version, including the root component's own, so the component is modified again the instant it is snapped, forever. Confirmed on a scratch workspace: the post-snap diff was nothing but version fields.

So only the durable part of the map is versioned: version and scope are emptied before the content is hashed (normalizeBitmapContentForVersioning), while name, defaultScope, mainFile and rootDir are kept. Versions are restored from the component heads on import, which is the correct source for them anyway. The .bitmap on disk is untouched — only the versioned copy is normalized.

Also fixed: adding a component inside the workspace root used to fail with "files already used by component", because the root had already claimed them. The root now yields to the more specific component and drops those files on its next scan.

Comment thread components/legacy/bit-map/bit-map.ts Outdated
Comment thread components/legacy/bit-map/bit-map.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit f0ca113

@davidfirst

Copy link
Copy Markdown
Member Author

Went through all 24 component issues one by one against the workspace-root component. The result was not "none of them are relevant" — testing changed the answer.

I first ignored everything dependency-derived (18 issues). That made things worse: with RelativeComponents suppressed, a root-level file with a relative import into a component dir gets past the friendly issue and dies at the model layer with unable to save Version object [...] dependencies should not have relativePaths followed by This error should have never happened. Please report this issue on Github. The issue was the only thing producing an actionable message for a real, unsupported situation.

So the list is narrowed to the three that misfire for a structural reason — the root component has no env toolchain, no compiler, and nothing imports it as a package:

  • MissingManuallyConfiguredPackages — the env dependency policy (@types/node and friends) is not installed for a component with no env toolchain. This was the actual blocker.
  • MissingDists — no compiler, so never any dist output.
  • MissingLinksFromNodeModulesToSrc — nothing resolves it as a package.

Everything else is kept. The dependency-related issues never fire for a component whose files hold no imports, so ignoring them buys nothing and costs the guard when they do fire.

Net effect: bit snap ws-root now works with no --ignore-issues flag, and bit status reports the root component as clean while still reporting real problems on it.

Comment thread scopes/component/tracker/add-components.ts Outdated
Comment thread components/legacy/bit-map/component-map.ts Outdated
Comment thread scopes/component/issues/issues.main.runtime.ts Outdated
Comment thread scopes/component/tracker/add-components.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit d166385

…nd write paths

the workspace-root component (rootDir ".") is a bag of the workspace's own config
files. three things treated it as a regular source component:

- env: it defaulted to the regular default env, giving it a compiler and a
  dependency policy it can never use. it now defaults to the empty env. an env
  set explicitly on it still wins.
- install: its dir is the workspace root, so handing it to the package manager
  collided with the root project - pnpm resolved it to an empty "file:" spec and
  failed to build the lockfile, breaking "bit install" entirely.
- write: importing it into another workspace wrote a .bitmap into a
  sub-directory, silently turning that dir into a broken nested workspace, and
  checking out an earlier version of it crashed on a non-BitError.

the empty env removes the compiler-derived issue structurally, so the
issue-ignore list added for this component is no longer needed and is reverted.
@davidfirst

Copy link
Copy Markdown
Member Author

Follow-up on two questions raised in review: what happens when a workspace-root component is imported, and what env it should get.

Env. It was defaulting to the regular default env, which hands a bag of config files a compiler and a dependency policy it can never satisfy. It now defaults to teambit.harmony/empty-env (which already exists as a core aspect). An env set explicitly on the component still wins — only the fallback changed.

This turned out to be the better fix for the component-issues question. With no compiler, MissingDists can't fire at all, so it's handled structurally rather than suppressed. And MissingManuallyConfiguredPackages was never root-specific — it fires for every component in a workspace that hasn't been installed yet, and clears on bit install. So the issue-ignore list from the previous commit is reverted: no issue-level special-casing is needed.

Import. Two real bugs, both reproduced:

  1. Importing a workspace-root component into another workspace wrote its .bitmap into the target sub-directory. .bitmap is what marks a workspace root, so that directory became a broken nested workspace — running any bit command from there operated on it instead of the real workspace, reporting the foreign components as new/invalid.
  2. bit checkout <version> and bit checkout reset on the component crashed with a raw addComponentToBitMap: rootDir cannot be "." — a plain Error, so it surfaced as an internal failure.

Fixed by never writing .bitmap from the model (writing it into a sub-directory corrupts, writing it onto the root would clobber the live map with a stale one while the operation is mutating it), and by allowing . as a rootDir only for the component that owns this workspace's root, with a proper BitError otherwise.

Third bug found on the way: bit install failed outright in any workspace with a root component — its dir is the workspace root, so it collided with the package manager's root project and pnpm produced an empty file: spec (Failed to parse suffix: Empty path after 'file:' scheme). It's now excluded from the install/link machinery.

17 e2e + 10 unit passing, lint clean.

Comment thread scopes/component/component-writer/component-writer.ts Outdated
Comment thread scopes/component/tracker/add-components.ts Outdated
Comment thread scopes/component/tracker/add-components.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 016b3c4

- remove/eject: rootDir "." was passed to RemovePath with recursive deletion, so
  removing the root component wiped the entire workspace - nested components,
  .bit, .bitmap and unrelated files. its files are the workspace's own, so
  untracking it now leaves them in place.
- re-adding "bit add ." threw, since files were compared against a "./" prefix
  they never have.
- a second component claiming the workspace root was accepted, then failed
  .bitmap's duplicate-rootDir validation on the next load. now rejected with a
  message naming the current owner.
- "bit add ." skipped dotfiles and enumerated node_modules; it now uses the same
  ignore list as the rescan, so both agree on what the root component owns.
- .bitTmp and the legacy .bit.map.json are excluded from the root file-set.
- the .bitignore/.gitignore lookup resolved against the process cwd rather than
  the workspace.
- the writer rejected a rootDir of "." whenever no .bitmap entry existed yet,
  which also blocked restoring a stashed root component. it now rejects only
  when a different component owns the root.
- .bitmap normalization no longer clears "scope": unlike "version" it is stable
  after the first export, and clearing it collapsed components from other scopes
  onto the workspace default on restore.
Comment thread e2e/harmony/add-harmony.e2e.ts
Comment thread components/legacy/bit-map/component-map.ts Outdated
Comment thread scopes/component/component-writer/component-writer.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit b2c0a9d

…nto "."

"bit import <root-component> --path ." crashed with an undefined path: "--path ."
resolves to an empty relative path, which was stored as an empty rootDir. it is
now normalized to ".", and the workspace root - which always holds .bit, .bitmap
and workspace.jsonc - is no longer rejected as "not empty" for the component
that owns it. this is the flow that restores a git-free workspace from its scope.
Comment thread components/legacy/bit-map/bit-map.ts Outdated
Comment thread components/legacy/bit-map/component-map.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 99c1fd8

Comment thread e2e/harmony/add-harmony.e2e.ts
Comment thread scopes/component/tracker/add-components.ts Outdated
Comment thread scopes/component/component-writer/component-writer.main.runtime.ts Outdated
Comment thread scopes/component/tracker/add-components.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit b49b410

…t-generated files

bit drops package.json, a root-level tsconfig.json and lint configs, and the npm/yarn
lockfiles from every component because it generates them. a workspace adopted from an
existing monorepo owns those files, and without them a workspace restored from the scope
can be neither installed nor built. with "trackAllFiles": true in teambit.workspace/workspace,
only the git-ignored files and the hard exclusions (node_modules, .env, ...) are left out.
@davidfirst davidfirst changed the title feat(bit-map): allow a component to own the workspace root (rootDir ".") feat(workspace): workspace-root component (rootDir ".") and the trackAllFiles flag Sep 11, 2026
Comment thread components/legacy/bit-map/component-map.ts Outdated
Comment thread components/legacy/consumer-component/consumer-component.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit d2b6186

Comment thread scopes/component/snapping/version-maker.ts
Comment thread scopes/component/snapping/snapping.main.runtime.ts
Comment thread scopes/component/tracker/add-components.ts
Comment thread scopes/component/component-writer/component-writer.ts
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 57708e5

Comment thread e2e/harmony/bit-ignore.e2e.ts
Comment thread e2e/harmony/add-harmony.e2e.ts Outdated
Comment thread scopes/component/component-writer/component-writer.main.runtime.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 216f3ee

Comment thread scopes/workspace/workspace-root/clone.cmd.ts Outdated
Comment thread scopes/workspace/workspace-root/clone.ts Outdated
Comment thread scopes/workspace/workspace-root/clone.ts Outdated
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 47c9c0b

Comment thread e2e/harmony/add-harmony.e2e.ts Outdated
Comment thread scopes/component/component-writer/component-writer.main.runtime.ts
Comment thread scopes/component/component-writer/component-writer.ts
Comment thread scopes/workspace/workspace-root/clone.ts
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit fbbf9b4

…-component-nesting

# Conflicts:
#	scopes/harmony/cli-reference/cli-reference.docs.mdx
Comment thread scopes/workspace/workspace-root/clone.ts Outdated
Comment thread scopes/component/snapping/version-maker.ts
Comment thread scopes/harmony/config/workspace-config.ts
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit f51ca92

Comment thread e2e/harmony/add-harmony.e2e.ts
Comment thread scopes/workspace/workspace-root/clone.ts
Comment thread scopes/component/tracker/add-components.ts
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 16122c6

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 16, 2026

Copy link
Copy Markdown

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

Qodo Logo

Comment thread components/legacy/bit-map/component-map.ts
Comment thread scopes/workspace/watcher/watcher.ts Outdated
Comment thread scopes/component/tracker/add-components.ts
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit be52daf

Comment on lines +263 to +265
it('should refuse, because the root would fail to load without its main file', () => {
const cmd = () => helper.command.addComponent('packages/comp1', { i: 'comp1' });
expect(cmd).to.throw('main file of the workspace-root component');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Root validation adds avoidable test cost 📘 Rule violation ➹ Performance

The new adding a nested component that holds the main file E2E block runs two full
addComponent() commands solely to exercise the deterministic
throwForTakingWorkspaceRootMainFile() path check. Both ordinary and ignored-main-file variants
stop at the same validation before any map write or link, so they add Harmony setup and command
overhead for branches that can be covered beside the tracker.
Agent Prompt
## Issue description
Two new Harmony E2E cases exercise only the deterministic workspace-root main-file path validation, adding unnecessary command and workspace setup overhead.

## Fix Focus Areas
- e2e/harmony/add-harmony.e2e.ts[263-271]
- scopes/component/tracker/add-components.ts[918-929]

## Recommended Fix
Extract or export the workspace-root main-file validation helper as needed, cover its ordinary and ignored-file-equivalent path branches in a co-located tracker `.spec.ts`, and remove the two redundant E2E cases.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

const consumer = this.consumer;
if (!consumer) return;
const rootMap = findWorkspaceRootMap(consumer.bitMap);
if (!rootMap) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Members keep stale root provenance 🐞 Bug ≡ Correctness

recordWorkspaceRoot() returns when findWorkspaceRootMap() finds no current root, leaving any
existing workspace-root aspect root value untouched. When a component imported from a rooted
workspace is tagged or snapped in a rootless one, its new version still identifies the old root, so
provenance consumers report workspace files that were not used for that version.
Agent Prompt
## Issue description
Components retain an old workspace-root association when tagged or snapped in a workspace that has no workspace-root component because `recordWorkspaceRoot()` returns without clearing existing aspect data.

## Fix Focus Areas
- scopes/component/snapping/version-maker.ts[775-789]
- scopes/workspace/workspace-root/workspace-root-data.ts[42-61]
- scopes/workspace/workspace-root/workspace-root-data.spec.ts[48-68]

## Recommended Fix
Add a workspace-root data helper that removes the existing `root` association, or removes the aspect entry when it has no other data. Invoke it for every versioned workspace member when no current root map exists, while preserving the root marker where applicable, and add coverage for re-versioning a component from a rooted workspace in a rootless workspace.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 3578fa4

Comment on lines +177 to +180
const patternsPerDir = await Promise.all(
Array.from(ignoreFileByDir, async ([fileDir, name]) => {
const absoluteDir = path.join(consumerPath, fileDir);
const patterns = name === BIT_IGNORE ? await getBitIgnoreFile(absoluteDir) : await getGitIgnoreFile(absoluteDir);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

9. Nested ignore precedence can reverse 🐞 Bug ≡ Correctness

getNestedIgnorePatterns() preserves the unsorted relativePaths insertion order when building
ignoreFileByDir, then concatenates each file's patterns in that same order. When traversal yields
a descendant ignore file before its ancestor, the ancestor's later rule overrides descendant
exceptions, so workspace-root scans claim a different file set than Git.
Agent Prompt
## Issue description
Nested ignore files are applied in filesystem traversal order rather than Git's ancestor-before-descendant precedence order, allowing parent rules to override child exceptions.

## Fix Focus Areas
- components/legacy/bit-map/component-map.ts[165-184]

## Recommended Fix
Sort the collected ignore-file entries by directory depth from shallowest to deepest before reading and flattening their patterns, with a deterministic secondary path ordering.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +293 to +295
if (componentRootDir === WORKSPACE_ROOT_DIR || existingComponentMap?.rootDir === WORKSPACE_ROOT_DIR) {
this.throwForNonWorkspaceRootComponent(component);
this.throwForSymlinksInTheWay(component);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

10. Root tracking fails on symlinked paths 🐞 Bug ≡ Correctness

getWriteParamsOfOneComponent() calls throwForSymlinksInTheWay() before honoring
skipWritingToFs, although persistComponentsData() performs no filesystem write for that option.
A bit import <root> --path . --track-only therefore rejects any incoming path backed by a symlink
even though track-only is explicitly routed through the no-write path.
Agent Prompt
## Issue description
Workspace-root imports run symlink write-safety validation even when track-only mode suppresses all filesystem persistence.

## Fix Focus Areas
- scopes/component/component-writer/component-writer.main.runtime.ts[291-295]
- scopes/component/component-writer/component-writer.main.runtime.ts[163-168]

## Recommended Fix
Keep workspace-root identity validation for bitmap tracking, but call `throwForSymlinksInTheWay()` only when `opts.skipWritingToFs` is false.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit dfda122

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.

2 participants