mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 08:15:53 +00:00
feat: 添加 skill learning 技能学习闭环系统
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
101
src/services/skillSearch/__tests__/prefetch.test.ts
Normal file
101
src/services/skillSearch/__tests__/prefetch.test.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
|
||||
import {
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
mkdtempSync,
|
||||
rmSync,
|
||||
writeFileSync,
|
||||
} from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { clearCommandsCache } from '../../../commands.js'
|
||||
import { getTurnZeroSkillDiscovery } from '../prefetch.js'
|
||||
import { clearSkillIndexCache } from '../localSearch.js'
|
||||
|
||||
let root: string
|
||||
let previousCwd: string
|
||||
const originalEnv = { ...process.env }
|
||||
|
||||
beforeEach(() => {
|
||||
root = mkdtempSync(join(tmpdir(), 'skill-search-prefetch-'))
|
||||
previousCwd = process.cwd()
|
||||
process.chdir(root)
|
||||
process.env = { ...originalEnv }
|
||||
process.env.CLAUDE_CONFIG_DIR = join(root, 'config')
|
||||
process.env.CLAUDE_SKILL_LEARNING_HOME = join(root, 'learning')
|
||||
process.env.SKILL_SEARCH_ENABLED = '1'
|
||||
process.env.SKILL_LEARNING_ENABLED = '1'
|
||||
process.env.NODE_ENV = 'test'
|
||||
process.env.ANTHROPIC_API_KEY = 'test-key'
|
||||
clearCommandsCache()
|
||||
clearSkillIndexCache()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
process.chdir(previousCwd)
|
||||
process.env = { ...originalEnv }
|
||||
clearCommandsCache()
|
||||
clearSkillIndexCache()
|
||||
try {
|
||||
rmSync(root, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
maxRetries: 10,
|
||||
retryDelay: 100,
|
||||
})
|
||||
} catch {
|
||||
// Windows can keep transient handles after dynamic command loading.
|
||||
}
|
||||
})
|
||||
|
||||
describe('skill search prefetch', () => {
|
||||
test('auto-loads high-confidence project skill content', async () => {
|
||||
const skillDir = join(root, '.claude', 'skills', 'feature-audit')
|
||||
mkdirSync(skillDir, { recursive: true })
|
||||
writeFileSync(
|
||||
join(skillDir, 'SKILL.md'),
|
||||
[
|
||||
'---',
|
||||
'name: feature-audit',
|
||||
'description: Audit feature flags and classify minimal implementations',
|
||||
'---',
|
||||
'',
|
||||
'# Feature Audit',
|
||||
'',
|
||||
'Use the feature flag audit workflow and classify flags as stub, shell, MVP, or thin-toggle.',
|
||||
].join('\n'),
|
||||
)
|
||||
|
||||
const attachment = await getTurnZeroSkillDiscovery(
|
||||
'audit feature flags for minimal implementation stubs',
|
||||
[],
|
||||
{ agentId: undefined } as any,
|
||||
)
|
||||
|
||||
expect(attachment?.type).toBe('skill_discovery')
|
||||
if (attachment?.type !== 'skill_discovery') {
|
||||
throw new Error('expected skill_discovery attachment')
|
||||
}
|
||||
expect(attachment.skills[0]?.name).toBe('feature-audit')
|
||||
expect(attachment.skills[0]?.autoLoaded).toBe(true)
|
||||
expect(attachment.skills[0]?.content).toContain(
|
||||
'feature flag audit workflow',
|
||||
)
|
||||
})
|
||||
|
||||
test('records a pending skill gap on the first unmatched prompt (no draft file yet)', async () => {
|
||||
const attachment = await getTurnZeroSkillDiscovery(
|
||||
'frobnicate zephyr ledger workflow',
|
||||
[],
|
||||
{ agentId: undefined } as any,
|
||||
)
|
||||
|
||||
expect(attachment?.type).toBe('skill_discovery')
|
||||
if (attachment?.type !== 'skill_discovery') {
|
||||
throw new Error('expected skill_discovery attachment')
|
||||
}
|
||||
expect(attachment.skills).toEqual([])
|
||||
expect(attachment.gap?.status).toBe('pending')
|
||||
expect(attachment.gap?.draftPath).toBeUndefined()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user