feat(skills): enable watcher wiring through daemon lifecycle

This commit is contained in:
William Valentin
2026-02-12 17:18:22 -08:00
parent 95091cc198
commit b773e2bbf3
6 changed files with 171 additions and 9 deletions
+34 -3
View File
@@ -9,7 +9,7 @@ import { GatewayServer } from '../gateway/index.js';
import { ChannelRegistry, PairingManager, type PairingStore } from '../channels/index.js';
import { HeartbeatMonitor } from '../automation/index.js';
import { McpManager } from '../mcp/index.js';
import { SkillRegistry, SkillInstaller, loadAllSkills } from '../skills/index.js';
import { SkillRegistry, SkillInstaller, SkillsWatcher, loadAllSkills } from '../skills/index.js';
import { assembleSystemPrompt } from '../prompt/index.js';
import { resolve } from 'path';
import { homedir } from 'os';
@@ -23,9 +23,10 @@ import type { RoutingPolicy } from '../routing/index.js';
export interface SkillsResult {
skillRegistry: SkillRegistry;
skillInstaller: SkillInstaller;
skillsWatcher?: SkillsWatcher;
}
export function initSkills(config: Config): SkillsResult {
export function initSkills(config: Config, lifecycle?: Lifecycle): SkillsResult {
const defaultManagedDir = resolve(homedir(), '.flynn/workspace/skills');
const skillRegistry = new SkillRegistry();
const skillInstaller = new SkillInstaller(config.skills.managed_dir ?? defaultManagedDir);
@@ -45,7 +46,37 @@ export function initSkills(config: Config): SkillsResult {
console.log(`Loaded ${skills.length} skill(s) (${available} available)`);
}
return { skillRegistry, skillInstaller };
const watchEnabled = config.skills.load.watch;
if (!watchEnabled || !lifecycle) {
return { skillRegistry, skillInstaller };
}
const skillDirs = [
config.skills.bundled_dir,
config.skills.managed_dir ?? defaultManagedDir,
config.skills.workspace_dir,
].filter((dir): dir is string => Boolean(dir));
const skillsWatcher = new SkillsWatcher({
skillDirs,
debounceMs: config.skills.load.watch_debounce_ms,
onSkillsChanged: ({ changedPaths }) => {
console.log(`Skills watcher detected changes in ${changedPaths.length} path(s)`);
},
});
skillsWatcher.start();
if (skillsWatcher.watchedDirectoryCount > 0) {
console.log(`Skills watcher started (${skillsWatcher.watchedDirectoryCount} dir(s), debounce ${config.skills.load.watch_debounce_ms}ms)`);
} else {
console.log('Skills watcher enabled, but no existing skill directories to watch');
}
lifecycle.onShutdown(async () => {
skillsWatcher.stop();
console.log('Skills watcher stopped');
});
return { skillRegistry, skillInstaller, skillsWatcher };
}
// ── MCP ─────────────────────────────────────────────────────────