feat(deps): resolve env peer dependencies from workspace root#10227
feat(deps): resolve env peer dependencies from workspace root#10227GiladShoham merged 11 commits intomasterfrom
Conversation
Redesign how Bit resolves env peer dependencies in workspaces: - Merge non-conflicting env peers to workspace root manifest instead of injecting per-component, reducing manifest bloat - Support `workspaceSingleton` property on env.jsonc peer entries to force single-version resolution at root for packages like @types/* and eslint - Support `overrides` boolean on env.jsonc peer entries to generate pnpm overrides forcing transitive deps to use the same version - workspace.jsonc policy always takes priority over env peers - Add `resolveEnvPeersFromRoot` config (default: true) to control the behavior - Add `forceEnvPeersToRoot` config (default: false) to force all peers to root - Improve env.jsonc parse error messages to include file path and env name Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR changes how env peer dependencies (from env.jsonc) are resolved during installation by preferring a single resolution at the workspace root, with new controls for handling conflicts and pinning via overrides.
Changes:
- Add workspace config/schema support for
resolveEnvPeersFromRootandforceEnvPeersToRoot. - Extend env peer policy entries with
workspaceSingletonandoverridesflags and propagate them through policy objects. - Update manifest generation + install flow to merge env peers to the root manifest (and collect env-derived pnpm overrides), with improved env.jsonc parse errors.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| workspace-jsonc-schema.json | Documents new workspace.jsonc options for env peer resolution behavior. |
| scopes/workspace/workspace/workspace.ts | Wraps env.jsonc parsing with a clearer syntax error. |
| scopes/workspace/install/install.main.runtime.ts | Threads resolveEnvPeersFromRoot into manifest calc and merges env-derived overrides with workspace overrides. |
| scopes/envs/envs/environments.main.runtime.ts | Improves env.jsonc parse error reporting with env name + file path. |
| scopes/envs/envs/env-jsonc.detector.ts | Adds parse error wrapping for env.jsonc dependency detection. |
| scopes/dependencies/dependency-resolver/policy/variant-policy/variant-policy.ts | Adds workspaceSingleton/overrides to policy entry values. |
| scopes/dependencies/dependency-resolver/policy/env-policy/env-policy.ts | Adds new env.jsonc peer entry fields and passes them into variant policy entries; tracks envId. |
| scopes/dependencies/dependency-resolver/package-manager.ts | Adds resolveEnvPeersFromRoot option to install options typing. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest.ts | Treats env peers as “defaults” when writing the root manifest. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts | Implements root merging, conflict handling, per-component injection, and env-derived overrides collection. |
| scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts | Wires workspace-level config into WorkspaceManifestFactory and passes envId into EnvPolicy. |
| scopes/dependencies/dependency-resolver/dependency-resolver-workspace-config.ts | Adds config interface docs for the new options. |
| scopes/dependencies/dependency-resolver/dependency-installer.ts | Returns { manifests, peerOverrides } from manifest calculation and threads resolveEnvPeersFromRoot to workspace manifest writing. |
You can also share your feedback on Copilot code review. Take the survey.
scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts
Outdated
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/manifest/workspace-manifest.ts
Outdated
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts
Show resolved
Hide resolved
Env peer dependencies that are also workspace components should not be added to the root manifest — they are linked locally, not installed. This matches the existing filter in _getEnvPeerDependencies. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of repeating the hint per conflict, show a single message after all warnings explaining how to pin a version in workspace.jsonc. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR changes how env peer dependencies (from env.jsonc) are resolved and applied during installation, prioritizing a single workspace-root resolution path to reduce per-component manifest bloat while adding opt-in knobs for singleton resolution and pnpm overrides.
Changes:
- Add workspace config + schema options to control resolving env peers from the workspace root and forcing conflicts to root.
- Extend env policy/variant policy entries to carry
workspaceSingletonandoverridesflags, and implement root-merge + per-component fallback for conflicting peers. - Thread env-derived pnpm overrides into install options, and improve
env.jsoncparse error handling.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| workspace-jsonc-schema.json | Documents new workspace config options for env peer resolution behavior. |
| scopes/workspace/workspace/workspace.ts | Adds try/catch around env.jsonc parsing and improves error reporting. |
| scopes/workspace/install/install.main.runtime.ts | Passes resolveEnvPeersFromRoot to manifest calculation and merges env-derived pnpm overrides with workspace overrides. |
| scopes/envs/envs/environments.main.runtime.ts | Adds contextualized parse errors when calculating env manifests. |
| scopes/envs/envs/env-jsonc.detector.ts | Adds explicit parse failure error for env.jsonc detector. |
| scopes/dependencies/dependency-resolver/policy/variant-policy/variant-policy.ts | Adds workspaceSingleton / overrides to policy entry values and wires them into entry creation. |
| scopes/dependencies/dependency-resolver/policy/env-policy/env-policy.ts | Adds peer entry flags and carries envId on EnvPolicy for later resolution. |
| scopes/dependencies/dependency-resolver/package-manager.ts | Adds resolveEnvPeersFromRoot to install options type plumbing. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest.ts | Ensures env peers can be merged into the root manifest (as defaults) and stores env-derived overrides. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts | Implements env peer merge-to-root logic, conflict resolution, per-component injection for non-singleton conflicts, and override collection. |
| scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts | Instantiates manifest factory with new flags and passes envId into env policy creation. |
| scopes/dependencies/dependency-resolver/dependency-resolver-workspace-config.ts | Adds workspace config interface fields + docs for the new behavior. |
| scopes/dependencies/dependency-resolver/dependency-installer.ts | Updates manifests computation to return env-derived overrides alongside manifests and passes new option into root manifest generation. |
You can also share your feedback on Copilot code review. Take the survey.
scopes/dependencies/dependency-resolver/dependency-resolver-workspace-config.ts
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts
Show resolved
Hide resolved
…sonc Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use console log with emoji and newlines so the hint stands out from the yellow warning messages above it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Implements a new dependency-resolution flow where env peer dependencies from env.jsonc are (by default) resolved once and merged into the workspace root manifest, with new configuration knobs and metadata (workspaceSingleton, overrides) to control conflict handling and pnpm overrides.
Changes:
- Add
resolveEnvPeersFromRoot/forceEnvPeersToRootworkspace configuration and schema support. - Extend env peer entries with
workspaceSingletonandoverrides, and propagate these through env/variant policy types. - Update install + manifest generation pipeline to (a) merge non-conflicting env peers to root, (b) inject conflicting peers per-component, and (c) generate pnpm overrides derived from env peers.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| workspace-jsonc-schema.json | Adds schema entries for the new workspace config flags. |
| scopes/workspace/workspace/workspace.ts | Wraps env.jsonc parsing with improved error handling. |
| scopes/workspace/install/install.main.runtime.ts | Passes resolveEnvPeersFromRoot into manifest calc and merges env-derived pnpm overrides. |
| scopes/envs/envs/environments.main.runtime.ts | Adds file/env-contextual env.jsonc parse error message. |
| scopes/envs/envs/env-jsonc.detector.ts | Adds parse error handling for env.jsonc detector. |
| scopes/dependencies/dependency-resolver/policy/variant-policy/variant-policy.ts | Extends policy entry value with workspaceSingleton and overrides. |
| scopes/dependencies/dependency-resolver/policy/env-policy/env-policy.ts | Adds peer entry flags + threads env id through EnvPolicy. |
| scopes/dependencies/dependency-resolver/package-manager.ts | Adds resolveEnvPeersFromRoot to install options typing. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest.ts | Changes root manifest env-peer merge behavior to respect workspace policy precedence. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts | Implements root-merge vs per-component injection + override generation + conflict resolution logic. |
| scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts | Wires new config flags into WorkspaceManifestFactory; passes env id into EnvPolicy. |
| scopes/dependencies/dependency-resolver/dependency-resolver-workspace-config.ts | Documents new config flags in the workspace config interface. |
| scopes/dependencies/dependency-resolver/dependency-installer.ts | Returns { manifests, peerOverrides } from getComponentManifests() and passes new option through. |
You can also share your feedback on Copilot code review. Take the survey.
scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts
Show resolved
Hide resolved
scopes/dependencies/dependency-resolver/manifest/workspace-manifest.ts
Outdated
Show resolved
Hide resolved
- overrides:true now implies singleton (forces single version at root) - Fix semver.coerce bug: use .version string instead of SemVer object - Guard semver.satisfies with semver.validRange to prevent crashes - Skip "+" version placeholders from peerOverrides and component injection - Check all dep sections (dev/peer/optional) before adding env peers to root - Use BitError instead of plain Error for consistent CLI error handling - Include file path in env.jsonc parse error messages - Fix error messages to say "JSONC" instead of "JSON" - Fix docs to say "envs" instead of "components" for conflict resolution Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| envSelfPeers = result.rootPolicy; | ||
| peerOverrides = result.peerOverrides; | ||
| if (result.componentPeerOverrides.size > 0) { | ||
| this.injectConflictingPeersToComponents(componentsManifestsMap, result.componentPeerOverrides); |
There was a problem hiding this comment.
we were talking with Gilad about possibly deprecating root components, if this approach works. But if we are injecting conflicting peers to components, then we do need root components to remain. Could we possibly be more strict and only allow singletons? If someone needs to work with a different set of peer dependencies, they could create a new workspace.
There was a problem hiding this comment.
Thanks Zoltan that was meant just for the Workspace because some tools like ESLint only support the workspace which failed when multiple envs are used in the same workspace. That allows us to ensure a single version to resolve - or let the user choose his own workspace version. I don't think it can replace bit_roots but think we should start optimize for its size (we will need it for envs for example among other things).
| * forcing all transitive dependencies to use the same version. | ||
| * Useful to prevent old versions from being pulled by published packages. | ||
| */ | ||
| overrides?: boolean; |
There was a problem hiding this comment.
"override" might be a better name as "overrides" is used for the map of overrides. Or something more descriptive to make the difference between the two fields clear. Like "overrideSubdeps" and "overrideRootDeps".
There was a problem hiding this comment.
Thanks Zoltan! I will change the name to override.
There was a problem hiding this comment.
Pull request overview
This PR changes how env (env.jsonc) peer dependencies are resolved during installation by defaulting to a workspace-root merge strategy (with conflict handling, optional forced-root behavior, and pnpm overrides support), while also improving env.jsonc JSONC parse error reporting.
Changes:
- Add workspace-level config (
resolveEnvPeersFromRoot,forceEnvPeersToRoot) and implement root-merge + conflict handling for env peer dependencies, with per-component fallback when conflicts aren’t forced/singleton. - Add per-peer flags (
workspaceSingleton,overrides) to env peer policy entries and propagate them through the policy model to drive root resolution + pnpm overrides generation. - Improve env.jsonc parse error messages to include env identity + file path for faster debugging.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| workspace-jsonc-schema.json | Documents new workspace.jsonc dependency-resolver options for env peer resolution behavior. |
| scopes/workspace/workspace/workspace.ts | Adds env.jsonc JSONC parse error handling that includes env id + file path. |
| scopes/workspace/install/install.main.runtime.ts | Threads resolveEnvPeersFromRoot into manifest calculation and merges env-generated peer overrides with workspace overrides. |
| scopes/envs/envs/environments.main.runtime.ts | Improves env.jsonc parse errors with env name/path context and consistent BitError formatting. |
| scopes/envs/envs/env-jsonc.detector.ts | Adds guarded parsing with a clearer error when env.jsonc cannot be parsed. |
| scopes/dependencies/dependency-resolver/policy/variant-policy/variant-policy.ts | Extends policy entry value to carry workspaceSingleton / overrides metadata. |
| scopes/dependencies/dependency-resolver/policy/env-policy/env-policy.ts | Adds envId tracking to EnvPolicy and parses new peer flags from env.jsonc. |
| scopes/dependencies/dependency-resolver/package-manager.ts | Adds resolveEnvPeersFromRoot to install options shape for plumbing. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest.ts | Emits env peers to root manifest as “defaults” while respecting existing workspace policy across all dep sections; resolves + placeholders. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts | Implements env peer root-merge algorithm, conflict resolution, per-component injection for non-singleton conflicts, and pnpm overrides collection. |
| scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts | Instantiates manifest factory with root-merge flags; passes envId into EnvPolicy creation. |
| scopes/dependencies/dependency-resolver/dependency-resolver-workspace-config.ts | Adds new workspace config options to the typed config interface. |
| scopes/dependencies/dependency-resolver/dependency-installer.ts | Changes manifests computation to return { manifests, peerOverrides } and plumbs resolveEnvPeersFromRoot into root manifest generation. |
| manifests[rootDir] = workspaceManifest.toJson({ | ||
| copyPeerToRuntime: copyPeerToRuntimeOnRoot, | ||
| installPeersFromEnvs, | ||
| resolveEnvPeersFromRoot, |
There was a problem hiding this comment.
Pull request overview
This PR changes Bit’s dependency resolution so env peer dependencies from env.jsonc are generally resolved once and merged into the workspace root manifest (instead of being injected into every component manifest), with new config flags to control conflict handling and new per-peer workspaceSingleton / overrides behaviors.
Changes:
- Add workspace-level config to control root-merging of env peers (
resolveEnvPeersFromRoot,forceEnvPeersToRoot) and implement root-merge + conflict handling logic. - Add per-peer flags in env policy (
workspaceSingleton,overrides) and plumb through to resolution/installation (including generating pnpm overrides). - Improve
env.jsoncJSONC parse errors with env name + file path context.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| workspace-jsonc-schema.json | Documents the new workspace.jsonc config flags in the schema. |
| scopes/workspace/workspace/workspace.ts | Improves env.jsonc parse error messaging (env id + file path). |
| scopes/workspace/install/install.main.runtime.ts | Threads resolveEnvPeersFromRoot into manifest calculation and merges env-generated overrides with workspace overrides. |
| scopes/envs/envs/environments.main.runtime.ts | Improves env.jsonc parse error messaging (env name + file path) using BitError. |
| scopes/envs/envs/env-jsonc.detector.ts | Wraps env.jsonc parsing with a clearer error message. |
| scopes/dependencies/dependency-resolver/policy/variant-policy/variant-policy.ts | Extends policy entry values to carry workspaceSingleton / overrides. |
| scopes/dependencies/dependency-resolver/policy/env-policy/env-policy.ts | Adds env peer entry flags + threads envId for better reporting/merging. |
| scopes/dependencies/dependency-resolver/package-manager.ts | Adds resolveEnvPeersFromRoot to install options plumbing. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest.ts | Merges env peers into root manifest as “defaults” while preserving workspace policy priority; carries peerOverrides. |
| scopes/dependencies/dependency-resolver/manifest/workspace-manifest-factory.ts | Implements root-merge algorithm, conflict resolution, per-component injection for conflicts, and override generation. |
| scopes/dependencies/dependency-resolver/dependency-resolver.main.runtime.ts | Wires the new config flags into workspace manifest creation and passes envId into EnvPolicy. |
| scopes/dependencies/dependency-resolver/dependency-resolver-workspace-config.ts | Adds the two new workspace config options with documentation comments. |
| scopes/dependencies/dependency-resolver/dependency-installer.ts | Updates manifest generation API to return peerOverrides alongside manifests and passes the new flag through. |
You can also share your feedback on Copilot code review. Take the survey.
| // Skip "+" placeholder — it's resolved at the workspace root level | ||
| if (version === '+') continue; | ||
| for (const envId of envIds) { | ||
| if (!componentPeerOverrides.has(envId)) { | ||
| componentPeerOverrides.set(envId, {}); | ||
| } | ||
| componentPeerOverrides.get(envId)![pkgName] = version; |
| // Filter out non-semver versions (like '+') for comparison | ||
| const semverVersions = versions.filter((v) => v !== '+' && semver.coerce(v) !== null); | ||
|
|
||
| if (semverVersions.length === 0) { | ||
| // All versions are non-semver (e.g., '+'), just pick the first | ||
| return versions[0]; | ||
| } | ||
|
|
||
| // For each version, count how many envs it could satisfy | ||
| let bestVersion = semverVersions[0]; | ||
| let bestCount = 0; | ||
|
|
||
| for (const candidateVersion of semverVersions) { | ||
| const coercedCandidate = semver.coerce(candidateVersion); | ||
| if (!coercedCandidate) continue; | ||
| let satisfiedCount = 0; | ||
| for (const [version, envIds] of envsByVersion) { | ||
| if (version === candidateVersion || version === '+') { | ||
| satisfiedCount += envIds.size; | ||
| } else if (semver.validRange(version)) { | ||
| // Check if the candidate could satisfy the range | ||
| if (semver.satisfies(coercedCandidate.version, version)) { | ||
| satisfiedCount += envIds.size; | ||
| } | ||
| } |
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zubeyralmaho
left a comment
There was a problem hiding this comment.
Detailed Code Review
Great architectural change — merging env peer deps to the workspace root instead of per-component injection is a significant improvement for both manifest size and IDE resolution. The backward-compatible resolveEnvPeersFromRoot: false escape hatch is a wise call. Here are my findings after going through all 13 changed files:
1. semver.coerce may misinterpret version ranges (workspace-manifest-factory.ts)
In resolveConflictingPeerVersions, semver.coerce is used to normalize versions for comparison. However, coerce can produce surprising results with range strings:
semver.coerce('^18.3.1') // → SemVer { version: '18.3.1' } ✓ (happens to work)
semver.coerce('>=16.8.0') // → SemVer { version: '16.8.0' } (extracts first number-like segment)
semver.coerce('~17.0.0 || ^18.0.0') // → SemVer { version: '17.0.0' } (only first part)If envs use supportedRange-style values (e.g., >=16.8.0 <19), coerce will silently extract a partial version. Consider using semver.minVersion(range) which is designed for ranges, falling back to semver.coerce only for exact versions:
const parsed = semver.validRange(candidateVersion)
? semver.minVersion(candidateVersion)
: semver.coerce(candidateVersion);2. Missing unit tests for core resolution logic
This PR introduces ~230 lines of new logic in mergeEnvPeersToRoot and resolveConflictingPeerVersions — these are the most critical functions in the entire change. They handle conflict resolution, singleton logic, and per-component fallback, but there are no unit tests covering:
- Two envs with the same peer at different versions (conflict path)
workspaceSingleton: trueforcing root resolutionoverride: truegenerating pnpm overrides- The
+placeholder version being skipped correctly in per-component injection - Workspace component packages being excluded from peer resolution
- The "majority wins" version selection algorithm
Since WorkspaceManifestFactory methods are private, testing could be done via the createFromComponents public API with mocked ComponentsManifestsMap entries. This logic is complex enough that it would really benefit from direct test coverage.
3. logger is optional but silently swallows conflict warnings (workspace-manifest-factory.ts)
constructor(
private dependencyResolver: DependencyResolverMain,
private aspectLoader: AspectLoaderMain,
private logger?: Logger, // ← optional
...
)When logger is undefined, all conflict warnings (this.logger?.consoleWarning?.(...)) and the hint message (this.logger?.console?.(...)) are silently dropped. In dependency-resolver.main.runtime.ts, the logger is always passed, so this isn't a runtime issue today. But making it required (non-optional) would make the contract explicit and prevent future callers from accidentally missing it.
4. injectConflictingPeersToComponents spread order concern (workspace-manifest-factory.ts)
manifest.dependencies.dependencies = {
...overrides, // env peer version
...manifest.dependencies.dependencies, // existing component deps
};The existing component deps win over the env peer overrides due to spread order. Is this intentional? If a component explicitly depends on react@17 but its env says react@18, the component's version wins. This seems correct for respecting explicit component dependencies, but it's worth a comment explaining the precedence since it's the opposite of what "override" typically implies.
5. Capsule hardcoded to false without explanation (dependency-resolver.main.runtime.ts)
const resolveEnvPeersFromRoot = context?.inCapsule ? false : (this.config.resolveEnvPeersFromRoot ?? true);This silently disables the feature for capsule environments. A brief comment explaining why capsules need per-component injection (e.g., isolated builds need self-contained manifests) would help future maintainers understand this isn't a bug.
6. entriesFromKey behavior change for non-peer entries (env-policy.ts)
const hasPeerProps = 'workspaceSingleton' in entry || 'override' in entry;
const value = hasPeerProps
? { version: entry[versionKey], workspaceSingleton: peerEntry.workspaceSingleton, override: peerEntry.override }
: entry[versionKey];This hasPeerProps check is applied to all policy keys (peers, dev, runtime), not just peers. If someone accidentally adds workspaceSingleton to a dev or runtime entry in env.jsonc, it would silently change the value format from string to object. Consider scoping this check to only the peers key:
const hasPeerProps = keyName === 'peers' && ('workspaceSingleton' in entry || 'override' in entry);7. toJson workspace.jsonc priority logic — race between two options (workspace-manifest.ts)
if (options.installPeersFromEnvs || options.resolveEnvPeersFromRoot) {Both installPeersFromEnvs and resolveEnvPeersFromRoot can trigger peer injection, but they now have different behaviors: the old path uses Object.assign (env wins), while the new path checks alreadyDefined (workspace wins). If both flags are somehow true simultaneously, the new "workspace wins" logic runs — is this the intended precedence? A comment or assertion would clarify.
8. Env.jsonc parse error improvement is a nice bonus
The try/catch additions in env-jsonc.detector.ts, environments.main.runtime.ts, and workspace.ts are a great quality-of-life improvement — including the file path and env name in parse errors will save debugging time. Clean and well-placed.
Summary
The overall design is solid. The layered conflict resolution (no-conflict → singleton → per-component) is well thought out, and the workspace.jsonc schema additions are well-documented. My main concerns are around the semver.coerce edge case in version resolution, and the lack of unit tests for the core algorithm. The rest are minor suggestions.
Nice work! 👏
Summary
workspaceSingletonsupport: New per-peer flag in env.jsonc that forces single-version resolution at workspace root even when envs conflict. Useful for@types/*packages and workspace-level tools (eslint, prettier).overridessupport: New per-peer boolean in env.jsonc that generates a pnpm override for that peer, forcing all transitive dependencies to use the same version. workspace.jsonc overrides take precedence.workspaceSingletonare injected per-component, allowing different envs to use different versions (e.g. React 18 and React 19 in the same workspace).New workspace.jsonc config options
resolveEnvPeersFromRoottruefalsefor legacy per-component injection.forceEnvPeersToRootfalseNew env.jsonc peer entry properties
{ "policy": { "peers": [ { "name": "@types/react", "version": "18.3.1", "supportedRange": "^18.0.0", "workspaceSingleton": true // force single version at workspace root }, { "name": "react", "version": "19.0.0", "supportedRange": "^19.0.0", "overrides": true // generate pnpm override to pin transitive deps } ] } }Tested
bit installworks on complex workspaces with multiple envs — env peers merged to root correctlyworkspaceSingleton: trueresolves conflicts to a single version at rootoverrides: truegenerates pnpm overrides🤖 Generated with Claude Code