Files
雷电芽衣 a7fc75bf6b chore(go): audit providers claudecode codex cursor gemini
Add managed_runtime.go (paths, config validation, identity, runtime file
changes, status checks) and shell_command.go (quoting, PowerShell
encoding, command parsing) and move the four providers onto them.

Claude-Session: https://claude.ai/code/session_01Agoc9bRVE9KL7mmWtey9Vq
2026-09-03 01:42:27 -04:00

150 lines
3.7 KiB
Go

package plugins
import (
"fmt"
"path/filepath"
)
// ClaudeCodePlugin manages Claude Code global user hooks.
type ClaudeCodePlugin struct {
rename renameFunc
}
// ManagesGuardRuntime reports that the guard is committed with the audit runtime.
func (p *ClaudeCodePlugin) ManagesGuardRuntime() bool {
return true
}
func requireClaudeHooksEnabled(document *claudeDocument) error {
if document.hooksDisabled {
return fmt.Errorf(
"Claude Code hooks are disabled by disableAllHooks: %s",
document.filePath,
)
}
return nil
}
// PreflightInstall validates settings and runtime identity before any write.
func (p *ClaudeCodePlugin) PreflightInstall(config InstallConfig) error {
document, err := readClaudeDocument()
if err != nil {
return err
}
if err := requireClaudeHooksEnabled(document); err != nil {
return err
}
_, _, err = preflightClaudeInstallation(config, document)
return err
}
func (p *ClaudeCodePlugin) Install(config InstallConfig) error {
document, err := readClaudeDocument()
if err != nil {
return err
}
if err := requireClaudeHooksEnabled(document); err != nil {
return err
}
paths, nodePath, err := preflightClaudeInstallation(config, document)
if err != nil {
return err
}
hooks, err := removeManagedClaudeHooks(document.hooks, "")
if err != nil {
return err
}
for _, item := range []struct{ event, script, status string }{
{"PreToolUse", paths.guardPath, claudeGuardStatusMessage},
{"PostToolUse", paths.auditPath, claudeAuditStatusMessage},
{"PostToolUseFailure", paths.auditPath, claudeAuditStatusMessage},
} {
hooks[item.event] = append(
hooks[item.event],
buildClaudeGroup(nodePath, item.script, item.status),
)
}
rendered, err := renderClaudeDocument(document, hooks)
if err != nil {
return fmt.Errorf("render Claude Code user settings: %w", err)
}
changes, err := prepareClaudeInstallationChanges(config, paths, rendered)
if err != nil {
return err
}
if err := writeManagedChanges(
changes,
"Install Claude Code hooks",
p.rename,
paths.runtimeRoot,
paths.agentDirectory,
filepath.Dir(document.filePath),
"Claude Code configuration directory",
); err != nil {
return err
}
fmt.Printf("Claude Code hooks installed at %s.\n", document.filePath)
fmt.Println("Claude Code verification: run /hooks and claude doctor.")
return nil
}
func (p *ClaudeCodePlugin) Uninstall(agentID string) error {
document, err := readClaudeDocument()
if err != nil {
return err
}
hooks, err := removeManagedClaudeHooks(document.hooks, agentID)
if err != nil {
return err
}
rendered, err := renderClaudeDocument(document, hooks)
if err != nil {
return fmt.Errorf("render Claude Code user settings: %w", err)
}
change, err := prepareRenderedClaudeChange(rendered)
if err != nil {
return err
}
return writeManagedChanges(
[]*fileChange{change},
"Uninstall Claude Code hooks",
p.rename,
"",
"",
filepath.Dir(document.filePath),
"Claude Code configuration directory",
)
}
func (p *ClaudeCodePlugin) Status() (PluginStatus, error) {
configPath, pathErr := claudeSettingsPath()
entry := SupportedAgents[claudeAgentKey]
status := PluginStatus{
AgentName: claudeAgentKey, DisplayName: entry.Name, ConfigPath: configPath,
}
if pathErr != nil {
return status, pathErr
}
document, err := readClaudeDocument()
if err != nil {
return status, err
}
if document.hooksDisabled {
return status, nil
}
contracts, err := claudeRuntimeContracts(document.hooks)
if err != nil {
return status, err
}
status.HookConfigured = len(contracts) > 0
if !status.HookConfigured {
return status, nil
}
status.HookScriptExists, err = claudeRuntimeFilesExist(contracts)
if err != nil {
return status, err
}
status.Installed = status.HookScriptExists
return status, nil
}