Migrate to per-agent subdirectories, uniform 8-agent support, cross-platform fixes

- All paths use ~/.elydora/{agentId}/ per-agent isolation
- Add copilot, letta plugins; split kiro into kirocli + kiroide
- Remove augment (SDK-only agent, not one-click)
- Fix filepath.Join usage (replace string concatenation)
- Fix stale comment referencing old ~/.elydora/agents/ path
- Uniform 8 agents: claudecode, cursor, gemini, kirocli, kiroide, opencode, copilot, letta

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 4.6 committed 2026-03-01 19:58:20 -05:00
1 parent c21e9fcfc6
commit d80819093a
14 files changed
+830 -199

No files matched your search

+33 -21
View File
@@ -20,7 +20,7 @@ func (p *CursorPlugin) configPath() (string, error) {
}
func (p *CursorPlugin) Install(config InstallConfig) error {
scriptPath, err := hookScriptPath("cursor")
scriptPath, err := hookScriptPath(config.AgentID)
if err != nil {
return err
}
@@ -34,7 +34,7 @@ func (p *CursorPlugin) Install(config InstallConfig) error {
guardPath := config.GuardScriptPath
if guardPath == "" {
guardPath, err = guardScriptPath("cursor")
guardPath, err = guardScriptPath(config.AgentID)
if err != nil {
return err
}
@@ -99,12 +99,7 @@ func (p *CursorPlugin) Install(config InstallConfig) error {
return nil
}
func (p *CursorPlugin) Uninstall() error {
scriptPath, err := hookScriptPath("cursor")
if err != nil {
return err
}
func (p *CursorPlugin) Uninstall(agentID string) error {
configPath, err := p.configPath()
if err != nil {
return err
@@ -165,21 +160,21 @@ func (p *CursorPlugin) Uninstall() error {
return err
}
os.Remove(scriptPath)
gPath, _ := guardScriptPath("cursor")
if gPath != "" {
os.Remove(gPath)
if agentID != "" {
scriptPath, _ := hookScriptPath(agentID)
if scriptPath != "" {
os.Remove(scriptPath)
}
gPath, _ := guardScriptPath(agentID)
if gPath != "" {
os.Remove(gPath)
}
}
fmt.Println("Uninstalled Elydora hook for Cursor.")
return nil
}
func (p *CursorPlugin) Status() (PluginStatus, error) {
scriptPath, err := hookScriptPath("cursor")
if err != nil {
return PluginStatus{}, err
}
configPath, err := p.configPath()
if err != nil {
return PluginStatus{}, err
@@ -191,10 +186,6 @@ func (p *CursorPlugin) Status() (PluginStatus, error) {
ConfigPath: configPath,
}
if _, err := os.Stat(scriptPath); err == nil {
status.HookScriptExists = true
}
settings, err := readJSONFile(configPath)
if err != nil {
return status, nil
@@ -205,12 +196,33 @@ func (p *CursorPlugin) Status() (PluginStatus, error) {
preConfigured := hasCursorElydoraEntry(hooks["preToolUse"])
postConfigured := hasCursorElydoraEntry(hooks["postToolUse"])
status.HookConfigured = preConfigured && postConfigured
// Extract hook script path from the configured command
scriptPath := extractCursorElydoraScriptPath(hooks["postToolUse"])
if scriptPath != "" {
if _, err := os.Stat(scriptPath); err == nil {
status.HookScriptExists = true
}
}
}
status.Installed = status.HookConfigured && status.HookScriptExists
return status, nil
}
// extractCursorElydoraScriptPath extracts the script path from a Cursor hook array's Elydora command entry.
func extractCursorElydoraScriptPath(hookArray interface{}) string {
arr, _ := hookArray.([]interface{})
for _, entry := range arr {
if m, ok := entry.(map[string]interface{}); ok {
if cmd, _ := m["command"].(string); strings.Contains(cmd, "elydora") {
return extractPathFromNodeCommand(cmd)
}
}
}
return ""
}
// hasCursorElydoraEntry checks if a Cursor hook array (flat format) contains an Elydora entry.
func hasCursorElydoraEntry(hookArray interface{}) bool {
arr, _ := hookArray.([]interface{})