/** * Hook install/uninstall for AI coding tools. * * Two integration models live in this file: * * 1. JSON-hook install (Claude Code only). Writes a `hooks` block into the * tool's settings.json with two entries: * - SessionEnd: `hippo session-end --log-file ` - spawns a detached * child that runs `hippo sleep` then `hippo capture --last-session` in * sequence, writing both outputs to the log file. The parent returns in * <100ms so the TUI teardown can't kill the child before it finishes. * - SessionStart: `hippo last-sleep --path ` - prints the log * written by the previous session's detached worker and then clears it, * so the user actually sees what was consolidated. * Earlier Claude Code forms are detected and migrated automatically: * - < 0.20.2: `Stop` hook firing `hippo sleep` on every assistant turn. * - < 0.21.0: bare `hippo sleep` in SessionEnd, no `--log-file`. * - 0.22.x: separate sleep + capture SessionEnd entries. * * 2. Plugin install (OpenCode only). OpenCode does NOT share Claude Code's * JSON-hook schema — its config has `additionalProperties: false` and no * `hooks` key, so v1.10.x-v1.11.1's JSON-hook installer broke opencode * launch (issue #24). Hippo now installs a TypeScript plugin at * `~/.config/opencode/plugins/hippo.ts` subscribing to opencode's * `session.idle` (→ `hippo session-end`) and `session.created` (→ * `hippo last-sleep`) events. See OPENCODE_PLUGIN_SOURCE below for the * plugin file content + design rationale; see installOpencodePlugin for * the installer + the migration that removes any pre-existing broken * `hooks` block from opencode.json. */ export type JsonHookTarget = 'claude-code'; export interface CodexWrapperPaths { wrapperDir: string; metadataPath: string; wrapperCmdPath: string; wrapperPs1Path: string; wrapperShPath: string; logFile: string; runsDir: string; historyPath: string; sessionsDir: string; } export interface CodexWrapperInstallResult { installed: boolean; metadataPath: string; realCodexPath: string; commandPath: string; backupPath: string; installMode: 'same-path' | 'cmd-shim'; } export interface CodexWrapperMetadata { originalCodexPath: string; realCodexPath: string; commandPath: string; backupPath: string; installMode: 'same-path' | 'cmd-shim'; logFile: string; historyPath: string; sessionsDir: string; installedAt: string; } export interface EnsureCodexWrapperResult { status: 'installed' | 'already-installed' | 'not-found'; metadataPath?: string; realCodexPath?: string; commandPath?: string; backupPath?: string; } export interface CodexSessionTranscriptOptions { codexHome: string; historyPath: string; startOffsetBytes: number; startedAtMs: number; } export interface JsonHookPaths { settings: string; logFile: string; display: string; } export interface InstallResult { target: JsonHookTarget; settingsPath: string; installedSessionEnd: boolean; installedSessionStart: boolean; installedUserPromptSubmit: boolean; installedPreCompact: boolean; installedCompactResume: boolean; migratedPinnedInjectRecent: boolean; migratedFromStop: boolean; migratedLegacySessionEnd: boolean; migratedSplitSessionEnd: boolean; } export interface ToolDetection { name: string; configDir: string; detected: boolean; kind: 'json-hook' | 'markdown-instruction' | 'plugin' | 'wrapper'; notes?: string; } declare const HIPPO_OPENCODE_PLUGIN_MARKER = "HIPPO_OPENCODE_PLUGIN_V1"; /** * The opencode plugin file we install at ~/.config/opencode/plugins/hippo.ts. * * Per https://opencode.ai/docs/plugins/, plugins are TS/JS modules exporting an * async function returning hooks. We subscribe to `event` and route: * session.idle → `hippo session-end` (Claude Code's SessionEnd equiv) * session.created → `hippo last-sleep` (Claude Code's SessionStart equiv) * * Design choices forced by plan-eng-critic Rev 0 review (2026-05-23): * * 1. No `import type { Plugin } from "@opencode-ai/plugin"`. The package's npm * publication status was unverifiable from the build sandbox (npmjs.com * returned 403); an unresolved type-only import would still crash the TS * runtime opencode uses to load the plugin. opencode infers plugin shape * from the returned object, so the type was convenience-only. * * 2. Defensive `typeof $ !== 'function'` guard. opencode runs in Bun (where * `$` is the shell-template helper), but a future Node-mode deployment * would have `$` undefined in the destructured context and the plugin * would throw on every session.idle, killing opencode sessions in a * hard-to-recover way (the idempotence marker prevents auto-reinstall). * Fail closed, let opencode continue. * * 3. `.quiet().nothrow()` on each `$\`...\`` so a missing hippo binary * (e.g. PATH-misconfigured user) does NOT throw out of the event handler. * The surrounding try/catch is belt-and-braces. * * 4. UserPromptSubmit equivalent NOT wired. opencode's `message.updated` * fires per-token, not per-prompt-submit; no clean per-prompt event. * Users wanting pinned-context auto-injection can call `hippo context` * via the MCP server (`hippo mcp`). * * 5. Versioned marker `HIPPO_OPENCODE_PLUGIN_V1` allows future versions to * overwrite cleanly. The installer's idempotence check requires BOTH * marker match AND content equality, so a plugin-source revision under * the same V1 marker re-writes the file on next install. */ export declare const OPENCODE_PLUGIN_SOURCE = "// HIPPO_OPENCODE_PLUGIN_V1\n// hippo-memory opencode plugin. DO NOT EDIT \u2014 regenerated on every\n// `hippo hook install opencode` from src/hooks.ts OPENCODE_PLUGIN_SOURCE\n// in https://github.com/kitfunso/hippo-memory. Local changes will be lost.\n\nexport const HippoPlugin = async ({ $ }) => {\n return {\n event: async ({ event }) => {\n // Defense in depth: opencode currently runs in Bun where $ is the shell\n // template helper. A non-Bun runtime would have $ as undefined; fail\n // closed instead of crashing the host session.\n if (typeof $ !== \"function\") return;\n try {\n if (event.type === \"session.idle\") {\n await $`hippo session-end`.quiet().nothrow();\n } else if (event.type === \"session.created\") {\n await $`hippo last-sleep`.quiet().nothrow();\n }\n } catch {\n // hippo CLI not on PATH or other failure \u2014 never crash the host session.\n }\n },\n };\n};\n"; export { HIPPO_OPENCODE_PLUGIN_MARKER }; /** * Default log path consumed by `hippo last-sleep`. Shared fallback when * a caller doesn't pass --path explicitly. */ export declare function defaultSleepLogPath(): string; /** * Diagnostic-only log path for `hippo pre-compact`. Deliberately separate * from the SessionEnd sleep log: `hippo last-sleep` truncates that file on * every SessionStart, which would wipe pre-compact lines before anyone * could read them. Nothing consumes this file programmatically — it exists * for manual troubleshooting only. Overridden by `--log-file`. */ export declare function defaultPreCompactLogPath(): string; export declare function resolveCodexWrapperPaths(): CodexWrapperPaths; export declare function detectRealCodexPath(): string | null; export declare function installCodexWrapper(realCodexPath?: string): CodexWrapperInstallResult; export declare function uninstallCodexWrapper(): boolean; export declare function ensureCodexWrapperInstalled(): EnsureCodexWrapperResult; /** * True if Codex wrapper metadata exists on this machine, i.e. the user opted * in to the wrapper at some point (via `hippo hook install codex`). */ export declare function isCodexWrapperInstalled(): boolean; /** * Repair-only variant of `ensureCodexWrapperInstalled`: re-ensures the wrapper * ONLY when wrapper metadata already exists — that metadata is the user's * opt-in record. Never performs a first install. Replacing another vendor's * binary must stay behind the explicit `hippo hook install codex` command; * doing it from postinstall or routine commands is a consent violation and * reads as binary hijacking to security scanners (issue #133). */ export declare function repairCodexWrapperIfInstalled(): EnsureCodexWrapperResult; export declare function resolveCodexSessionTranscript(options: CodexSessionTranscriptOptions): string | null; export declare function resolveJsonHookPaths(target: JsonHookTarget): JsonHookPaths; export declare function installJsonHooks(target: JsonHookTarget): InstallResult; export declare function uninstallJsonHooks(target: JsonHookTarget): boolean; export interface OpencodePluginInstallResult { installed: boolean; pluginPath: string; migratedLegacyHooks: boolean; jsonRepairFailed: boolean; } export declare function resolveOpencodePluginPath(): string; export declare function installOpencodePlugin(): OpencodePluginInstallResult; export declare function uninstallOpencodePlugin(): boolean; /** * Detect which AI coding tools are installed based on config directory presence. * Used by `hippo setup` to decide which JSON-hook installs to run. */ export declare function detectInstalledTools(): ToolDetection[]; //# sourceMappingURL=hooks.d.ts.map