{"_id":"npm-script-lens","_rev":"28-5ce8298fbfe3b148dea769209bb30d2d","name":"npm-script-lens","dist-tags":{"latest":"1.18.0"},"versions":{"0.3.0":{"name":"npm-script-lens","version":"0.3.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@0.3.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"7727fe814f1fa8c047113b4891493ab1007ef869","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-0.3.0.tgz","fileCount":13,"integrity":"sha512-l8+RgM4h/fbJ1UgOR7prDJ4MNOeChi/7PdCs1cCbyPi5jhTxFWvcT/oUVOrdYQMay9MigL/Ug3GCgNVXfwUCxA==","signatures":[{"sig":"MEUCIQCXAW3lPgVkik6wDnuc7X1wc7wsS98iToTMf4OhcVJtrAIgVmtUvWvEVZl0W4yw3x5fkKqkeXScKae9BUVKom6EJuM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79773},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"bfcef9d07ab90c2a2fd9c3a7d35a369f35b21414","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_0.3.0_1784639384653_0.4255101251745459","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"npm-script-lens","version":"0.3.1","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@0.3.1","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"dab047881d429fa9eed2bc5e8f783bcdb497aeb1","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-0.3.1.tgz","fileCount":13,"integrity":"sha512-3uRBqSfKn+m0ErZ/DfaURAZScVHe5WlJJ3ZyOpIj8ALtWIi0Ca+RY+2QwJmqzc4gRZ+/EcuFBeKuov91SV7chg==","signatures":[{"sig":"MEYCIQDd+MT6AZhBVVlkta+XHJmXXSTdO0ymyEKUMNft7uwpPQIhAKJ+NJfvxQvT0+zWK+74lYPeZqiDEpwPR6TgOMlc/ISK","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":79748},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"7fa5dab2308d91b81550b23ba343b6859c633db3","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_0.3.1_1784640477351_0.9698650021846662","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"npm-script-lens","version":"0.4.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@0.4.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"1fee38a54c30a54c3aafa5e2f0d88d693b625488","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-0.4.0.tgz","fileCount":13,"integrity":"sha512-8ZBUiHjT19GH36bCQkIo0MHfIHdmnCOn1NwCALwQZm20gpWNfiT4srR+Pok2gKfl17so7oaah/urIpBwt4Ewfg==","signatures":[{"sig":"MEQCIEpcF/fcaueDFa6SrA+m7iSLYNjpTKSpgNxCJMxV9nABAiAMWrubptRojhv3wX7FCglHn+riPRr++M0dpQVhabe1gg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":86652},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"6b5fabf22bce721c5b6d07485267b1177b111286","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_0.4.0_1784641263532_0.1527010945618572","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"npm-script-lens","version":"0.5.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@0.5.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"59560f246916b0f2ec1ef0acc74ccc56f8fd9a34","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-0.5.0.tgz","fileCount":13,"integrity":"sha512-i0OcodfTtu8Sz4xVCd5McO4a0pumCebaDPKI46kiT8vK7gGSKj95Sa07MJ6mRm2MPx/sL3n6a44vMr2z8ndsNw==","signatures":[{"sig":"MEUCIQDZ2WcgmWfGPyJqN5JaH+pgnNgn50aHTOmmHtomvnqZ/QIgT0agYQLf2dpYDcnEH0PUvA0Lp8Dn9o08KnTJ2u1PIjo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":94889},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"e0ca50ec816dac4f2f0dfa586da42e35e6b37f2c","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_0.5.0_1784810544329_0.9417223426916965","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"npm-script-lens","version":"0.7.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@0.7.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"641ea3ca170ef488b09ba393679b41c9ed217d01","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-0.7.0.tgz","fileCount":15,"integrity":"sha512-cbxx6SAHBQAlXLQD16qiOzzSx0BmGGeNZc++/DtIIL6yuYHX++aqzILuRhlxBCgPS+0GIrfYJWgjwaC0THye4Q==","signatures":[{"sig":"MEQCIEzTQwsXgvF5FfXaAixbz3SjbxZwKb0izUeTdsotkfsnAiAoIPkPWE/l0J9v6zBLM8o5mU7/hmzxVZ7gzcLCgNUiEA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":129404},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"75df5d3ec6c127b16acb383e1e1a9f76c6132372","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_0.7.0_1784898831647_0.48906347335829636","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"npm-script-lens","version":"1.0.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.0.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"8c81417697b4ef38c24af817412fdf0825ef3820","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.0.0.tgz","fileCount":20,"integrity":"sha512-GR1UhnFYMRPZxXvUA4veoKT511yEt/57QA0mtMr9vNi97GSE9pMNOfyY+TjIFFdaUx8rRiiM/ycN10BrbPVodQ==","signatures":[{"sig":"MEUCIQCReL1KfJcULyqzDt+uEhFl2KDhY3fpW01VBGDX/vYu1AIgF65DUPLLN/IamhT+TvmD9kGB9/QKxL+ORKTLhRWylHc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":201322},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"70632556964e7d44e45bc17abb8e6114e69285e3","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.0.0_1784950449414_0.48805241778288244","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"npm-script-lens","version":"1.0.1","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.0.1","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"b76960f1309eb8940925365f57d09cc17d7df62e","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.0.1.tgz","fileCount":20,"integrity":"sha512-yD89qBpbVVmVbfmGusW+UbWgoIR86H9d4BiqKAQOplcSHj8HauN5NlQRdlJjaUYOd5dfF9kTYlRxkffuMOoaaw==","signatures":[{"sig":"MEUCICWYyqxr8Ldb18nQYdvglbnyOt8kbO9xwKgyRqrnQ3qgAiEAvJ1qbVB5t4uiyWQTqV+pAQAImhY6cAZCpp4byE3Crio=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":201630},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"98c81816982aeb3a4b10e99691dae73a673eddf7","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.0.1_1784950796179_0.7370074483138209","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"npm-script-lens","version":"1.1.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.1.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"30c87192ee915366cf8f2c52bc18c419a8b6eb70","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.1.0.tgz","fileCount":21,"integrity":"sha512-Y4rVqPafeep6Ht4BhZ8dCBeHPQJoRUENhXRYXF85CXNwIOpXxDc1BxYa5zxHVUmqNFkPih06h9BB7lHYYmDb1g==","signatures":[{"sig":"MEYCIQC5Ag/Fk4JBVFtVvlN52ThOdmF37gLTt7lhwTvz5MbnaQIhANOYQOZqYMK17Yv1JE4c7C/ZOZU5SkEYNqtmM8Kj7lfe","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":209777},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"eda4e5a08b69e29481c534a16729887552fd07db","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.1.0_1784968809122_0.3210399514686104","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"npm-script-lens","version":"1.2.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","postinstall","audit"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.2.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"e47161c8f8b6e0b8efe10c98e34c7e422c087d43","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.2.0.tgz","fileCount":23,"integrity":"sha512-h+ZQIAeASe+WsFom51pQrETytCPMXV1Y4U/ie0pIPcjI/ZYoYR8xw6jWLsxDj1RIx/P9yO/SMmxRWTwrilOHLQ==","signatures":[{"sig":"MEYCIQDiDtfofypVkH5yMmZUhow4Q00ZJNGypp8/Jp1dFoHsDgIhAMlJ/BsCwOB9Od98SF6HScRryL+gQpKypLvS7/s6AdXn","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":253509},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"bc0f8a9b5c3daa1d4ab80298ea05471202819600","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.2.0_1785128603213_0.9094449393015516","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"npm-script-lens","version":"1.3.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","postinstall","audit","binding.gyp","node-gyp","gyp"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.3.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"1c0227d1a1e017fc46af72e301dde1739a44b70e","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.3.0.tgz","fileCount":24,"integrity":"sha512-vg7L7jIXumt3WCYBrBqTeFswqES4NZm51F9tIIG7ZUui71lQysWeKBVirmVK5d0sCOSUzbtgdtGLg9bUcXzvwg==","signatures":[{"sig":"MEUCIQDiYNPas3uG8LSnePgZzDVTybmL5L2Q0/AjYkciMeQVhgIgB3/yQffHCLbWYKKqKAF2tLRtpGac3l2afQgvnCHCd2k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":283735},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"4ed2d78b498459333ebed75e412cf4ecdd4e344f","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^12.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.3.0_1785141023450_0.13674696412247633","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"npm-script-lens","version":"1.4.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","postinstall","audit","binding.gyp","node-gyp","gyp"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.4.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"d58822ac4d0af5971ceb781a530087535108501b","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.4.0.tgz","fileCount":24,"integrity":"sha512-tQ8r2scNGq57MlWq8rSClsgrlGDxhnn2TWB2QN5XtyBmWKCVf6VJICaTQ7xsdMu61k5Obwh49EnFQ7b8PoVFvw==","signatures":[{"sig":"MEUCIQCXFslStlNnnWT7apKA3kitq04dwx9dw6y5B5p6PeixJAIgfeoufozihNfZQ3yHV5Xh0SZ0DsBAThNlpkFDZHSsq/o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":285728},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"54da7ec83138fe59866c95ec32b480f4102a1449","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.4.0_1785149907501_0.5800672360125201","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"npm-script-lens","version":"1.5.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.5.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"ce944db96d174b57431d3135efd260f928e5796a","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.5.0.tgz","fileCount":25,"integrity":"sha512-Uo/wjVrRSP+3AL9zpcIBxhS9hKc7GPMlW5ZbqGUZGCD+6sMa9hvAJuVwBhE8Y3vEvvUJqK5YFsUT11U1GIHjXw==","signatures":[{"sig":"MEUCIQDdOuHH3xoa/H1Yye0U7elfAxJ/f7pjm2bpRFEjFz0e1gIgZUuNeUm8bTzPbpXxcarQH/uEHedZie8eQF5K+hGsvC4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":337099},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"6bab9845828807966e11fac3d78cd7fd456dea10","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.5.0_1785636733322_0.32373801142114744","host":"s3://npm-registry-packages-npm-production"}},"1.6.0":{"name":"npm-script-lens","version":"1.6.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.6.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"59ab0f7cfd4952871dd9ab2a04a104e4d51549f7","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.6.0.tgz","fileCount":26,"integrity":"sha512-N9zIbayiH7NjSL5RdJQbbXr1xfXKDxIC4H3fDfRagTdGp38xZouw9KHglYerF/kVj610UWgjffawhRdxEAeXSw==","signatures":[{"sig":"MEUCICJ8fTtEnpO8SeC1zNyhggzzCL+Ln8vtqH6lA4VrK9jyAiEAmOocSdkb8hX1Y6VRLchjIIpMbW5CqSFkBxweVAxdCh4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":346667},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"5b6022300b7e219bb8759e3444ad8b8855fb992c","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.6.0_1785899168721_0.05606271909318128","host":"s3://npm-registry-packages-npm-production"}},"1.7.0":{"name":"npm-script-lens","version":"1.7.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.7.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"3ac5976cb0f2f9b47006f4018a2270752f9513fd","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.7.0.tgz","fileCount":26,"integrity":"sha512-O+OO572oTEhAjUOPMcfHtIxNfQ55981qiuvWukUh36ehOwkStWaSf5C/KFDtsk942v2j8gy/tbRvqvVNucWqfQ==","signatures":[{"sig":"MEQCIF5mv2cuLMjqf7edygKO4DhOM5JFaGql+GTmN0hwgg/rAiAYceBZJBYqRzRl2H2DIUpdxsAPvpO9CjSymBHA5uizHw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":362358},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"fb5d412ec3ac8cfd8ab8d8d9960c93128ec57520","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.7.0_1786079766027_0.5852824473534024","host":"s3://npm-registry-packages-npm-production"}},"1.8.0":{"name":"npm-script-lens","version":"1.8.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.8.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"e89631c058a43e88eabc1c454786136d123e3c1d","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.8.0.tgz","fileCount":27,"integrity":"sha512-CbT4MwF0jU9GGlriKfsAlwWbkQs0ABBVPLGkwfFpGK3OGhaM/FIe1jzC53j74VDtPAOXQ6aljkh8X/OCPXXxow==","signatures":[{"sig":"MEQCIAiKwIMZ/ZWjuHtxEt5MN6YksSkeixcZfEa3bqc/9RKgAiBW7gtBmh8OSgHeSaBJt+Mf+JIlrJIaxQSutz4sjfO3Dg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":402054},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"9b993ef7e2fdbd6a24473f0fd28ba3533af0efae","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.8.0_1786195367579_0.10607439634656046","host":"s3://npm-registry-packages-npm-production"}},"1.9.0":{"name":"npm-script-lens","version":"1.9.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.9.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"f5b3389069152137270ef718a28ff45c8236ddd0","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.9.0.tgz","fileCount":27,"integrity":"sha512-2osoe1AaillqpArR7OdkBhSBGEDHAEDxw+QwgdLD6EU6ZHPL6DeYyvf45EyAukL4UQAqexK6drmcI6G+phgDdg==","signatures":[{"sig":"MEUCIHQZX/DdphRLO1r6GmnRzJmvYMQsYeLBTj0Xt0UJGoVZAiEA/nViQ1K0a8baYm0gMKO7/eFXU4Jn9c5+aNmvrVnOjTw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":412234},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"870ae2a524e1d89816af738e411fd2f15796b565","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.9.0_1786589395560_0.6706768480501277","host":"s3://npm-registry-packages-npm-production"}},"1.10.0":{"name":"npm-script-lens","version":"1.10.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.10.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"206b839124381d78e63fda5d780aaf7dd8d9fa9d","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.10.0.tgz","fileCount":32,"integrity":"sha512-LudBNGZZnbWKnIcbThXW3wizp7xgA7aAUbM+tupHwd139tj5tWQKJaFMU22FFIwsQPrbe8mZ/llTf7UYBNGlrA==","signatures":[{"sig":"MEQCIB0heAs06psD9qQeif1l1MND+R2v5ChcGmM2Zlam2hLrAiAoMETgCcAwnflEjvg2jek3aXWztfDDSx+AvQBz5nV7rw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":446781},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"82e9f4a71e1147932ca34211fe6f4cd5adb381ca","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.10.0_1786686251488_0.21620517468791456","host":"s3://npm-registry-packages-npm-production"}},"1.11.0":{"name":"npm-script-lens","version":"1.11.0","keywords":["npm","security","supply-chain","lifecycle-scripts","allowScripts","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.11.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"4fcd7b33529582a4031d6f41eae69122c2335d32","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.11.0.tgz","fileCount":32,"integrity":"sha512-WF5ejQKaz7gynP+gdKI+SqcZxSBAqEtPgjRNG1GxsS/jhN4UwSUzIt4QmVAmetizj5kTVLKaUvjZ9fBHjexf7w==","signatures":[{"sig":"MEQCIH7qNf+v+Gpvq2C1q5s8+W4HXrSlVXnzxvkVgPYoXM8KAiAEAVH5NGZD+aUPQAmm3bAs+Q0fLXy17x+NDR6Lil15jg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":468941},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"cd6f6ed283a51e78a6de3073033a800e002beb3a","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"Audit npm lifecycle scripts for behavioral risks (exec/network/fs) before approving them under npm v12's allowScripts","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.11.0_1786724719990_0.19401749112142896","host":"s3://npm-registry-packages-npm-production"}},"1.11.1":{"name":"npm-script-lens","version":"1.11.1","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.11.1","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"e114e752be69882f2dc38bfbb0d09da3c70558ba","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.11.1.tgz","fileCount":32,"integrity":"sha512-v1Tf6W0aMxj9FbdWqMqQsPC89DqxlZjyULQmjzyWd+sJ7DcWe0mV5CFvH8tfnyH8RN+wsXOi3AJ7TDvQGG7brg==","signatures":[{"sig":"MEQCIF/vwT4+UlDB9SaF0j0usWDSXlJ55hA4skTncC8eoWLEAiBWQ3SLpnIPwEFf8IetA9bETl90+9aCKDpIWBGSLk4mgA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":469226},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"e163fcd39e771151ee5eede1158022cee8cea6e1","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^15.0.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.11.1_1786727478615_0.5203681586010738","host":"s3://npm-registry-packages-npm-production"}},"1.11.2":{"name":"npm-script-lens","version":"1.11.2","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.11.2","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"8ae25f4f95beb9d138272e6f5a1926729f534e03","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.11.2.tgz","fileCount":32,"integrity":"sha512-jdwLeGebL2PqeMCH3XOpEkpBn2vhMSJp5dNWqPmfCizJZIs8P1q+AKm/FFJJ4wkt+Lm4sHktCTMAvFFi2mnmQA==","signatures":[{"sig":"MEQCIBbYlQIO2aZVyBwmzPq1pJJIYR9ydIwr8IuhVEALRakWAiBGuK+v9MW2zajdC9gkCASWfnyfnKcbNBXMg99zwVWLGQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":470099},"main":"src/cli.js","engines":{"node":">=20"},"gitHead":"6a100884783621ca6b5d7f5c40bc4bd0ce10cb3b","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^14.0.3","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.11.2_1786947356074_0.7700479008141718","host":"s3://npm-registry-packages-npm-production"}},"1.12.0":{"name":"npm-script-lens","version":"1.12.0","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.12.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"97c93d2a6c03804ec99d1a0a538326b6d52e0699","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.12.0.tgz","fileCount":32,"integrity":"sha512-Xisfp6CxRuUmEKnqdxK/zdkxGKSTml36+rdote8rgoyEp6FHQQjjYk6gnhgLxk1ki+kRZj1EzNkzyZCMabnOAQ==","signatures":[{"sig":"MEYCIQCIHIIxvUATXvBJNeqwr311y8g5c4THgYJh9YeJWrb0SAIhALqi5CKaH2MXG0DmukNb2SogWgS1AanqJyFv3+wbDJSM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":470099},"main":"src/cli.js","engines":{"node":">=18"},"gitHead":"18ca0b4e644518fd13f59dd8583be27eb7b3e0d9","scripts":{"test":"node --test"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^13.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.12.0_1786951260586_0.6709677237217813","host":"s3://npm-registry-packages-npm-production"}},"1.13.0":{"name":"npm-script-lens","version":"1.13.0","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.13.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"cb1743c0d19e5fe4040e70f53a22bbea16ddbb17","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.13.0.tgz","fileCount":32,"integrity":"sha512-Q/2F+1Xn0e50VoR4ZH8WedPFglilEjId3D4BJ87ZUqz+ye5KFd0NAlPA8Y5ZUaMT9XlJrl2Bf0UC375yh+vdwQ==","signatures":[{"sig":"MEYCIQDGFTEDxSlBKCEaXTWku5xvTnNYK/Ir1IQTteEBjkTKCwIhANCOtQhoj2g6Tzi7yG/rg4uz1ozDP8P1AyA6WlyFzFDY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":475735},"main":"src/cli.js","engines":{"node":">=18"},"gitHead":"748675095ea9bffdb158321d1803b54cf5376ad1","scripts":{"test":"node --test","demo:report":"node src/cli.js audit --path fixtures/demo --out fixtures/demo-report.md"},"_npmUser":{"name":"booyaka","email":"cbosch101@gmail.com"},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"10.9.3","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.18.0","dependencies":{"acorn":"^8.12.0","commander":"^13.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.13.0_1786954591107_0.46874953797645524","host":"s3://npm-registry-packages-npm-production"}},"1.13.1":{"name":"npm-script-lens","version":"1.13.1","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.13.1","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"84addb80d136d6e06c540628b42a8b8155ab23b9","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.13.1.tgz","fileCount":32,"integrity":"sha512-5p22JAePYTf45NDrWn9hTI6pKodhacGuBr2ynAe5Lm+s/FOBIBlGnE09FxJXaBQuWGTg5hBowBuAfaMhwlY53g==","signatures":[{"sig":"MEYCIQCoPIyAB60xkngmZl43nKAI01ZjUKJ75/1X+zNACgt0qwIhALP3e0UFsBzrl8kztylNZ729kEz9P9nBXijthYntcgym","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/npm-script-lens@1.13.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":475735},"main":"src/cli.js","engines":{"node":">=18"},"gitHead":"822104c29695986673c258691a798e9003beabe8","scripts":{"test":"node --test","demo:report":"node src/cli.js audit --path fixtures/demo --out fixtures/demo-report.md"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:40be98d6-dbbb-4005-a59e-06e7f3323a09"}},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"11.19.0","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.23.2","dependencies":{"acorn":"^8.12.0","commander":"^13.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.13.1_1786957336908_0.7099576296786316","host":"s3://npm-registry-packages-npm-production"}},"1.14.0":{"name":"npm-script-lens","version":"1.14.0","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.14.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"7fb7cfdbecdac1af6a4466d6f0e7fc724316013a","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.14.0.tgz","fileCount":33,"integrity":"sha512-bi2OCYiS0C8TQHfFOo5TNUadUMrpkUmIP60BtudGfj9L70/wx5qgpnutzH0cv/SOSR9U+2N49XupJyMfyKpMsQ==","signatures":[{"sig":"MEUCIFICIVMcl0tjliIhKSzwzIshvtz9tXKTOIVEKaxkfWBFAiEA1D0wVVZntfqjMo/5Mrj6mL0Hz7Tumm9Za8fQtfYRQR4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/npm-script-lens@1.14.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":504830},"main":"src/cli.js","engines":{"node":">=18"},"gitHead":"ba32b7efdcca91464bbcc08bd2908373359d953a","scripts":{"test":"node --test","demo:report":"node src/cli.js audit --path fixtures/demo --out fixtures/demo-report.md"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:40be98d6-dbbb-4005-a59e-06e7f3323a09"}},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"11.19.0","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.23.2","dependencies":{"acorn":"^8.12.0","commander":"^13.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.14.0_1787375187846_0.6419409719151317","host":"s3://npm-registry-packages-npm-production"}},"1.15.0":{"name":"npm-script-lens","version":"1.15.0","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks","bun","deno","runtime-bootstrap","chaindrop"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.15.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"bede1036a80e5e7fd92e51d8e9d05100c12062ea","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.15.0.tgz","fileCount":33,"integrity":"sha512-OvpMAafVgBUSCSr4c/XuX4xLb3Djn5YmKIJ1Lfrx3Qckrguybp882F356le9B89UBhBrQKNLKgByxqDkeXOo2Q==","signatures":[{"sig":"MEQCIBm98og90tVsLE7EgsskrHK+w//5hYKHAtJJtN8PQmNsAiBLcLK+uTCHo51Eskw4NyircuVTaPJgEUG46zEZXIVuEA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/npm-script-lens@1.15.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":522210},"main":"src/cli.js","engines":{"node":">=18"},"gitHead":"1c178cc30cc63045cc0608b661a829964e8d4286","scripts":{"test":"node --test","demo:report":"node src/cli.js audit --path fixtures/demo --out fixtures/demo-report.md"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:40be98d6-dbbb-4005-a59e-06e7f3323a09"}},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"11.19.1","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.23.2","dependencies":{"acorn":"^8.12.0","commander":"^13.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.15.0_1788141448229_0.8511026728854647","host":"s3://npm-registry-packages-npm-production"}},"1.16.0":{"name":"npm-script-lens","version":"1.16.0","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks","bun","deno","runtime-bootstrap","chaindrop","min-release-age","minimumReleaseAge","npmMinimalAgeGate","cooldown","minimum-release-age"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.16.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"9511faa9bc706b03dc496daf19e38fda16e1c983","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.16.0.tgz","fileCount":33,"integrity":"sha512-wpq2edhwC2uye4TFAYR9Vvb3cDUgF1g+QwK1hl6+Z9fQBpIaD+aAw+NaTkvkWqedgGxk74bI/ui+/v6G1yfIXQ==","signatures":[{"sig":"MEUCIAid7AqOZiIR+X3bt3bZ+VjoslvPcrn5rDbll5Lr6y/4AiEA1c1JcnjFGHhLlDU4RkrhqeiAVXhk5mu4fopl3HidLe8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/npm-script-lens@1.16.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":589153},"main":"src/cli.js","engines":{"node":">=18"},"gitHead":"3a90565126b0e660687efb908d7adfe9be633a10","scripts":{"test":"node --test","demo:report":"node src/cli.js audit --path fixtures/demo --out fixtures/demo-report.md"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:40be98d6-dbbb-4005-a59e-06e7f3323a09"}},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"11.19.1","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.23.2","dependencies":{"acorn":"^8.12.0","commander":"^13.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.16.0_1788833808218_0.6372254095970891","host":"s3://npm-registry-packages-npm-production"}},"1.17.0":{"name":"npm-script-lens","version":"1.17.0","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks","bun","deno","runtime-bootstrap","chaindrop","min-release-age","minimumReleaseAge","npmMinimalAgeGate","cooldown","minimum-release-age"],"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","_id":"npm-script-lens@1.17.0","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"bin":{"npm-script-lens":"src/cli.js"},"dist":{"shasum":"40dc75d3b04c5a495de42376385cf02f0ea7ab8a","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.17.0.tgz","fileCount":34,"integrity":"sha512-9eX/vResQcjbsFwYRTWkI7aDi/d/edVcEgzomkokn1gr+Jaq2JqZHBhr7yfmFDNeOw2SUOWT94/jk6aE0x77yw==","signatures":[{"sig":"MEYCIQCrLSopBj9/ELa+FCPf6P0L04LoG4UviGfMD20rTMpfgwIhANa74XrroiYtuKu0V9x6avd77vIBxIG8ogtzMR2C40pV","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCk7uOaRoePYACMTPj6eWJzTON2ZiUZs09gRAskXG8kJwIgEaY+w7slaQib9c8DKp2SFPKqf6SEU9i6WRmqVMwE6C0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/npm-script-lens@1.17.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":625261},"main":"src/cli.js","engines":{"node":">=18"},"gitHead":"2cd52b151ee4bfd103f790cb6ec4bef942996e40","scripts":{"test":"node --test","demo:report":"node src/cli.js audit --path fixtures/demo --out fixtures/demo-report.md"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:40be98d6-dbbb-4005-a59e-06e7f3323a09"}},"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"11.20.0","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"_nodeVersion":"22.23.2","dependencies":{"acorn":"^8.12.0","commander":"^13.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/npm-script-lens_1.17.0_1790129338330_0.34331985304285273","host":"s3://npm-registry-packages-npm-production"}},"1.18.0":{"_id":"npm-script-lens@1.18.0","bin":{"npm-script-lens":"src/cli.js"},"bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"dist":{"shasum":"d5de753fbe95483ebbb7283cc2867a164f15fe3b","tarball":"https://registry.npmjs.org/npm-script-lens/-/npm-script-lens-1.18.0.tgz","fileCount":34,"integrity":"sha512-YPw1ltJgOEzvNdXuTt9tEwauIpPEO8Albklu3maYzf5Ez7cEKBRwJ5G89gY+kb5OqdV6ABTuj+oqTeHZqeNZ8g==","signatures":[{"sig":"MEQCIHX1V93qktNbZNSBaccKMKl/ruQHsugzQxzku1kWKehKAiBj85aKwySIGcgMSuplz++PLNhEL7U3hL4Rw/8LQX+oow==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDRHhdp4Xw5F0wvI4Gkwr/MoIJrM5nKWTk57o7YOp0oyAIgOe/jd9/E5OpIgoYlCO0J+9N6jKyaU7cUb1gkj2oMRcE="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/npm-script-lens@1.18.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":632598},"main":"src/cli.js","name":"npm-script-lens","author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"engines":{"node":">=18"},"gitHead":"7507e543fbfbc123dded499ba4a9f2ecdf208a95","license":"MIT","scripts":{"test":"node --test","demo:report":"node src/cli.js audit --path fixtures/demo --out fixtures/demo-report.md"},"version":"1.18.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:40be98d6-dbbb-4005-a59e-06e7f3323a09"}},"homepage":"https://github.com/Booyaka101/npm-script-lens#readme","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks","bun","deno","runtime-bootstrap","chaindrop","min-release-age","minimumReleaseAge","npmMinimalAgeGate","cooldown","minimum-release-age"],"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"_npmVersion":"11.20.0","description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","directories":{},"maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"_nodeVersion":"22.23.2","dependencies":{"acorn":"^8.12.0","commander":"^13.1.0","acorn-walk":"^8.3.0","tar-stream":"^3.1.7","acorn-loose":"^8.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/npm-script-lens_1.18.0_1790200433674_0.5438143487476967"}}},"time":{"created":"2026-07-21T13:09:44.556Z","modified":"2026-09-23T21:53:54.119Z","0.3.0":"2026-07-21T13:09:44.794Z","0.3.1":"2026-07-21T13:27:57.493Z","0.4.0":"2026-07-21T13:41:03.699Z","0.5.0":"2026-07-23T12:42:24.455Z","0.7.0":"2026-07-24T13:13:51.819Z","1.0.0":"2026-07-25T03:34:09.551Z","1.0.1":"2026-07-25T03:39:56.343Z","1.1.0":"2026-07-25T08:40:09.273Z","1.2.0":"2026-07-27T05:03:23.384Z","1.3.0":"2026-07-27T08:30:23.584Z","1.4.0":"2026-07-27T10:58:27.639Z","1.5.0":"2026-08-02T02:12:13.461Z","1.6.0":"2026-08-05T03:06:08.882Z","1.7.0":"2026-08-07T05:16:06.167Z","1.8.0":"2026-08-08T13:22:47.726Z","1.9.0":"2026-08-13T02:49:55.705Z","1.10.0":"2026-08-14T05:44:11.659Z","1.11.0":"2026-08-14T16:25:20.135Z","1.11.1":"2026-08-14T17:11:18.780Z","1.11.2":"2026-08-17T06:15:56.212Z","1.12.0":"2026-08-17T07:21:00.727Z","1.13.0":"2026-08-17T08:16:31.257Z","1.13.1":"2026-08-17T09:02:17.068Z","1.14.0":"2026-08-22T05:06:28.065Z","1.15.0":"2026-08-31T01:57:28.389Z","1.16.0":"2026-09-08T02:16:48.396Z","1.17.0":"2026-09-23T02:08:58.431Z","1.18.0":"2026-09-23T21:53:53.768Z"},"bugs":{"url":"https://github.com/Booyaka101/npm-script-lens/issues"},"author":{"name":"cbosch101","email":"cbosch101@gmail.com"},"license":"MIT","homepage":"https://github.com/Booyaka101/npm-script-lens#readme","keywords":["npm","security","supply-chain","supply-chain-security","lifecycle-scripts","install-scripts","preinstall","approve-scripts","allowScripts","allowBuilds","trustedDependencies","provenance","attestation","sigstore","slsa","allow-git","allow-remote","trusted-publishing","staged-publishing","oidc","postinstall","audit","binding.gyp","node-gyp","gyp","folderOpen","tasks.json","claude-code-hooks","bun","deno","runtime-bootstrap","chaindrop","min-release-age","minimumReleaseAge","npmMinimalAgeGate","cooldown","minimum-release-age"],"repository":{"url":"git+https://github.com/Booyaka101/npm-script-lens.git","type":"git"},"description":"See what an install script actually does before you approve it: behavioral analysis, binding.gyp inspection and resolved provenance identity for npm 12 allowScripts, pnpm allowBuilds, yarn and bun","maintainers":[{"name":"booyaka","email":"cbosch101@gmail.com"}],"readme":"# npm-script-lens\n\n**Know what an install script actually does before you approve it.**\n\n_The install-script-approval tool for **npm · pnpm · yarn · bun**, from your **CLI**, **CI**, **editor**, and **AI agent**._\n\nSince [npm v12 (July 8, 2026)](https://github.blog/changelog/2026-07-08-npm-install-time-security-and-gat-bypass2fa-deprecation/), dependency lifecycle scripts (`preinstall`, `install`, `postinstall`) and implicit `node-gyp` builds **no longer run unless explicitly allowed** via the `allowScripts` field in `package.json`. [git and remote-URL dependencies **no longer resolve at all**](#git-and-remote-dependencies-the-other-two-npm-v12-flips) unless opted in via `allow-git`/`allow-remote`. And npm isn't alone: **pnpm** (`allowBuilds`), **yarn** Berry (`dependenciesMeta.built`), and **bun** (`trustedDependencies`) all made install scripts opt-in too. That leaves every team, on every package manager, staring at a list of package names asking: *which of these are safe to approve?*\n\n`npm-script-lens` answers that with evidence, not vibes: the review-report mode the community asked for in [npm/rfcs#897](https://github.com/npm/rfcs/issues/897). For every package in your lockfile (`package-lock.json`, `npm-shrinkwrap.json`, `yarn.lock` (classic and berry), `pnpm-lock.yaml`, or `bun.lock`) it:\n\n1. fetches the version metadata from the public npm registry,\n2. stream-downloads the tarball and indexes its source files (`tar-stream`, nothing written to disk), skipped entirely for the majority of packages with no install-time scripts, which is why real audits take seconds,\n3. statically analyzes each `preinstall`/`install`/`postinstall` script with `acorn`, including the JS the script actually runs: `node <file>` targets, `node -e` eval bodies, relative `require()`/`import` chains, `path.join(__dirname, …)` indirections, and `npm run <target>` recursion into the package's own scripts (3 levels deep, cycle-safe). Packages that ship a root `binding.gyp` with no install script get their **implicit `node-gyp rebuild`** surfaced too, since npm v12 blocks those builds as well. (`prepare` is deliberately excluded: npm never runs it for registry-installed deps, and flagging leftover `\"prepare\": \"husky install\"` lines would be noise.)\n4. **reads inside `binding.gyp`** (and the `.gypi`/`.gyp` files it includes) for native packages, see [the gyp lens](#the-gyp-lens-what-is-actually-inside-bindinggyp), because gyp *runs* the commands in that file at configure time,\n5. scores the behavior and emits a Markdown report plus a **ready-to-paste, version-pinned `allowScripts` block**,\n6. adds context to every risky package: **how it entered your tree** (`via prisma → @prisma/engines`), **whether OSV lists it as malicious** (⛔ hard flag, always denied), and **publisher trust signals** (publish age, weekly downloads, maintainer count, and the [resolved provenance identity](#provenance-an-identity-not-a-checkbox): which repository, workflow, ref and commit the attestation claims built it), so \"🔴 HIGH, 74M dl/wk, 10 years old\" reads differently from \"🔴 HIGH, published 4 days ago, 12 dl/wk\".\n\n| Risk | Meaning |\n|---|---|\n| 🔴 HIGH | spawns processes (`child_process`, `execa`, `node-gyp`, unresolved binaries) **or runs constructed code** (`eval`, `new Function`, `vm`, string-built `require()`, base64/char-code payload decoding) **or reads a credential store and reaches the network** (`~/.npmrc`, `NPM_TOKEN`, `.aws/credentials`, …) |\n| 🟠 MEDIUM | network access (`http(s).get/request`, `fetch`, `axios`/`got`/`node-fetch`/…) without exec |\n| 🟡 LOW | filesystem writes, `process.env` reads, or a credential read with no network access |\n| 🟢 SAFE | none of the above |\n\nResults are cached on disk keyed `name@version` + tool version (published tarballs are immutable), so repeat audits are near-instant and fully offline. `--no-cache` opts out; `NPM_SCRIPT_LENS_CACHE_DIR` relocates the cache.\n\n## CLI\n\n```bash\nnpx npm-script-lens audit --path ./my-project --fail-on-high\n# --path PATH   project dir or lockfile: package-lock.json, npm-shrinkwrap.json,\n#               yarn.lock, pnpm-lock.yaml, bun.lock (default: .). A directory\n#               with no lockfile searches upward like npm does; a directory of\n#               checkouts audits every project underneath\n# --json        machine-readable output ({results, allowScripts}, or {projects}\n#               when more than one project was found)\n# --out FILE    write report to a file\n# --sarif FILE  also write SARIF 2.1.0 for GitHub code scanning\n# --html FILE   also write a self-contained, shareable HTML report\n# --diff BASE   audit only packages added/upgraded vs a base lockfile\n# --since REF   like --diff, but extract the base lockfile from a git ref\n# --offline     analyze node_modules on disk instead of the registry\n# --no-trust    skip OSV/downloads/provenance enrichment\n# --no-cache    disable the on-disk result cache\n# --fail-on-high  exit 1 if any package scores HIGH or is known malicious\n# --cooldown [h]  exit 1 if any locked version is younger than N hours (default 72)\n# --cooldown-allow PKG...  exempt from --cooldown, by name or name@version\n# --fail-on-downgrade  exit 1 if any package resolves below the highest trust\n#               tier it previously reached (npm/cli#9242); policy\n#               trustPolicy: \"no-downgrade\" reports without failing\n# --fail-on-runtime-bootstrap  exit 1 if any package installs another JS runtime\n#               (bun, deno) at install time; policy runtimeBootstrapPolicy:\n#               \"fail\" arms the same gate\n# --runtime     also read the code each package runs when required (main,\n#               exports, bin) for C2/exfil endpoints and payload loaders, see\n#               Payloads without install scripts\n# --fail-on-runtime-payload  exit 1 on a HIGH RUNTIME_PAYLOAD (implies --runtime)\n```\n\nReviewing a PR? Audit only what changed, and see what **upgrades gained**:\n\n```bash\nnpx npm-script-lens audit --since origin/main --fail-on-high   # base lockfile pulled from the ref for you\n# …or point --diff at a base lockfile you extracted yourself:\ngit show origin/main:package-lock.json > /tmp/base-lock.json\nnpx npm-script-lens audit --diff /tmp/base-lock.json --fail-on-high\n```\n\nIn diff mode, a package that was already in the tree but changed version is compared against the base version's analysis: `**⚠️ gained vs 1.2.0:** net: fetch()` is the fingerprint of a hijacked release (event-stream, the 2025 Shai-Hulud wave); `no new capabilities vs 1.2.0` is a boring upgrade.\n\n## The gyp lens: what is actually inside `binding.gyp`?\n\n`npm-script-lens` is the only install-script allowlist/approval tool that reads\n**inside** `binding.gyp` and `.gypi`, and the only one that **diffs them\nbetween versions**.\n\nEvery such tool (including this one, before v1.3.0) treated `binding.gyp` as a\nflag: present ⇒ \"implicit `node-gyp rebuild`\". But gyp *evaluates* that file\nbefore a line of C is compiled, and executes the commands in it,\n[`subprocess.run(contents, stdout=PIPE, shell=use_shell, …)`](https://github.com/nodejs/gyp-next/blob/main/pylib/gyp/input.py)\nin gyp-next. So the build file is a place to put install-time code where\napproval tooling was not looking. That is what the June 2026 campaign used:\n[ReversingLabs, 2026-06-04](https://www.reversinglabs.com/blog/npm-bindinggyp-cicd-secrets)\n(286 malicious versions across 56 packages), whose payload was a single line:\n\n```json\n{\"targets\":[{\"target_name\":\"Setup\",\"type\":\"none\",\"sources\":[\"<!(node index.js > /dev/null 2>&1 && echo stub.c)\"]}]}\n```\n\n[Aikido's 2026-06-09 teardown](https://www.aikido.dev/blog/exploring-binding-gyp-npm-build-system)\nenumerates the channels; `npm-script-lens` covers all of them:\n\n| Channel | What it does |\n|---|---|\n| `<!(` `<!@(` | command expansion: gyp runs it in a shell and substitutes the output |\n| `>!(` `>!@(` `^!(` `^!@(` | the same thing in gyp's *late* and *latelate* phases, one character apart from `<!(`, and invisible to a naive scan |\n| `<!pymod_do_main(` (+ `>`/`^`) | imports a Python module and calls its `DoMain()` |\n| `<\\|(` `>\\|(` `^\\|(` | listfile expansion |\n| `actions[].action` · `rules[].action` · `postbuilds[].action` | explicit build steps that run commands |\n| `make_global_settings` | replaces `CC`/`CXX`/`LINK`, a compiler hijack |\n| `conditions` | flagged when the condition string reaches for the Python-eval sandbox escape (`__class__`, `__subclasses__`, `__import__`, `__builtins__`) |\n\nPlain `<(var)` / `<@(var)` interpolation is **never** flagged, real files mix\nboth, and `bufferutil`'s `<!(cc -v …)` sitting next to its `<(clang_version)`\nis a committed regression test.\n\n`review` prints what will run above the file itself. Real output for\n`better-sqlite3@11.10.0`, note the findings come from `deps/sqlite3.gyp`, a\nfile the parent `binding.gyp` only *references*:\n\n```\n── better-sqlite3@11.10.0  [🔴 HIGH]\n   deps/sqlite3.gyp:28  actions[].action build action → node copy.js <(SHARED_INTERMEDIATE_DIR)/sqlite3\n   deps/sqlite3.gyp:41  actions[].action build action → node copy.js <(SHARED_INTERMEDIATE_DIR)/sqlite3 <(sqlite3)\n   ┌─ binding.gyp (39 lines)\n   │   1  # ===\n   │   2  # This is the main GYP file, which builds better-sqlite3 with SQLite itself.\n   …\n```\n\nIn `audit`, these become `gyp:` signals that score **HIGH** (a shell command at\ninstall time is a shell command), appear in `--sarif` under the rule\n`gyp-exec-channel`, and can be banned outright via a policy's\n`denyCapabilities: [\"gyp\"]`.\n\n> **Upgrading from ≤ 1.2.0?** A `manifest --check` baseline containing native\n> packages may now show a new `gyp` capability, the tool sees something it\n> previously could not. Re-baseline once with `manifest --write` and commit it.\n\n## RUNTIME_BOOTSTRAP: installing a different runtime to step outside the model\n\nApproval tooling models a **Node** payload. It reads the JavaScript that\n`preinstall` runs, follows its `require()` chain, and scores what it does. That\nmodel has an edge, and on 2026-08-04 the ChainDrop worm walked out of it across\n[more than 400 packages](https://www.microsoft.com/en-us/security/blog/2026/08/04/chaindrop-supply-chain-compromise-anatomy-self-propagating-worm/).\n\nIts preinstall was `node setup.mjs`, a command this tool already followed. The\nescape was inside that JavaScript. The dropper fetched a real, signed Bun\nrelease from the project's own GitHub releases, unpacked it, and ran a bundled\nsecond stage under that fresh interpreter. Microsoft's own detections name the\ntechnique: \"Suspicious installation of Bun runtime.\" Two things about that stage\ndefeated a Node-shaped scan: it ran under a different interpreter, and it was\nnever `require()`d, it was passed as a file path to a spawn call, so the\nrequire-walk never reached it.\n\nSo the runtime table is no longer one entry long. A file handed to `node`,\n`nodejs`, `bun`, `deno run`, `tsx`, `ts-node`, or the `npx` / `bunx` / `bun x`\nrunner forms is opened from the tarball and analyzed with the same acorn pass,\nand its capabilities merge into the package score. Inside that pass, a download\nwhose URL points at a JavaScript-runtime distribution is flagged, and a\n`child_process` / `spawn` / `exec` call whose string argument resolves to a file\nin the tarball is queued into the same walk, so the second stage is analyzed\nlike any other entry point.\n\nA package that does this gets a `RUNTIME_BOOTSTRAP` finding, scored **HIGH**,\nthat names the technique instead of folding it into a generic \"spawns\nprocesses\":\n\n```\n🔴 HIGH  RUNTIME_BOOTSTRAP  downloads bun from oven-sh/bun releases, then runs it on the bundled payload\n```\n\nThe capabilities of that bundled payload (its network calls, its environment\nreads) are merged into the same finding and attributed to the bootstrapped\nruntime, so a stage that reads a token and phones home reads as exactly that,\nnot as a mystery second file. The detector recognises the two runtimes' own\ninstall scripts, their release archive names, the `oven-sh/bun` release URLs, a\nglobal install of bun or deno through a package manager, and a shell pipe that\ninstalls one of them. Both shapes ChainDrop used land here: the `node setup.mjs`\ndropper, and the shell one-liner that installs bun and then runs a bundled\npayload with it.\n\nInstalling a runtime is the signal; **using one is not**. A package that runs\n`bun run build` on a script it already ships is not flagged, that is an ordinary\nbun-native build. An alternate-runtime entry point that does not resolve to a\nfile in the tarball degrades to the generic HIGH rather than crashing.\n\nIn `audit --diff` / `--since`, a version that newly acquires a runtime bootstrap\ngets an explicit line, because ChainDrop republished each hijacked package as an\nordinary patch bump:\n\n```\n⚠️ gained vs 1.0.0: runtime bootstrap (bun)\n```\n\n`--fail-on-runtime-bootstrap` exits 1 on the pattern, independent of\n`--fail-on-high`, and a checked-in `runtimeBootstrapPolicy: \"fail\"` in\n`script-lens.policy.json` arms the same gate for a whole team. The finding rides\n`--json` (`results[].runtimeBootstrap`) and SARIF (rule `runtime-bootstrap`,\nlevel error) alongside every other finding.\n\n## Payloads without install scripts\n\nEverything above reads what runs at install time. In September 2026 the btree\ncampaign ([Checkmarx](https://checkmarx.com/zero-post/npm-btree-malware-campaign-affects-millions-of-downloads-no-need-for-install-script/))\nskipped that entirely. `indexed-btree` and ten companion packages had no\nlifecycle scripts, so there was nothing to approve and nothing for an\n`allowScripts` review to show. The loader was in `BTree.prototype.set`: on the\nhundredth insert it spawned a detached `node` on a bundled, obfuscated\n`extended/sharedLoad.min.js`, which looked up its C2 on an Ethereum testnet and\nposted what it collected to chat bots. It ran the first time your own code used\nthe library.\n\n`--runtime` reads that code. For each package it takes `main`, every `exports`\ntarget (all conditions, subpaths and nesting) and every `bin`, falling back to\n`index.js` like Node does. It then follows relative `require`/`import` and any\nfile the code spawns node on, with the same acorn pass the install-script\nanalysis uses. A bin is read whatever its name if it opens with `#!`. Type\ndeclarations, `.json`, `.node`, source maps, wildcard subpaths and folder\nmappings (`\"./\": \"./\"`) are skipped.\n\n```bash\nnpx npm-script-lens diff some-lib@1.4.2 some-lib@1.4.3 --runtime\nnpx npm-script-lens audit --runtime                       # every locked package\nnpx npm-script-lens audit --fail-on-runtime-payload       # the same, and exit 1 on HIGH\n```\n\nOn the repo's inert re-creation of the btree release (`fixtures/runtime`):\n\n```\nbtree-good@1.0.0 → btree-good@1.0.1\nruntime code (main/exports/bin): index.js\nGAINED: c2 (extended/sharedLoad.min.js) contract 0x5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e5e\nGAINED: c2 (extended/sharedLoad.min.js) eth-sepolia.g.alchemy.com\nGAINED: c2 (extended/sharedLoad.min.js) eth_call\nGAINED: exec-local (index.js) process.execPath extended/sharedLoad.min.js (detached)\nGAINED: exec (index.js) child_process.spawn()\nGAINED: exec (index.js) require('child_process')\nGAINED: exfil (extended/sharedLoad.min.js) api.telegram.org/bot\nGAINED: net (extended/sharedLoad.min.js) fetch()\n```\n\nA plain `diff` of the same two versions exits 0, since no script changed.\nWith `--runtime`, gaining `exec`, `exec-local`, `c2`, `exfil` or `obf` exits 1.\nGaining only `net`, `fs` or `env` is printed but does not fail, because\nordinary releases gain those all the time. A signal that moved to another file\nis not a gain, and neither is a bundler renaming `worker.3f9a1c2b.js` to\n`worker.8e41d0aa.js`. The upgrades checked before release (chalk 5.4.0 →\n5.4.1, commander 14.0.2 → 14.0.3, semver 7.6.2 → 7.6.3, debug 4.3.6 → 4.3.7,\nms 2.1.2 → 2.1.3, axios 1.7.7 → 1.7.8, date-fns 3.6.0 → 4.1.0) all print\n`no runtime capability changes`.\n\nWhat it looks for:\n\n- **exec-local**: node, `process.execPath`, bun or tsx started on a file in the\n  same tarball, with `(detached)` when it outlives the parent. That is the\n  loader shape. A worker pool does it too, so on its own it is MEDIUM.\n- **c2**: an Ethereum RPC host (testnets, infura, alchemy, publicnode, ankr),\n  `eth_call`, and a 40-hex contract address in a file that also names an RPC\n  host.\n- **exfil**: Telegram bot, Slack and Discord webhook endpoints, including ones\n  split across `'…' + '…'` concatenation. A docs link to the same service does\n  not count.\n- **obf: string-array rotation**: the prelude javascript-obfuscator emits when\n  it encodes a file's strings into a rotated array. No file in a 746-package\n  web3 tree (22,570 JS files) has it.\n\n`audit --runtime` reports only those four as `RUNTIME_PAYLOAD`, never plain\nexec or network, which most libraries have. A lone RPC host is normal in a\nweb3 client and a lone local spawn in a worker pool, so one kind alone is\nMEDIUM. An exfil endpoint, or two kinds together, is HIGH, and only HIGH fails\n`--fail-on-runtime-payload`. On that 746-package web3 tree it took 20 seconds\nand reported 0 HIGH and 12 MEDIUM: wallet SDKs naming their infura\nendpoints, RPC clients that build `eth_call` requests, ethers' block explorer\nhosts, and pm2 starting its own daemon detached. Runtime mode downloads every\ntarball, not just the ones with install scripts, so the first run is slower\nthan a normal audit. Results are cached like everything else.\n\nWith `--diff` or `--since`, a finding on an upgraded package marks each hit\nthe old version did not have as **new since** that version, and says so when\nevery hit was already there. That is the line to read first: a wallet SDK\nthat always named infura is not news, the same SDK gaining a Telegram\nendpoint is.\n\nA package with no finding is not always a clean read. When an entry point\ncould not be read (over 2 MB, declared but not in the package) or the walk\nran out of budget, the report lists it under _Runtime code only partly read_\nso the silence is not mistaken for a pass.\n\nWhat it cannot see. Strings built at runtime stay opaque: a URL decoded from\nan obfuscated string array, fetched from somewhere, or assembled from pieces\nthat are not all literals. The real `sharedLoad.min.js` is that kind of file.\nGoing by Checkmarx's description of it, expect `exec-local` on the loader and the string-array rotation on the\npayload, not the endpoints. That is still two kinds, so HIGH, and still a\nfailing `diff`. Real Telegram client libraries name the bare API host and add\nthe `/bot` path later, so they do not fire, and neither would a payload written\nthe same way. The walk reads up to 200 files per package, with no limit\non how deep the `require` chain goes. `main` and everything it pulls in\ncome first, then each `exports` target and `bin` in turn. Past 200 the\noutput says `partial` (date-fns, with 1,480 exports targets, reaches it), and\nanything beyond it is unread. A declared entry point that is not in the\ntarball is reported with the reason, not fatal.\n\n## diff: what did an upgrade change in the install scripts?\n\nBefore you bump a pin, see exactly which install-time behavior a new version adds or changes, the surface npm v12 will ask you to re-approve. `diff` compares the `preinstall`/`install`/`postinstall` scripts (and the implicit `node-gyp rebuild` that ships with a root `binding.gyp`) between two versions, straight from the registry:\n\n```bash\nnpx npm-script-lens diff sharp@0.32.6 sharp@0.33.0\n# --json   emit { unchanged, added, removed, modified, gyp } instead of colored text\n# --runtime  also compare the code each version runs when required, see\n#            Payloads without install scripts\n```\n\n```\nsharp@0.32.6 → sharp@0.33.0\nREMOVED: implicit node-gyp rebuild (binding.gyp)\nMODIFIED: install\n    - (node install/libvips && node install/dll-copy && prebuild-install) || …\n    + node install/check\n```\n\n- **UNCHANGED** (green): key present in both, byte-identical\n- **ADDED** (red): a new script, or a gained `binding.gyp` → `ADDED: implicit node-gyp rebuild (binding.gyp)`\n- **REMOVED** (yellow): a script that went away\n- **MODIFIED** (red): same key, changed content, with a line-level diff\n- **PROVENANCE IDENTITY CHANGED** (red): the attested build identity moved, see below\n\n`diff` also resolves each version's [provenance identity](#provenance-an-identity-not-a-checkbox) and compares it. A version built from `acme/widget .github/workflows/release.yml@refs/tags/v1.2.0` upgrading to one built from `.github/workflows/hotfix.yml@refs/heads/main` prints:\n\n```\nPROVENANCE IDENTITY CHANGED  workflow .github/workflows/release.yml → .github/workflows/hotfix.yml, ref refs/tags/v1.2.0 → refs/heads/main\n```\n\nand exits 1, the same gate as an added or modified install script: the workflow that produced the artifact is not the one that produced the version you already trust. Provenance appearing or disappearing across the upgrade gates too. A new commit alone never does (every release has one), and an identity that cannot be resolved on either side is never compared, so registry hiccups cannot fail your CI. When the identity is present and unchanged, a green `UNCHANGED: provenance identity …` line says so.\n\n`binding.gyp` is compared **by content, not by existence** (fixed in 1.3.0). A\nversion that keeps its build file but *rewrites* it changes what runs at\ninstall time, and used to slip through as `UNCHANGED` / exit 0, the shape the\nJune 2026 wave-2 releases had. Now:\n\n```\n$ npx npm-script-lens diff bufferutil@4.0.8 bufferutil@4.0.9\nbufferutil@4.0.8 → bufferutil@4.0.9\nUNCHANGED: install\nMODIFIED: binding.gyp (implicit node-gyp rebuild, contents changed)\n      {\n    +   'variables': {\n    +     'openssl_fips': ''\n    +   },\n        'targets': [\n…\n$ echo $?\n1\n```\n\n`--json` carries `{ gyp: { changed, gainedChannels } }`; `gainedChannels` lists\ngyp execution channels present in the new version and absent from the old (here\nit is empty, a benign build-file edit, no new way to run a command). It also\ncarries `{ provenance: { changed, changes, old, new } }` with the resolved\nidentity of both sides.\n\nExit `0` when everything is unchanged; exit `1` the moment any script is **added or modified** or the **provenance identity changed**, so a Renovate/Dependabot CI step can fail the moment an upgrade grows its install-time surface. (A pure removal stays exit `0`.)\n\n## git and remote dependencies: the other two npm v12 flips\n\nnpm v12 doesn't just gate install *scripts*, it also stops resolving **git\ndependencies** (`github:user/repo`, `git+ssh://…`) and **remote tarball URLs**\n(`https://…/pkg.tgz`) unless you opt in via `allow-git` / `allow-remote` in\n`.npmrc`. Both are the strict enum `all` | `none` | `root` (default `none`);\n`root` allows only deps declared in your **root** package.json, so a single\n*transitive* git dep forces `all`. There's no migration tooling upstream, the\n[official discussion](https://github.com/orgs/community/discussions/198547)'s\nbest offer is `grep -r 'git+' package.json`. `sources` does the whole job:\n\n```bash\nnpx npm-script-lens sources                # report + the minimal correct .npmrc\nnpx npm-script-lens sources --check        # CI: exit 1 on insufficient, over-permissive, or invalid config\nnpx npm-script-lens sources --write        # merge the minimal values into .npmrc (comment-preserving)\nnpx npm-script-lens sources --json         # { git, remote, npmrc }\n```\n\nReal output for a project with a root-declared git dep and a transitive one:\n\n```\ngit dependencies (2)\n  ROOT        left-pad @ github:left-pad/left-pad\n  TRANSITIVE  some-pkg @ git+ssh://git@github.com/a/b.git   via my-lib -> some-pkg\nremote dependencies (0)\n\nminimal correct .npmrc:\n  allow-git=all\n\nallow-git=all is required because 1 git dependency is transitive; allow-git=root would otherwise suffice.\nRe-point or drop `some-pkg` (via my-lib) to tighten this to allow-git=root.\n```\n\nIt reads all four lockfile dialects (package-lock v1/v2/v3, yarn classic +\nberry, pnpm, bun.lock) with **zero network calls**, and `--check` fails in\nthree *distinct* ways so CI tells you what to do:\n\n- **insufficient**: npm v12 will refuse the install (missing `.npmrc`, or\n  `root` committed while a transitive git dep exists);\n- **over-permissive**: `all` committed where `root` (or nothing) suffices:\n  the least-privilege ratchet;\n- **invalid**: `allow-git=true` or a bare `--allow-git`, which several\n  published migration guides recommend, is **not in the enum**: npm treats it\n  as unset and your install still breaks. The check names the valid three.\n\n`allow --ci-check` folds the insufficient/invalid cases into its fast CI gate\ntoo, and `doctor` reports whether your npm has the keys at all (they appeared\nin 11.10.0 / 11.15.0) and warns that `allow-git=root` is unreliable on npm 11\n([npm/cli#9189](https://github.com/npm/cli/issues/9189), closed via PR #9206,\nroot-level git deps were wrongly rejected): prefer `all` there. The `.npmrc`\nemitter is npm-only; for yarn/pnpm/bun lockfiles the dependency report still\nworks, the write is skipped with a note.\n\n## cooldown: don't be the first to install a version\n\nEvery other check here asks *what does this package do?*. Cooldown asks only\n*how old is this version?*\n\nOn 2026-08-04 attackers compromised the `keyv` maintainer's GitHub account\n(~127M weekly downloads) and pushed the Mini Shai-Hulud worm into `keyv`,\n`cacheable`, `flat-cache` and `file-entry-cache`. It spread to nine unrelated\norganisations in about half an hour and 400+ packages that day, and, like\nevery worm before it, was identified and unpublished within hours. The install\nthat hurts you is the one that lands inside that window.\n\nSo don't go first.\n\n```bash\n# fail the build if any locked version is younger than 72h (the default)\nnpm-script-lens audit --cooldown\n\n# stricter, or looser\nnpm-script-lens audit --cooldown 24\n\n# ship a genuine same-day fix anyway\nnpm-script-lens audit --cooldown --cooldown-allow hotfix-pkg@2.0.1\n```\n\n```\n✗ cooldown 72h: 1 package version(s) published too recently:\n  keyv@5.5.5  6.0h old  (clears 2026-08-07 14:00Z)\n\nThese may be perfectly fine. Cooldown does not inspect them. It declines to be\namong the first to install a version, because npm worms are typically caught\nwithin hours. Wait, pin to an older version, or exempt with --cooldown-allow.\n```\n\nNotes:\n\n- It is **opt-in**. Without the flag, nothing changes.\n- Age comes from the absolute publish timestamp at evaluation time, never from\n  a cached day-resolution age, a stale cache errs toward *older*, which would\n  fail open on precisely the young version this is meant to catch.\n- Packages with no publish date (`--offline`, private registries) are listed as\n  unchecked rather than blocked.\n- Because a poisoned version doesn't need a lifecycle hook to hurt you,\n  `--cooldown` fetches publish dates for **every** locked package, not just the\n  ones with install scripts. That is more registry traffic than a plain audit.\n\n## cooldown config: your package manager has one too, in a different unit\n\n`--cooldown` above is a CI gate. It reads the lockfile and fails the build.\nIt says nothing about the cooldown a contributor's own `pnpm install` applies,\nand all four managers now have one:\n\n| manager | file | key | unit | its own default |\n|---|---|---|---|---|\n| npm | `.npmrc` | `min-release-age` | **days** | `null`, no gate |\n| pnpm | `pnpm-workspace.yaml` | `minimumReleaseAge` | **minutes** | `1440` since pnpm 11, `0` before |\n| yarn | `.yarnrc.yml` | `npmMinimalAgeGate` | **minutes**, or a duration string | `1d` since Yarn 4.15.0 |\n| bun | `bunfig.toml` `[install]` | `minimumReleaseAge` | **seconds** | `null`, no gate |\n\nSo `3` is three days, three minutes or three seconds depending on the file, and\ngetting it wrong does not fail. The install succeeds and the gate is not there.\n[yarnpkg/berry#6991](https://github.com/yarnpkg/berry/issues/6991) is that\nhappening to someone: they set `npmMinimalAgeGate: \"7d\"` from the docs and a\nfive-day-old release installed anyway, because their Yarn predated duration\nstrings and read it through `parseInt`, giving seven minutes.\n\n```bash\nnpm-script-lens cooldown            # report, always exits 0\nnpm-script-lens cooldown --check    # exit 1 on MISSING, UNIT-SUSPECT or DRIFT\nnpm-script-lens cooldown --write --cooldown 72\n```\n\nA pnpm project with `minimumReleaseAge: 3` and a CI job running\n`npm-script-lens audit --cooldown 72`:\n\n```\n$ npm-script-lens cooldown --check\ncooldown config — pnpm (pnpm-workspace.yaml)\n  UNIT-SUSPECT  minimumReleaseAge: 3  → 3 minutes (pnpm counts MINUTES), not 3 days\n                pnpm's own default is 1440 (1 day); 3 gates essentially nothing\n  DRIFT         configured 0.05h < enforced 72h (--cooldown in .github/workflows/ci.yml)\n                A version this project's own CI would block still installs on a contributor's machine.\n  fix:  npm-script-lens cooldown --write --cooldown 72\n        writes  minimumReleaseAge: 4320\n```\n\n`--write` then puts `4320` in, leaving every other key, comment, blank line and\nthe file's EOL style exactly as they were.\n\nThe four statuses:\n\n- **OK**: configured, in the right unit, at or above what CI enforces. The\n  converted hours is printed either way, so you can check the arithmetic.\n- **MISSING**: nothing configured while `--cooldown` is enforced in CI. Only\n  CI is protected; every local install goes straight through. If a pnpm project\n  has `minimumReleaseAge` sitting in `.npmrc`, the finding says so and points at\n  that line: pnpm reads only auth and registry settings from `.npmrc`, so the\n  value is dead where it is.\n- **UNIT-SUSPECT**: the value gates under an hour or over a month, *and* the\n  same number reads as a sensible cooldown in one of the other managers' units.\n  Both halves are required, so a deliberately odd threshold with no plausible\n  alternative reading is reported OK, not flagged.\n- **DRIFT**: configured below the enforced threshold, or exempt lists that\n  disagree with `--cooldown-allow`. The comparison uses what the manager\n  *actually* gates, which is not always what the file says: an old Yarn\n  truncating `7d` to seven minutes drifts on seven minutes.\n\nTwo more lines appear in the report but never fail `--check`, because neither\nis something the project got wrong:\n\n- **PARTIAL**: a config file this tool cannot round-trip. Nothing is rewritten.\n- **UNSUPPORTED**: a `--cooldown-allow` entry this manager cannot express, so\n  it was left out rather than written into a key that would ignore it.\n\nWhere the enforced number comes from: `--cooldown <hours>` if you pass it,\notherwise the strictest `--cooldown` this repo's own CI configs run\n(`.github/workflows/*.yml`, `.gitlab-ci.yml`, `.circleci/config.yml`, searched\nupward so a monorepo package finds the root's). If nothing enforces a cooldown\nanywhere, there is no MISSING and no DRIFT to report.\n\nExemptions are translated into the manager's own exclude key, and only in the\nforms that manager accepts:\n\n| manager | exclude key | accepts |\n|---|---|---|\n| npm | `min-release-age-exclude` | names or minimatch globs |\n| pnpm | `minimumReleaseAgeExclude` | names, `@myorg/*` patterns, versions joined with `\\|\\|` |\n| yarn | `npmPreapprovedPackages` | package descriptors or name globs |\n| bun | `minimumReleaseAgeExcludes` | package names only |\n\n`npm-script-lens cooldown --write --cooldown-allow urgent-fix pkg@1.2.3`\nagainst a bun project writes `urgent-fix` and skips `pkg@1.2.3` with a note:\nbun matches on names, so writing the descriptor would be a gate you believe in\nand bun ignores. Nothing is ever exempted that you did not pass.\n\nYarn specifics, because Yarn's gate has moved four times:\n\n- Duration strings (`3d`, `1w`) arrived in **4.11.0**\n  ([#6942](https://github.com/yarnpkg/berry/pull/6942)). Below that the setting\n  is `SettingsType.NUMBER` and a string is silently truncated by `parseInt`.\n  This is reported **against the version your project pins** (`packageManager`,\n  then `yarnPath`), never as a blanket warning: on current Yarn `7d` is exact.\n- `--write` emits Yarn's own `3d` idiom, and bare minutes instead on a project\n  pinned below 4.11.0.\n- A per-scope gate under `npmScopes`\n  ([#7156](https://github.com/yarnpkg/berry/pull/7156), Yarn 4.17.0) is read\n  and reported. It is never rewritten: exempting an internal registry is what\n  that feature is for.\n\nOther surfaces:\n\n```bash\nnpm-script-lens audit --cooldown 72 --cooldown-config   # both halves in one run\nnpm-script-lens cooldown --json\nnpm-script-lens cooldown --check --sarif cooldown.sarif # rule cooldown-config\nnpm-script-lens doctor                                  # one line, with the converted hours\n```\n\nIn the Action, opt in the same way as `sources-check`:\n\n```yaml\n- uses: Booyaka101/npm-script-lens@v1\n  with:\n    cooldown-check: 'true'\n```\n\nLimits worth knowing: a `bunfig.toml` this tool cannot round-trip (a multi-line\narray, for instance) is reported `PARTIAL` and `--write` refuses it rather than\nreformatting your file. The enforced threshold is found by reading `--cooldown`\nout of CI *files*; a threshold assembled from a shell variable at runtime is not\nvisible to it, so pass `--cooldown <hours>` in that case. And this reads\ncommitted config only, never your global `~/.npmrc`: the point is what everyone\nwho clones the repo gets.\n\n## Provenance: an identity, not a checkbox\n\nThe malicious `keyv@6.0.0` of 2026-08-04 carried a **valid** npm attestation\nnaming GitHub Actions as its trusted publisher.\n[Snyk's teardown](https://snyk.io/blog/inside-keyv-npm-compromise-preinstall-malware-trusted-provenance-ide-hooks/)\ndraws the boundary in one sentence: *\"Provenance can faithfully attest a build\nwhose source or workflow context has already been compromised.\"* A green\n`provenance ✓` on its own is therefore close to worthless as a trust signal,\nand this tool no longer stops there. When a version carries an attestation,\nthe audit resolves what it actually **claims**, from the registry's\nattestation endpoint (the SLSA v1 predicate): the source repository, workflow\npath, ref, commit and builder. The trust line in every report reads:\n\n```\n2.1y old · 127M dl/wk · 1 maintainer · provenance ✓ github.com/jaredwray/keyv .github/workflows/release.yml@refs/heads/main 4a91c0e\n```\n\nand `provenance ✓ (identity unavailable)` when the registry's answer is not a\nshape this build can resolve. The identity rides the same 24h trust cache, and\n`--offline` / `--no-trust` make zero attestation requests.\n\n**What we read, and what we do not verify.** This tool reads the claims the\nregistry serves over TLS and does **not** verify Sigstore signatures or\ntransparency-log inclusion. That is the same trust boundary as the tarball\nitself: if you trust the registry to hand you the package bytes, these are the\nclaims it hands you alongside them. Nothing here should be described as\ncryptographic verification, because it is not.\n\n**Honesty about what this catches.** ChainDrop's attacker published through\neach project's own repository and own release workflow, so the attested\nidentity matched perfectly and **this feature would not have caught it**.\nNeither would it have caught the TanStack compromise three months earlier\n(2026-05-11, 84 malicious versions across 42 `@tanstack/*` packages, the first\nworm to ship validly-attested malicious packages). There, a\n`pull_request_target` workflow that publishes nothing poisoned a shared pnpm\ncache; `release.yml` restored it on main; the payload read the OIDC token out\nof the runner's memory and posted straight to the registry. The\n[postmortem](https://tanstack.com/blog/npm-supply-chain-compromise-postmortem)\nis explicit about what an identity check would have seen: *\"The token's\nattested identity still matched `TanStack/router release.yml@refs/heads/main`.\"*\nWorth noting that this tool's own [DANGEROUS gate](#release-gates-who-can-publish-today)\nwould have missed it too, since it flags a publish path reachable from\n`pull_request_target` and that publish path was not reachable from one. The\nlink was a shared cache scope, not the trigger graph.\n\nThe defence in this tool for both events is [`--cooldown`](#cooldown-dont-be-the-first-to-install-a-version),\nand the window is narrow enough for it to work: TanStack's malicious versions\nwere publicly identified within 20 to 26 minutes.\nWhat identity resolution does catch: an attested repository that disagrees\nwith the package's declared repository, and a build identity that **moves**\nbetween the version you trust and the version you are installing, the\n[`diff` gate above](#diff-what-did-an-upgrade-change-in-the-install-scripts)\nand the `expectProvenance` [policy pin](#governance-policy). Honesty about prior art, because there is real prior art here. npmjs.com's\npackage page already shows Build Environment, Build Summary, Source Commit and\nBuild File for a provenance-carrying version. `npm audit signatures` checks\nregistry signatures and attestations. And\n[cosign](https://blog.sigstore.dev/cosign-verify-bundles/) already pins an\nexpected identity, cryptographically, which this tool does not do:\n\n```bash\ncosign verify-blob-attestation --bundle npm-provenance.sigstore.json --new-bundle-format \\\n  --certificate-oidc-issuer=\"https://token.actions.githubusercontent.com\" \\\n  --certificate-identity-regexp=\"^https://github.com/npm/node-semver/.github/workflows/release-integration.yml.?\" \\\n  semver-7.6.3.tgz\n```\n\nIf you need cryptographic assurance for one package, use that, not this. What\nthose tools do not do is work at **tree scale**: cosign verifies one artifact\nagainst one bundle you already fetched, and the npmjs.com page covers one\npackage you are already looking at. This tool resolves the identity for\n**every dependency in one CI run**, **diffs it across an upgrade**, and\nexpresses the expectation as **checked-in policy** rather than a regex in a\nshell command. That is the gap it fills, and it is narrower than \"we surface\nprovenance identity.\"\n\nTwo more surfaces carry it: `audit --diff`/`--since` reports\n`provenance identity changed vs <base>` per upgraded package next to the\ncapabilities-gained note (informational there, it never changes the audit exit\ncode), and SARIF gains `provenance-identity-changed` (warning) plus\n`provenance-repo-drift` (note). The repo-drift note fires when the attestation\nnames a different owner/repo than the packument declares, with both values\nspelled out. It is deliberately informational and never gates anything: npm\nrequires your `package.json` repository to match where you publish from with\nprovenance and re-checks the linked source when provenance is viewed, so a\nlive mismatch is almost always a repo rename or transfer since publish, not an\nattack. Monorepo subpaths never count as drift. `doctor` reports whether the\nattestation endpoint answered.\n\n## trust: the downgrade a stolen token cannot avoid\n\nThe March 2026 axios compromise had a tell that no behavioral scan needed: the\nattacker had the maintainer's npm token but not the maintainer's CI, so where\nevery recent legitimate release carried a provenance attestation, the malicious\n`1.14.1` and `0.30.4` carried none. That drop, a version resolving **below the\nhighest trust tier its package previously reached**, is what\n[npm/cli#9242](https://github.com/npm/cli/issues/9242) (59 👍, open since\nApril 2026) and [yarnpkg/berry#7101](https://github.com/yarnpkg/berry/issues/7101)\nask their package managers to refuse. **pnpm shipped it natively as\n`trust-policy=no-downgrade` in 10.21. npm and Yarn have not**, and this command\nis that gate for their lockfiles (and pnpm's and bun's too):\n\n```bash\nnpx npm-script-lens trust --fail-on-downgrade\n```\n\n```\nnpm-script-lens trust: provenance downgrade check (npm/cli#9242, trusted publisher > provenance > none)\nchecked 3 registry package(s)\n\nTRUST DOWNGRADE (1)\n  axios@1.13.3  provenance -> none\n    highest prior trust: provenance (axios@1.13.2, published 2025-11-04)\n    resolved version has no attestations\n    pnpm >= 10.21 would refuse this install under trust-policy=no-downgrade\n```\n\nThat output is real, not staged: axios `1.13.3` (published 2026-01-25, still on\nthe registry today) genuinely carries no attestations while `1.13.2` before it\ncarried provenance. Exit code is 1 only under `--fail-on-downgrade`, and only\nwhen a downgrade is present.\n\nThe ladder matches #9242: **trusted publisher > provenance > none**. A\ntrusted-publisher (OIDC) publish is recognized by the registry's\n`_npmUser.trustedPublisher` stamp on the version; provenance is\n`dist.attestations` on the version (the SLSA predicate rides along); absent\nattestations is none. One packument request per package answers all three\ntiers for every version at once, cached 24h alongside the other trust data.\n\nWhat never fires a finding: packages that have never published with\nattestations (there is no ratchet to fall from), a package's first published\nversion, versions published *after* the one you resolve (a later provenance\nadoption says nothing about your pin), git/remote-sourced dependencies (their\nhistory is not the registry's), and an unreachable registry, which warns once\nand exits 0 rather than failing your build on network weather. A previously\nunpublished version leaves a gap that is compared **around**, never counted as\na downgrade. Deprecated versions still count toward the max.\n\n`audit` runs the same check when you opt in, either with\n`audit --fail-on-downgrade` or with the policy key, and emits the finding in\nthe report, `--json` (`results[].trustDowngrade`) and SARIF (rule\n`trust-downgrade`, level error, anchored to the package's lockfile line):\n\n```jsonc\n// script-lens.policy.json, npm/cli#9242's keys so your config carries over\n// if npm ever ships trust-policy natively\n{\n  \"trustPolicy\": \"no-downgrade\",          // #9242: trust-policy (default \"off\")\n  \"trustPolicyExclude\": [\"pkg@1.2.3\"],    // #9242: trust-policy-exclude[]\n  \"trustPolicyIgnoreAfter\": 525600        // #9242: trust-policy-ignore-after (minutes)\n}\n```\n\n`trustPolicy: \"no-downgrade\"` makes every `audit` surface the finding without\nchanging any exit code; the exit only flips under `--fail-on-downgrade`, so no\nexisting CI changes colour without opting in. `trustPolicyExclude` allows a\nnamed version despite its drop (a maintainer who genuinely moved off CI);\n`trustPolicyIgnoreAfter` retires prior evidence older than the window. The\n`trust` command also takes them directly as `--exclude pkg@version` and\n`--ignore-after minutes`.\n\n**Honest limitations.** A package whose 0.x maintenance line is published by\nhand while the 1.x line uses CI will flag the 0.x versions, exactly as pnpm's\n`trust-policy=no-downgrade` refuses them (real example: axios `0.30.x`);\nthat is what `trustPolicyExclude` is for. And like the\n[provenance identity check](#provenance-an-identity-not-a-checkbox), this\nreads registry claims over TLS, it does not verify Sigstore signatures. It\nalso cannot catch an attacker who compromises the CI itself and publishes\n*with* provenance, the ChainDrop shape; `--cooldown` and the identity diff are\nthe tools for that half.\n\n## publish: will your release workflow survive January 2027?\n\nThe other side of the same coin: npm-script-lens guards the *install* side of\nyour workflows; `publish` guards the *publish* side. The [GitHub changelog of\n2026-07-31](https://github.blog/changelog/2026-07-31-restricting-npm-bypass-2fa-granular-access-tokens/)\nis explicit: *\"2FA-bypass tokens will also lose direct publish. Their\npublishing surface will reduce to reading private packages and staging a\npublish, which a maintainer approves with 2FA. We are targeting January 2027\nfor this update.\"* Phase 1 already shipped on 2026-07-31, so publishing is the\nlast thing those tokens can still do. If your release workflow does\n`npm publish` with `NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}`, it has an\nexpiry date.\n\n```bash\nnpx npm-script-lens publish            # classify every CI publish path + the migration patch\nnpx npm-script-lens publish --check    # CI: exit 1 when a path uses a long-lived token or is BROKEN\nnpx npm-script-lens publish --json     # { cliff, floors, counts, paths, repo, engines }\nnpx npm-script-lens publish --sarif f  # rules publish-token-cliff + publish-oidc-broken, workflow-line anchored\n```\n\nIt reads `.github/workflows/*.yml`, `.github/actions/**/action.yml`,\n`.gitlab-ci.yml` and `.circleci/config.yml` (no network, no YAML dependency),\nfinds `npm publish`, `npm stage publish`, `pnpm publish`, `yarn npm publish`,\n`np`, `semantic-release`, `changesets/action` and `JS-DevTools/npm-publish`,\nand classifies each path as exactly one of:\n\n- **TRUSTED**: an id-token grant (`permissions: id-token: write` or\n  `write-all`; GitLab `id_tokens` with audience `npm:registry.npmjs.org`;\n  CircleCI `NPM_ID_TOKEN`) and no token: already on [trusted publishing\n  (OIDC)](https://docs.npmjs.com/trusted-publishers), survives the cliff;\n- **STAGED**: `npm stage publish`, where a maintainer approves with 2FA\n  (`npm stage approve <stage-id>`), survives the cliff;\n- **TOKEN**: `NODE_AUTH_TOKEN`/`NPM_TOKEN` in the env, or an `.npmrc` write\n  containing `_authToken`. **Stops working around January 2027**, and fails\n  `--check`;\n- **BROKEN**: trusted publishing is granted, but the job's\n  `actions/setup-node` is v6 or older *and* passes\n  `registry-url: https://registry.npmjs.org`. Every setup-node release up to\n  v6 answers that input by writing\n  `//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}` into an `.npmrc` and\n  exporting a dummy `NODE_AUTH_TOKEN`, so npm sees auth as configured and\n  never starts the OIDC exchange, so the publish fails with ENEEDAUTH/E404\n  ([npm/documentation#1960](https://github.com/npm/documentation/issues/1960);\n  fixed in\n  [setup-node v7.0.0](https://github.com/actions/setup-node/releases/tag/v7.0.0)).\n  The official trusted-publishers docs still show the broken `@v6` recipe.\n  Fails `--check`; the report gives all three fixes (bump to `@v7`, drop\n  `registry-url:`, or `sed -i '/_authToken/d' \"$NPM_CONFIG_USERCONFIG\"`) and a\n  job that already strips the line stays TRUSTED. An unresolvable setup-node\n  ref (SHA pin, branch, expression) gets a ⚠️ note, never a downgrade;\n- **UNKNOWN**: a publish exists but the auth is ambiguous (third-party\n  reusable workflows, both grant and token, neither visible): reported, never\n  a failure.\n\nA publish step hidden behind `uses: ./.github/actions/release` is followed\ninto the composite action itself (and into local reusable workflows, nested up\nto 3 levels): the path anchors to the real `action.yml` line, an indented\n`via .github/workflows/release.yml:11 (job release, step \"Release\")` line\nshows the call chain, and the auth threads the way GitHub threads it:\ncomposite actions cannot declare `permissions`, so the id-token grant is\nalways the calling job's, and a composite\n`env: NODE_AUTH_TOKEN: ${{ inputs.npm-token }}` is resolved through the\ncalling step's `with:` map back to `secrets.NPM_TOKEN`. A publishing composite\nunder `.github/actions/` that no workflow in the repo references is still\nreported (UNKNOWN, since it may be called from another repo). Third-party actions\n(`actions/checkout@v4`) are never flagged.\n\nThen it does the three checks no migration blog performs:\n\n1. **Version floors**, verbatim from docs.npmjs.com: trusted publishing\n   *\"requires npm CLI version 11.5.1 or later and Node version 22.14.0 or\n   higher\"*; staged publishing *\"requires npm CLI version 11.15.0 or later and\n   Node version 22.14.0 or higher.\"* A `setup-node` pin (or an\n   `engines.node` minimum) below the floor is called out with exactly which\n   fix it blocks. Migrating a workflow that's pinned to Node 20 fails at the\n   first publish, so the pin bump is part of the fix.\n2. **Runner eligibility.** Trusted publishing supports **only** GitHub-hosted\n   runners, GitLab.com shared runners and CircleCI cloud: *\"Self-hosted\n   runners are not currently supported but are planned for future releases.\"*\n   A `runs-on: self-hosted` publish job gets trusted publishing marked\n   **UNAVAILABLE** and is routed to the one path that survives there:\n   `npm stage publish` + `npm stage approve <stage-id>`.\n3. **The npmjs.com side, pre-filled.** Trusted publishing also needs config on\n   npmjs.com; `publish` emits the settings checklist filled in from your repo\n   (org/user, repository, workflow filename *with its extension*, the\n   environment name if the job declares one, and the allowed actions).\n\nReal output for a workflow publishing with a token on Node 20:\n\n```\npublish paths (1)\n  TOKEN     .github/workflows/release.yml:15  npm publish   [job release · ubuntu-latest]\n            long-lived token: NODE_AUTH_TOKEN in the publish step env (line 17)\n\n⛔ 1 TOKEN publish path. Direct token publishing stops working around January 2027.\n\nfix for .github/workflows/release.yml:15, switch to trusted publishing (OIDC):\n  add to the `release` job (or the workflow top level) in .github/workflows/release.yml:\n    + permissions:\n    +   id-token: write\n  remove the token from the publish step (line 17):\n    - env:\n    -   NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n  ⚠️  node-version 20 (.github/workflows/release.yml:12) is below the Node 22.14.0 floor …\n\nnpmjs.com trusted-publisher settings (package Settings → Trusted publisher):\n  GitHub organization or user: acme\n  repository:                  widget\n  workflow filename:           release.yml   (with its extension, exactly as on disk)\n  environment:                 (the job declares none, leave blank)\n  allowed actions:             npm publish   (also allow \"npm stage publish\" if you plan to stage releases)\n```\n\n`doctor` reports the same readiness mix (naming the setup-node ref on a\nBROKEN path), and the GitHub Action's [`publish-check` input](#github-action)\nfails the job with an `::error` and a `publish-token-cliff` /\n`publish-oidc-broken` SARIF result when a TOKEN or BROKEN path remains.\n\n### Release gates: who can publish *today*?\n\nAuth answers \"will this path publish after January 2027\". It does not answer\nthe ChainDrop question. On 2026-08-04 that worm published 2,234 poisoned\nversions across 444 npm package names by taking over a maintainer's GitHub\naccount and letting each project's own release workflow build, sign and\npublish, with valid provenance, because the authorized build system produced\nit. So `publish` now reports two more facts per resolved path: the **trigger**\n(which workflow events reach the job, with file:line) and the **gate** (what\nhuman action, if any, stands between a commit and `npm publish`):\n\n- **DANGEROUS**: reachable from `pull_request_target` or `workflow_run`.\n  crates.io removed both from Trusted Publishing (development update,\n  2026-01-21): *\"Both triggers have been involved in past CI security\n  incidents, where attackers exploited workflow permissions to escalate\n  access or obtain publishing credentials.\"* Fails `--check` on its own.\n- **REVIEWABLE**: the job declares `environment:`, the one hook GitHub offers\n  for required reviewers. PyPI's security model: *\"Dedicated environments\n  allow for additional protections like required reviewers, which can be used\n  to require manual approval for a workflow using the environment.\"*\n- **MANUAL**: only `workflow_dispatch` and/or `release` reach the job.\n- **TAG**: `push` with a tags-only filter.\n- **AUTO**: a branch push, bare push, schedule or pull_request, with no\n  environment. Any commit that lands publishes.\n- **UNKNOWN**: not determinable (e.g. `on: workflow_call` with no caller in\n  this repo). Never affects the exit code.\n\nThe worked example, a release workflow publishing on every merge to main:\n\n```\npublish paths (1)\n  TRUSTED   .github/workflows/release.yml:22  npm publish   [job release · ubuntu-latest]\n            trusted publishing (OIDC): id-token: write granted (line 9), no\n            token in the env\n            trigger: push → branches: [main]   (.github/workflows/release.yml:3)\n            gate:    AUTO: any commit that lands on main publishes to npm. The\n                     job declares no environment:, so GitHub cannot require an\n                     approval.\n            fix:     add `environment: release` to job \"release\" (line 11) and\n                     set required reviewers on it (PyPI: \"Dedicated environments\n                     allow for additional protections like required reviewers\");\n                     or move to `on: release: types: [published]`; or publish\n                     with `npm stage publish` + `npm stage approve <stage-id>`.\n```\n\n(Reports reflow to your terminal width, so the wrapping above is what an\n80-column terminal shows. Piped or redirected output is not reflowed.)\n\nAdd `environment: release` to that job and the gate reads REVIEWABLE.\nHonesty note: whether required reviewers are actually configured on an\nenvironment is a repository setting, not a file, so this tool cannot verify\nit; REVIEWABLE says \"verify required reviewers are configured on it\" rather\nthan implying it checked. Triggers thread through local reusable workflows\nand composite actions (a path reached via `.github/actions/release` inherits\nthe calling workflow's `on:`). GitLab jobs classify from `environment:`,\n`when: manual` and tag-only `rules:`/`only:`; CircleCI from an approval-type\njob upstream in the same workflow; anything else stays UNKNOWN, never a\nguess.\n\n`publish --check` exits 1 on DANGEROUS (plus TOKEN and BROKEN, as before).\n`--require-gate <none|tag|manual|environment>` (default `none`) raises the\nbar: `tag` fails AUTO paths, `manual` also fails TAG, `environment` demands\nREVIEWABLE. SARIF gains `publish-dangerous-trigger` (error) and, under\n`--require-gate`, `publish-ungated` (warning), anchored to the trigger line.\n\nTo be clear about what is new here: zizmor's `dangerous-triggers` audit\nalready flags `pull_request_target` and `workflow_run` generically, in any\nworkflow. What zizmor (41 audits), poutine (13 rules) and octoscan do not do\nis attribute a trigger and a human approval gate to a *resolved npm publish\npath*, through composite actions and reusable workflows, with a\nregistry-precedent fix ladder. That attribution is this release.\n\n## hooks: what runs when the folder is *opened*?\n\nnpm-script-lens covers three moments where code runs without you asking:\ninstall time (`audit`/`allow`), resolution time (`sources`), publish time\n(`publish`). The 2026-08-04 keyv/ChainDrop worm used a fourth: **open\ntime**. [Wiz's teardown](https://www.wiz.io/blog/keyv-and-cacheable-npm-supply-chain-attack)\nsays it plainly: *\"Persistence is attempted via Claude Code hooks and VS Code\n`tasks.json`\"*, two separately-hashed `setup.mjs` payloads, one under\n`.claude`, one under `.vscode`. And the tarball half predates the worm:\n[hijacked npm packages](https://thehackernews.com/2026/06/hijacked-npm-and-go-packages-use-vs.html)\n`html-to-gutenberg` and `fetch-page-assets` (2026-05-25) shipped a hidden VS\nCode task named `eslint-check` with `\"runOn\": \"folderOpen\"`, firing when the\npackage directory itself is opened as a workspace.\n\n```bash\nnpx npm-script-lens hooks                  # scan the working tree (monorepo subdirs included)\nnpx npm-script-lens hooks --check          # CI: exit 1 at or above the --fail-on floor (default high)\nnpx npm-script-lens hooks --deps           # also scan every locked dependency's tarball\nnpx npm-script-lens hooks --json           # { findings, partial, caveats, deps }\nnpx npm-script-lens hooks --sarif hooks.sarif   # rule hook-auto-run, anchored to the real file:line\n```\n\nTwo surfaces (one table row each in `src/hooks.js`, adding an editor is a\none-file patch):\n\n- **`.vscode/tasks.json`**: any task whose `runOptions.runOn` is\n  `\"folderOpen\"`, with its label, command+args, type, and whether\n  `presentation.reveal: \"silent\"` hides the terminal.\n- **`.claude/settings.json`**: a [documented project-level, committable\n  hooks location](https://code.claude.com/docs/en/hooks). Auto-firing events\n  (`SessionStart`, `Setup`, `InstructionsLoaded`) tier at full strength;\n  agent-triggered ones (`PreToolUse`, `PostToolUse`, …) are collected, tiered\n  one level lower and labelled. The four non-command hook types (`http`,\n  `mcp_tool`, `prompt`, `agent`, with `command`, the complete documented\n  set) are reported, but never as command execution.\n\nBoth files permit comments and trailing commas, so the reader is a tolerant\nJSONC parser in the same spirit as [the gyp lens](#the-gyp-lens-what-is-actually-inside-bindinggyp):\na file that will not parse is reported `partial` (with a raw-text hint when\n`folderOpen` or an auto event name appears in the bytes), never passed\nsilently, never a crash. Every command string feeds the **same** shell-signal\nextraction and `score()` that `audit` applies to a lifecycle script, the\nrisk ladder is not forked. Real output for a repo carrying both worm\nartifacts:\n\n```\n.vscode/tasks.json:4  HIGH  folderOpen task \"eslint-check\" → node .vscode/setup.mjs (silent)\n.claude/settings.json:3  HIGH  SessionStart hook → node .claude/setup.mjs\n2 open-time execution entries found (2 HIGH).\n```\n\n`--deps` additionally downloads every locked dependency's tarball (cached,\nlike audit results) and scans it for shipped `.vscode`/`.claude` surfaces, a\nfolderOpen task inside a *package* is a payload, not a team convention, so it\nis **HIGH regardless of command**.\n\nThe two surfaces gate very differently, and the tool prints each caveat next\nto its own surface rather than one softened blend:\n\n> **VS Code:** a `.vscode/tasks.json` finding means *\"this runs once you\n> trust this folder and allow automatic tasks\"*, not *\"this has run\"*,\n> [VS Code 1.117](https://code.visualstudio.com/docs/debugtest/tasks)\n> defaults `task.allowAutomaticTasks` to `off` with a one-time Allow/Disallow\n> prompt, workspace settings can no longer define that key, and automatic\n> tasks never run in an untrusted workspace. The residual gap\n> ([microsoft/vscode#309406](https://github.com/microsoft/vscode/issues/309406))\n> is that the prompt does **not** display the command it is about to allow.\n>\n> **Claude Code:** a `SessionStart` finding means *\"this runs on your next\n> session in this trusted folder\"*, there is **no hook review gate** before\n> a project `.claude/settings.json` command hook fires (*\"Claude Code doesn't\n> use the same hook review gate as Codex\"*, Datadog Security Labs, 2026-08).\n\nInterpolations (`${workspaceFolder}`, `${CLAUDE_PROJECT_DIR}`) are kept\nliteral, never resolved. `.claude/settings.local.json` is out of scope, it\nis machine-local and gitignored, so it neither ships in a tarball nor arrives\nwith a clone.\n\n## review: see what you're approving, not just its name\n\nnpm v12's own pending list stops at the script *command*:\n\n```\n$ npm approve-scripts --allow-scripts-pending\nsharp@0.33.5   install: node install/check\n```\n\nWhat's inside `install/check`? npm can't tell you, [the #1 complaint in the v12 migration discussion](https://github.com/orgs/community/discussions/198547). `review` picks up exactly where npm stops:\n\n```bash\nnpx npm-script-lens review                        # show every pending approval with evidence\nnpx npm-script-lens review --output-allowscripts  # …and write the decisions into package.json\n```\n\nFor each package awaiting an `allowScripts` decision it shows the script command, the **first 40 lines of the actual file the command runs** (from the version-pinned registry tarball, or `node_modules` with `--offline`), the behavioral scan verdict with signals, the OSV malware check, and publisher trust:\n\n```\n── sharp@0.33.5  [🔴 HIGH]\n   1.9y old · 75M dl/wk · 1 maintainer · no provenance\n   OSV: no known malicious advisories\n   install: node install/check\n     exec: node-gyp rebuild --directory=src\n     exec: require('child_process')\n   ┌─ install/check.js (first 40 of 42 lines)\n   │   1  // Copyright 2013 Lovell Fuller and others.\n   │   2  // SPDX-License-Identifier: Apache-2.0\n   …\n```\n\nThe pending set comes from your own npm when it can answer: with npm ≥ 12, `review` runs `npm install --dry-run --json` and reads its `unreviewedScripts`, so what you review is literally what npm would block, even before a lockfile exists. On npm < 12 (or `--offline`) it computes the same set from the lockfile minus your `allowScripts` entries (bare-name and pinned keys both count, and `false` is a decision too, matching npm v12's semantics exactly).\n\n`--output-allowscripts` merges version-pinned entries for every reviewed package into `package.json`, preserving existing decisions: SAFE/LOW default to `true`, HIGH/MEDIUM and OSV-flagged packages to `false`, so flip after reading the evidence. `--json` emits the whole review (pending, risk, content, suggested block) for scripting. `NPM_SCRIPT_LENS_NPM` overrides which npm the dry-run uses.\n\n## allow: pre-approve the safe packages, hold the risky ones, in any package manager\n\n`allow` runs the scan and splits every package that has install-time scripts into two buckets, the ones behavioral analysis found harmless (SAFE/LOW) go straight into the allowlist; everything that spawns processes, reaches the network, is known-malicious, or couldn't be fetched (MEDIUM/HIGH) is held back in a `_review` list for a human. It emits the block in **your package manager's native format**, auto-detected from the lockfile, on stdout, with a one-line summary on stderr:\n\n```bash\nnpx npm-script-lens allow                     # scan, print the native allowlist block + _review\nnpx npm-script-lens allow --write             # …and merge the auto-approved entries into the right file\nnpx npm-script-lens allow --manager pnpm      # force a manager instead of auto-detecting\nnpx npm-script-lens allow --input audit.json  # classify a saved `audit --json` result, no rescan\n```\n\nEvery major package manager adopted the same \"scripts are opt-in, keep an allowlist\" model. `allow` writes each one's native format: same risk policy, same analysis, different file:\n\n| manager | allowlist | file | `allow --write` target |\n|---|---|---|---|\n| **npm** 12 | `allowScripts: { \"pkg@1.2.3\": true }` | package.json | package.json |\n| **pnpm** 10.26+/11 | `allowBuilds: { pkg: true }` | pnpm-workspace.yaml | pnpm-workspace.yaml (comment-preserving) |\n| **yarn** Berry | `dependenciesMeta.<pkg>.built: true` | package.json | package.json + `enableScripts: false` in .yarnrc.yml |\n| **bun** | `trustedDependencies: [\"pkg\"]` | package.json | package.json |\n\n```jsonc\n// npm project → allowScripts (version-pinned)\n{ \"allowScripts\": { \"core-js@3.38.1\": true }, \"_review\": [\"sharp@0.32.6\"] }\n// pnpm project → allowBuilds (by name)\n{ \"allowBuilds\": { \"core-js\": true }, \"_review\": [\"sharp@0.32.6\"] }\n```\n\n```\n1 package auto-approved, 1 need manual review. (pnpm, allowlist in pnpm-workspace.yaml)   ← stderr\n```\n\n> **bun caveat** (surfaced automatically): defining `trustedDependencies` *replaces* bun's built-in trusted list, so packages bun trusted by default (esbuild, sharp…) stop running scripts unless listed. **yarn** needs `enableScripts: false` to turn `dependenciesMeta` into an allowlist, and `allow --write` sets it for you.\n\n### CI guard\n\n`allow --ci-check` runs **no scan**, it's a fast gate for CI. It exits `1` when all three are true: a workflow in `.github/workflows/` runs `npm install`/`npm i`/`npm ci`, `package.json` has no `allowScripts` block, and the local npm is v12+ (probed via `npm --version`). That is exactly the combination where npm v12 will silently skip every dependency's install scripts and your build breaks with no obvious cause.\n\n```bash\nnpx npm-script-lens allow --ci-check\n# CI will break on npm v12: run lens allow to generate allowScripts block.  (exit 1)\n```\n\nAny one of those conditions being false, npm < 12, an existing `allowScripts` block, or no `npm install` in CI, passes with a one-line reason. To fix a failing check, run `allow --write`: it writes the auto-approved entries and leaves the `_review` packages out (writing them would be deciding for you, so they stay pending until a human looks).\n\n## Governance policy\n\nBy default `allow`/`review`/`sync` auto-approve SAFE/LOW behavioral risk. A `script-lens.policy.json` in the project root (or `--policy <file>`) turns that fixed heuristic into a team decision:\n\n```json\n{\n  \"autoApprove\": {\n    \"maxRisk\": \"LOW\",            // approve up to this risk (SAFE|LOW|MEDIUM|HIGH)\n    \"denyCapabilities\": [\"net\"], // never auto-approve a script that reaches the network…\n    \"minAgeDays\": 30,            // …or a version published < 30 days ago (needs trust data)\n    \"requireProvenance\": false,  // …or one without a provenance attestation\n    \"expectProvenance\": {        // pin the attested build identity per package\n      \"keyv\": \"jaredwray/keyv:.github/workflows/release.yml\"\n    }\n  },\n  \"waivers\": {\n    \"sharp\": { \"allow\": true, \"reason\": \"vetted native build\", \"expires\": \"2027-01-01\" }\n  },\n  \"runtimeBootstrapPolicy\": \"fail\" // exit audit 1 on a RUNTIME_BOOTSTRAP finding\n}\n```\n\nWaivers are explicit human decisions that override the heuristic until they expire, an auditable record of *why* a risky package was trusted. With no policy file present, behavior is exactly the built-in default.\n\n`runtimeBootstrapPolicy: \"fail\"` is the checked-in form of\n[`--fail-on-runtime-bootstrap`](#runtime_bootstrap-installing-a-different-runtime-to-step-outside-the-model):\neither arms the gate so `audit` exits 1 when a package installs another\nJavaScript runtime at install time. It defaults to `\"off\"`, so no existing CI\nchanges colour without opting in.\n\nBe","readmeFilename":"README.md"}