110 lines
3.0 KiB
TypeScript
110 lines
3.0 KiB
TypeScript
import type {
|
|
PreCompactInput,
|
|
PreCompactOutput,
|
|
ClaudeHooksConfig,
|
|
} from "./types"
|
|
import { findMatchingHooks, executeHookCommand, log } from "../../shared"
|
|
import { DEFAULT_CONFIG } from "./plugin-config"
|
|
import { isHookCommandDisabled, type PluginExtendedConfig } from "./config-loader"
|
|
|
|
export interface PreCompactContext {
|
|
sessionId: string
|
|
cwd: string
|
|
}
|
|
|
|
export interface PreCompactResult {
|
|
context: string[]
|
|
elapsedMs?: number
|
|
hookName?: string
|
|
continue?: boolean
|
|
stopReason?: string
|
|
suppressOutput?: boolean
|
|
systemMessage?: string
|
|
}
|
|
|
|
export async function executePreCompactHooks(
|
|
ctx: PreCompactContext,
|
|
config: ClaudeHooksConfig | null,
|
|
extendedConfig?: PluginExtendedConfig | null
|
|
): Promise<PreCompactResult> {
|
|
if (!config) {
|
|
return { context: [] }
|
|
}
|
|
|
|
const matchers = findMatchingHooks(config, "PreCompact", "*")
|
|
if (matchers.length === 0) {
|
|
return { context: [] }
|
|
}
|
|
|
|
const stdinData: PreCompactInput = {
|
|
session_id: ctx.sessionId,
|
|
cwd: ctx.cwd,
|
|
hook_event_name: "PreCompact",
|
|
hook_source: "opencode-plugin",
|
|
}
|
|
|
|
const startTime = Date.now()
|
|
let firstHookName: string | undefined
|
|
const collectedContext: string[] = []
|
|
|
|
for (const matcher of matchers) {
|
|
for (const hook of matcher.hooks) {
|
|
if (hook.type !== "command") continue
|
|
|
|
if (isHookCommandDisabled("PreCompact", hook.command, extendedConfig ?? null)) {
|
|
log("PreCompact hook command skipped (disabled by config)", { command: hook.command })
|
|
continue
|
|
}
|
|
|
|
const hookName = hook.command.split("/").pop() || hook.command
|
|
if (!firstHookName) firstHookName = hookName
|
|
|
|
const result = await executeHookCommand(
|
|
hook.command,
|
|
JSON.stringify(stdinData),
|
|
ctx.cwd,
|
|
{ forceZsh: DEFAULT_CONFIG.forceZsh, zshPath: DEFAULT_CONFIG.zshPath }
|
|
)
|
|
|
|
if (result.exitCode === 2) {
|
|
log("PreCompact hook blocked", { hookName, stderr: result.stderr })
|
|
continue
|
|
}
|
|
|
|
if (result.stdout) {
|
|
try {
|
|
const output = JSON.parse(result.stdout) as PreCompactOutput
|
|
|
|
if (output.hookSpecificOutput?.additionalContext) {
|
|
collectedContext.push(...output.hookSpecificOutput.additionalContext)
|
|
} else if (output.context) {
|
|
collectedContext.push(...output.context)
|
|
}
|
|
|
|
if (output.continue === false) {
|
|
return {
|
|
context: collectedContext,
|
|
elapsedMs: Date.now() - startTime,
|
|
hookName: firstHookName,
|
|
continue: output.continue,
|
|
stopReason: output.stopReason,
|
|
suppressOutput: output.suppressOutput,
|
|
systemMessage: output.systemMessage,
|
|
}
|
|
}
|
|
} catch {
|
|
if (result.stdout.trim()) {
|
|
collectedContext.push(result.stdout.trim())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
context: collectedContext,
|
|
elapsedMs: Date.now() - startTime,
|
|
hookName: firstHookName,
|
|
}
|
|
}
|