[TERMINAL · SKILLS]
> mounting /skills...
> indexing skill manifests...
> linking agents: claude · codex · gemini · cursor
> ready.
[░░░░░░░░░░░░░░░░░░░░░░░░░░░░] 0%
Use Cases/Build an Automated Dependency Update Pipeline

Build an Automated Dependency Update Pipeline

Automate npm/pip dependency updates with vulnerability scanning, compatibility testing, and auto-merge for safe updates — keeping 200 dependencies current and closing CVEs in hours instead of months.

Development#typescript#tsconfig#type-checking#type-safety#javascript-migration
Works with:claude-codeopenai-codexgemini-clicursor

Skills stack · 5 skills

Avg quality 97/100·All SAFE
>

typescript

v1.0.0

Sets up and repairs TypeScript projects: picks tsconfig.json settings for a Node.js service, an npm library or a bundled web app, runs type-checking in CI, and replaces `any` and unsafe casts with types the compiler can verify. Use when someone asks to "set up TypeScript", "fix this tsconfig", "fix a TypeScript error", "upgrade to TypeScript 6 or 7", "migrate JavaScript to TypeScript", "publish types for a package", "run .ts files in Node" or "make this type-safe". Covers the changed defaults in TypeScript 6.0 and 7.0, module and moduleResolution, strict mode, project references, declaration output, narrowing, satisfies and common compiler errors.

93/100 quality
7.30× impact
SAFE· stale score
View skill
>

github-actions

v1.1.0

GitHub Actions runs CI/CD pipelines defined as YAML workflows inside a GitHub repository. Use when someone asks to "set up CI", "add a GitHub Actions workflow", "run tests on every pull request", "cache dependencies", "build a matrix", "deploy from Actions", "push a Docker image to ghcr.io" or "reuse a workflow", or needs triggers, secrets, environments, artifacts and permissions explained.

100/100 quality
2.66× impact
SAFE· stale score
View skill
>

docker-helper

v1.1.0

Build, debug, and optimize Docker configurations. Use when a user asks to create a Dockerfile, fix Docker build errors, optimize image size, write docker-compose files, debug container issues, set up multi-stage builds, or troubleshoot networking between containers. Covers Dockerfile best practices and compose orchestration.

100/100 quality
1.44× impact
SAFE· stale score
View skill
>

vitest

v1.1.0

Vitest is a test runner for JavaScript and TypeScript built on Vite, with a Jest-compatible API, built-in mocking, snapshots and code coverage. Use when a user asks to set up or run unit tests in a Vite or Node project, write tests with describe/it/expect, mock modules with vi.mock, add coverage thresholds, configure vitest.config.ts or test projects, migrate from Jest, or upgrade to Vitest 5.

100/100 quality
1.50× impact
SAFE· stale score
View skill
>

zod

v1.1.0

Zod is a TypeScript-first schema library that validates data at runtime and infers static types from the same schema. Use when validating API request bodies, form input, environment variables or config files, parsing untrusted JSON, or migrating from Zod 3 to Zod 4. Covers z.object, safeParse, z.infer, coercion, discriminated unions, refinements, JSON Schema output and the v4 API changes.

93/100 quality
3.87× impact
SAFE· stale score
View skill
$

The Problem

A monorepo has 200+ npm dependencies. Nobody updates them — "if it works, don't touch it." Result: 47 known CVEs across transitive dependencies, 3 are critical. The team tried Dependabot but got 50 PRs per week that nobody reviews. When someone finally updates a major dependency, it breaks 3 things because the codebase was 18 months behind. A security audit flags the CVEs, and now it's a 2-week emergency project to update everything at once.

Step 1: Dependency Scanner and Risk Scorer

typescript
// src/deps/scanner.ts
import { z } from 'zod';
import { execSync } from 'child_process';

const DependencyUpdate = z.object({
  name: z.string(),
  currentVersion: z.string(),
  latestVersion: z.string(),
  updateType: z.enum(['patch', 'minor', 'major']),
  isDevDep: z.boolean(),
  hasBreakingChanges: z.boolean(),
  cveCount: z.number().int(),
  cveSeverity: z.enum(['none', 'low', 'medium', 'high', 'critical']),
  riskScore: z.number().min(0).max(100),
  autoMergeable: z.boolean(),
  changelog: z.string().optional(),
});

export async function scanDependencies(): Promise<z.infer<typeof DependencyUpdate>[]> {
  // Get outdated packages
  const outdatedRaw = execSync('npm outdated --json 2>/dev/null || true', { encoding: 'utf8' });
  const outdated = JSON.parse(outdatedRaw || '{}');

  // Get audit results
  const auditRaw = execSync('npm audit --json 2>/dev/null || true', { encoding: 'utf8' });
  const audit = JSON.parse(auditRaw || '{"vulnerabilities":{}}');

  const updates: z.infer<typeof DependencyUpdate>[] = [];

  for (const [name, info] of Object.entries(outdated) as any) {
    const updateType = getUpdateType(info.current, info.latest);
    const vulns = audit.vulnerabilities?.[name];
    const maxSeverity = vulns?.severity ?? 'none';
    const cveCount = vulns?.via?.length ?? 0;

    const riskScore = calculateRisk(updateType, maxSeverity, info.type === 'devDependencies');
    const autoMergeable = riskScore < 30; // Low-risk updates auto-merge

    updates.push({
      name,
      currentVersion: info.current,
      latestVersion: info.latest,
      updateType,
      isDevDep: info.type === 'devDependencies',
      hasBreakingChanges: updateType === 'major',
      cveCount,
      cveSeverity: maxSeverity,
      riskScore,
      autoMergeable,
    });
  }

  return updates.sort((a, b) => b.riskScore - a.riskScore);
}

function getUpdateType(current: string, latest: string): 'patch' | 'minor' | 'major' {
  const [cMajor, cMinor] = current.split('.').map(Number);
  const [lMajor, lMinor] = latest.split('.').map(Number);
  if (cMajor !== lMajor) return 'major';
  if (cMinor !== lMinor) return 'minor';
  return 'patch';
}

function calculateRisk(updateType: string, severity: string, isDev: boolean): number {
  let score = 0;

  // Update type risk
  if (updateType === 'major') score += 50;
  else if (updateType === 'minor') score += 20;
  else score += 5;

  // CVE severity
  const severityScores: Record<string, number> = { critical: 40, high: 30, medium: 15, low: 5, none: 0 };
  score += severityScores[severity] ?? 0;

  // Dev dependencies are lower risk
  if (isDev) score = Math.floor(score * 0.5);

  return Math.min(100, score);
}

Step 2: Update Strategy Engine

typescript
// src/deps/strategy.ts
import type { DependencyUpdate } from './scanner';

interface UpdateBatch {
  name: string;
  updates: DependencyUpdate[];
  strategy: 'auto-merge' | 'test-then-merge' | 'manual-review';
  priority: number;
}

export function createUpdateBatches(updates: DependencyUpdate[]): UpdateBatch[] {
  const batches: UpdateBatch[] = [];

  // Batch 1: Critical CVEs (immediate, individual PRs)
  const criticalCVEs = updates.filter(u => u.cveSeverity === 'critical' || u.cveSeverity === 'high');
  for (const update of criticalCVEs) {
    batches.push({
      name: `security: ${update.name}@${update.latestVersion}`,
      updates: [update],
      strategy: update.updateType === 'patch' ? 'auto-merge' : 'test-then-merge',
      priority: 1,
    });
  }

  // Batch 2: Safe patches (grouped, auto-merge)
  const safePatches = updates.filter(u =>
    u.updateType === 'patch' && u.cveSeverity === 'none' && !criticalCVEs.includes(u)
  );
  if (safePatches.length > 0) {
    batches.push({
      name: `chore: patch updates (${safePatches.length} packages)`,
      updates: safePatches,
      strategy: 'auto-merge',
      priority: 3,
    });
  }

  // Batch 3: Dev dependency updates (grouped, auto-merge)
  const devUpdates = updates.filter(u =>
    u.isDevDep && u.updateType !== 'major' && !criticalCVEs.includes(u) && !safePatches.includes(u)
  );
  if (devUpdates.length > 0) {
    batches.push({
      name: `chore: dev dependency updates (${devUpdates.length} packages)`,
      updates: devUpdates,
      strategy: 'auto-merge',
      priority: 4,
    });
  }

  // Batch 4: Minor updates (test first)
  const minorUpdates = updates.filter(u =>
    u.updateType === 'minor' && !u.isDevDep && !criticalCVEs.includes(u)
  );
  if (minorUpdates.length > 0) {
    batches.push({
      name: `chore: minor updates (${minorUpdates.length} packages)`,
      updates: minorUpdates,
      strategy: 'test-then-merge',
      priority: 5,
    });
  }

  // Batch 5: Major updates (individual PRs, manual review)
  const majorUpdates = updates.filter(u => u.updateType === 'major' && !criticalCVEs.includes(u));
  for (const update of majorUpdates) {
    batches.push({
      name: `feat: upgrade ${update.name} to ${update.latestVersion}`,
      updates: [update],
      strategy: 'manual-review',
      priority: 10,
    });
  }

  return batches.sort((a, b) => a.priority - b.priority);
}

Step 3: GitHub Actions Workflow

yaml
# .github/workflows/dependency-updates.yml
name: Automated Dependency Updates
on:
  schedule:
    - cron: '0 6 * * 1' # Monday 6 AM
  workflow_dispatch:

jobs:
  scan-and-update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci

      - name: Scan dependencies
        run: npx tsx src/deps/scanner.ts > scan-results.json

      - name: Create update batches
        run: npx tsx src/deps/strategy.ts < scan-results.json > batches.json

      - name: Apply updates and create PRs
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          BATCHES=$(cat batches.json)
          echo "$BATCHES" | node -e "
            const fs = require('fs');
            const batches = JSON.parse(fs.readFileSync('/dev/stdin', 'utf8'));
            
            for (const batch of batches) {
              console.log('Processing: ' + batch.name);
              console.log('Strategy: ' + batch.strategy);
              console.log('Updates: ' + batch.updates.map(u => u.name + '@' + u.latestVersion).join(', '));
              console.log('---');
            }
          "

      - name: Run tests for auto-merge candidates
        run: npm test

      - name: Auto-merge safe updates
        if: success()
        run: echo "Auto-merging safe patches..."

Results

  • CVE closure time: hours (was months — 47 CVEs fixed in first week)
  • Critical CVEs: auto-patched same day they're published
  • 50 Dependabot PRs/week: replaced by 3-5 batched, prioritized PRs
  • Safe patch auto-merge: 60% of updates merged without human review
  • Major version lag: never more than 1 major version behind
  • Security audit: zero CVE findings (was 47)
  • Developer time on deps: 1 hour/week reviewing major updates (was 0 hours = ignored)

Related use cases