144 lines
3.8 KiB
Go
144 lines
3.8 KiB
Go
package plugins
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type kimiMutation struct {
|
|
document kimiDocument
|
|
raw []byte
|
|
remove bool
|
|
}
|
|
|
|
// KimiPlugin manages Kimi Code and legacy kimi-cli global lifecycle hooks.
|
|
type KimiPlugin struct{}
|
|
|
|
func (p *KimiPlugin) Install(config InstallConfig) error {
|
|
if config.AgentID == "" {
|
|
return fmt.Errorf("agent ID is required")
|
|
}
|
|
documents, err := readAllKimiConfigs()
|
|
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
|
|
}
|
|
additions := []kimiHook{
|
|
buildKimiHook("PreToolUse", buildKimiCommand(nodePath, config.GuardScriptPath)),
|
|
buildKimiHook("PostToolUse", buildKimiCommand(nodePath, hookPath)),
|
|
}
|
|
mutations := make([]kimiMutation, 0, len(documents))
|
|
for _, document := range documents {
|
|
raw, err := renderKimiHooks(document, keptKimiHookIndices(document.hooks, ""), additions)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := parseKimiDocument(document.contract, raw, true); err != nil {
|
|
return fmt.Errorf("validate rendered %s: %w", document.contract.label, err)
|
|
}
|
|
mutations = append(mutations, kimiMutation{document: document, raw: raw})
|
|
}
|
|
|
|
runtimeConfig := config
|
|
runtimeConfig.AgentName = kimiAgentKey
|
|
if err := GenerateHookScript(hookPath, runtimeConfig); err != nil {
|
|
return fmt.Errorf("generate hook script: %w", err)
|
|
}
|
|
for _, mutation := range mutations {
|
|
if err := writeKimiConfig(mutation.document, mutation.raw); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
fmt.Printf("%s: global PreToolUse and PostToolUse hooks installed.\n", kimiRuntimeNames(documents))
|
|
return nil
|
|
}
|
|
|
|
func (p *KimiPlugin) Uninstall(agentID string) error {
|
|
documents, err := readAllKimiConfigs()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
mutations := make([]kimiMutation, 0, len(documents))
|
|
for _, document := range documents {
|
|
keep := keptKimiHookIndices(document.hooks, agentID)
|
|
if len(keep) == len(document.hooks) {
|
|
continue
|
|
}
|
|
raw, err := renderKimiHooks(document, keep, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := parseKimiDocument(document.contract, raw, true); err != nil {
|
|
return fmt.Errorf("validate rendered %s: %w", document.contract.label, err)
|
|
}
|
|
mutations = append(mutations, kimiMutation{
|
|
document: document,
|
|
raw: raw,
|
|
remove: strings.TrimSpace(string(raw)) == "",
|
|
})
|
|
}
|
|
for _, mutation := range mutations {
|
|
if mutation.remove {
|
|
if err := removeKimiConfig(mutation.document); err != nil {
|
|
return err
|
|
}
|
|
continue
|
|
}
|
|
if err := writeKimiConfig(mutation.document, mutation.raw); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *KimiPlugin) Status() (PluginStatus, error) {
|
|
documents, err := readAllKimiConfigs()
|
|
status := PluginStatus{
|
|
AgentName: kimiAgentKey,
|
|
DisplayName: "Kimi Code",
|
|
}
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
status.ConfigPath = documents[0].contract.configPath
|
|
contracts := make([]kimiRuntimeContract, 0, len(documents))
|
|
for _, document := range documents {
|
|
contract := kimiRuntimeForDocument(document)
|
|
if contract == nil {
|
|
continue
|
|
}
|
|
contracts = append(contracts, *contract)
|
|
status.ConfigPath = contract.configPath
|
|
}
|
|
if len(contracts) == 0 {
|
|
return status, nil
|
|
}
|
|
status.HookConfigured = true
|
|
status.HookScriptExists, err = kimiRuntimeScriptsExist(contracts)
|
|
if err != nil {
|
|
return status, err
|
|
}
|
|
status.Installed = status.HookScriptExists
|
|
return status, nil
|
|
}
|