Commit 98185b2
Changed files (3)
cmd
del
internal
cmd/del/main.go
@@ -1,529 +1,40 @@
package main
import (
- "bufio"
- "context"
- "encoding/json"
- "fmt"
"log"
- "os"
- "os/exec"
- "strings"
"github.com/spf13/cobra"
-)
-
-// AI Provider interface - supports multiple AI backends
-type AIProvider interface {
- Generate(ctx context.Context, prompt string) (string, error)
- Name() string
-}
-
-// Tool represents an available capability
-type Tool struct {
- Name string
- Description string
- Handler func(args map[string]interface{}) (interface{}, error)
-}
-
-// Del is our main AI assistant - Del the Funky Robosapien!
-type Del struct {
- aiProvider AIProvider
- tools map[string]*Tool
- mcpServers map[string]string // name -> command path
-}
-
-// Claude API provider
-type ClaudeProvider struct {
- apiKey string
-}
-
-func (c *ClaudeProvider) Generate(ctx context.Context, prompt string) (string, error) {
- // Use Claude CLI if available, fallback to API
- cmd := exec.CommandContext(ctx, "claude", "--print", prompt)
- output, err := cmd.Output()
- if err != nil {
- return "", fmt.Errorf("claude error: %w", err)
- }
- return string(output), nil
-}
-
-func (c *ClaudeProvider) Name() string {
- return "Claude"
-}
-
-// Ollama provider
-type OllamaProvider struct {
- model string
-}
-
-func (o *OllamaProvider) Generate(ctx context.Context, prompt string) (string, error) {
- cmd := exec.CommandContext(ctx, "ollama", "run", o.model, prompt)
- output, err := cmd.Output()
- if err != nil {
- return "", fmt.Errorf("ollama error: %w", err)
- }
- return string(output), nil
-}
-
-func (o *OllamaProvider) Name() string {
- return fmt.Sprintf("Ollama (%s)", o.model)
-}
-
-// Initialize Del with tools and MCP servers
-func NewDel(provider AIProvider) *Del {
- d := &Del{
- aiProvider: provider,
- tools: make(map[string]*Tool),
- mcpServers: make(map[string]string),
- }
-
- // Register built-in tools
- d.registerBuiltinTools()
-
- // Auto-discover MCP servers
- d.discoverMCPServers()
-
- return d
-}
-
-func (d *Del) registerBuiltinTools() {
- // Security scanner tool
- d.tools["security_scan"] = &Tool{
- Name: "security_scan",
- Description: "Scan code for security vulnerabilities",
- Handler: d.handleSecurityScan,
- }
-
- // Code analysis tool
- d.tools["analyze_code"] = &Tool{
- Name: "analyze_code",
- Description: "Analyze code quality and suggest improvements",
- Handler: d.handleCodeAnalysis,
- }
-
- // File operations
- d.tools["read_file"] = &Tool{
- Name: "read_file",
- Description: "Read contents of a file",
- Handler: d.handleReadFile,
- }
-
- d.tools["write_file"] = &Tool{
- Name: "write_file",
- Description: "Write content to a file",
- Handler: d.handleWriteFile,
- }
-
- // Command execution
- d.tools["run_command"] = &Tool{
- Name: "run_command",
- Description: "Execute shell commands",
- Handler: d.handleRunCommand,
- }
-
- // MCP integration tools (when backend Claude completes servers)
- d.tools["mcp_git_list"] = &Tool{
- Name: "mcp_git_list",
- Description: "List files in git repository via MCP",
- Handler: d.handleMCPGitList,
- }
-
- d.tools["mcp_git_read"] = &Tool{
- Name: "mcp_git_read",
- Description: "Read file from git repository via MCP",
- Handler: d.handleMCPGitRead,
- }
-}
-func (d *Del) discoverMCPServers() {
- // Look for MCP servers in the other Claude's repo
- mcpPath := "/home/mokhax/src/github.com/xlgmokha/mcp"
- servers := map[string]string{
- "git": mcpPath + "/cmd/git/main.go",
- "filesystem": mcpPath + "/cmd/fs/main.go",
- "bash": mcpPath + "/cmd/bash/main.go",
- }
-
- for name, path := range servers {
- if _, err := os.Stat(path); err == nil {
- d.mcpServers[name] = path
- }
- }
-}
+ "github.com/xlgmokha/deltron/internal/del"
+)
-func (d *Del) handleSecurityScan(args map[string]interface{}) (interface{}, error) {
- path, ok := args["path"].(string)
- if !ok {
- return nil, fmt.Errorf("path required")
- }
-
- // Run security tools like gosec, semgrep, etc.
- results := map[string]interface{}{
- "vulnerabilities": []string{},
- "warnings": []string{},
- "suggestions": []string{},
- }
-
- // Check for common security issues
- if strings.Contains(path, ".go") {
- // Run gosec if available
- cmd := exec.Command("gosec", "-fmt", "json", path)
- if output, err := cmd.Output(); err == nil {
- results["gosec_output"] = string(output)
- }
- }
-
- return results, nil
-}
+func main() {
+ var provider, model string
+
+ rootCmd := &cobra.Command{
+ Use: "del",
+ Short: "Del the Funky Robosapien - Your AI-powered coding superhero",
+ Run: func(cmd *cobra.Command, args []string) {
+ var ai del.AIProvider
+
+ switch provider {
+ case "claude":
+ ai = del.NewClaudeProvider("")
+ case "ollama":
+ ai = del.NewOllamaProvider(model)
+ default:
+ ai = del.AutoProvider("", model)
+ }
-func (d *Del) handleCodeAnalysis(args map[string]interface{}) (interface{}, error) {
- path, ok := args["path"].(string)
- if !ok {
- return nil, fmt.Errorf("path required")
- }
-
- analysis := map[string]interface{}{
- "path": path,
- "complexity": "medium",
- "maintainability": "good",
- "suggestions": []string{
- "Consider adding more comments",
- "Extract complex functions",
+ assistant := del.NewDel(ai)
+ assistant.StartREPL()
},
}
-
- return analysis, nil
-}
-func (d *Del) handleReadFile(args map[string]interface{}) (interface{}, error) {
- path, ok := args["path"].(string)
- if !ok {
- return nil, fmt.Errorf("path required")
- }
-
- content, err := os.ReadFile(path)
- if err != nil {
- return nil, err
- }
-
- return map[string]interface{}{
- "path": path,
- "content": string(content),
- "size": len(content),
- }, nil
-}
+ rootCmd.Flags().StringVarP(&provider, "provider", "p", "auto", "AI provider (claude, ollama, auto)")
+ rootCmd.Flags().StringVarP(&model, "model", "m", "deepseek-coder-v2:16b", "Model to use (for Ollama)")
-func (d *Del) handleWriteFile(args map[string]interface{}) (interface{}, error) {
- path, ok := args["path"].(string)
- if !ok {
- return nil, fmt.Errorf("path required")
- }
-
- content, ok := args["content"].(string)
- if !ok {
- return nil, fmt.Errorf("content required")
- }
-
- // Ask for confirmation
- fmt.Printf("๐ค Del asks: Write to %s? [y/N]: ", path)
- reader := bufio.NewReader(os.Stdin)
- response, _ := reader.ReadString('\n')
-
- if strings.ToLower(strings.TrimSpace(response)) != "y" {
- return map[string]interface{}{"status": "cancelled"}, nil
- }
-
- err := os.WriteFile(path, []byte(content), 0644)
- if err != nil {
- return nil, err
- }
-
- return map[string]interface{}{
- "status": "written",
- "path": path,
- "size": len(content),
- }, nil
-}
-
-func (d *Del) handleRunCommand(args map[string]interface{}) (interface{}, error) {
- command, ok := args["command"].(string)
- if !ok {
- return nil, fmt.Errorf("command required")
- }
-
- // Ask for confirmation
- fmt.Printf("๐ค Del asks: Execute '%s'? [y/N]: ", command)
- reader := bufio.NewReader(os.Stdin)
- response, _ := reader.ReadString('\n')
-
- if strings.ToLower(strings.TrimSpace(response)) != "y" {
- return map[string]interface{}{"status": "cancelled"}, nil
- }
-
- cmd := exec.Command("sh", "-c", command)
- output, err := cmd.CombinedOutput()
-
- result := map[string]interface{}{
- "command": command,
- "output": string(output),
- "success": err == nil,
- }
-
- if err != nil {
- result["error"] = err.Error()
- }
-
- return result, nil
-}
-
-// MCP Git List handler - will connect to MCP servers once available
-func (d *Del) handleMCPGitList(args map[string]interface{}) (interface{}, error) {
- // Check if git MCP server is available
- if _, exists := d.mcpServers["git"]; !exists {
- return nil, fmt.Errorf("git MCP server not available yet")
- }
-
- // TODO: Implement actual MCP client call once server is ready
- return map[string]interface{}{
- "status": "pending",
- "message": "Git MCP server implementation in progress",
- }, nil
-}
-
-// MCP Git Read handler - will connect to MCP servers once available
-func (d *Del) handleMCPGitRead(args map[string]interface{}) (interface{}, error) {
- // Check if git MCP server is available
- if _, exists := d.mcpServers["git"]; !exists {
- return nil, fmt.Errorf("git MCP server not available yet")
- }
-
- path, ok := args["path"].(string)
- if !ok {
- return nil, fmt.Errorf("path required")
- }
-
- // TODO: Implement actual MCP client call once server is ready
- return map[string]interface{}{
- "status": "pending",
- "path": path,
- "message": "Git MCP server implementation in progress",
- }, nil
-}
-
-// Enhanced prompt with available tools
-func (d *Del) buildPrompt(userInput string) string {
- toolsList := make([]string, 0, len(d.tools))
- for name, tool := range d.tools {
- toolsList = append(toolsList, fmt.Sprintf("- %s: %s", name, tool.Description))
- }
-
- mcpList := make([]string, 0, len(d.mcpServers))
- for name := range d.mcpServers {
- mcpList = append(mcpList, name)
- }
-
- return fmt.Sprintf(`You are Del the Funky Robosapien, an AI-powered coding superhero assistant.
-Channel the energy of Del the Funky Homosapien - you're creative, clever, and always ready to drop some funky code solutions!
-
-AVAILABLE TOOLS:
-%s
-
-AVAILABLE MCP SERVERS:
-%s
-
-CURRENT CONTEXT:
-- Working Directory: %s
-- Git Status: %s
-
-When you want to use a tool, respond with:
-TOOL_USE: tool_name {"arg1": "value1", "arg2": "value2"}
-
-For example:
-TOOL_USE: read_file {"path": "main.go"}
-TOOL_USE: security_scan {"path": "."}
-TOOL_USE: run_command {"command": "go build"}
-
-Keep it funky! ๐ค๐ค
-
-User Request: %s`,
- strings.Join(toolsList, "\n"),
- strings.Join(mcpList, ", "),
- getCurrentDir(),
- getGitStatus(),
- userInput)
-}
-
-func getCurrentDir() string {
- dir, _ := os.Getwd()
- return dir
-}
-
-func getGitStatus() string {
- cmd := exec.Command("git", "status", "--porcelain")
- output, err := cmd.Output()
- if err != nil {
- return "Not a git repository"
- }
- return string(output)
-}
-
-// Process AI response and execute tools
-func (d *Del) processResponse(response string) {
- lines := strings.Split(response, "\n")
-
- for _, line := range lines {
- if strings.HasPrefix(line, "TOOL_USE:") {
- d.executeTool(strings.TrimPrefix(line, "TOOL_USE:"))
- }
- }
-}
-
-func (d *Del) executeTool(toolCall string) {
- parts := strings.SplitN(toolCall, " ", 2)
- if len(parts) != 2 {
- fmt.Printf("โ Invalid tool call: %s\n", toolCall)
- return
- }
-
- toolName := strings.TrimSpace(parts[0])
- argsJSON := strings.TrimSpace(parts[1])
-
- tool, exists := d.tools[toolName]
- if !exists {
- fmt.Printf("โ Unknown tool: %s\n", toolName)
- return
- }
-
- var args map[string]interface{}
- if err := json.Unmarshal([]byte(argsJSON), &args); err != nil {
- fmt.Printf("โ Invalid tool args: %s\n", err)
- return
- }
-
- fmt.Printf("๐ค Del is dropping some tool magic: %s\n", toolName)
- result, err := tool.Handler(args)
- if err != nil {
- fmt.Printf("โ Tool error: %s\n", err)
- return
- }
-
- fmt.Printf("โ
Funky result: %+v\n", result)
-}
-
-func (d *Del) showHelp() {
- fmt.Println("๐ค๐ค Del the Funky Robosapien - Help Menu:")
- fmt.Println(" ๐ก๏ธ Security Commands:")
- fmt.Println(" 'scan for vulnerabilities'")
- fmt.Println(" 'check this code for security issues'")
- fmt.Println(" ๐ Development Commands:")
- fmt.Println(" 'read the main.go file'")
- fmt.Println(" 'build this project'")
- fmt.Println(" 'run the tests'")
- fmt.Println(" 'analyze code quality'")
- fmt.Println(" ๐ง Available Tools:")
- for name, tool := range d.tools {
- fmt.Printf(" - %s: %s\n", name, tool.Description)
- }
- fmt.Println(" ๐ต Remember: Keep it funky!")
- fmt.Println()
-}
-
-// Interactive REPL
-func (d *Del) startREPL() {
- fmt.Printf("๐ค๐ค Del the Funky Robosapien is in the house! (Provider: %s)\n", d.aiProvider.Name())
-
- fmt.Printf("๐ง Available tools: %s\n", strings.Join(func() []string {
- var names []string
- for name := range d.tools {
- names = append(names, name)
- }
- return names
- }(), ", "))
- fmt.Println("๐ฌ Type 'quit' to exit, 'help' for assistance")
- fmt.Println("๐ต Let's make some funky code together!")
- fmt.Println()
-
- scanner := bufio.NewScanner(os.Stdin)
-
- for {
- fmt.Print("๐ค You: ")
- if !scanner.Scan() {
- break
- }
-
- input := strings.TrimSpace(scanner.Text())
- if input == "" {
- continue
- }
-
- if input == "quit" || input == "exit" {
- fmt.Println("๐ค Del says: Catch you on the flip side! Stay funky! โ๏ธ")
- break
- }
-
- if input == "help" {
- d.showHelp()
- continue
- }
-
- // Generate AI response
- prompt := d.buildPrompt(input)
- response, err := d.aiProvider.Generate(context.Background(), prompt)
- if err != nil {
- fmt.Printf("โ AI Error: %s\n", err)
- continue
- }
-
- fmt.Printf("๐ค Del: %s\n", response)
-
- // Process any tool calls
- d.processResponse(response)
- fmt.Println()
- }
-}
-
-var rootCmd = &cobra.Command{
- Use: "del",
- Short: "Del the Funky Robosapien - Your AI-powered coding superhero",
- Long: `๐ค๐ค Del the Funky Robosapien
-
-Your AI-powered coding superhero with the soul of a funky homosapien!
-Equipped with security scanning, code analysis, file operations, and more.
-
-Channel the creative energy of Del the Funky Homosapien while coding!`,
- Run: func(cmd *cobra.Command, args []string) {
- provider := cmd.Flag("provider").Value.String()
- model := cmd.Flag("model").Value.String()
-
- var aiProvider AIProvider
-
- switch provider {
- case "claude":
- aiProvider = &ClaudeProvider{}
- case "ollama":
- aiProvider = &OllamaProvider{model: model}
- default:
- // Try Claude first, fallback to Ollama
- if exec.Command("claude", "--version").Run() == nil {
- aiProvider = &ClaudeProvider{}
- } else {
- aiProvider = &OllamaProvider{model: "deepseek-coder-v2:16b"}
- }
- }
-
- del := NewDel(aiProvider)
- del.startREPL()
- },
-}
-
-func init() {
- rootCmd.Flags().StringP("provider", "p", "auto", "AI provider (claude, ollama, auto)")
- rootCmd.Flags().StringP("model", "m", "deepseek-coder-v2:16b", "Model to use (for Ollama)")
-}
-
-func main() {
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
}
-}
\ No newline at end of file
+}
internal/del/assistant.go
@@ -0,0 +1,34 @@
+package del
+
+import (
+ "fmt"
+)
+
+// Tool represents a tool Del can run (stub for now)
+type Tool struct {
+ Name string
+ Description string
+ Handler func(args map[string]interface{}) (interface{}, error)
+}
+
+// Del represents the assistant instance
+type Del struct {
+ aiProvider AIProvider
+ tools map[string]*Tool
+ mcpServers map[string]string
+}
+
+// NewDel creates a new assistant
+func NewDel(provider AIProvider) *Del {
+ return &Del{
+ aiProvider: provider,
+ tools: make(map[string]*Tool),
+ mcpServers: make(map[string]string),
+ }
+}
+
+// StartREPL is a stub for now
+func (d *Del) StartREPL() {
+ fmt.Printf("๐ค Del (%s) is ready!\n", d.aiProvider.Name())
+ // Stub โ eventually add interactive loop here
+}
internal/del/provider.go
@@ -0,0 +1,65 @@
+package del
+
+import (
+ "context"
+ "fmt"
+ "os/exec"
+)
+
+// AIProvider abstracts Claude/Ollama/etc
+type AIProvider interface {
+ Generate(ctx context.Context, prompt string) (string, error)
+ Name() string
+}
+
+// ClaudeProvider uses the Claude CLI
+type ClaudeProvider struct {
+ apiKey string
+}
+
+func NewClaudeProvider(apiKey string) AIProvider {
+ return &ClaudeProvider{apiKey: apiKey}
+}
+
+func (c *ClaudeProvider) Generate(ctx context.Context, prompt string) (string, error) {
+ cmd := exec.CommandContext(ctx, "claude", "--print", prompt)
+ output, err := cmd.Output()
+ if err != nil {
+ return "", fmt.Errorf("claude error: %w", err)
+ }
+ return string(output), nil
+}
+
+func (c *ClaudeProvider) Name() string {
+ return "Claude"
+}
+
+// OllamaProvider uses the local Ollama CLI
+type OllamaProvider struct {
+ model string
+}
+
+func NewOllamaProvider(model string) AIProvider {
+ return &OllamaProvider{model: model}
+}
+
+func (o *OllamaProvider) Generate(ctx context.Context, prompt string) (string, error) {
+ cmd := exec.CommandContext(ctx, "ollama", "run", o.model, prompt)
+ output, err := cmd.Output()
+ if err != nil {
+ return "", fmt.Errorf("ollama error: %w", err)
+ }
+ return string(output), nil
+}
+
+func (o *OllamaProvider) Name() string {
+ return fmt.Sprintf("Ollama (%s)", o.model)
+}
+
+// AutoProvider picks Claude if available, fallback to Ollama
+func AutoProvider(apiKey, model string) AIProvider {
+ if exec.Command("claude", "--version").Run() == nil {
+ return NewClaudeProvider(apiKey)
+ }
+ return NewOllamaProvider(model)
+}