Enforces exact version pinning for all package.json dependencies. Detects and fixes floating versions (^, ~, >, >=, <, <=) to ensure reproducible builds. Keywords include package.json, dependencies, version pinning, npm, yarn, reproducible builds, lockfile, semver, devDependencies.
Ensures all package dependencies are pinned to exact versions (no ^, ~, >, >=, <, <= prefixes). This guarantees reproducible builds across environments and prevents unexpected breaking changes from transitive dependency updates.
Invoke this skill:
yarn add - automatically detects floating versionsThe following package.json files are scanned (node_modules excluded):
find . -name "package.json" -not -path "*/node_modules/*" -not -path "*/.next/*"
Expected locations:
package.json (root monorepo)frontend/package.jsonbackend/package.jsonshared/package.jsondocs-site/package.json (if present)# Find all project package.json files
find . -name "package.json" -not -path "*/node_modules/*" -not -path "*/.next/*" -not -path "*/generated/*"
For each package.json, check for version specifiers with prefixes:
Floating (BAD):
"^1.2.3" - caret range (allows minor/patch updates)"~1.2.3" - tilde range (allows patch updates)">=1.2.3" - greater than or equal">1.2.3" - greater than"<=1.2.3" - less than or equal"<1.2.3" - less than"1.2.x" - x-range"*" - any versionPinned (GOOD):
"1.2.3" - exact version"*" - ONLY acceptable for workspace packages (e.g., "@kleidi/shared": "*")## Dependency Pin Audit Report
### Summary
- Files scanned: X
- Floating versions found: Y
- Action required: YES/NO
### Unpinned Dependencies Found
| File | Package | Current | Should Be |
| -------------------- | ------------ | ------- | --------- |
| backend/package.json | @otplib/core | ^12.0.1 | 12.0.1 |
| backend/package.json | dotenv | ^17.2.3 | 17.2.3 |
### Workspace References (Acceptable)
| File | Package | Version | Status |
| -------------------- | -------------- | ------- | -------------- |
| backend/package.json | @kleidi/shared | \* | OK (workspace) |
For each floating version, strip the prefix:
# Example: Fix a single dependency in backend/package.json
# Before: "@otplib/core": "^12.0.1"
# After: "@otplib/core": "12.0.1"
Use precise JSON editing to update only the version string, preserving formatting.
After fixing any floating versions, always run yarn install to update the lockfile:
yarn install
This ensures:
yarn.lock) reflects the exact pinned versionsRun this to find all floating versions:
# Find all floating versions in package.json files
for file in $(find . -name "package.json" -not -path "*/node_modules/*" -not -path "*/.next/*" -not -path "*/generated/*"); do
echo "=== $file ==="
# Extract dependencies and devDependencies with floating versions
node -e "
const pkg = require('$file');
const floatingPattern = /^[\^~><]/;
const check = (deps, type) => {
if (!deps) return;
Object.entries(deps).forEach(([name, version]) => {
if (floatingPattern.test(version)) {
console.log(type + ': ' + name + ' = ' + version);
}
});
};
check(pkg.dependencies, 'dep');
check(pkg.devDependencies, 'devDep');
"
done
# Remove ^ prefix from all deps in a file
sed -i '' 's/"\^/"/g' package.json
# More precise: only in dependencies/devDependencies sections
# Use Edit tool for precision
For each floating dependency, use the Edit tool to replace:
OLD: "@otplib/core": "^12.0.1"
NEW: "@otplib/core": "12.0.1"
Workspace packages (monorepo internal) use * to reference the local version:
{
"dependencies": {
"@kleidi/shared": "*" // OK - workspace reference
}
}
Some deps may use git URLs or file paths - these are acceptable:
{
"dependencies": {
"some-fork": "github:user/repo#commit" // OK - specific commit
}
}
yarn addWhen adding a new package, yarn typically adds it with ^:
yarn add some-package
# Results in: "some-package": "^1.2.3"
Immediately run dep-pinner skill to fix:
1. Run detection script
2. Fix any floating versions found
3. Run `yarn install` to update lockfile (MANDATORY for Cloudflare)
4. Verify build still works
Consider adding to Phase 5 (Commit & Push):
[Before Commit]
↓
[Dep Pinner Check] ──── FLOATING FOUND ──→ Fix & Retry
↓ ALL PINNED
[Commit]
## Dependency Pin Audit
**Status:** PASS
**Files Scanned:** 5
**Floating Versions:** 0
All dependencies are properly pinned. Ready to commit.
## Dependency Pin Audit
**Status:** FAIL - ACTION REQUIRED
**Files Scanned:** 5
**Floating Versions:** 4
### Unpinned Dependencies
#### backend/package.json
| Type | Package | Current | Fixed |
| ------ | ---------------------- | ------- | ------ |
| dep | @otplib/core | ^12.0.1 | 12.0.1 |
| dep | @otplib/preset-default | ^12.0.1 | 12.0.1 |
| dep | @simplewebauthn/server | ^13.2.2 | 13.2.2 |
| dep | dotenv | ^17.2.3 | 17.2.3 |
| dep | otplib | ^12.0.1 | 12.0.1 |
| dep | qrcode | ^1.5.4 | 1.5.4 |
| devDep | @simplewebauthn/types | ^12.0.0 | 12.0.0 |
| devDep | @types/qrcode | ^1.5.6 | 1.5.6 |
### Fix Applied
All floating versions have been pinned. Please verify with:
```bash
yarn install
git diff package.json
```
yarn install to update lockfile
## Verification After Fix
After pinning dependencies:
```bash
# 1. Reinstall to update lockfile
yarn install
# 2. Verify no floating versions remain
grep -E '"\^|"~|">=|">|"<=|"<' */package.json package.json
# 3. Run tests to ensure compatibility
yarn test
Packages frequently added with floating versions:
| Package | Typical Float | Pin To |
|---|---|---|
| @types/* | ^X.Y.Z | X.Y.Z |
| dotenv | ^X.Y.Z | X.Y.Z |
| jest | ^X.Y.Z | X.Y.Z |
| typescript | ^X.Y.Z | X.Y.Z |
| eslint | ^X.Y.Z | X.Y.Z |
| Version Format | Status | Action |
|---|---|---|
"1.2.3" | Pinned | None |
"^1.2.3" | Floating | Strip ^ |
"~1.2.3" | Floating | Strip ~ |
">=1.2.3" | Floating | Research & pin exact |
"*" (workspace) | Acceptable | None |
"*" (external) | Bad | Research & pin exact |
"git+..." | Acceptable | Verify commit hash |
Run this skill:
yarn add - immediate check