mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
fix: keep agent listings fresh after file edits
Agent definitions are cached across command invocations, so edits made through the shared file helper must invalidate both the agent definition cache and the underlying markdown file cache. This keeps the TUI creation path and /agents command output consistent after creating, updating, or deleting custom agents. Constraint: The TUI agent wizard and /agents command share cached agent definition loaders Rejected: Clear only getAgentDefinitionsWithOverrides | the nested markdown file memoization can still return stale files Confidence: high Scope-risk: narrow Directive: Any future agent file mutation path must call clearAgentDefinitionsCache after a successful write or delete Tested: bun test src/tools/AgentTool/loadAgentsDir.cache.test.ts Tested: bun run check:server Not-tested: Full verify still blocked by existing agent-utils global coverage baseline
This commit is contained in:
parent
3193e741c7
commit
571d771025
@ -4,6 +4,7 @@ import type { SettingSource } from 'src/utils/settings/constants.js'
|
||||
import { getManagedFilePath } from 'src/utils/settings/managedPath.js'
|
||||
import type { AgentMemoryScope } from '../../tools/AgentTool/agentMemory.js'
|
||||
import {
|
||||
clearAgentDefinitionsCache,
|
||||
type AgentDefinition,
|
||||
isBuiltInAgent,
|
||||
isPluginAgent,
|
||||
@ -200,6 +201,7 @@ export async function saveAgentToFile(
|
||||
}
|
||||
throw e
|
||||
}
|
||||
clearAgentDefinitionsCache()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -233,6 +235,7 @@ export async function updateAgentFile(
|
||||
)
|
||||
|
||||
await writeFileAndFlush(filePath, content)
|
||||
clearAgentDefinitionsCache()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,6 +258,7 @@ export async function deleteAgentFromFile(
|
||||
throw e
|
||||
}
|
||||
}
|
||||
clearAgentDefinitionsCache()
|
||||
}
|
||||
|
||||
async function writeFileAndFlush(
|
||||
|
||||
98
src/tools/AgentTool/loadAgentsDir.cache.test.ts
Normal file
98
src/tools/AgentTool/loadAgentsDir.cache.test.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
|
||||
import * as fs from 'node:fs/promises'
|
||||
import * as os from 'node:os'
|
||||
import * as path from 'node:path'
|
||||
import { getCwdState, setCwdState } from '../../bootstrap/state.js'
|
||||
import { agentsHandler } from '../../cli/handlers/agents.js'
|
||||
import { saveAgentToFile } from '../../components/agents/agentFileUtils.js'
|
||||
import {
|
||||
clearAgentDefinitionsCache,
|
||||
getAgentDefinitionsWithOverrides,
|
||||
} from './loadAgentsDir.js'
|
||||
|
||||
let tmpHome: string
|
||||
let originalHome: string | undefined
|
||||
let originalUserProfile: string | undefined
|
||||
let originalClaudeConfigDir: string | undefined
|
||||
let originalCwdState: string
|
||||
|
||||
describe('agent definition cache invalidation', () => {
|
||||
beforeEach(async () => {
|
||||
tmpHome = await fs.mkdtemp(path.join(os.tmpdir(), 'agent-def-cache-'))
|
||||
originalHome = process.env.HOME
|
||||
originalUserProfile = process.env.USERPROFILE
|
||||
originalClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR
|
||||
originalCwdState = getCwdState()
|
||||
|
||||
process.env.HOME = tmpHome
|
||||
process.env.USERPROFILE = tmpHome
|
||||
process.env.CLAUDE_CONFIG_DIR = path.join(tmpHome, '.claude')
|
||||
clearAgentDefinitionsCache()
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
if (originalHome === undefined) {
|
||||
delete process.env.HOME
|
||||
} else {
|
||||
process.env.HOME = originalHome
|
||||
}
|
||||
|
||||
if (originalUserProfile === undefined) {
|
||||
delete process.env.USERPROFILE
|
||||
} else {
|
||||
process.env.USERPROFILE = originalUserProfile
|
||||
}
|
||||
|
||||
if (originalClaudeConfigDir === undefined) {
|
||||
delete process.env.CLAUDE_CONFIG_DIR
|
||||
} else {
|
||||
process.env.CLAUDE_CONFIG_DIR = originalClaudeConfigDir
|
||||
}
|
||||
|
||||
setCwdState(originalCwdState)
|
||||
clearAgentDefinitionsCache()
|
||||
await fs.rm(tmpHome, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('shows a newly-created project agent in the /agents output after an initial cached read', async () => {
|
||||
const projectRoot = path.join(tmpHome, 'project')
|
||||
await fs.mkdir(projectRoot, { recursive: true })
|
||||
setCwdState(projectRoot)
|
||||
|
||||
const agentType = 'cache-created-agent'
|
||||
const before = await getAgentDefinitionsWithOverrides(projectRoot)
|
||||
|
||||
expect(before.allAgents.some(agent => agent.agentType === agentType)).toBe(false)
|
||||
|
||||
await saveAgentToFile(
|
||||
'projectSettings',
|
||||
agentType,
|
||||
'Use this agent to verify cache invalidation.',
|
||||
undefined,
|
||||
'You verify cache invalidation.',
|
||||
true,
|
||||
)
|
||||
|
||||
const after = await getAgentDefinitionsWithOverrides(projectRoot)
|
||||
|
||||
expect(after.allAgents).toContainEqual(
|
||||
expect.objectContaining({
|
||||
agentType,
|
||||
source: 'projectSettings',
|
||||
}),
|
||||
)
|
||||
|
||||
const logs: string[] = []
|
||||
const originalLog = console.log
|
||||
console.log = (...args: unknown[]) => {
|
||||
logs.push(args.map(String).join(' '))
|
||||
}
|
||||
try {
|
||||
await agentsHandler()
|
||||
} finally {
|
||||
console.log = originalLog
|
||||
}
|
||||
|
||||
expect(logs.join('\n')).toContain(agentType)
|
||||
})
|
||||
})
|
||||
@ -394,6 +394,7 @@ export const getAgentDefinitionsWithOverrides = memoize(
|
||||
|
||||
export function clearAgentDefinitionsCache(): void {
|
||||
getAgentDefinitionsWithOverrides.cache.clear?.()
|
||||
loadMarkdownFilesForSubdir.cache.clear?.()
|
||||
clearPluginAgentCache()
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user