feat: Complete fleet — 94 skills across 10+ domains
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>
This commit is contained in:
233
skills/pnpm/references/features-hooks.md
Normal file
233
skills/pnpm/references/features-hooks.md
Normal file
@@ -0,0 +1,233 @@
|
||||
---
|
||||
name: pnpm-hooks
|
||||
description: 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:
|
||||
|
||||
```js
|
||||
// .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
|
||||
|
||||
```js
|
||||
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
|
||||
|
||||
```js
|
||||
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
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Remove optional dependency that causes issues
|
||||
if (pkg.optionalDependencies?.fsevents) {
|
||||
delete pkg.optionalDependencies.fsevents
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
### Replace Package
|
||||
|
||||
```js
|
||||
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
|
||||
|
||||
```js
|
||||
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.
|
||||
|
||||
```js
|
||||
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:
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Log messages
|
||||
context.log('Processing package...')
|
||||
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
## Use with TypeScript
|
||||
|
||||
For type hints, use JSDoc:
|
||||
|
||||
```js
|
||||
// .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
|
||||
|
||||
```js
|
||||
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
|
||||
|
||||
```js
|
||||
function readPackage(pkg, context) {
|
||||
// Remove all optional fsevents
|
||||
if (pkg.optionalDependencies) {
|
||||
delete pkg.optionalDependencies.fsevents
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
### Debug Resolution
|
||||
|
||||
```js
|
||||
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
|
||||
|
||||
1. Ensure file is named `.pnpmfile.cjs` (not `.js`)
|
||||
2. Check file is at workspace root
|
||||
3. Run `pnpm install` to trigger hooks
|
||||
|
||||
### Debug hooks
|
||||
|
||||
```bash
|
||||
# See hook logs
|
||||
pnpm install --reporter=append-only
|
||||
```
|
||||
|
||||
<!--
|
||||
Source references:
|
||||
- https://pnpm.io/pnpmfile
|
||||
-->
|
||||
Reference in New Issue
Block a user