--- name: dependencies description: | Manage pure dependency changesets via the changeset_deps_regen (delete- and-recreate) and changeset_deps_detect (read-only) MCP tools. The regen flow enforces our convention of one-package-per-changeset and one- dependency-changeset-per-package. user-invocable: false allowed-tools: - savvy-mcp/changeset_deps_regen - savvy-mcp/changeset_deps_detect --- # Manage Dependency Changesets This is an agent-internal skill. The changeset-manager agent invokes it during the reconcile flow whenever a branch's diff includes changes to any `package.json`'s `dependencies` / `devDependencies` / `peerDependencies` / `optionalDependencies` fields. ## The single-package convention **Always write one package per changeset file.** Although `@changesets/cli` accepts multi-package frontmatter, this project treats one changeset = one package as the rule. `changeset_deps_regen` enforces this: it never writes a multi-package dependency changeset, and a workspace package may have at most **one** changeset file whose only content is a `## Dependencies` table. ## Primary path: `changeset_deps_regen` Call the `savvy-mcp-changeset_deps_regen` tool. Args: | Arg | Effect | | --- | --- | | `dryRun` | `true` prints the plan without writing or deleting anything. Prefer running with `dryRun: true` first to preview, then re-invoke without it (or `dryRun: false`) to apply. | | `package` | Restrict to a single workspace package. Only that package's pure-dep changeset is deleted and re-written. | | `packages` | Restrict to a list of workspace packages in one call (unioned with `package`). Prefer this over invoking the tool once per package. | | `exclude` | Skip these packages entirely: nothing is written for them and their existing changesets are left untouched. Use when one package's dep diff is already covered by a narrative changeset. | | `base` | Override the base branch (defaults to `.changeset/config.json#baseBranch`, typically `main`). | | `cwd` | Target a workspace other than the current directory. | What it does: 1. Computes the cumulative dep diff from the merge base with the project's base branch to the working tree — committed, staged, unstaged. 2. Finds every "pure dependency changeset" in `.changeset/*.md`. Strict detection: single-package frontmatter, exactly one `## Dependencies` heading, no other body content. 3. Deletes the stale ones for each package being rewritten (or, on `dryRun`, reports what it would delete). A changeset already present at the merge base is never deleted. 4. Writes one `--deps.md` (unscoped: `-deps.md`) per workspace package with current dep changes: single-package frontmatter, `patch` bump, one `## Dependencies` section, one CSH005 table (Dependency | Type | Action | From | To). The filename is derived from the package, so a re-run overwrites the same file in place and a no-op regen produces no file churn; a legacy random-named pure-dependency changeset for the same package is deleted on the first regen that rewrites it. The stable path is only written when it is free (absent, or this branch's own pure-dependency changeset for that package); a merge-base file, a prose or mixed changeset, or another package's file there is left untouched and the write goes to the first free `…-deps-2.md` sibling. **Table rows carry resolved versions and omit `devDependency` rows.** `catalog:`/`workspace:` specifiers in the table are resolved to concrete versions before they land in the changeset, and devDependency changes are excluded entirely — they don't affect the published package's contract. Use `changeset_deps_detect` when you need the full diff including devDependencies. **No-version-change field moves produce no rows.** A dependency moved between fields (e.g. `devDependencies` → `dependencies`) with the same resolved version is a contract change worth narrative prose, not a version movement — the diff drops the would-be removed/added row pair. Document such reclassifications in a hand-written changeset instead. `structuredContent` shape: ```jsonc { "root": "...", "deleted": ["..."], // changeset files removed (or would be removed, on dryRun) "written": ["..."], // changeset files written (or would be written, on dryRun) "skippedMixed": ["..."], // changesets with Dependencies + other sections — never touched "dryRun": true } ``` Present a human-readable summary by reading `deleted`, `written`, and `skippedMixed` from `structuredContent` directly — `content[0].text` is just that same object serialized as JSON, not a rendered transcript. ## Secondary path: `changeset_deps_detect` Call the `savvy-mcp-changeset_deps_detect` tool. Read-only — no `.changeset/*.md` files are written or deleted. Returns the same cumulative dependency diff `changeset_deps_regen` would act on, per workspace package, and **includes devDependency rows** (unlike regen's output). Useful when you want to *see* what would change before committing to a regen, or when folding a dep change into a hand-authored mixed changeset. Args: `base`, `package`, `packages`, `exclude`, `cwd` — same semantics as `changeset_deps_regen`. `structuredContent` shape: ```jsonc { "root": "...", "packages": [ { "package": "@scope/foo", "relativePath": "packages/foo", "rows": [ { "dependency": "effect", "type": "dependency", "action": "updated", "from": "3.18.0", "to": "3.19.1" } ] } ] } ``` ## When to invoke - **The diff touches any `package.json`'s dep fields.** Look at the `changeset_inspect` (`mode: "branch"`) result: if any of the `files[]` entries are a workspace `package.json` with `status: "modified"` or `"added"` (a brand-new package ships with its own dependencies too), call `changeset_deps_regen`. - **An existing `.changeset/*.md` has a stale Dependencies table.** `changeset_deps_regen` will detect and replace it. - **Don't run during squash** — squash is for consolidating feature/fix changesets. Dependency changesets are regenerated, not merged. ## What this skill does not do - It does not modify mixed changesets (Dependencies + other sections). Those were authored by a human and the agent leaves them alone. The `skippedMixed` array surfaces them for the user's awareness — if they want to clean up they can edit by hand. - It does not compute lockfile-only movements. Only declared dependency changes in `package.json` produce table rows. Lockfile resolution drift (e.g., `^3.0.0` resolving to `3.18.0` vs `3.19.0`) is intentionally treated as noise. - It does not promote bumps above `patch`. A peer dependency crossing a major boundary is still a `patch` for the workspace package itself — the human can hand-edit the bump if consumers need warning. ## Error handling Both tools propagate typed errors from the MCP server — no stdout parsing required: - **Success** — a typed object in `structuredContent`; `content[0].text` carries that same object serialized as JSON, not a rendered transcript. - **`GitError`** — typically a missing base branch or git command failure. Report the error message and stop. - **`WorkspaceRootNotFoundError`** — the `cwd` isn't inside a recognized workspace. Report the error message and stop.