/** * Installs the hooks that let the Brain speak through each agent host's own tools (see * HostRecall / HostAdapters) and capture red → green fixes run through the host's shell (see * FixCapture). Without them the Brain only ever saw Lemma's MCP tools — and agents mostly read, * edit and test with their native ones. * * - Claude Code — `.claude/settings.local.json` PostToolUse (personal, never the team's * versioned settings.json; gitignored if the repo doesn't ignore it yet). * - Codex — `~/.codex/hooks.json` PostToolUse, same format as Claude Code. * - Cursor — `~/.cursor/hooks.json` postToolUse + postToolUseFailure. * - OpenCode — a plugin in `~/.config/opencode/plugins/` (it has no hook protocol). * * Codex/Cursor/OpenCode go in user-level config: their project-level files are the team's and * versioned, and the hook is repo-agnostic anyway (silent wherever the Brain has nothing). * * Same constraints as the git hook installer: * - Merge, never overwrite. Other hooks and settings are kept exactly as they were; Lemma's * entry is found by its command and updated in place (idempotent). * - A config file that isn't valid JSON — or a plugin file Lemma didn't write — is left alone, * and the caller gets what to add by hand. * - Never break a tool call: the command is guarded so a missing binary is a silent no-op. */ export declare function hookCommand(host: 'claude' | 'codex' | 'cursor'): string; export declare const CLAUDE_HOOK_COMMAND: string; export declare const CLAUDE_HOOK_MATCHER = "Bash|Read|Edit|MultiEdit|Write|NotebookEdit"; export declare const CODEX_HOOK_MATCHER = "Bash|apply_patch|Edit|Write"; export declare const CURSOR_POST_MATCHER = "Read|Shell|Write"; export declare const CURSOR_FAILURE_MATCHER = "Shell"; export interface HookInstallOutcome { status: 'installed' | 'updated' | 'unchanged' | 'manual'; file: string; /** Set when the file couldn't be merged safely; holds what to add by hand. */ snippet?: string; /** True when `.claude/settings.local.json` was appended to .gitignore (Claude Code only). */ gitignored?: boolean; } export declare function installClaudeHooks(cwd?: string): HookInstallOutcome; export declare function installCodexHooks(home?: string): HookInstallOutcome; /** Cursor format: `{ version: 1, hooks: { : [{ command, matcher? }] } }`. */ export declare function installCursorHooks(home?: string): HookInstallOutcome; /** * OpenCode has no hook protocol, so the hook is a plugin: it forwards each finished tool call * to `lemma-brain-ingest --host=opencode` and appends the note it prints (if any) to the tool's * output — the only place a plugin can put text the model reads. Arguments are taken from * tool.execute.before, keyed by call id, because the after-hook's input doesn't carry them. */ export declare const OPENCODE_PLUGIN = "// managed by `lemma init` \u2014 delete this file to disable Lemma Brain recall in OpenCode\nimport { spawnSync } from \"node:child_process\";\n\nexport const LemmaBrainRecall = async ({ directory }) => {\n const argsByCall = new Map();\n return {\n \"tool.execute.before\": async (input, output) => {\n if (!input || !input.callID) return;\n argsByCall.set(input.callID, (output && output.args) || {});\n if (argsByCall.size > 200) argsByCall.delete(argsByCall.keys().next().value);\n },\n \"tool.execute.after\": async (input, output) => {\n try {\n const args = argsByCall.get(input.callID) || input.args || {};\n argsByCall.delete(input.callID);\n if (!output || typeof output.output !== \"string\") return;\n const payload = { tool: input.tool, sessionID: input.sessionID, args, output: output.output, metadata: output.metadata || {}, directory };\n const r = spawnSync(\"lemma-brain-ingest\", [\"--hook-result\", \"--host=opencode\"], { input: JSON.stringify(payload), encoding: \"utf8\", timeout: 5000 });\n const note = typeof r.stdout === \"string\" ? r.stdout.trim() : \"\";\n if (note) output.output += \"\\n\\n\" + note;\n } catch {\n // A recall hint must never be the reason a tool call fails.\n }\n },\n };\n};\n"; export declare function installOpenCodePlugin(home?: string): HookInstallOutcome; export interface HostHookReport { host: 'Claude Code' | 'Codex' | 'Cursor' | 'OpenCode'; outcome: HookInstallOutcome; } /** * Claude Code is always wired (project-local file). The other hosts only when their config * directory already exists — Lemma doesn't create a Cursor or Codex setup on a machine that has * neither. */ export declare function installHostHooks(cwd?: string, home?: string): HostHookReport[]; //# sourceMappingURL=hostHooks.d.ts.map