feat(skills): target watcher updates with safe fallback
This commit is contained in:
@@ -16,10 +16,10 @@ describe('initSkills watcher wiring', () => {
|
||||
}
|
||||
});
|
||||
|
||||
function writeSkill(rootDir: string, name: string): void {
|
||||
function writeSkill(rootDir: string, name: string, instructions = `# ${name}\n\nTest skill.`): void {
|
||||
const skillDir = join(rootDir, name);
|
||||
mkdirSync(skillDir, { recursive: true });
|
||||
writeFileSync(join(skillDir, 'SKILL.md'), `# ${name}\n\nTest skill.`);
|
||||
writeFileSync(join(skillDir, 'SKILL.md'), instructions);
|
||||
}
|
||||
|
||||
function makeConfig(overrides: Record<string, unknown> = {}) {
|
||||
@@ -62,7 +62,7 @@ describe('initSkills watcher wiring', () => {
|
||||
expect(result.skillsWatcher?.isRunning).toBe(false);
|
||||
});
|
||||
|
||||
it('reloads registry from disk when watcher callback fires', () => {
|
||||
it('applies targeted add/update changes for a mapped skill path', () => {
|
||||
vi.useFakeTimers();
|
||||
const root = mkdtempSync(join(tmpdir(), 'flynn-services-'));
|
||||
roots.push(root);
|
||||
@@ -85,7 +85,35 @@ describe('initSkills watcher wiring', () => {
|
||||
writeSkill(managedDir, 'beta');
|
||||
result.skillsWatcher?.notifyPathChanged(join(managedDir, 'beta', 'SKILL.md'));
|
||||
vi.advanceTimersByTime(20);
|
||||
expect(result.skillRegistry.get('beta')).toBeDefined();
|
||||
|
||||
writeSkill(managedDir, 'beta', '# beta\n\nUpdated instructions.');
|
||||
result.skillsWatcher?.notifyPathChanged(join(managedDir, 'beta', 'SKILL.md'));
|
||||
vi.advanceTimersByTime(20);
|
||||
expect(result.skillRegistry.get('beta')?.instructions).toContain('Updated instructions.');
|
||||
|
||||
result.skillsWatcher?.stop();
|
||||
});
|
||||
|
||||
it('unregisters a removed mapped skill path', () => {
|
||||
vi.useFakeTimers();
|
||||
const root = mkdtempSync(join(tmpdir(), 'flynn-services-'));
|
||||
roots.push(root);
|
||||
const managedDir = join(root, 'skills');
|
||||
mkdirSync(managedDir, { recursive: true });
|
||||
writeSkill(managedDir, 'alpha');
|
||||
writeSkill(managedDir, 'beta');
|
||||
|
||||
const config = makeConfig({
|
||||
skills: {
|
||||
managed_dir: managedDir,
|
||||
load: { watch: true, watch_debounce_ms: 20 },
|
||||
},
|
||||
});
|
||||
const lifecycle = new Lifecycle();
|
||||
|
||||
const result = initSkills(config, lifecycle);
|
||||
expect(result.skillRegistry.get('alpha')).toBeDefined();
|
||||
expect(result.skillRegistry.get('beta')).toBeDefined();
|
||||
|
||||
rmSync(join(managedDir, 'alpha'), { recursive: true, force: true });
|
||||
@@ -97,4 +125,32 @@ describe('initSkills watcher wiring', () => {
|
||||
|
||||
result.skillsWatcher?.stop();
|
||||
});
|
||||
|
||||
it('falls back to full reload for ambiguous paths', () => {
|
||||
vi.useFakeTimers();
|
||||
const root = mkdtempSync(join(tmpdir(), 'flynn-services-'));
|
||||
roots.push(root);
|
||||
const managedDir = join(root, 'skills');
|
||||
mkdirSync(managedDir, { recursive: true });
|
||||
writeSkill(managedDir, 'alpha');
|
||||
|
||||
const config = makeConfig({
|
||||
skills: {
|
||||
managed_dir: managedDir,
|
||||
load: { watch: true, watch_debounce_ms: 20 },
|
||||
},
|
||||
});
|
||||
const lifecycle = new Lifecycle();
|
||||
|
||||
const result = initSkills(config, lifecycle);
|
||||
expect(result.skillRegistry.get('alpha')).toBeDefined();
|
||||
expect(result.skillRegistry.get('beta')).toBeUndefined();
|
||||
|
||||
writeSkill(managedDir, 'beta');
|
||||
result.skillsWatcher?.notifyPathChanged(join(root, 'not-a-skill-path'));
|
||||
vi.advanceTimersByTime(20);
|
||||
|
||||
expect(result.skillRegistry.get('beta')).toBeDefined();
|
||||
result.skillsWatcher?.stop();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user