Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4.3 KiB
4.3 KiB
name, description
| name | description |
|---|---|
| pnpm-hooks | Customize package resolution and dependency behavior with pnpmfile hooks |
pnpm Hooks
pnpm provides hooks via .pnpmfile.cjs to customize how packages are resolved and their metadata is processed.
Setup
Create .pnpmfile.cjs at workspace root:
// .pnpmfile.cjs
function readPackage(pkg, context) {
// Modify package metadata
return pkg
}
function afterAllResolved(lockfile, context) {
// Modify lockfile
return lockfile
}
module.exports = {
hooks: {
readPackage,
afterAllResolved
}
}
readPackage Hook
Called for every package before resolution. Use to modify dependencies, add missing peer deps, or fix broken packages.
Add Missing Peer Dependency
function readPackage(pkg, context) {
if (pkg.name === 'some-broken-package') {
pkg.peerDependencies = {
...pkg.peerDependencies,
react: '*'
}
context.log(`Added react peer dep to ${pkg.name}`)
}
return pkg
}
Override Dependency Version
function readPackage(pkg, context) {
// Fix all lodash versions
if (pkg.dependencies?.lodash) {
pkg.dependencies.lodash = '^4.17.21'
}
if (pkg.devDependencies?.lodash) {
pkg.devDependencies.lodash = '^4.17.21'
}
return pkg
}
Remove Unwanted Dependency
function readPackage(pkg, context) {
// Remove optional dependency that causes issues
if (pkg.optionalDependencies?.fsevents) {
delete pkg.optionalDependencies.fsevents
}
return pkg
}
Replace Package
function readPackage(pkg, context) {
// Replace deprecated package
if (pkg.dependencies?.['old-package']) {
pkg.dependencies['new-package'] = pkg.dependencies['old-package']
delete pkg.dependencies['old-package']
}
return pkg
}
Fix Broken Package
function readPackage(pkg, context) {
// Fix incorrect exports field
if (pkg.name === 'broken-esm-package') {
pkg.exports = {
'.': {
import: './dist/index.mjs',
require: './dist/index.cjs'
}
}
}
return pkg
}
afterAllResolved Hook
Called after the lockfile is generated. Use for post-resolution modifications.
function afterAllResolved(lockfile, context) {
// Log all resolved packages
context.log(`Resolved ${Object.keys(lockfile.packages || {}).length} packages`)
// Modify lockfile if needed
return lockfile
}
Context Object
The context object provides utilities:
function readPackage(pkg, context) {
// Log messages
context.log('Processing package...')
return pkg
}
Use with TypeScript
For type hints, use JSDoc:
// .pnpmfile.cjs
/**
* @param {import('type-fest').PackageJson} pkg
* @param {{ log: (msg: string) => void }} context
* @returns {import('type-fest').PackageJson}
*/
function readPackage(pkg, context) {
return pkg
}
module.exports = {
hooks: {
readPackage
}
}
Common Patterns
Conditional by Package Name
function readPackage(pkg, context) {
switch (pkg.name) {
case 'package-a':
pkg.dependencies.foo = '^2.0.0'
break
case 'package-b':
delete pkg.optionalDependencies.bar
break
}
return pkg
}
Apply to All Packages
function readPackage(pkg, context) {
// Remove all optional fsevents
if (pkg.optionalDependencies) {
delete pkg.optionalDependencies.fsevents
}
return pkg
}
Debug Resolution
function readPackage(pkg, context) {
if (process.env.DEBUG_PNPM) {
context.log(`${pkg.name}@${pkg.version}`)
context.log(` deps: ${Object.keys(pkg.dependencies || {}).join(', ')}`)
}
return pkg
}
Hooks vs Overrides
| Feature | Hooks (.pnpmfile.cjs) | Overrides |
|---|---|---|
| Complexity | Can use JavaScript logic | Declarative only |
| Scope | Any package metadata | Version only |
| Use case | Complex fixes, conditional logic | Simple version pins |
Prefer overrides for simple version fixes. Use hooks when you need:
- Conditional logic
- Non-version modifications (exports, peer deps)
- Logging/debugging
Troubleshooting
Hook not running
- Ensure file is named
.pnpmfile.cjs(not.js) - Check file is at workspace root
- Run
pnpm installto trigger hooks
Debug hooks
# See hook logs
pnpm install --reporter=append-only