From 22df72ac7fd0cf3f9d1f4069ef4a7bb8cfd2f390 Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Sun, 3 May 2026 19:04:54 -0700 Subject: [PATCH] chore(release): clarify local npm auth bootstrap --- doc/PUBLISHING.md | 4 ++++ scripts/bootstrap-npm-package.mjs | 29 ++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/doc/PUBLISHING.md b/doc/PUBLISHING.md index 492a9250b3f..5bf67c6b20e 100644 --- a/doc/PUBLISHING.md +++ b/doc/PUBLISHING.md @@ -212,6 +212,10 @@ The helper script: - runs `npm pack --dry-run` in the package directory - only runs the real `npm publish --access public` when `--publish` is provided +For the real `--publish` step, the maintainer machine must already be authenticated to npm. +If `npm whoami` returns `401`, run `npm login` or `npm adduser` locally as an npm org member first, then rerun the helper. +That local human auth is fine for the one-time bootstrap publish; we just do not want the same auth model inside CI. + After that first publish succeeds: 1. open `https://www.npmjs.com/package/@paperclipai/adapter-acpx-local` diff --git a/scripts/bootstrap-npm-package.mjs b/scripts/bootstrap-npm-package.mjs index 786aff87898..b2bb5180b26 100644 --- a/scripts/bootstrap-npm-package.mjs +++ b/scripts/bootstrap-npm-package.mjs @@ -92,6 +92,32 @@ function runChecked(command, args, options = {}) { } } +function ensureNpmAuth() { + const result = runCommand("npm", ["whoami"]); + const stdout = result.stdout ?? ""; + const stderr = result.stderr ?? ""; + + if (stdout) process.stdout.write(stdout); + if (stderr) process.stderr.write(stderr); + + if (result.status === 0) { + return; + } + + const output = `${stdout}\n${stderr}`.trim(); + if (/\bE401\b|401 Unauthorized/i.test(output)) { + throw new Error( + [ + "npm auth check failed.", + "Run `npm login` or `npm adduser` on this maintainer machine with an npm account that can publish to the @paperclipai scope, then rerun with --publish.", + "Do not use this auth flow in CI; it is only for the one-time human bootstrap publish.", + ].join(" "), + ); + } + + throw new Error("npm whoami failed"); +} + function inspectNpmPackage(packageName) { const result = runCommand("npm", ["view", packageName, "version", "--json"]); @@ -168,7 +194,7 @@ function main(argv) { if (publish) { process.stdout.write("Checking npm auth with npm whoami...\n"); - runChecked("npm", ["whoami"]); + ensureNpmAuth(); } if (!skipBuild && typeof pkg.pkg?.scripts?.build === "string") { @@ -208,6 +234,7 @@ if (isDirectRun) { } export { + ensureNpmAuth, inspectNpmPackage, parseArgs, resolveTargetPackage,