mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-18 15:39:47 +02:00
fix(cli): accept npm 12 array output when resolving published version (#14000)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The CLI `install` and `update` commands resolve the published version with `npm view paperclipai@<spec> version --json` > - npm 12 changed the output of this command. It wraps a single value in an array: `["2026.916.1"]` instead of `"2026.916.1"` > - `parseResolvedVersion()` accepts only a bare JSON string, so it throws "npm returned an unexpected version response" > - Node 26 ships with npm 12, so a new install with the official `install.sh` fails for these users > - This pull request makes the parser accept a one-element string array > - The benefit is that install and update work with npm 12 and with older npm versions ## Linked Issues or Issue Description Fixes #12226 ## What Changed - `cli/src/commands/install.ts`: `parseResolvedVersion()` returns the value when npm returns a one-element array of strings. Other shapes still throw the same error. - `cli/src/__tests__/install-command.test.ts`: add a test for npm 11 output, npm 12 output, and plain-text output. The test also checks that a multi-element array still throws. ## Verification - Before the fix: on Node 26.8.2 with npm 12.0.2, `bash install.sh` fails with `npm returned an unexpected version response: [ "2026.916.1" ]`. - `npm view paperclipai@latest version --json` gives `["2026.916.1"]` with npm 12.0.2 and `"2026.916.1"` with npm 11.20.0. - `cd cli && npx vitest run src/__tests__/install-command.test.ts src/__tests__/update-command.test.ts src/__tests__/channels.test.ts`: 40 tests pass. - Without the source change, the new test fails with the same error as the bug report. ## Risks - Low risk. The change adds one accepted input shape. Existing accepted shapes do not change. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell and file editing). It helped to find the cause, write the change and the test, and run the tests. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
1 parent
fa062b202d
commit
e15435b651
2 files changed
+12
No files matched your search
@@ -10,6 +10,7 @@ import {
|
||||
resolveGitInstallRequest,
|
||||
resolveGitInstallWorkspacePackages,
|
||||
resolveNpmInstallRequest,
|
||||
resolvePublishedVersion,
|
||||
runCommandWithDiagnostics,
|
||||
} from "../commands/install.js";
|
||||
import { uninstallCommand } from "../commands/uninstall.js";
|
||||
@@ -62,6 +63,15 @@ describe("managed install commands", () => {
|
||||
expect(() => resolveNpmInstallRequest({ version: "latest" })).toThrow();
|
||||
});
|
||||
|
||||
it("parses npm view version output from npm 11 and npm 12", async () => {
|
||||
for (const stdout of ['"2026.916.1"\n', '[\n "2026.916.1"\n]\n', "2026.916.1\n"]) {
|
||||
const runCommand = vi.fn(async () => ({ stdout, stderr: "" }));
|
||||
await expect(resolvePublishedVersion("latest", runCommand)).resolves.toBe("2026.916.1");
|
||||
}
|
||||
const multiple = vi.fn(async () => ({ stdout: '["2026.916.0","2026.916.1"]', stderr: "" }));
|
||||
await expect(resolvePublishedVersion("latest", multiple)).rejects.toThrow("unexpected version response");
|
||||
});
|
||||
|
||||
it("resolves branch, tag, full SHA, and short SHA refs through GitHub", async () => {
|
||||
const sha = "a".repeat(40);
|
||||
const runCommand = vi.fn(async (_file: string, _args: string[]) => ({ stdout: JSON.stringify({ sha }), stderr: "" }));
|
||||
|
||||
@@ -111,6 +111,8 @@ function parseResolvedVersion(stdout: string): string {
|
||||
try {
|
||||
const parsed = JSON.parse(trimmed) as unknown;
|
||||
if (typeof parsed === "string") return parsed;
|
||||
// npm 12 wraps single-value `npm view --json` output in an array.
|
||||
if (Array.isArray(parsed) && parsed.length === 1 && typeof parsed[0] === "string") return parsed[0];
|
||||
} catch {
|
||||
if (EXACT_VERSION_PATTERN.test(trimmed)) return trimmed;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user