Additional abstractions for both sqlite and chroma.

This commit is contained in:
2025-12-16 01:36:43 +00:00
parent 7e49113d24
commit 6c28ecb22a
20 changed files with 834 additions and 483 deletions
+94
View File
@@ -6,6 +6,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
)
@@ -49,3 +50,96 @@ func WriteError(hookName string, err error) {
fmt.Fprintf(os.Stderr, "[%s] Error: %v\n", hookName, err)
WriteResponse(hookName, false)
}
// BaseInput contains common fields shared by all hook inputs.
type BaseInput struct {
SessionID string `json:"session_id"`
CWD string `json:"cwd"`
PermissionMode string `json:"permission_mode"`
HookEventName string `json:"hook_event_name"`
}
// HookContext provides common context for hook handlers.
type HookContext struct {
HookName string
Port int
Project string
SessionID string
CWD string
RawInput []byte
}
// HookHandler is a function that handles hook-specific logic.
// It receives the context and returns an optional context string and error.
type HookHandler[T any] func(ctx *HookContext, input *T) (additionalContext string, err error)
// RunHook executes a hook with common boilerplate handling.
// It handles: internal call skip, stdin reading, JSON unmarshaling,
// worker startup, and project ID generation.
func RunHook[T any](hookName string, handler HookHandler[T]) {
// Skip if this is an internal call (from SDK processor)
if os.Getenv("CLAUDE_MNEMONIC_INTERNAL") == "1" {
WriteResponse(hookName, true)
return
}
// Read input from stdin
inputData, err := io.ReadAll(os.Stdin)
if err != nil {
WriteError(hookName, err)
os.Exit(1)
}
// Parse input
var input T
if err := json.Unmarshal(inputData, &input); err != nil {
WriteError(hookName, err)
os.Exit(1)
}
// Ensure worker is running
port, err := EnsureWorkerRunning()
if err != nil {
WriteError(hookName, err)
os.Exit(1)
}
// Extract base fields using interface assertion or reflection
var base BaseInput
_ = json.Unmarshal(inputData, &base)
// Generate project ID from CWD
project := ProjectIDWithName(base.CWD)
// Create context
ctx := &HookContext{
HookName: hookName,
Port: port,
Project: project,
SessionID: base.SessionID,
CWD: base.CWD,
RawInput: inputData,
}
// Run hook-specific handler
additionalContext, err := handler(ctx, &input)
if err != nil {
WriteError(hookName, err)
os.Exit(1)
}
// Output response
if additionalContext != "" {
response := map[string]interface{}{
"continue": true,
"hookSpecificOutput": map[string]interface{}{
"hookEventName": hookName,
"additionalContext": additionalContext,
},
}
_ = json.NewEncoder(os.Stdout).Encode(response)
os.Exit(0)
}
WriteResponse(hookName, true)
}