docs(FN-1510): add skill selection resolver pattern to memory

This commit is contained in:
gsxdsm
2026-04-14 08:02:09 -07:00
parent 0afb5eb31d
commit 7849ec2a51
2 changed files with 29 additions and 0 deletions

View File

@@ -1011,3 +1011,31 @@ All major timers/intervals properly cleared on shutdown:
3. Watch for listener count growth — especially `task:created`, `task:updated` (SSE subscriptions)
4. Watch for `beforeExit code=0` without preceding shutdown log (unexpected exit)
5. `db=failed` indicates database connectivity issues
## Skill Selection Resolver (FN-1510)
The skill selection resolver (`packages/engine/src/skill-resolver.ts`) computes deterministic session skill sets from project settings and optional caller overrides.
**Key patterns:**
- `resolveSessionSkills(context)` reads `.fusion/settings.json` (primary) or `.pi/settings.json` (fallback) for skill patterns
- Skill patterns use `+` prefix (include) or `-` prefix (exclude); unprefixed patterns are treated as `+`
- `requestedSkillNames` acts as intersection filter on top of pattern-based selection (case-insensitive name matching)
- `filterActive: false` means no filtering (all discovered skills pass through); `filterActive: true` means filtering is active
- `createSkillsOverrideFromSelection()` returns the `skillsOverride` callback for `DefaultResourceLoader`
- `skillsOverride` is only set when `skillSelection` is provided in `AgentOptions`; omitting it preserves existing behavior
**Settings format:**
```json
{
"skills": ["+skills/foo/SKILL.md", "-skills/bar/SKILL.md"],
"packages": [
{ "source": "@myorg/ai-kit", "skills": ["+skills/custom/SKILL.md"] }
]
}
```
**Test patterns:**
- Use in-memory mock filesystem (`Map<string, string>`) for unit tests
- `mockFiles.set(path, content)` and `mockFiles.get(path)` for read/write
- `mockFiles.clear()` in `beforeEach` to reset state between tests
- `vi.resetModules()` when using `vi.doMock` inside tests

View File

@@ -680,6 +680,7 @@ describe("SettingsModal", () => {
render(<SettingsModal onClose={onClose} addToast={addToast} initialSection="scheduling" />);
await waitFor(() => expect(fetchSettings).toHaveBeenCalled());
await waitFor(() => expect(fetchGlobalConcurrency).toHaveBeenCalled());
const input = screen.getByLabelText("Global Max Concurrent") as HTMLInputElement;
expect(input.value).toBe("8");