Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .agents/skills/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ This directory contains all Claude Code skills for the web-widgets repository.
├── openspec-onboard/ # Guided OpenSpec onboarding
├── openspec-propose/ # Propose new change with all artifacts
├── openspec-sync-specs/ # Sync delta specs to main specs
└── openspec-verify-change/ # Verify implementation matches artifacts
├── openspec-verify-change/ # Verify implementation matches artifacts
└── bump-transitive/ # Surgically bump a vulnerable transitive dependency
```

## Usage
Expand All @@ -28,6 +29,7 @@ Skills are automatically loaded by Claude Code. Users can invoke them via slash
- `/code-review` — Review current PR
- `/debug-widget` — Debug widget runtime issues
- `/openspec-*` or `/opsx:*` — OpenSpec workflow commands
- `/bump-transitive` — Bump a vulnerable transitive dep to its latest safe patch per major

## Skill Format

Expand Down
103 changes: 103 additions & 0 deletions .agents/skills/bump-transitive/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
---
name: bump-transitive
description: Surgically bump a vulnerable transitive dependency to its latest patch per major using pnpm.overrides, then clean up without leaving override traces in package.json.
---

# Fix Vulnerable Transitive Dependency

Use when a security advisory identifies a vulnerable transitive package (one not directly in any `package.json`) and you need to force it to a safe version across the monorepo without bumping unrelated packages.

The user will provide the package name and the fixed versions from the advisory.

## Process

### 1. Discover all versions in use

Run `pnpm why -r` to see every resolved version and the full dependency chain explaining why each exists:

```sh
pnpm why -r <package>
```

Each top-level line (`<package>@x.y.z`) is a distinct version in the graph. The tree below it shows which packages pull it in — useful for understanding whether a version can be collapsed or must stay separate.

To extract just the version list:

```sh
pnpm why -r <package> | grep '^<package>@'
```

### 2. Find latest safe version per major

For each major currently in the lockfile, find the latest available version on npm:

```sh
npm view <package> versions --json | node -e "
const v = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
const majors = {};
v.forEach(ver => {
const m = parseInt(ver.split('.')[0]);
if (!majors[m]) majors[m] = [];
majors[m].push(ver);
});
Object.entries(majors).forEach(([m, vers]) => {
console.log('Major', m, '— latest:', vers[vers.length-1]);
});
"
```

Cross-reference with the advisory's "Fixed in" versions — use whichever is higher.

### 3. Add overrides to root package.json

In the `pnpm.overrides` section of the root `package.json`, add one entry per major using the `@major` selector syntax:

```json
"pnpm": {
"overrides": {
"<package>@1": "1.x.y",
"<package>@2": "2.x.y",
"<package>@5": "5.x.y"
}
}
```

Only add majors that are actually present in the lockfile.

### 4. First pnpm install — update the lockfile

```sh
pnpm install
```

This writes the pinned versions into `pnpm-lock.yaml`.

### 5. Remove the overrides from package.json

Delete the entries added in step 3. The lockfile now has the correct versions recorded and will enforce them on its own.

### 6. Second pnpm install — clean up

```sh
pnpm install
```

This removes the override snapshot from the lockfile's config block and leaves a clean state: no trace of the rewrite in `package.json`, no stale override metadata in the lockfile.

### 7. Verify

Check that the lockfile diff is surgical — only the target package versions changed:

```sh
git diff pnpm-lock.yaml | grep '^[-+]' | grep -v '^---\|^+++' | grep -v '<package>'
```

The only non-target lines should be inconsequential formatting shuffles (identical values on both sides of the diff). If other packages were bumped, investigate before proceeding.

## Rules

- **Never run `pnpm update` or `pnpm upgrade`** — these re-resolve the entire dependency graph.
- **Never delete `pnpm-lock.yaml`** — regenerating it from scratch bumps everything within semver ranges.
- **Never use `--frozen-lockfile`** on either install — the first install must update the lockfile, the second must reconcile the config snapshot.
- Only add overrides for majors actually present in the lockfile — do not add speculative entries.
- If the package is a **direct** dependency (appears in a `package.json` `dependencies`/`devDependencies`), edit that file directly instead of using overrides.
Loading