fix(claude-code-hooks): cache idle hook config and parent lookups
Reduce repeated session.idle work by reusing hook config loads across a short TTL and by retrying parent session lookup instead of permanently caching transient failures. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
const { afterEach, beforeEach, describe, expect, mock, test } = require("bun:test")
|
||||
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
import { getOpenCodeConfigDir } from "../../shared"
|
||||
|
||||
const { clearPluginExtendedConfigCache, loadPluginExtendedConfig } = await import("./config-loader")
|
||||
|
||||
describe("loadPluginExtendedConfig", () => {
|
||||
const originalDateNow = Date.now
|
||||
let originalWorkingDirectory = ""
|
||||
let tempDirectory = ""
|
||||
let userConfigPath = ""
|
||||
let projectConfigPath = ""
|
||||
let originalUserConfig: string | null = null
|
||||
let mockedNow = 0
|
||||
|
||||
beforeEach(() => {
|
||||
//#given
|
||||
originalWorkingDirectory = process.cwd()
|
||||
tempDirectory = mkdtempSync(join(tmpdir(), "omo-cc-plugin-project-config-"))
|
||||
userConfigPath = join(getOpenCodeConfigDir({ binary: "opencode" }), "opencode-cc-plugin.json")
|
||||
projectConfigPath = join(tempDirectory, ".opencode", "opencode-cc-plugin.json")
|
||||
mkdirSync(getOpenCodeConfigDir({ binary: "opencode" }), { recursive: true })
|
||||
mkdirSync(join(tempDirectory, ".opencode"), { recursive: true })
|
||||
originalUserConfig = existsSync(userConfigPath)
|
||||
? readFileSync(userConfigPath, "utf8")
|
||||
: null
|
||||
process.chdir(tempDirectory)
|
||||
mockedNow = 1_000
|
||||
Date.now = () => mockedNow
|
||||
clearPluginExtendedConfigCache()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
clearPluginExtendedConfigCache()
|
||||
Date.now = originalDateNow
|
||||
process.chdir(originalWorkingDirectory)
|
||||
rmSync(tempDirectory, { recursive: true, force: true })
|
||||
if (originalUserConfig === null) {
|
||||
rmSync(userConfigPath, { force: true })
|
||||
} else {
|
||||
writeFileSync(userConfigPath, originalUserConfig)
|
||||
}
|
||||
})
|
||||
|
||||
test("#given cached extended config #when files change within ttl #then cached config is reused", async () => {
|
||||
//#given
|
||||
writeConfigFile(userConfigPath, ["user-first"])
|
||||
writeConfigFile(projectConfigPath, ["project-first"])
|
||||
|
||||
//#when
|
||||
const firstResult = await loadPluginExtendedConfig()
|
||||
writeConfigFile(userConfigPath, ["user-second"])
|
||||
writeConfigFile(projectConfigPath, ["project-second"])
|
||||
mockedNow += 5_000
|
||||
const secondResult = await loadPluginExtendedConfig()
|
||||
|
||||
//#then
|
||||
expect(firstResult).toEqual({
|
||||
disabledHooks: {
|
||||
Stop: ["project-first"],
|
||||
},
|
||||
})
|
||||
expect(secondResult).toEqual(firstResult)
|
||||
})
|
||||
|
||||
test("#given cached extended config #when ttl expires or cache clears #then updated config is reloaded", async () => {
|
||||
//#given
|
||||
writeConfigFile(userConfigPath, ["user-first"])
|
||||
writeConfigFile(projectConfigPath, ["project-first"])
|
||||
await loadPluginExtendedConfig()
|
||||
|
||||
//#when
|
||||
writeConfigFile(userConfigPath, ["user-second"])
|
||||
writeConfigFile(projectConfigPath, ["project-second"])
|
||||
mockedNow += 31_000
|
||||
const ttlReloaded = await loadPluginExtendedConfig()
|
||||
|
||||
writeConfigFile(userConfigPath, ["user-third"])
|
||||
writeConfigFile(projectConfigPath, ["project-third"])
|
||||
clearPluginExtendedConfigCache()
|
||||
const manuallyReloaded = await loadPluginExtendedConfig()
|
||||
|
||||
//#then
|
||||
expect(ttlReloaded).toEqual({
|
||||
disabledHooks: {
|
||||
Stop: ["project-second"],
|
||||
},
|
||||
})
|
||||
expect(manuallyReloaded).toEqual({
|
||||
disabledHooks: {
|
||||
Stop: ["project-third"],
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function writeConfigFile(filePath: string, stopPatterns: string[]): void {
|
||||
writeFileSync(
|
||||
filePath,
|
||||
JSON.stringify({
|
||||
disabledHooks: {
|
||||
Stop: stopPatterns,
|
||||
},
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
export {}
|
||||
Reference in New Issue
Block a user