166 lines
4.2 KiB
Go
166 lines
4.2 KiB
Go
package plugins
|
|
|
|
import "fmt"
|
|
|
|
// CodexPlugin manages OpenAI Codex user lifecycle hooks.
|
|
type CodexPlugin struct{}
|
|
|
|
func (p *CodexPlugin) Install(config InstallConfig) error {
|
|
if config.AgentID == "" {
|
|
return fmt.Errorf("agent ID is required")
|
|
}
|
|
configPath, err := codexConfigPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
settings, exists, err := readHookJSONObject(configPath, "Codex hooks config")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exists {
|
|
settings = map[string]any{"description": codexOwnedDescription}
|
|
}
|
|
hooks, err := codexHooksObject(settings)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
preGroups, err := codexEventGroups(hooks, "PreToolUse")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
postGroups, err := codexEventGroups(hooks, "PostToolUse")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
preGroups, _, err = withoutCodexHandlers(preGroups, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
postGroups, _, err = withoutCodexHandlers(postGroups, "")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if config.GuardScriptPath == "" {
|
|
return fmt.Errorf("guard script path is required")
|
|
}
|
|
guardExists, err := regularFileExists(config.GuardScriptPath, "Elydora guard runtime")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !guardExists {
|
|
return fmt.Errorf("Elydora guard runtime is missing: %s", config.GuardScriptPath)
|
|
}
|
|
hookPath, err := hookScriptPath(config.AgentID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if config.HookScript != "" {
|
|
hookPath = config.HookScript
|
|
}
|
|
nodePath, err := resolveNodeRuntime()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
hooks["PreToolUse"] = append(preGroups, codexMatcherGroup(
|
|
codexHandler(nodePath, config.GuardScriptPath, codexGuardStatusMessage),
|
|
))
|
|
hooks["PostToolUse"] = append(postGroups, codexMatcherGroup(
|
|
codexHandler(nodePath, hookPath, codexAuditStatusMessage),
|
|
))
|
|
next := cloneCodexObject(settings)
|
|
next["hooks"] = hooks
|
|
|
|
runtimeConfig := config
|
|
runtimeConfig.AgentName = codexAgentKey
|
|
if err := GenerateHookScript(hookPath, runtimeConfig); err != nil {
|
|
return fmt.Errorf("generate hook script: %w", err)
|
|
}
|
|
if err := writeHookJSONObjectAtomic(configPath, next); err != nil {
|
|
return fmt.Errorf("write Codex hooks config: %w", err)
|
|
}
|
|
fmt.Println("Codex: run /hooks to review and trust the Elydora hooks.")
|
|
return nil
|
|
}
|
|
|
|
func (p *CodexPlugin) Uninstall(agentID string) error {
|
|
configPath, err := codexConfigPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
settings, exists, err := readHookJSONObject(configPath, "Codex hooks config")
|
|
if err != nil || !exists {
|
|
return err
|
|
}
|
|
hooks, err := codexHooksObject(settings)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
preGroups, err := codexEventGroups(hooks, "PreToolUse")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
postGroups, err := codexEventGroups(hooks, "PostToolUse")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filteredPre, preChanged, err := withoutCodexHandlers(preGroups, agentID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
filteredPost, postChanged, err := withoutCodexHandlers(postGroups, agentID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !preChanged && !postChanged {
|
|
return nil
|
|
}
|
|
hooks["PreToolUse"] = filteredPre
|
|
hooks["PostToolUse"] = filteredPost
|
|
if codexSettingsOwned(settings, hooks) {
|
|
return removeHookFile(configPath, "Codex hooks config")
|
|
}
|
|
next := cloneCodexObject(settings)
|
|
next["hooks"] = hooks
|
|
return writeHookJSONObjectAtomic(configPath, next)
|
|
}
|
|
|
|
func (p *CodexPlugin) Status() (PluginStatus, error) {
|
|
configPath, err := codexConfigPath()
|
|
status := PluginStatus{
|
|
AgentName: codexAgentKey,
|
|
DisplayName: "OpenAI Codex",
|
|
ConfigPath: configPath,
|
|
}
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
settings, exists, err := readHookJSONObject(configPath, "Codex hooks config")
|
|
if err != nil || !exists {
|
|
return status, err
|
|
}
|
|
hooks, err := codexHooksObject(settings)
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
guard, err := findCodexHandler(hooks, "PreToolUse", codexGuardStatusMessage)
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
audit, err := findCodexHandler(hooks, "PostToolUse", codexAuditStatusMessage)
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
if guard == nil || audit == nil {
|
|
return status, nil
|
|
}
|
|
status.HookConfigured = true
|
|
status.HookScriptExists, err = codexRuntimeScriptsExist(guard, audit)
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
status.Installed = status.HookScriptExists
|
|
return status, nil
|
|
}
|