mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-16 10:15:10 +00:00
fix(shared-manager): allow external claude symlink chains
This commit is contained in:
1 parent
2ba68a7c41
commit
05dea22238
2 files changed
+71
-8
No files matched your search
@@ -154,6 +154,71 @@ describe('SharedManager', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('shared symlink lifecycle', () => {
|
||||
it('preserves external ~/.claude symlinks during upgrade reconciliation', () => {
|
||||
const manager = new SharedManager();
|
||||
const externalCommandsDir = path.join(tempRoot, 'Documents', 'claude-config', 'commands');
|
||||
const externalSettingsPath = path.join(
|
||||
tempRoot,
|
||||
'Documents',
|
||||
'claude-config',
|
||||
'settings.json'
|
||||
);
|
||||
const claudeCommandsPath = path.join(claudeDir(), 'commands');
|
||||
const claudeSettingsPath = path.join(claudeDir(), 'settings.json');
|
||||
const sharedCommandsPath = path.join(ccsDir(), 'shared', 'commands');
|
||||
const sharedSettingsPath = path.join(ccsDir(), 'shared', 'settings.json');
|
||||
const logSpy = spyOn(console, 'log').mockImplementation(() => {});
|
||||
|
||||
fs.mkdirSync(externalCommandsDir, { recursive: true });
|
||||
fs.mkdirSync(path.dirname(externalSettingsPath), { recursive: true });
|
||||
fs.mkdirSync(claudeDir(), { recursive: true });
|
||||
fs.mkdirSync(path.join(ccsDir(), 'shared'), { recursive: true });
|
||||
fs.writeFileSync(externalSettingsPath, JSON.stringify({ theme: 'dark' }), 'utf8');
|
||||
fs.symlinkSync(externalCommandsDir, claudeCommandsPath, 'dir');
|
||||
fs.symlinkSync(externalSettingsPath, claudeSettingsPath, 'file');
|
||||
fs.symlinkSync(claudeCommandsPath, sharedCommandsPath, 'dir');
|
||||
fs.symlinkSync(claudeSettingsPath, sharedSettingsPath, 'file');
|
||||
|
||||
manager.ensureSharedDirectories();
|
||||
|
||||
expect(
|
||||
logSpy.mock.calls.some(([message]) =>
|
||||
String(message).includes('Skipping commands: circular symlink detected') ||
|
||||
String(message).includes('Skipping settings.json: circular symlink detected')
|
||||
)
|
||||
).toBe(false);
|
||||
expect(fs.lstatSync(sharedCommandsPath).isSymbolicLink()).toBe(true);
|
||||
expect(
|
||||
path.resolve(path.dirname(sharedCommandsPath), fs.readlinkSync(sharedCommandsPath))
|
||||
).toBe(claudeCommandsPath);
|
||||
expect(fs.lstatSync(sharedSettingsPath).isSymbolicLink()).toBe(true);
|
||||
expect(
|
||||
path.resolve(path.dirname(sharedSettingsPath), fs.readlinkSync(sharedSettingsPath))
|
||||
).toBe(claudeSettingsPath);
|
||||
});
|
||||
|
||||
it('still blocks real circular links back into ~/.ccs/shared', () => {
|
||||
const manager = new SharedManager();
|
||||
const claudeCommandsPath = path.join(claudeDir(), 'commands');
|
||||
const sharedCommandsPath = path.join(ccsDir(), 'shared', 'commands');
|
||||
const logSpy = spyOn(console, 'log').mockImplementation(() => {});
|
||||
|
||||
fs.mkdirSync(claudeDir(), { recursive: true });
|
||||
fs.mkdirSync(sharedCommandsPath, { recursive: true });
|
||||
fs.symlinkSync(sharedCommandsPath, claudeCommandsPath, 'dir');
|
||||
|
||||
manager.ensureSharedDirectories();
|
||||
|
||||
expect(
|
||||
logSpy.mock.calls.some(([message]) =>
|
||||
String(message).includes('Skipping commands: circular symlink detected')
|
||||
)
|
||||
).toBe(true);
|
||||
expect(fs.lstatSync(sharedCommandsPath).isDirectory()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('marketplace registry ownership', () => {
|
||||
it('writes global and instance registries with different authoritative install locations', () => {
|
||||
const globalRegistryPath = path.join(claudeDir(), 'plugins', 'known_marketplaces.json');
|
||||
|
||||
Reference in new issue
Block a user