From 78f14c1d9f7b4fb985b5576b9c4ba24e4e147e0d Mon Sep 17 00:00:00 2001 From: Antonio Zaitoun Date: Wed, 14 Oct 2026 16:14:00 +0300 Subject: [PATCH] fix(lockfile): stamp the current capa version when pins change The builder kept the generator from the existing lockfile, so adding a skill after upgrading capa left an old version in capabilities.lock. Restamp generator together with generatedAt when the pins change; a no-op install still leaves the file untouched. Closes #310 --- src/shared/__tests__/lockfile.test.ts | 15 +++++++++++++++ src/shared/lockfile.ts | 4 +++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/shared/__tests__/lockfile.test.ts b/src/shared/__tests__/lockfile.test.ts index b63590a6..87f764da 100644 --- a/src/shared/__tests__/lockfile.test.ts +++ b/src/shared/__tests__/lockfile.test.ts @@ -282,6 +282,21 @@ describe('lockfile', () => { expect(b.build().generatedAt).not.toBe('2026-01-01T00:00:00.000Z'); }); + it('stamps the current generator only when a pin changes (#310)', () => { + const initial: Lockfile = { + ...emptyLockfile(), + generator: 'capa@2.2.0', + skills: [sampleSkill], + }; + const unchanged = new LockfileBuilder(initial); + unchanged.upsertSkill(sampleSkill); + expect(unchanged.build().generator).toBe('capa@2.2.0'); + + const added = new LockfileBuilder(initial); + added.upsertSkill({ ...sampleSkill, id: 'new-skill' }); + expect(added.build().generator).toBe(emptyLockfile().generator); + }); + it('starts empty when given null', () => { const b = new LockfileBuilder(null); const lf = b.build(); diff --git a/src/shared/lockfile.ts b/src/shared/lockfile.ts index a955713e..062b503d 100644 --- a/src/shared/lockfile.ts +++ b/src/shared/lockfile.ts @@ -531,11 +531,13 @@ export class LockfileBuilder { ? { providerConfig: sortProviderConfig(this.providerConfig) } : {}), }; - // Only bump generatedAt when pins/generator actually changed. + // Only restamp generator/generatedAt when the pins changed, so a no-op + // install after a capa upgrade leaves the lockfile untouched. if ( this.initialSemanticKey === null || lockfileSemanticKey(lockfile) !== this.initialSemanticKey ) { + lockfile.generator = `capa@${VERSION}`; lockfile.generatedAt = new Date().toISOString(); } return lockfile;