mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(coding-agent): use per-ref cache folders for pinned temporary git extensions
Temporary git extensions (-e git:...@ref) were cached in a folder keyed only by host and repo path. After changing the pinned ref, pi reused the old checkout without refreshing it and kept loading the first downloaded commit. Include the ref in the temporary folder hash so each ref gets its own checkout. Unpinned sources keep their existing folder. closes #9982
This commit is contained in:
parent
5fd446ca18
commit
f444ea5eaf
3 changed files with 34 additions and 3 deletions
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
- Fixed X11 clipboard text being misidentified as an image when the clipboard owner accepts unadvertised image targets ([#9786](https://github.com/earendil-works/pi/issues/9786)).
|
||||
- Prevented managed git packages from automatically installing Pi peer dependencies and added warnings for extension packages that list host-provided modules in `dependencies` ([#9863](https://github.com/earendil-works/pi/issues/9863)).
|
||||
- Fixed pinned git extensions loaded with `-e` continuing to use the first downloaded commit after the ref changes ([#9982](https://github.com/earendil-works/pi/issues/9982)).
|
||||
|
||||
## [0.87.1] - 2026-09-22
|
||||
|
||||
|
|
|
|||
|
|
@ -2123,7 +2123,8 @@ export class DefaultPackageManager implements PackageManager {
|
|||
|
||||
private getGitInstallPath(source: GitSource, scope: SourceScope): string {
|
||||
if (scope === "temporary") {
|
||||
return this.getTemporaryDir(`git-${source.host}`, source.path);
|
||||
// Include the ref in the hash so each pinned ref gets its own checkout.
|
||||
return this.getTemporaryDir(`git-${source.host}`, source.path, source.ref);
|
||||
}
|
||||
const installRoot = this.getGitInstallRoot(scope);
|
||||
if (!installRoot) {
|
||||
|
|
@ -2143,10 +2144,10 @@ export class DefaultPackageManager implements PackageManager {
|
|||
return join(this.agentDir, "git");
|
||||
}
|
||||
|
||||
private getTemporaryDir(prefix: string, suffix?: string): string {
|
||||
private getTemporaryDir(prefix: string, suffix?: string, ref?: string): string {
|
||||
const root = this.resolveManagedPath(getExtensionTempFolder(this.agentDir), prefix);
|
||||
const hash = createHash("sha256")
|
||||
.update(`${prefix}-${suffix ?? ""}`)
|
||||
.update(`${prefix}-${suffix ?? ""}${ref ? `@${ref}` : ""}`)
|
||||
.digest("hex")
|
||||
.slice(0, 8);
|
||||
return this.resolveManagedPath(root, hash, suffix ?? "");
|
||||
|
|
|
|||
|
|
@ -2615,6 +2615,35 @@ export default function(api) { api.registerTool({ name: "test", description: "te
|
|||
expect(refreshTemporaryGitSourceSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// https://github.com/earendil-works/pi/issues/9982
|
||||
it("should load a new checkout when a pinned temporary git source changes ref", async () => {
|
||||
const managerWithInternals = packageManager as unknown as PackageManagerInternals;
|
||||
const oldSource = "git:github.com/example/repo@aaaaaaa";
|
||||
const newSource = "git:github.com/example/repo@bbbbbbb";
|
||||
const oldParsed = managerWithInternals.parseSource(oldSource);
|
||||
const newParsed = managerWithInternals.parseSource(newSource);
|
||||
if (oldParsed.type !== "git" || newParsed.type !== "git") {
|
||||
throw new Error("Expected git sources");
|
||||
}
|
||||
|
||||
const oldPath = managerWithInternals.getGitInstallPath(oldParsed, "temporary");
|
||||
mkdirSync(join(oldPath, "extensions"), { recursive: true });
|
||||
writeFileSync(join(oldPath, "extensions", "old.ts"), "export default function() {};");
|
||||
|
||||
const installParsedSourceSpy = vi
|
||||
.spyOn(packageManager as any, "installParsedSource")
|
||||
.mockImplementation(async () => {
|
||||
const newPath = managerWithInternals.getGitInstallPath(newParsed, "temporary");
|
||||
mkdirSync(join(newPath, "extensions"), { recursive: true });
|
||||
writeFileSync(join(newPath, "extensions", "new.ts"), "export default function() {};");
|
||||
});
|
||||
|
||||
const result = await packageManager.resolveExtensionSources([newSource], { temporary: true });
|
||||
expect(installParsedSourceSpy).toHaveBeenCalledTimes(1);
|
||||
expect(result.extensions.some((r) => pathEndsWith(r.path, "extensions/new.ts") && r.enabled)).toBe(true);
|
||||
expect(result.extensions.some((r) => pathEndsWith(r.path, "extensions/old.ts"))).toBe(false);
|
||||
});
|
||||
|
||||
it("should not run npm view during resolve for installed unpinned packages", async () => {
|
||||
process.env.PI_OFFLINE = "1";
|
||||
const installedPath = join(tempDir, ".pi", "npm", "node_modules", "example");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue