Skip to content

feat(add): linkWorkspacePackages + saveWorkspaceProtocol#539

Merged
jdx merged 3 commits intomainfrom
feat/link-workspace-packages
May 8, 2026
Merged

feat(add): linkWorkspacePackages + saveWorkspaceProtocol#539
jdx merged 3 commits intomainfrom
feat/link-workspace-packages

Conversation

@jdx
Copy link
Copy Markdown
Contributor

@jdx jdx commented May 7, 2026

Summary

Closes the workspace-protocol gap surfaced by pnpm's monorepo/index.ts batch 2 ports. Two new settings on aube add:

  • linkWorkspacePackages (bool, default false): when true, aube add <name> prefers a local workspace sibling over the registry. The packument fetch is skipped, the manifest specifier is built from saveWorkspaceProtocol, and the resolver picks up the local copy on the next install (existing aube behavior on bare semver ranges, so no resolver change required).
  • saveWorkspaceProtocol ("true" | "false" | "rolling", default "rolling"): controls the spec form written to package.json. rolling writes workspace:^ (no version), true writes workspace:^<version>, false writes ^<version>. The --save-workspace-protocol / --no-save-workspace-protocol CLI flags override per-invocation.

update_manifest_for_add now reads settings from the workspace yaml root rather than the immediate project dir so a sub-project's add picks up the workspace-wide policy.

Tests

Bats ports in test/pnpm_monorepo_index.bats:

  • pnpm/test/monorepo/index.ts:112 (default saveWorkspaceProtocol, --save-dev, --save-optional --no-save-workspace-protocol)
  • pnpm/test/monorepo/index.ts:156 (explicit saveWorkspaceProtocol: rolling)
  • aube-side regression guard for saveWorkspaceProtocol: true (no pnpm equivalent; the three protocol variants share one code path so coverage of the third form is the only way to catch a silent regression there)

Test plan

  • cargo clippy --all-targets -- -D warnings
  • cargo fmt --check
  • cargo test -p aube (430 tests)
  • bats test/pnpm_monorepo_index.bats (9 tests, all green)

🤖 Generated with Claude Code


Note

Medium Risk
Changes aube add dependency resolution and manifest-writing behavior in workspaces, which can alter package.json specifiers and skip registry fetches based on new settings/flags. Risk is moderated by explicit opt-in defaults, guardrails for aliases/range mismatches, and added bats coverage.

Overview
aube add can now prefer local workspace siblings over the registry via new linkWorkspacePackages (default false), skipping packument fetches when a matching sibling exists and writing the manifest entry according to saveWorkspaceProtocol (rolling workspace:^, pinned workspace:^<version>, or registry-style ^<version>).

Adds --save-workspace-protocol and --no-save-workspace-protocol flags to override the per-workspace policy for a single invocation, reads these workspace-owned settings from the workspace-yaml root (so subprojects honor workspace policy), updates workspace yaml schema/docs/CLI help generation, and introduces new bats tests covering rolling/pinned/opt-out behavior plus regression guards for aliases and explicit range mismatches.

Reviewed by Cursor Bugbot for commit 195e61d. Bugbot is set up for automated code reviews on this repo. Configure here.

Two new workspace settings on `aube add`, matching pnpm's CLI:

- `linkWorkspacePackages` (bool, default false): when true,
  `aube add <name>` prefers a local workspace sibling over the
  registry. The packument fetch is skipped, the manifest specifier
  is built from `saveWorkspaceProtocol`, and the resolver picks up
  the local copy on the next install (existing aube behavior on
  bare semver ranges).
- `saveWorkspaceProtocol` (`"true" | "false" | "rolling"`, default
  `"rolling"`): controls the spec form written to package.json.
  `rolling` writes `workspace:^` (no version), `true` writes
  `workspace:^<version>`, `false` writes `^<version>`. The
  `--save-workspace-protocol` / `--no-save-workspace-protocol`
  CLI flags override per-invocation.

`update_manifest_for_add` now reads its settings from the workspace
yaml root rather than the immediate project dir so a sub-project's
add picks up the workspace-wide policy.

Closes the workspace-protocol gap for the monorepo/index.ts batch-2
ports. Bats coverage at `test/pnpm_monorepo_index.bats`:

- monorepo/index.ts:112 (default save-workspace-protocol)
- monorepo/index.ts:156 (`saveWorkspaceProtocol: rolling`)
- regression guard for `saveWorkspaceProtocol: true` (no pnpm
  equivalent; the three protocol variants share one code path)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 7, 2026

Greptile Summary

This PR closes the workspace-protocol gap for aube add by introducing two new settings — linkWorkspacePackages and saveWorkspaceProtocol — along with matching --save-workspace-protocol / --no-save-workspace-protocol CLI flags. Both issues surfaced in the prior review cycle are resolved: the aliased-spec guard (spec.alias.is_some()) is now in the eligibility block, and the workspace_protocol_override tri-state is computed via a shared workspace_protocol_override_from_flags helper used by both run() and from_args().

  • linkWorkspacePackages (default false) makes aube add <name> prefer a local workspace sibling over the registry; explicit version ranges that the sibling cannot satisfy correctly fall through to the registry path.
  • saveWorkspaceProtocol (rolling / true / false, default rolling) controls the manifest spec form; workspace_settings_cwd reads settings from the workspace yaml root so sub-project adds honour the workspace-wide policy.
  • Six new bats tests cover the rolling/pinned/registry variants, aliased-spec regression, and version-range mismatch/match guards.

Confidence Score: 5/5

The workspace-linking logic is well-guarded against tricky edge cases and the manifest-write branching is correct across all three saveWorkspaceProtocol variants.

Both defects identified in the previous review round are demonstrably fixed in this diff. The eligibility guards, version-satisfies check, spec-form selection, and per-invocation override all behave correctly under the scenarios tested and the edge cases examined during review. The bats suite provides concrete regression coverage for every code path including the aliased-spec and version-mismatch cases.

No files require special attention.

Important Files Changed

Filename Overview
crates/aube/src/commands/add.rs Core implementation of linkWorkspacePackages and saveWorkspaceProtocol; aliased-spec guard (spec.alias.is_some()) correctly added, workspace_protocol_override_from_flags helper eliminates the duplicate computation flagged in the prior review.
crates/aube-manifest/src/workspace.rs Adds link_workspace_packages (Option) and save_workspace_protocol (Option<yaml_serde::Value>) fields to WorkspaceConfig; "deep" is explicitly documented as unsupported so the plain-bool typing is intentional.
crates/aube-settings/settings.toml Declares linkWorkspacePackages and saveWorkspaceProtocol with correct source chains (env, npmrc, workspaceYaml); no CLI source intentionally since the flags are handled in AddArgs.
test/pnpm_monorepo_index.bats Six new bats tests cover rolling/pinned/registry spec forms, aliased-spec regression, version-range mismatch guard, and version-range match; well-structured fixture and assertions.
aube.usage.kdl Adds --save-workspace-protocol and --no-save-workspace-protocol flag definitions with accurate long-help text; clap overrides_with wiring is consistent.
docs/cli/add.md Documentation for the two new flags matches the implementation; no inaccuracies found.
docs/cli/commands.json Generated JSON entries for the two new flags are consistent with the KDL and Markdown docs.
docs/settings/index.md Settings reference correctly documents both new settings, their source chains, and the intentional non-support of pnpm's "deep" value.

Reviews (3): Last reviewed commit: "fix(add): validate range against sibling..." | Re-trigger Greptile

Comment thread crates/aube/src/commands/add.rs
Comment thread crates/aube/src/commands/add.rs Outdated
Comment thread crates/aube/src/commands/add.rs Outdated
- Skip aliased specs in the linkWorkspacePackages eligibility block.
  `workspace:` resolves by manifest key, so writing
  `"my-alias": "workspace:^"` would point the resolver at a sibling
  named `my-alias` (which doesn't exist) and 404 on the registry
  fallback. Aliased specs now fall through to the registry path.
  Regression-guarded by a new bats test.
- Split the `aube add` settings context so `tag` / `savePrefix` /
  `catalogMode` keep reading from the project's own dir (`load_npmrc_entries`
  doesn't walk up, so a sub-project's `.npmrc` would have been silently
  dropped after the previous workspace-root switch). Only
  `linkWorkspacePackages` and `saveWorkspaceProtocol` now read from
  the workspace yaml root.
- DRY up the `workspace_protocol_override` tri-state: extract a single
  `workspace_protocol_override_from_flags(save, no_save)` helper and
  call it from both `run()` and `AddManifestOptions::from_args`.
- Add `linkWorkspacePackages` and `saveWorkspaceProtocol` as typed
  fields on `WorkspaceConfig` so `meta::workspace_yaml_keys_deserialize_onto_workspace_config`
  passes (Linux + Windows CI). `saveWorkspaceProtocol` is
  `Option<yaml_serde::Value>` because pnpm's setting accepts the bool
  `true`/`false` and the string `"rolling"`; the resolver normalizes
  via `SaveWorkspaceProtocol::from_str_normalized`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread crates/aube-manifest/src/workspace.rs
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 8dbfeed. Configure here.

Comment thread crates/aube/src/commands/add.rs
Two follow-up review fixes on the linkWorkspacePackages path:

- Validate the user's explicit version range against the workspace
  sibling's actual version before triggering a workspace link.
  `aube add project-2@^1.0.0` against a sibling at 2.0.0 used to
  silently write `workspace:^` and link the incompatible local
  copy; it now falls through to the registry path. Bare adds (no
  `@<range>`) keep the implicit dist-tag behavior since
  `has_explicit_range` is false in that case. Two new bats tests
  cover the satisfies-true and satisfies-false branches.
- Drop the `"deep"` mention from `linkWorkspacePackages` docs.
  The field is `Option<bool>` so `linkWorkspacePackages: "deep"`
  in `pnpm-workspace.yaml` would have failed deserialization. The
  feature is intentionally not implemented — aube's resolver
  already prefers workspace siblings on bare semver ranges, so
  pnpm's transitive-link semantics are aube's default — and the
  docs now say so explicitly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jdx jdx merged commit 9a28bd2 into main May 8, 2026
18 checks passed
@jdx jdx deleted the feat/link-workspace-packages branch May 8, 2026 12:47
@greptile-apps greptile-apps Bot mentioned this pull request May 9, 2026
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