@@ -9,6 +9,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `pi update` reinstalling npm packages that are already at the latest published version by checking the installed package version before running `npm install <pkg>@latest` ([#3000](https://github.com/badlogic/pi-mono/issues/3000))
|
||||
- Fixed built-in tool wrapping to use the same extension-runner context path as extension tools, so built-in tools receive execution context and `read` can warn when the current model does not support images ([#3429](https://github.com/badlogic/pi-mono/issues/3429))
|
||||
- Fixed threaded `/resume` session relationships and current-session detection to canonicalize symlinked session paths during selector comparisons, so shared session directories no longer break parent-child matching or active-session delete protection ([#3364](https://github.com/badlogic/pi-mono/issues/3364))
|
||||
- Fixed `/session`, Sessions docs, and CLI help to consistently document that session reuse supports both file paths and session IDs, and that `/session` shows the current session ID ([#3390](https://github.com/badlogic/pi-mono/issues/3390))
|
||||
|
||||
@@ -1001,6 +1001,20 @@ export class DefaultPackageManager implements PackageManager {
|
||||
const parsed = this.parseSource(source);
|
||||
if (parsed.type === "npm") {
|
||||
if (parsed.pinned) return;
|
||||
|
||||
const installedPath = this.getNpmInstallPath(parsed, scope);
|
||||
const installedVersion = existsSync(installedPath) ? this.getInstalledNpmVersion(installedPath) : undefined;
|
||||
if (installedVersion) {
|
||||
try {
|
||||
const latestVersion = await this.getLatestNpmVersion(parsed.name);
|
||||
if (latestVersion === installedVersion) {
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Preserve existing update behavior when version lookup fails.
|
||||
}
|
||||
}
|
||||
|
||||
await this.withProgress("update", source, `Updating ${source}...`, async () => {
|
||||
await this.installNpm(
|
||||
{
|
||||
|
||||
@@ -1455,13 +1455,22 @@ export default function(api) { api.registerTool({ name: "test", description: "te
|
||||
});
|
||||
|
||||
describe("offline mode and network timeouts", () => {
|
||||
it("should update project npm packages using @latest", async () => {
|
||||
it("should update project npm packages using @latest when newer version is available", async () => {
|
||||
const installedPath = join(tempDir, ".pi", "npm", "node_modules", "example");
|
||||
mkdirSync(installedPath, { recursive: true });
|
||||
writeFileSync(join(installedPath, "package.json"), JSON.stringify({ name: "example", version: "1.0.0" }));
|
||||
settingsManager.setProjectPackages(["npm:example"]);
|
||||
|
||||
const runCommandCaptureSpy = vi.spyOn(packageManager as any, "runCommandCapture").mockResolvedValue('"1.2.3"');
|
||||
const runCommandSpy = vi.spyOn(packageManager as any, "runCommand").mockResolvedValue(undefined);
|
||||
|
||||
await packageManager.update("npm:example");
|
||||
|
||||
expect(runCommandCaptureSpy).toHaveBeenCalledWith(
|
||||
"npm",
|
||||
["view", "example", "version", "--json"],
|
||||
expect.objectContaining({ cwd: tempDir, timeoutMs: expect.any(Number) }),
|
||||
);
|
||||
expect(runCommandSpy).toHaveBeenCalledWith(
|
||||
"npm",
|
||||
["install", "example@latest", "--prefix", join(tempDir, ".pi", "npm")],
|
||||
@@ -1469,6 +1478,25 @@ export default function(api) { api.registerTool({ name: "test", description: "te
|
||||
);
|
||||
});
|
||||
|
||||
it("should skip project npm update when installed version matches latest", async () => {
|
||||
const installedPath = join(tempDir, ".pi", "npm", "node_modules", "example");
|
||||
mkdirSync(installedPath, { recursive: true });
|
||||
writeFileSync(join(installedPath, "package.json"), JSON.stringify({ name: "example", version: "1.2.3" }));
|
||||
settingsManager.setProjectPackages(["npm:example"]);
|
||||
|
||||
const runCommandCaptureSpy = vi.spyOn(packageManager as any, "runCommandCapture").mockResolvedValue('"1.2.3"');
|
||||
const runCommandSpy = vi.spyOn(packageManager as any, "runCommand").mockResolvedValue(undefined);
|
||||
|
||||
await packageManager.update("npm:example");
|
||||
|
||||
expect(runCommandCaptureSpy).toHaveBeenCalledWith(
|
||||
"npm",
|
||||
["view", "example", "version", "--json"],
|
||||
expect.objectContaining({ cwd: tempDir, timeoutMs: expect.any(Number) }),
|
||||
);
|
||||
expect(runCommandSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should suggest npm source prefixes for update lookups", async () => {
|
||||
settingsManager.setProjectPackages(["npm:example"]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user