🎯 Use case
This file lives under “hooks/”, which covers reusable UI or integration hooks. On the API surface it exposes useSkillsChange — mainly functions, hooks, or classes. Dependencies touch React UI. It composes internal code from commands, services, and utils (relative imports).
Generated from folder role, exports, dependency roots, and inline comments — not hand-reviewed for every path.
🧠 Inline summary
import { useCallback, useEffect } from 'react' import type { Command } from '../commands.js' import { clearCommandMemoizationCaches, clearCommandsCache,
📤 Exports (heuristic)
useSkillsChange
📚 External import roots
Package roots from from "…" (relative paths omitted).
react
🖥️ Source preview
import { useCallback, useEffect } from 'react'
import type { Command } from '../commands.js'
import {
clearCommandMemoizationCaches,
clearCommandsCache,
getCommands,
} from '../commands.js'
import { onGrowthBookRefresh } from '../services/analytics/growthbook.js'
import { logError } from '../utils/log.js'
import { skillChangeDetector } from '../utils/skills/skillChangeDetector.js'
/**
* Keep the commands list fresh across two triggers:
*
* 1. Skill file changes (watcher) — full cache clear + disk re-scan, since
* skill content changed on disk.
* 2. GrowthBook init/refresh — memo-only clear, since only `isEnabled()`
* predicates may have changed. Handles commands like /btw whose gate
* reads a flag that isn't in the disk cache yet on first session after
* a flag rename: getCommands() runs before GB init (main.tsx:2855 vs
* showSetupScreens at :3106), so the memoized list is baked with the
* default. Once init populates remoteEvalFeatureValues, re-filter.
*/
export function useSkillsChange(
cwd: string | undefined,
onCommandsChange: (commands: Command[]) => void,
): void {
const handleChange = useCallback(async () => {
if (!cwd) return
try {
// Clear all command caches to ensure fresh load
clearCommandsCache()
const commands = await getCommands(cwd)
onCommandsChange(commands)
} catch (error) {
// Errors during reload are non-fatal - log and continue
if (error instanceof Error) {
logError(error)
}
}
}, [cwd, onCommandsChange])
useEffect(() => skillChangeDetector.subscribe(handleChange), [handleChange])
const handleGrowthBookRefresh = useCallback(async () => {
if (!cwd) return
try {
clearCommandMemoizationCaches()
const commands = await getCommands(cwd)
onCommandsChange(commands)
} catch (error) {
if (error instanceof Error) {
logError(error)
}
}
}, [cwd, onCommandsChange])
useEffect(
() => onGrowthBookRefresh(handleGrowthBookRefresh),
[handleGrowthBookRefresh],
)
}