fix(cli): honor helper refresh opt-out before locking

This commit is contained in:
dajiaohuang
2026-08-14 17:10:34 -04:00
committed by ruv
parent 0c73bab4d0
commit fa11ee8c24
3 changed files with 29 additions and 0 deletions
+2
View File
@@ -176,6 +176,8 @@ v3/@claude-flow/cli/plugins/
# regenerated on demand, not source. The signed manifest source of truth lives
# in v3/@claude-flow/cli/.claude/helpers/helpers.manifest.json.
.claude/helpers/.helpers-version
.claude/helpers/.helpers-refresh.lock
.claude/helpers/*.tmp-*
.claude/helpers/helpers.manifest.json
# Runtime proven-config adoption state (per-install, not source)
@@ -329,6 +329,27 @@ describe('autoRefreshHelpersIfStale', () => {
}
});
it('honors .LOCKED before attempting to acquire the refresh lock', async () => {
const { cwd, helpersDir } = makeProject();
writeFileSync(join(helpersDir, 'hook-handler.cjs'), 'HAND-MAINTAINED');
writeFileSync(join(helpersDir, HELPERS_STAMP_FILE), '1.0.0');
writeFileSync(join(helpersDir, '.LOCKED'), '');
const lockPath = join(helpersDir, HELPERS_REFRESH_LOCK_FILE);
writeFileSync(lockPath, JSON.stringify({ pid: process.pid, token: 'other-owner' }));
try {
const r = await autoRefreshHelpersIfStale(cwd, {
versionOverride: '2.0.0',
lockWaitMsOverride: 0,
});
expect(r.refreshed).toBe(false);
expect(r.blocked).toMatch(/\.LOCKED marker present/);
expect(readFileSync(lockPath, 'utf-8')).toContain('other-owner');
} finally {
unlinkSync(lockPath);
}
});
it('recovers an abandoned lock created before owner metadata was written', async () => {
const { cwd, helpersDir } = makeProject();
writeFileSync(join(helpersDir, 'hook-handler.cjs'), 'INITIAL-HANDLER');
@@ -394,6 +394,12 @@ async function refreshOneHelpersDir(
opts: RefreshOptions,
): Promise<{ refreshed: boolean; from?: string; to?: string; blocked?: string }> {
if (!fs.existsSync(path.join(helpersDir, 'hook-handler.cjs'))) return { refreshed: false };
// Respect the repository opt-out before creating even a transient lock file
// in a directory whose helpers are intentionally maintained by hand. Keep
// the check in the locked path too in case the marker appears while waiting.
if (fs.existsSync(path.join(helpersDir, '.LOCKED'))) {
return { refreshed: false, blocked: '.LOCKED marker present — refresh skipped (delete to re-enable)' };
}
try { if (fs.readFileSync(path.join(helpersDir, HELPERS_STAMP_FILE), 'utf-8').trim() === version) return { refreshed: false }; }
catch { /* unstamped: continue to the locked path */ }