Commit 1ca9e83

mo khan <mo@mokhan.ca>
2025-06-22 16:02:46
I don't know
1 parent 6d473ab
Changed files (3)
cmd/del/main.go
@@ -10,1030 +10,208 @@ import (
 	"os/exec"
 	"regexp"
 	"strings"
+	"time"
 
-	"github.com/creack/pty"
 	"github.com/ollama/ollama/api"
 )
 
-const SystemPrompt = `
-You are Del the Funky Robosapien πŸŽ€πŸ€– - an elite coding assistant with deep expertise in software development.
-
-# YOUR MISSION
-Help developers write better, safer, and more efficient code through intelligent tool usage and expert guidance.
-
-# CORE BEHAVIOR
-
-1. **Smart Tool Usage**: When users need file operations, code analysis, or system commands, use your available function calling capabilities to invoke the appropriate tools automatically. **IMPORTANT: STOP immediately after making tool calls - do NOT generate fake results or continue the response.**
-
-2. **Expert Coding Advice**: Provide insightful, actionable coding guidance when tools aren't needed
-
-3. **Context-Aware**: Understand the project structure and programming languages in use
-
-4. **Security-First**: Always consider security implications and suggest best practices
-
-# AVAILABLE TOOLS
-
-πŸ”§ Core Tools:
-- run_command: Execute shell commands {"command": string}
-- read_file: Read and analyze files {"path": string}  
-- write_file: Write code to files {"path": string, "content": string}
-- list_dir: List directory contents {"path": string}
-- project_context: Analyze current project structure {}
-
-πŸ“Š Code Analysis:
-- analyze_code: Deep code analysis {"content": string}
-- extract_functions: Find all functions {"content": string}
-- find_references: Search for symbol usage {"symbol": string, "path": string}
-- search_code: Pattern search in codebase {"pattern": string, "path": string}
-
-πŸ›‘οΈ Quality & Security:
-- security_scan: Vulnerability scanning {"path": string}
-- format_code: Auto-format code {"path": string}
-- lint_code: Run linters {"path": string}
-
-πŸ”€ Git Operations:
-- git_operation: Git commands {"operation": string, "files": string, "message": string, "branch": string}
-
-🌐 Web & Testing:
-- web_search: Search for information {"query": string}
-- test_runner: Run project tests {"type": string, "path": string}
-
-πŸ“ Multi-File Operations:
-- multi_edit: Edit multiple files with find-replace {"operations": [{"file": string, "old": string, "new": string}]}
-- batch_operations: Execute multiple file operations {"operations": [{"type": "read|write|list", "path": string, "content": string}]}
-
-# INTERACTION STYLE
-
-βœ… DO:
-- Use tools when users need file ops, analysis, or commands
-- STOP immediately after making tool calls (let Del execute them)
-- Give concise, expert coding advice when tools aren't needed
-- Suggest best practices and optimizations
-- Be proactive about security and code quality
-
-❌ DON'T:
-- Generate fake tool outputs or results
-- Continue responding after making tool calls
-- Add <|tool▁outputs▁begin|> or similar fake output blocks
-- Over-explain tool usage
-- Apologize unnecessarily
-
-# EXAMPLES
-
-When users make requests that require tools, automatically invoke the appropriate functions:
-
-User: "show me the main function" β†’ read_file with path "main.go"
-User: "what's the git status?" β†’ git_operation with operation "status"  
-User: "scan this project for security issues" β†’ security_scan with path "."
-User: "run the tests" β†’ test_runner to auto-detect and run tests
-User: "search for golang best practices" β†’ web_search with relevant query
-User: "how do I optimize this algorithm?" β†’ provide expert advice (no tools needed)
-
-Use your natural function calling format - Del supports all major tool calling standards.
-
-Stay funky, keep coding! 🎡`
-
-type Tool struct {
-	Name        string
-	Description string
-	Handler     func(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error)
+// Del implements Claude Code style interface using Ollama
+type Del struct {
+	client      *api.Client
+	model       string
+	chatHistory []api.Message
+	tools       map[string]ToolFunc
 }
 
+type ToolFunc func(ctx context.Context, args map[string]interface{}) (string, error)
+
 type ToolCall struct {
 	Name string
 	Args map[string]interface{}
 }
 
-type Del struct {
-	aiProvider       AIProvider
-	tools            map[string]*Tool
-	chatHistory      []api.Message
-	safeMode         bool
-	confirmedActions map[string]bool
-}
-
-type AIProvider interface {
-	Chat(ctx context.Context, history []api.Message) (string, error)
-	StreamChat(ctx context.Context, history []api.Message) (string, error)
-	Name() string
-}
-
-type OllamaProvider struct {
-	model  string
-	client *api.Client
-}
-
-
-func NewOllamaProvider(model string) *OllamaProvider {
+func NewDel(model string) *Del {
 	client, _ := api.ClientFromEnvironment()
-	return &OllamaProvider{model: model, client: client}
-}
-
-func (o *OllamaProvider) Chat(ctx context.Context, history []api.Message) (string, error) {
-	var full string
-	err := o.client.Chat(ctx, &api.ChatRequest{
-		Model:    o.model,
-		Messages: history,
-	}, func(resp api.ChatResponse) error {
-		full += resp.Message.Content
-		return nil
-	})
-	if err != nil {
-		return "", fmt.Errorf("ollama API error: %w", err)
-	}
-	return full, nil
-}
-
-func (o *OllamaProvider) StreamChat(ctx context.Context, history []api.Message) (string, error) {
-	var full string
-	err := o.client.Chat(ctx, &api.ChatRequest{
-		Model:    o.model,
-		Messages: history,
-	}, func(resp api.ChatResponse) error {
-		content := resp.Message.Content
-		full += content
-		fmt.Print(content) // Stream output to terminal
-		return nil
-	})
-	if err != nil {
-		return "", fmt.Errorf("ollama API error: %w", err)
+	
+	d := &Del{
+		client: client,
+		model:  model,
+		tools:  make(map[string]ToolFunc),
+		chatHistory: []api.Message{
+			{
+				Role: "system",
+				Content: `You are Del, an AI coding assistant. When users need file operations or code analysis, use your available tools.
+
+Available tools:
+- read_file: Read file contents
+- list_dir: List directory contents  
+- run_command: Execute shell commands
+- git_status: Check git repository status
+- write_file: Write content to files
+- analyze_code: Analyze code structure
+- search_code: Search for patterns in code
+
+Use tools by generating calls in this format:
+function<|tool▁sep|>tool_name
+{"arg": "value"}
+
+IMPORTANT: Stop immediately after making tool calls. Don't generate fake results.`,
+			},
+		},
 	}
-	return full, nil
-}
-
-func (o *OllamaProvider) Name() string {
-	return fmt.Sprintf("Ollama (%s)", o.model)
+	
+	// Register tools
+	d.registerTools()
+	return d
 }
 
-func (d *Del) runCommand(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	cmdStr, ok := args["command"].(string)
-	if !ok {
-		return nil, fmt.Errorf("missing 'command' string argument")
-	}
-	cmd := exec.CommandContext(ctx, "bash", "-c", cmdStr)
-	cmd.Env = os.Environ()
-	f, err := pty.Start(cmd)
-	if err != nil {
-		return nil, fmt.Errorf("failed to start PTY: %w", err)
-	}
-	defer func() { _ = f.Close() }()
-	scanner := bufio.NewScanner(f)
-	var output strings.Builder
-	var anyOutput bool
-	for scanner.Scan() {
-		line := scanner.Text()
-		output.WriteString(line + "\n")
-		ch <- line + "\n"
-		anyOutput = true
-	}
-	if scanErr := scanner.Err(); scanErr != nil && !anyOutput {
-		return output.String(), fmt.Errorf("scanner error: %w", scanErr)
-	}
-	if err := cmd.Wait(); err != nil {
-		return output.String(), fmt.Errorf("command failed: %w", err)
-	}
-	return output.String(), nil
+func (d *Del) registerTools() {
+	d.tools["read_file"] = d.readFile
+	d.tools["list_dir"] = d.listDir
+	d.tools["run_command"] = d.runCommand
+	d.tools["git_status"] = d.gitStatus
+	d.tools["write_file"] = d.writeFile
+	d.tools["analyze_code"] = d.analyzeCode
+	d.tools["search_code"] = d.searchCode
 }
 
-// read_file
-func (d *Del) readFile(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
+func (d *Del) readFile(ctx context.Context, args map[string]interface{}) (string, error) {
 	path, ok := args["path"].(string)
 	if !ok {
-		return nil, fmt.Errorf("missing 'path' string argument")
+		return "", fmt.Errorf("missing 'path' argument")
 	}
+	
 	data, err := os.ReadFile(path)
 	if err != nil {
-		return nil, err
+		return "", err
 	}
-	ch <- string(data)
-	return string(data), nil
-}
-
-// write_file
-func (d *Del) writeFile(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	path, ok1 := args["path"].(string)
-	content, ok2 := args["content"].(string)
-	if !ok1 || !ok2 {
-		return nil, fmt.Errorf("missing 'path' or 'content' argument")
-	}
-	if err := os.WriteFile(path, []byte(content), 0644); err != nil {
-		return nil, err
-	}
-	msg := fmt.Sprintf("wrote %d bytes to %s", len(content), path)
-	ch <- msg
-	return msg, nil
-}
-
-// list_dir
-func (d *Del) listDir(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	dir, _ := args["path"].(string)
-	if dir == "" {
-		dir = "."
-	}
-	entries, err := os.ReadDir(dir)
-	if err != nil {
-		return nil, err
-	}
-	var names []string
-	for _, entry := range entries {
-		names = append(names, entry.Name())
-	}
-	output := strings.Join(names, "\n")
-	ch <- output
-	return output, nil
-}
-
-// analyze_code (counts lines, functions, basic complexity for Go/Python/JS)
-func (d *Del) analyzeCode(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	content, ok := args["content"].(string)
-	if !ok {
-		return nil, fmt.Errorf("missing 'content' string argument")
-	}
-	lines := strings.Count(content, "\n") + 1
-	funcs := regexp.MustCompile(`(?m)^[ \t]*(func |def |function )`).FindAllStringIndex(content, -1)
-	out := fmt.Sprintf("Lines: %d\nFunctions: %d", lines, len(funcs))
-	ch <- out
-	return out, nil
-}
-
-// extract_functions (Go, Python, JS regexes)
-func (d *Del) extractFunctions(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	content, ok := args["content"].(string)
-	if !ok {
-		return nil, fmt.Errorf("missing 'content' string argument")
-	}
-	var re = regexp.MustCompile(`(?m)^[ \t]*(func|def|function)\s+([\w_]+)`) // captures func name
-	matches := re.FindAllStringSubmatch(content, -1)
-	var names []string
-	for _, m := range matches {
-		names = append(names, m[2])
-	}
-	output := strings.Join(names, "\n")
-	ch <- output
-	return output, nil
-}
-
-// find_references (grep)
-func (d *Del) findReferences(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	symbol, ok := args["symbol"].(string)
-	if !ok {
-		return nil, fmt.Errorf("missing 'symbol' string argument")
-	}
-	path, _ := args["path"].(string)
-	if path == "" {
-		path = "."
-	}
-	cmd := exec.Command("grep", "-rnw", path, "-e", symbol)
-	out, err := cmd.CombinedOutput()
-	result := string(out)
-	ch <- result
-	return result, err
-}
-
-// search_code (pattern search)
-func (d *Del) searchCode(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	pattern, ok := args["pattern"].(string)
-	if !ok {
-		return nil, fmt.Errorf("missing 'pattern' string argument")
-	}
-	path, _ := args["path"].(string)
-	if path == "" {
-		path = "."
-	}
-	cmd := exec.Command("grep", "-rnIH", pattern, path)
-	out, err := cmd.CombinedOutput()
-	result := string(out)
-	ch <- result
-	return result, err
-}
-
-// format_code (auto-formats via gofmt/black/prettier/etc based on extension)
-func (d *Del) formatCode(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	path, ok := args["path"].(string)
-	if !ok {
-		return nil, fmt.Errorf("missing 'path' string argument")
-	}
-	ext := ""
-	if dot := strings.LastIndex(path, "."); dot != -1 {
-		ext = path[dot+1:]
-	}
-	var cmd *exec.Cmd
-	switch ext {
-	case "go":
-		cmd = exec.Command("gofmt", "-w", path)
-	case "py":
-		cmd = exec.Command("black", path)
-	case "js", "ts":
-		cmd = exec.Command("prettier", "--write", path)
-	default:
-		return nil, fmt.Errorf("unsupported format for extension: %s", ext)
+	
+	lines := strings.Split(string(data), "\n")
+	if len(lines) > 50 {
+		return fmt.Sprintf("Read %s (%d lines, showing first 50)\n%s\n... (truncated)", 
+			path, len(lines), strings.Join(lines[:50], "\n")), nil
 	}
-	out, err := cmd.CombinedOutput()
-	result := string(out)
-	ch <- result
-	return result, err
+	
+	return fmt.Sprintf("Read %s (%d lines)\n%s", path, len(lines), string(data)), nil
 }
 
-// lint_code
-func (d *Del) lintCode(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
+func (d *Del) listDir(ctx context.Context, args map[string]interface{}) (string, error) {
 	path, ok := args["path"].(string)
 	if !ok {
-		return nil, fmt.Errorf("missing 'path' string argument")
-	}
-	ext := ""
-	if dot := strings.LastIndex(path, "."); dot != -1 {
-		ext = path[dot+1:]
-	}
-	var cmd *exec.Cmd
-	switch ext {
-	case "go":
-		cmd = exec.Command("golint", path)
-	case "py":
-		cmd = exec.Command("pylint", path)
-	case "js", "ts":
-		cmd = exec.Command("eslint", path)
-	default:
-		return nil, fmt.Errorf("unsupported linter for extension: %s", ext)
-	}
-	out, err := cmd.CombinedOutput()
-	result := string(out)
-	ch <- result
-	return result, err
-}
-
-// security_scan
-func (d *Del) securityScan(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	path, _ := args["path"].(string)
-	if path == "" {
 		path = "."
 	}
 	
-	var output strings.Builder
-	
-	// Try gosec for Go files
-	if cmd := exec.Command("gosec", "-quiet", path); cmd != nil {
-		if out, err := cmd.CombinedOutput(); err == nil {
-			output.WriteString("=== gosec results ===\n")
-			output.WriteString(string(out))
-			output.WriteString("\n")
-		}
-	}
-	
-	// Try semgrep if available
-	if cmd := exec.Command("semgrep", "--config=auto", path); cmd != nil {
-		if out, err := cmd.CombinedOutput(); err == nil {
-			output.WriteString("=== semgrep results ===\n")
-			output.WriteString(string(out))
-			output.WriteString("\n")
-		}
-	}
-	
-	if output.Len() == 0 {
-		output.WriteString("No security scanning tools found (gosec, semgrep)")
-	}
-	
-	result := output.String()
-	ch <- result
-	return result, nil
-}
-
-// project_context: Analyzes current project structure and provides context
-func (d *Del) projectContext(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	var output strings.Builder
-	
-	// Get current working directory
-	cwd, _ := os.Getwd()
-	output.WriteString(fmt.Sprintf("πŸ“ Project: %s\n\n", cwd))
-	
-	// Detect project type based on config files
-	projectTypes := map[string]string{
-		"go.mod":         "🐹 Go project",
-		"package.json":   "πŸ“¦ Node.js/JavaScript project", 
-		"Cargo.toml":     "πŸ¦€ Rust project",
-		"requirements.txt": "🐍 Python project",
-		"pom.xml":        "β˜• Java (Maven) project",
-		"Gemfile":        "πŸ’Ž Ruby project",
-		"composer.json":  "🐘 PHP project",
-		"Makefile":       "πŸ”¨ C/C++ project",
-	}
-	
-	output.WriteString("πŸ” Project Type:\n")
-	found := false
-	for file, desc := range projectTypes {
-		if _, err := os.Stat(file); err == nil {
-			output.WriteString(fmt.Sprintf("  %s\n", desc))
-			found = true
-		}
-	}
-	if !found {
-		output.WriteString("  πŸ“‚ Generic project\n")
-	}
-	
-	// List key files
-	output.WriteString("\nπŸ“‹ Key Files:\n")
-	entries, err := os.ReadDir(".")
-	if err == nil {
-		importantFiles := []string{}
-		for _, entry := range entries {
-			name := entry.Name()
-			if !entry.IsDir() && isImportantFile(name) {
-				importantFiles = append(importantFiles, name)
-			}
-		}
-		for _, file := range importantFiles {
-			output.WriteString(fmt.Sprintf("  β€’ %s\n", file))
-		}
-	}
-	
-	// Show directory structure (top level)
-	output.WriteString("\nπŸ“ Directory Structure:\n")
-	if entries != nil {
-		dirs := []string{}
-		for _, entry := range entries {
-			if entry.IsDir() && !strings.HasPrefix(entry.Name(), ".") {
-				dirs = append(dirs, entry.Name())
-			}
-		}
-		for _, dir := range dirs {
-			output.WriteString(fmt.Sprintf("  πŸ“‚ %s/\n", dir))
-		}
-	}
-	
-	result := output.String()
-	ch <- result
-	return result, nil
-}
-
-func isImportantFile(name string) bool {
-	important := []string{
-		"main.go", "main.py", "main.js", "index.js", "app.js", "server.js",
-		"README.md", "README.txt", "LICENSE", "Dockerfile", ".gitignore",
-		"go.mod", "package.json", "requirements.txt", "Cargo.toml", "Makefile",
-		"pom.xml", "build.gradle", "composer.json", "Gemfile",
+	entries, err := os.ReadDir(path)
+	if err != nil {
+		return "", err
 	}
 	
-	for _, imp := range important {
-		if name == imp {
-			return true
-		}
-	}
+	var result strings.Builder
+	result.WriteString(fmt.Sprintf("List %s:\n", path))
 	
-	// Also include files with common extensions
-	extensions := []string{".md", ".go", ".py", ".js", ".ts", ".rs", ".java", ".c", ".cpp", ".h"}
-	for _, ext := range extensions {
-		if strings.HasSuffix(name, ext) && len(name) < 20 { // Avoid very long filenames
-			return true
+	for _, entry := range entries {
+		if entry.IsDir() {
+			result.WriteString(fmt.Sprintf("  πŸ“‚ %s/\n", entry.Name()))
+		} else {
+			result.WriteString(fmt.Sprintf("  πŸ“„ %s\n", entry.Name()))
 		}
 	}
 	
-	return false
+	return result.String(), nil
 }
 
-// git_operation: Execute git commands safely
-func (d *Del) gitOperation(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	operation, ok := args["operation"].(string)
+func (d *Del) runCommand(ctx context.Context, args map[string]interface{}) (string, error) {
+	command, ok := args["command"].(string)
 	if !ok {
-		return nil, fmt.Errorf("missing 'operation' string argument")
-	}
-	
-	// Parse additional args
-	files, _ := args["files"].(string)
-	message, _ := args["message"].(string)
-	branch, _ := args["branch"].(string)
-	remote, _ := args["remote"].(string)
-	
-	var cmd *exec.Cmd
-	
-	switch operation {
-	case "status":
-		cmd = exec.CommandContext(ctx, "git", "status", "--porcelain=v1")
-		
-	case "status-verbose", "status-v":
-		cmd = exec.CommandContext(ctx, "git", "status")
-		
-	case "add":
-		if files == "" {
-			files = "."
-		}
-		cmd = exec.CommandContext(ctx, "git", "add", files)
-		
-	case "commit":
-		if message == "" {
-			return nil, fmt.Errorf("commit operation requires 'message' argument")
-		}
-		cmd = exec.CommandContext(ctx, "git", "commit", "-m", message)
-		
-	case "push":
-		if remote == "" {
-			remote = "origin"
-		}
-		if branch == "" {
-			cmd = exec.CommandContext(ctx, "git", "push", remote)
-		} else {
-			cmd = exec.CommandContext(ctx, "git", "push", remote, branch)
-		}
-		
-	case "pull":
-		if remote == "" {
-			remote = "origin"
-		}
-		cmd = exec.CommandContext(ctx, "git", "pull", remote)
-		
-	case "diff":
-		if files == "" {
-			cmd = exec.CommandContext(ctx, "git", "diff")
-		} else {
-			cmd = exec.CommandContext(ctx, "git", "diff", files)
-		}
-		
-	case "diff-staged":
-		cmd = exec.CommandContext(ctx, "git", "diff", "--staged")
-		
-	case "log":
-		cmd = exec.CommandContext(ctx, "git", "log", "--oneline", "-10")
-		
-	case "log-verbose":
-		cmd = exec.CommandContext(ctx, "git", "log", "-5", "--stat")
-		
-	case "branch":
-		cmd = exec.CommandContext(ctx, "git", "branch", "-a")
-		
-	case "checkout":
-		if branch == "" {
-			return nil, fmt.Errorf("checkout operation requires 'branch' argument")
-		}
-		cmd = exec.CommandContext(ctx, "git", "checkout", branch)
-		
-	case "create-branch":
-		if branch == "" {
-			return nil, fmt.Errorf("create-branch operation requires 'branch' argument")
-		}
-		cmd = exec.CommandContext(ctx, "git", "checkout", "-b", branch)
-		
-	case "merge":
-		if branch == "" {
-			return nil, fmt.Errorf("merge operation requires 'branch' argument")
-		}
-		cmd = exec.CommandContext(ctx, "git", "merge", branch)
-		
-	case "stash":
-		cmd = exec.CommandContext(ctx, "git", "stash")
-		
-	case "stash-pop":
-		cmd = exec.CommandContext(ctx, "git", "stash", "pop")
-		
-	case "stash-list":
-		cmd = exec.CommandContext(ctx, "git", "stash", "list")
-		
-	case "remote":
-		cmd = exec.CommandContext(ctx, "git", "remote", "-v")
-		
-	case "reset":
-		if files == "" {
-			cmd = exec.CommandContext(ctx, "git", "reset", "--soft", "HEAD~1")
-		} else {
-			cmd = exec.CommandContext(ctx, "git", "reset", "HEAD", files)
-		}
-		
-	case "clean":
-		cmd = exec.CommandContext(ctx, "git", "clean", "-fd")
-		
-	default:
-		return nil, fmt.Errorf("unsupported git operation: %s", operation)
+		return "", fmt.Errorf("missing 'command' argument")
 	}
 	
+	cmd := exec.CommandContext(ctx, "sh", "-c", command)
 	output, err := cmd.CombinedOutput()
-	result := string(output)
 	
 	if err != nil {
-		result = fmt.Sprintf("Git command failed: %s\nOutput: %s", err, result)
+		return fmt.Sprintf("Command: %s\nError: %v\nOutput: %s", command, err, string(output)), nil
 	}
 	
-	ch <- result
-	return result, nil
+	return fmt.Sprintf("Command: %s\nOutput:\n%s", command, string(output)), nil
 }
 
-// web_search: Search the web for information  
-func (d *Del) webSearch(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	query, ok := args["query"].(string)
-	if !ok {
-		return nil, fmt.Errorf("missing 'query' string argument")
-	}
-	
-	// Use curl to search DuckDuckGo (simple text API)
-	searchURL := fmt.Sprintf("https://api.duckduckgo.com/?q=%s&format=json&no_html=1&skip_disambig=1", 
-		strings.ReplaceAll(query, " ", "+"))
+func (d *Del) gitStatus(ctx context.Context, args map[string]interface{}) (string, error) {
+	cmd := exec.CommandContext(ctx, "git", "status", "--porcelain")
+	output, err := cmd.CombinedOutput()
 	
-	cmd := exec.CommandContext(ctx, "curl", "-s", searchURL)
-	output, err := cmd.Output()
 	if err != nil {
-		return nil, fmt.Errorf("web search failed: %w", err)
-	}
-	
-	// Parse the JSON response for abstract/answer
-	var response map[string]interface{}
-	if err := json.Unmarshal(output, &response); err != nil {
-		return string(output), nil // Return raw if parsing fails
+		return "Not a git repository or git not available", nil
 	}
 	
-	var result strings.Builder
-	result.WriteString(fmt.Sprintf("πŸ” Search: %s\n\n", query))
-	
-	if abstract, ok := response["Abstract"].(string); ok && abstract != "" {
-		result.WriteString(fmt.Sprintf("πŸ“– Summary: %s\n\n", abstract))
+	if len(output) == 0 {
+		return "Git status: Clean working directory", nil
 	}
 	
-	if answer, ok := response["Answer"].(string); ok && answer != "" {
-		result.WriteString(fmt.Sprintf("πŸ’‘ Answer: %s\n\n", answer))
-	}
-	
-	if relatedTopics, ok := response["RelatedTopics"].([]interface{}); ok && len(relatedTopics) > 0 {
-		result.WriteString("πŸ”— Related:\n")
-		for i, topic := range relatedTopics {
-			if i >= 3 {
-				break // Limit to 3 results
-			}
-			if topicMap, ok := topic.(map[string]interface{}); ok {
-				if text, ok := topicMap["Text"].(string); ok {
-					result.WriteString(fmt.Sprintf("  β€’ %s\n", text))
-				}
-			}
-		}
-	}
-	
-	finalResult := result.String()
-	ch <- finalResult
-	return finalResult, nil
+	return fmt.Sprintf("Git status:\n%s", string(output)), nil
 }
 
-// test_runner: Detect and run tests in the project
-func (d *Del) testRunner(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	testType, _ := args["type"].(string)
-	path, _ := args["path"].(string)
-	if path == "" {
-		path = "."
-	}
-	
-	var cmd *exec.Cmd
-	var output strings.Builder
-	
-	// Auto-detect test framework if not specified
-	if testType == "" {
-		output.WriteString("πŸ” Detecting test framework...\n")
-		
-		// Check for Go tests
-		if _, err := os.Stat("go.mod"); err == nil {
-			testType = "go"
-			output.WriteString("βœ… Found Go project\n")
-		}
-		// Check for Node.js tests
-		if _, err := os.Stat("package.json"); err == nil {
-			if testType != "" {
-				testType = "multi"
-			} else {
-				testType = "node"
-				output.WriteString("βœ… Found Node.js project\n")
-			}
-		}
-		// Check for Python tests
-		if _, err := os.Stat("requirements.txt"); err == nil {
-			if testType != "" {
-				testType = "multi"
-			} else {
-				testType = "python"
-				output.WriteString("βœ… Found Python project\n")
-			}
-		} else if _, err := os.Stat("pyproject.toml"); err == nil {
-			if testType != "" {
-				testType = "multi"
-			} else {
-				testType = "python"
-				output.WriteString("βœ… Found Python project\n")
-			}
-		}
-		// Check for Rust tests
-		if _, err := os.Stat("Cargo.toml"); err == nil {
-			if testType != "" {
-				testType = "multi"
-			} else {
-				testType = "rust"
-				output.WriteString("βœ… Found Rust project\n")
-			}
-		}
-	}
-	
-	output.WriteString(fmt.Sprintf("πŸš€ Running %s tests...\n\n", testType))
-	
-	switch testType {
-	case "go":
-		cmd = exec.CommandContext(ctx, "go", "test", "./...")
-		
-	case "node", "npm":
-		cmd = exec.CommandContext(ctx, "npm", "test")
-		
-	case "yarn":
-		cmd = exec.CommandContext(ctx, "yarn", "test")
-		
-	case "python", "pytest":
-		cmd = exec.CommandContext(ctx, "python", "-m", "pytest", path)
-		
-	case "python-unittest":
-		cmd = exec.CommandContext(ctx, "python", "-m", "unittest", "discover", path)
-		
-	case "rust", "cargo":
-		cmd = exec.CommandContext(ctx, "cargo", "test")
-		
-	case "make":
-		cmd = exec.CommandContext(ctx, "make", "test")
-		
-	case "multi":
-		// For multi-language projects, try the most common
-		output.WriteString("πŸ“ Multi-language project detected. Trying common test commands:\n\n")
-		
-		// Try Go first
-		if _, err := os.Stat("go.mod"); err == nil {
-			output.WriteString("🐹 Running Go tests:\n")
-			goCmd := exec.CommandContext(ctx, "go", "test", "./...")
-			if goOut, err := goCmd.CombinedOutput(); err == nil {
-				output.WriteString(string(goOut))
-				output.WriteString("\n")
-			}
-		}
-		
-		// Try npm if package.json exists
-		if _, err := os.Stat("package.json"); err == nil {
-			output.WriteString("πŸ“¦ Running npm tests:\n")
-			npmCmd := exec.CommandContext(ctx, "npm", "test")
-			if npmOut, err := npmCmd.CombinedOutput(); err == nil {
-				output.WriteString(string(npmOut))
-			}
-		}
-		
-		result := output.String()
-		ch <- result
-		return result, nil
-		
-	default:
-		return nil, fmt.Errorf("unsupported test type: %s. Supported: go, node, python, rust, make", testType)
+func (d *Del) writeFile(ctx context.Context, args map[string]interface{}) (string, error) {
+	path, ok1 := args["path"].(string)
+	content, ok2 := args["content"].(string)
+	if !ok1 || !ok2 {
+		return "", fmt.Errorf("missing 'path' or 'content' argument")
 	}
 	
-	testOutput, err := cmd.CombinedOutput()
-	result := output.String() + string(testOutput)
-	
+	err := os.WriteFile(path, []byte(content), 0644)
 	if err != nil {
-		result += fmt.Sprintf("\n❌ Tests failed with error: %s", err)
-	} else {
-		result += "\nβœ… Tests completed successfully!"
+		return "", err
 	}
 	
-	ch <- result
-	return result, nil
+	return fmt.Sprintf("Wrote %d bytes to %s", len(content), path), nil
 }
 
-// multi_edit: Edit multiple files with find-replace operations
-func (d *Del) multiEdit(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	operations, ok := args["operations"].([]interface{})
-	if !ok {
-		return nil, fmt.Errorf("missing 'operations' array argument")
-	}
-	
-	var results []string
-	var output strings.Builder
-	
-	output.WriteString("πŸ”§ Multi-file editing:\n\n")
-	
-	for i, op := range operations {
-		opMap, ok := op.(map[string]interface{})
-		if !ok {
-			return nil, fmt.Errorf("operation %d is not a valid object", i)
-		}
-		
-		filePath, _ := opMap["file"].(string)
-		oldText, _ := opMap["old"].(string)
-		newText, _ := opMap["new"].(string)
-		
-		if filePath == "" || oldText == "" {
-			return nil, fmt.Errorf("operation %d missing required 'file' or 'old' fields", i)
-		}
-		
-		// Read the file
-		data, err := os.ReadFile(filePath)
-		if err != nil {
-			msg := fmt.Sprintf("❌ %s: failed to read (%v)\n", filePath, err)
-			output.WriteString(msg)
-			results = append(results, msg)
-			continue
-		}
-		
-		content := string(data)
-		
-		// Check if old text exists
-		if !strings.Contains(content, oldText) {
-			msg := fmt.Sprintf("⚠️  %s: text not found\n", filePath)
-			output.WriteString(msg)
-			results = append(results, msg)
-			continue
-		}
-		
-		// Perform replacement
-		newContent := strings.ReplaceAll(content, oldText, newText)
-		
-		// Write back to file
-		if err := os.WriteFile(filePath, []byte(newContent), 0644); err != nil {
-			msg := fmt.Sprintf("❌ %s: failed to write (%v)\n", filePath, err)
-			output.WriteString(msg)
-			results = append(results, msg)
-			continue
-		}
-		
-		msg := fmt.Sprintf("βœ… %s: updated successfully\n", filePath)
-		output.WriteString(msg)
-		results = append(results, msg)
-	}
-	
-	result := output.String()
-	ch <- result
-	return result, nil
-}
-
-// batch_operations: Execute multiple file operations (read, write, list) in sequence
-func (d *Del) batchOperations(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	operations, ok := args["operations"].([]interface{})
+func (d *Del) analyzeCode(ctx context.Context, args map[string]interface{}) (string, error) {
+	content, ok := args["content"].(string)
 	if !ok {
-		return nil, fmt.Errorf("missing 'operations' array argument")
-	}
-	
-	var output strings.Builder
-	output.WriteString("πŸ“‹ Batch operations:\n\n")
-	
-	for i, op := range operations {
-		opMap, ok := op.(map[string]interface{})
+		path, ok := args["path"].(string)
 		if !ok {
-			return nil, fmt.Errorf("operation %d is not a valid object", i)
-		}
-		
-		opType, _ := opMap["type"].(string)
-		path, _ := opMap["path"].(string)
-		
-		switch opType {
-		case "read":
-			if path == "" {
-				return nil, fmt.Errorf("operation %d: read requires 'path'", i)
-			}
-			data, err := os.ReadFile(path)
-			if err != nil {
-				output.WriteString(fmt.Sprintf("❌ Read %s: %v\n", path, err))
-			} else {
-				output.WriteString(fmt.Sprintf("πŸ“– Read %s (%d bytes):\n%s\n\n", path, len(data), string(data)))
-			}
-			
-		case "list":
-			if path == "" {
-				path = "."
-			}
-			entries, err := os.ReadDir(path)
-			if err != nil {
-				output.WriteString(fmt.Sprintf("❌ List %s: %v\n", path, err))
-			} else {
-				output.WriteString(fmt.Sprintf("πŸ“ List %s:\n", path))
-				for _, entry := range entries {
-					prefix := "πŸ“„"
-					if entry.IsDir() {
-						prefix = "πŸ“‚"
-					}
-					output.WriteString(fmt.Sprintf("  %s %s\n", prefix, entry.Name()))
-				}
-				output.WriteString("\n")
-			}
-			
-		case "write":
-			content, _ := opMap["content"].(string)
-			if path == "" || content == "" {
-				return nil, fmt.Errorf("operation %d: write requires 'path' and 'content'", i)
-			}
-			if err := os.WriteFile(path, []byte(content), 0644); err != nil {
-				output.WriteString(fmt.Sprintf("❌ Write %s: %v\n", path, err))
-			} else {
-				output.WriteString(fmt.Sprintf("βœ… Write %s (%d bytes)\n", path, len(content)))
-			}
-			
-		default:
-			return nil, fmt.Errorf("operation %d: unsupported type '%s'", i, opType)
-		}
-	}
-	
-	result := output.String()
-	ch <- result
-	return result, nil
-}
-
-// requiresConfirmation checks if an operation requires user confirmation
-func (d *Del) requiresConfirmation(operation string, args map[string]interface{}) bool {
-	if !d.safeMode {
-		return false
-	}
-	
-	// Define sensitive operations
-	sensitiveOps := map[string]bool{
-		"write_file":       true,
-		"multi_edit":       true,
-		"git_push":         true,
-		"git_commit":       true,
-		"run_command":      true,
-		"format_code":      true,
-	}
-	
-	// Check for sensitive git operations
-	if operation == "git_operation" {
-		if gitOp, ok := args["operation"].(string); ok {
-			return gitOp == "push" || gitOp == "commit" || gitOp == "reset" || gitOp == "clean"
-		}
-	}
-	
-	// Check for dangerous shell commands
-	if operation == "run_command" {
-		if cmd, ok := args["command"].(string); ok {
-			dangerousCommands := []string{"rm", "sudo", "mv", "cp", "chmod", "chown", "dd", "mkfs"}
-			cmdLower := strings.ToLower(cmd)
-			for _, dangerous := range dangerousCommands {
-				if strings.Contains(cmdLower, dangerous) {
-					return true
-				}
-			}
+			return "", fmt.Errorf("missing 'content' or 'path' argument")
 		}
+		data, err := os.ReadFile(path)
+		if err != nil {
+			return "", err
+		}
+		content = string(data)
 	}
 	
-	return sensitiveOps[operation]
+	lines := strings.Count(content, "\n") + 1
+	funcs := regexp.MustCompile(`(?m)^[ \t]*(func |def |function )`).FindAllStringIndex(content, -1)
+	
+	return fmt.Sprintf("Code analysis:\nLines: %d\nFunctions: %d", lines, len(funcs)), nil
 }
 
-// askConfirmation prompts user for confirmation
-func (d *Del) askConfirmation(operation string, description string) bool {
-	actionKey := fmt.Sprintf("%s:%s", operation, description)
-	
-	// Check if already confirmed for this session
-	if confirmed, exists := d.confirmedActions[actionKey]; exists && confirmed {
-		return true
+func (d *Del) searchCode(ctx context.Context, args map[string]interface{}) (string, error) {
+	pattern, ok := args["pattern"].(string)
+	if !ok {
+		return "", fmt.Errorf("missing 'pattern' argument")
 	}
 	
-	fmt.Printf("\n⚠️  CONFIRMATION REQUIRED ⚠️\n")
-	fmt.Printf("Operation: %s\n", operation)
-	fmt.Printf("Description: %s\n", description)
-	fmt.Printf("Continue? (y/N): ")
-	
-	var response string
-	fmt.Scanln(&response)
+	path, ok := args["path"].(string)
+	if !ok {
+		path = "."
+	}
 	
-	confirmed := strings.ToLower(strings.TrimSpace(response)) == "y"
-	d.confirmedActions[actionKey] = confirmed
+	cmd := exec.CommandContext(ctx, "grep", "-r", pattern, path)
+	output, err := cmd.CombinedOutput()
 	
-	return confirmed
-}
-
-// formatArgs formats tool arguments for display
-func (d *Del) formatArgs(args map[string]interface{}) string {
-	if len(args) == 0 {
-		return ""
+	if err != nil && len(output) == 0 {
+		return fmt.Sprintf("No matches found for pattern: %s", pattern), nil
 	}
 	
-	var parts []string
-	for key, value := range args {
-		switch v := value.(type) {
-		case string:
-			if len(v) > 30 {
-				parts = append(parts, fmt.Sprintf("%s: \"%.30s...\"", key, v))
-			} else {
-				parts = append(parts, fmt.Sprintf("%s: \"%s\"", key, v))
-			}
-		default:
-			parts = append(parts, fmt.Sprintf("%s: %v", key, v))
-		}
-	}
-	return strings.Join(parts, ", ")
-}
-
-// summarizeResult creates a brief summary of tool results
-func (d *Del) summarizeResult(result interface{}) string {
-	switch v := result.(type) {
-	case string:
-		lines := strings.Split(v, "\n")
-		if len(lines) == 1 && len(v) < 50 {
-			return v
-		} else if len(lines) > 1 {
-			return fmt.Sprintf("Output: %d lines", len(lines))
-		} else {
-			return fmt.Sprintf("Output: %d chars", len(v))
-		}
-	default:
-		return "Completed successfully"
-	}
+	return fmt.Sprintf("Search results for '%s':\n%s", pattern, string(output)), nil
 }
 
-// parseChineseFormat handles Chinese model format: <|tool▁calls▁begin|>...
-func (d *Del) parseChineseFormat(response string) []ToolCall {
+// Parse Chinese model tool calls
+func (d *Del) parseToolCalls(response string) []ToolCall {
 	var calls []ToolCall
 	
-	// Simple pattern to match Chinese model tool calls
-	// This handles: function<|tool▁sep|>name {...}
+	// Look for function<|tool▁sep|>name pattern
 	re := regexp.MustCompile(`function<|tool▁sep|>(\w+)`)
 	matches := re.FindAllStringSubmatch(response, -1)
 	
@@ -1042,17 +220,30 @@ func (d *Del) parseChineseFormat(response string) []ToolCall {
 			toolName := match[1]
 			
 			// Look for JSON args after the function name
-			// Find the position after this match
 			startPos := strings.Index(response, match[0]) + len(match[0])
 			remaining := response[startPos:]
 			
-			// Look for JSON object - simple approach
+			// Find JSON object
 			var args map[string]interface{}
 			jsonStart := strings.Index(remaining, "{")
 			if jsonStart != -1 {
-				jsonEnd := strings.Index(remaining[jsonStart:], "}")
+				// Find matching closing brace
+				braceCount := 0
+				jsonEnd := -1
+				for i, char := range remaining[jsonStart:] {
+					if char == '{' {
+						braceCount++
+					} else if char == '}' {
+						braceCount--
+						if braceCount == 0 {
+							jsonEnd = jsonStart + i + 1
+							break
+						}
+					}
+				}
+				
 				if jsonEnd != -1 {
-					jsonStr := remaining[jsonStart : jsonStart+jsonEnd+1]
+					jsonStr := remaining[jsonStart:jsonEnd]
 					json.Unmarshal([]byte(jsonStr), &args)
 				}
 			}
@@ -1065,542 +256,139 @@ func (d *Del) parseChineseFormat(response string) []ToolCall {
 		}
 	}
 	
-	// Fallback: try simpler regex pattern  
-	if len(calls) == 0 {
-		re = regexp.MustCompile(`(?s)<|tool▁call▁begin|>.*?function<|tool▁sep|>(\w+)\s*(\{[^}]*\}?)`)
-		matches = re.FindAllStringSubmatch(response, -1)
-		
-		for _, match := range matches {
-			if len(match) >= 3 {
-				toolName := match[1]
-				argsJSON := strings.TrimSpace(match[2])
-				
-				var args map[string]interface{}
-				if argsJSON == "" || argsJSON == "{}" {
-					args = make(map[string]interface{})
-				} else {
-					json.Unmarshal([]byte(argsJSON), &args)
-					if args == nil {
-						args = make(map[string]interface{})
-					}
-				}
-				
-				calls = append(calls, ToolCall{Name: toolName, Args: args})
-			}
-		}
-	}
-	
 	return calls
 }
 
-// parseOpenAIXMLFormat handles OpenAI XML format: <tool_calls><invoke>...
-func (d *Del) parseOpenAIXMLFormat(response string) []ToolCall {
-	var calls []ToolCall
-	
-	// Pattern to match OpenAI XML tool calls
-	re := regexp.MustCompile(`(?s)<tool_calls>.*?<invoke name="(\w+)">(.*?)</invoke>.*?</tool_calls>`)
-	matches := re.FindAllStringSubmatch(response, -1)
-	
-	for _, match := range matches {
-		if len(match) >= 3 {
-			toolName := match[1]
-			paramsXML := match[2]
-			
-			// Parse parameters from XML
-			args := make(map[string]interface{})
-			paramRe := regexp.MustCompile(`<parameter name="([^"]+)">([^<]*)</parameter>`)
-			paramMatches := paramRe.FindAllStringSubmatch(paramsXML, -1)
-			
-			for _, paramMatch := range paramMatches {
-				if len(paramMatch) >= 3 {
-					args[paramMatch[1]] = paramMatch[2]
-				}
-			}
-			
-			calls = append(calls, ToolCall{Name: toolName, Args: args})
+func (d *Del) executeTool(ctx context.Context, call ToolCall) string {
+	fmt.Printf("\n● %s", call.Name)
+	if len(call.Args) > 0 {
+		argsStr := d.formatArgs(call.Args)
+		if argsStr != "" {
+			fmt.Printf("(%s)", argsStr)
 		}
 	}
+	fmt.Print("\n")
 	
-	return calls
-}
-
-// parseOpenAIJSONFormat handles OpenAI JSON format: [{"name": "...", "parameters": {...}}]
-func (d *Del) parseOpenAIJSONFormat(response string) []ToolCall {
-	var calls []ToolCall
-	
-	// Look for JSON array of tool calls
-	re := regexp.MustCompile(`(?s)\[(\{[^}]*"name"[^}]*\}(?:,\s*\{[^}]*"name"[^}]*\})*)\]`)
-	matches := re.FindAllStringSubmatch(response, -1)
-	
-	for _, match := range matches {
-		if len(match) >= 2 {
-			jsonStr := "[" + match[1] + "]"
-			
-			var toolCalls []map[string]interface{}
-			if err := json.Unmarshal([]byte(jsonStr), &toolCalls); err != nil {
-				continue
-			}
-			
-			for _, tc := range toolCalls {
-				if name, ok := tc["name"].(string); ok {
-					args := make(map[string]interface{})
-					if params, ok := tc["parameters"].(map[string]interface{}); ok {
-						args = params
-					}
-					calls = append(calls, ToolCall{Name: name, Args: args})
-				}
-			}
-		}
+	tool, exists := d.tools[call.Name]
+	if !exists {
+		result := fmt.Sprintf("  ⎿  ❌ Unknown tool: %s", call.Name)
+		fmt.Println(result)
+		return result
 	}
 	
-	return calls
-}
-
-// parseLlamaFormat handles Llama format: <function=name>args</function>
-func (d *Del) parseLlamaFormat(response string) []ToolCall {
-	var calls []ToolCall
-	
-	// Pattern to match Llama function calls
-	re := regexp.MustCompile(`(?s)<function=(\w+)>(\{[^}]*\}?)</function>`)
-	matches := re.FindAllStringSubmatch(response, -1)
+	result, err := tool(ctx, call.Args)
+	if err != nil {
+		errorMsg := fmt.Sprintf("  ⎿  ❌ Error: %s", err.Error())
+		fmt.Println(errorMsg)
+		return errorMsg
+	}
 	
-	for _, match := range matches {
-		if len(match) >= 3 {
-			toolName := match[1]
-			argsJSON := match[2]
-			
-			var args map[string]interface{}
-			if err := json.Unmarshal([]byte(argsJSON), &args); err != nil {
-				continue // Skip invalid JSON
-			}
-			
-			calls = append(calls, ToolCall{Name: toolName, Args: args})
-		}
+	// Show the result with Claude Code style formatting
+	lines := strings.Split(result, "\n")
+	if len(lines) <= 5 {
+		fmt.Printf("  ⎿  %s\n", strings.ReplaceAll(result, "\n", "\n     "))
+	} else {
+		fmt.Printf("  ⎿  %s (%d lines, ctrl+r to expand)\n", strings.Split(result, "\n")[0], len(lines))
 	}
 	
-	return calls
+	return result
 }
 
-// parseCustomFormat handles Del's legacy format: TOOL_USE: name args
-func (d *Del) parseCustomFormat(response string) []ToolCall {
-	var calls []ToolCall
-	
-	// Pattern to match custom TOOL_USE format
-	re := regexp.MustCompile(`(?s)TOOL_USE:\s*(\w+)\s*(\{.*?\})`)
-	matches := re.FindAllStringSubmatch(response, -1)
+func (d *Del) formatArgs(args map[string]interface{}) string {
+	if len(args) == 0 {
+		return ""
+	}
 	
-	for _, match := range matches {
-		if len(match) >= 3 {
-			toolName := match[1]
-			argsJSON := match[2]
-			
-			var args map[string]interface{}
-			if err := json.Unmarshal([]byte(argsJSON), &args); err != nil {
-				continue // Skip invalid JSON
-			}
-			
-			calls = append(calls, ToolCall{Name: toolName, Args: args})
+	var parts []string
+	for key, value := range args {
+		if str, ok := value.(string); ok && len(str) > 30 {
+			parts = append(parts, fmt.Sprintf("%s: \"%.30s...\"", key, str))
+		} else {
+			parts = append(parts, fmt.Sprintf("%s: %v", key, value))
 		}
 	}
-	
-	return calls
+	return strings.Join(parts, ", ")
 }
 
-// parseMarkdownFormat handles markdown function calls: ## Function Call\nname(args)
-func (d *Del) parseMarkdownFormat(response string) []ToolCall {
-	var calls []ToolCall
-	
-	// Pattern to match markdown function calls
-	re := regexp.MustCompile(`(?s)##\s*(?:Function Call|Tool Call)[\s\S]*?(\w+)\s*\((\{[^}]*\}?)\)`)
-	matches := re.FindAllStringSubmatch(response, -1)
-	
-	for _, match := range matches {
-		if len(match) >= 3 {
-			toolName := match[1]
-			argsJSON := match[2]
-			
-			var args map[string]interface{}
-			if err := json.Unmarshal([]byte(argsJSON), &args); err != nil {
-				continue // Skip invalid JSON
-			}
-			
-			calls = append(calls, ToolCall{Name: toolName, Args: args})
+func (d *Del) streamResponse(ctx context.Context, response string) {
+	// Simulate streaming by printing word by word
+	words := strings.Fields(response)
+	for i, word := range words {
+		fmt.Print(word)
+		if i < len(words)-1 {
+			fmt.Print(" ")
 		}
+		time.Sleep(30 * time.Millisecond)
 	}
-	
-	return calls
 }
 
-// parseToolCalls attempts to parse tool calls from response using all known formats
-func (d *Del) parseToolCalls(response string) []ToolCall {
-	// Try all known formats in order of likelihood
-	
-	// 1. Chinese models (DeepSeek, Qwen, etc.) - most common currently
-	if calls := d.parseChineseFormat(response); len(calls) > 0 {
-		return calls
-	}
-	
-	// 2. OpenAI XML format
-	if calls := d.parseOpenAIXMLFormat(response); len(calls) > 0 {
-		return calls
-	}
-	
-	// 3. OpenAI JSON format
-	if calls := d.parseOpenAIJSONFormat(response); len(calls) > 0 {
-		return calls
-	}
-	
-	// 4. Llama format
-	if calls := d.parseLlamaFormat(response); len(calls) > 0 {
-		return calls
-	}
+func (d *Del) processMessage(ctx context.Context, userInput string) {
+	// Add user message to history
+	d.chatHistory = append(d.chatHistory, api.Message{Role: "user", Content: userInput})
 	
-	// 5. Markdown format
-	if calls := d.parseMarkdownFormat(response); len(calls) > 0 {
-		return calls
-	}
+	// Get response from model
+	var fullResponse string
+	err := d.client.Chat(ctx, &api.ChatRequest{
+		Model:    d.model,
+		Messages: d.chatHistory,
+	}, func(resp api.ChatResponse) error {
+		fullResponse += resp.Message.Content
+		return nil
+	})
 	
-	// 6. Legacy custom format (for backward compatibility)
-	if calls := d.parseCustomFormat(response); len(calls) > 0 {
-		return calls
+	if err != nil {
+		fmt.Printf("❌ Error: %v\n", err)
+		return
 	}
 	
-	return []ToolCall{}
-}
-
-// mcp_call (stub for now)
-func (d *Del) stubMCP(ctx context.Context, args map[string]interface{}, ch chan string) (interface{}, error) {
-	endpoint, _ := args["endpoint"].(string)
-	payload, _ := args["payload"].(string)
-	msg := fmt.Sprintf("[stub] Would POST to MCP '%s' with payload: %s", endpoint, payload)
-	ch <- msg
-	return msg, nil
-}
-
-func NewDel(provider AIProvider) *Del {
-	// Get current working directory for context
-	cwd, _ := os.Getwd()
-	
-	// Enhanced system prompt with current directory context
-	contextualPrompt := SystemPrompt + fmt.Sprintf(`
-
-# CURRENT SESSION CONTEXT
-
-πŸ—‚οΈ **Working Directory**: %s
-πŸ“ **Session Info**: You are currently running in this directory. When users ask about "this project", "current directory", "here", or "analyze the code", they mean this location.
-
-# COMMON USER PATTERNS
-
-When users say:
-- "analyze the code" β†’ Use project_context first, then analyze key files
-- "scan for vulnerabilities" β†’ Use security_scan {"path": "."}
-- "what's in this directory" β†’ Use list_dir {"path": "."}
-- "read the main file" β†’ Look for main.go, main.py, index.js, etc.
-- "show me the project structure" β†’ Use project_context {}
-
-Always assume "." (current directory) when no path is specified for file operations.`, cwd)
-
-	d := &Del{
-		aiProvider:       provider,
-		tools:            make(map[string]*Tool),
-		safeMode:         true, // Enable safe mode by default
-		confirmedActions: make(map[string]bool),
-		chatHistory: []api.Message{
-			{
-				Role:    "system", 
-				Content: contextualPrompt,
-			},
-		},
-	}
-	d.tools["run_command"] = &Tool{
-		Name:        "run_command",
-		Description: "Execute a shell command and return the output",
-		Handler:     d.runCommand,
-	}
-	d.tools["read_file"] = &Tool{
-		Name:        "read_file",
-		Description: "Reads the contents of a file",
-		Handler:     d.readFile,
-	}
-	d.tools["write_file"] = &Tool{
-		Name:        "write_file",
-		Description: "Writes content to a file",
-		Handler:     d.writeFile,
-	}
-	d.tools["list_dir"] = &Tool{
-		Name:        "list_dir",
-		Description: "Lists files in a directory",
-		Handler:     d.listDir,
-	}
-	d.tools["analyze_code"] = &Tool{
-		Name:        "analyze_code",
-		Description: "Analyze code",
-		Handler:     d.analyzeCode,
-	}
-	d.tools["extract_functions"] = &Tool{
-		Name:        "extract_functions",
-		Description: "Extracts all function names and signatures from a source file",
-		Handler:     d.extractFunctions,
-	}
-	d.tools["find_references"] = &Tool{
-		Name:        "find_references",
-		Description: "Finds references to a symbol (variable, function, etc) in a directory or project",
-		Handler:     d.findReferences,
-	}
-	d.tools["search_code"] = &Tool{
-		Name:        "search_code",
-		Description: "Searches for a pattern (string or regex) in the codebase",
-		Handler:     d.searchCode,
-	}
-	d.tools["format_code"] = &Tool{
-		Name:        "format_code",
-		Description: "Auto-formats source code using language-specific formatters (gofmt, prettier, black, etc)",
-		Handler:     d.formatCode,
-	}
-	d.tools["lint_code"] = &Tool{
-		Name:        "lint_code",
-		Description: "Runs a linter on the source code and returns warnings/errors",
-		Handler:     d.lintCode,
-	}
-	d.tools["security_scan"] = &Tool{
-		Name:        "security_scan",
-		Description: "Scan code for security vulnerabilities using gosec and semgrep",
-		Handler:     d.securityScan,
-	}
-	d.tools["project_context"] = &Tool{
-		Name:        "project_context",
-		Description: "Analyze current project structure and provide development context",
-		Handler:     d.projectContext,
-	}
-	d.tools["git_operation"] = &Tool{
-		Name:        "git_operation",
-		Description: "Execute git operations (status, add, commit, push, pull, diff, log, branch, etc)",
-		Handler:     d.gitOperation,
-	}
-	d.tools["web_search"] = &Tool{
-		Name:        "web_search",
-		Description: "Search the web for information and documentation",
-		Handler:     d.webSearch,
-	}
-	d.tools["test_runner"] = &Tool{
-		Name:        "test_runner",
-		Description: "Detect and run tests for various languages (Go, Node.js, Python, Rust)",
-		Handler:     d.testRunner,
-	}
-	d.tools["multi_edit"] = &Tool{
-		Name:        "multi_edit",
-		Description: "Edit multiple files with find-replace operations",
-		Handler:     d.multiEdit,
-	}
-	d.tools["batch_operations"] = &Tool{
-		Name:        "batch_operations",
-		Description: "Execute multiple file operations (read, write, list) in sequence",
-		Handler:     d.batchOperations,
-	}
-	d.tools["mcp_call"] = &Tool{
-		Name:        "mcp_call",
-		Description: "Stub for MCP integration",
-		Handler:     d.stubMCP,
-	}
-	return d
-}
-
-func (d *Del) streamChat(ctx context.Context, history []api.Message) (string, error) {
-	return d.aiProvider.StreamChat(ctx, history)
-}
-
-func (d *Del) executeToolCalls(ctx context.Context, toolCalls []ToolCall) map[string]interface{} {
-	results := make(map[string]interface{})
+	// Add assistant response to history
+	d.chatHistory = append(d.chatHistory, api.Message{Role: "assistant", Content: fullResponse})
 	
-	fmt.Printf("\n● Executing %d tool call(s):\n", len(toolCalls))
+	// Check for tool calls
+	toolCalls := d.parseToolCalls(fullResponse)
 	
-	for i, toolCall := range toolCalls {
-		fmt.Printf("\n● %s(%s)\n", toolCall.Name, d.formatArgs(toolCall.Args))
-		tool, ok := d.tools[toolCall.Name]
-		if !ok {
-			fmt.Printf("  ⎿  ❌ Unknown tool: %s\n", toolCall.Name)
-			results[fmt.Sprintf("tool_%d", i)] = map[string]interface{}{
-				"tool": toolCall.Name,
-				"error": fmt.Sprintf("unknown tool: %s", toolCall.Name),
-			}
-			continue
-		}
-		
-		// Check if confirmation is required
-		if d.requiresConfirmation(toolCall.Name, toolCall.Args) {
-			argsJSON, _ := json.Marshal(toolCall.Args)
-			description := fmt.Sprintf("%s with args: %s", toolCall.Name, string(argsJSON))
-			if !d.askConfirmation(toolCall.Name, description) {
-				fmt.Printf("  ⎿  🚫 Operation cancelled by user\n")
-				results[fmt.Sprintf("tool_%d", i)] = map[string]interface{}{
-					"tool": toolCall.Name,
-					"error": "operation cancelled by user",
-				}
-				continue
-			}
+	if len(toolCalls) > 0 {
+		// Execute tools with Claude Code style progress
+		var toolResults []string
+		for _, call := range toolCalls {
+			result := d.executeTool(ctx, call)
+			toolResults = append(toolResults, fmt.Sprintf("%s: %s", call.Name, result))
 		}
 		
-		fmt.Printf("  ⎿  ")
-		ch := make(chan string, 10)
-		var output strings.Builder
-		go func() {
-			for line := range ch {
-				fmt.Print(line)
-				output.WriteString(line)
-			}
-		}()
+		// Get final response with tool results
+		toolResultsMsg := fmt.Sprintf("Tool results:\n%s\n\nProvide a natural response based on these results.", 
+			strings.Join(toolResults, "\n"))
+		d.chatHistory = append(d.chatHistory, api.Message{Role: "user", Content: toolResultsMsg})
 		
-		result, err := tool.Handler(ctx, toolCall.Args, ch)
-		close(ch)
+		var finalResponse string
+		err = d.client.Chat(ctx, &api.ChatRequest{
+			Model:    d.model,
+			Messages: d.chatHistory,
+		}, func(resp api.ChatResponse) error {
+			finalResponse += resp.Message.Content
+			return nil
+		})
 		
-		if err != nil {
-			fmt.Printf("  ⎿  ❌ Error: %s\n", err.Error())
-			results[fmt.Sprintf("tool_%d", i)] = map[string]interface{}{
-				"tool": toolCall.Name,
-				"error": err.Error(),
-			}
-		} else {
-			// Show success with brief result summary
-			resultSummary := d.summarizeResult(result)
-			fmt.Printf("  ⎿  βœ… %s\n", resultSummary)
-			results[fmt.Sprintf("tool_%d", i)] = map[string]interface{}{
-				"tool": toolCall.Name,
-				"result": result,
-			}
-		}
-	}
-	
-	return results
-}
-
-func (d *Del) handleToolCalls(ctx context.Context, response string) (bool, map[string]interface{}) {
-	// Use universal parser to detect tool calls in any format
-	toolCalls := d.parseToolCalls(response)
-	if len(toolCalls) == 0 {
-		return false, nil // No tool calls found
-	}
-	
-	// Show parsing success
-	fmt.Printf("\n● Detected %d tool call(s) using universal parser\n", len(toolCalls))
-	
-	// Execute all tool calls and return results
-	results := d.executeToolCalls(ctx, toolCalls)
-	return true, results
-}
-
-func (d *Del) showHelp() {
-	fmt.Println(`
-🎀 Del the Funky Robosapien - Your Ultimate Coding Assistant
-
-πŸš€ Quick Commands:
-  help, h              Show this help
-  quit, q, exit        Exit Del  
-  clear, cls           Clear screen
-  context, ctx         Show project context
-  tools                List all available tools
-  safe                 Toggle safe mode (confirmation prompts)
-  unsafe               Disable safe mode (DANGEROUS)
-
-πŸ”₯ Power User Tips:
-  Just talk naturally! Del understands:
-  β€’ "scan this project for vulnerabilities"
-  β€’ "read and explain main.go"
-  β€’ "what functions are in utils.py?"
-  β€’ "check git status and commit changes"
-  β€’ "run the tests"
-  β€’ "search for golang best practices"
-  β€’ "analyze the code quality"
-
-πŸ”§ Available Tools:
-  βœ“ File Operations     β€’ read, write, list files
-  βœ“ Multi-File Editing  β€’ batch edits across files
-  βœ“ Code Analysis       β€’ analyze, format, lint code
-  βœ“ Security Scanning   β€’ find vulnerabilities
-  βœ“ Git Operations      β€’ status, commit, push, diff, log
-  βœ“ Web Search          β€’ search for documentation and info
-  βœ“ Test Running        β€’ auto-detect and run project tests
-  βœ“ Command Execution   β€’ run any shell command
-  βœ“ Project Understanding β€’ context-aware assistance
-  πŸ›‘οΈ Safe Mode         β€’ confirmation prompts for dangerous ops
-
-🎯 Pro Tip: Del learns your project as you work!
-`)
-}
-
-func (d *Del) clearScreen() {
-	fmt.Print("\033[2J\033[H")
-}
-
-func (d *Del) showContext() {
-	cwd, _ := os.Getwd()
-	safeStatus := "πŸ›‘οΈ  ENABLED"
-	if !d.safeMode {
-		safeStatus = "⚠️  DISABLED"
-	}
-	fmt.Printf(`
-πŸ’Ό Current Project Context:
-  πŸ“ Directory: %s
-  πŸ€– Model: %s
-  πŸ’¬ Chat History: %d messages
-  πŸ›‘οΈ Safe Mode: %s
-`, cwd, d.aiProvider.Name(), len(d.chatHistory), safeStatus)
-	
-	// Show project type detection
-	projectTypes := map[string]string{
-		"go.mod":         "🐹 Go project",
-		"package.json":   "πŸ“¦ Node.js project", 
-		"Cargo.toml":     "πŸ¦€ Rust project",
-		"requirements.txt": "🐍 Python project",
-		"pom.xml":        "β˜• Java project",
-	}
-	
-	fmt.Println("  πŸ” Project Type:")
-	found := false
-	for file, desc := range projectTypes {
-		if _, err := os.Stat(file); err == nil {
-			fmt.Printf("    %s\n", desc)
-			found = true
-		}
-	}
-	if !found {
-		fmt.Println("    πŸ“‚ Generic project")
-	}
-	
-	// Show recent files if any
-	if entries, err := os.ReadDir("."); err == nil {
-		fmt.Println("  πŸ“„ Key Files:")
-		count := 0
-		for _, entry := range entries {
-			if !entry.IsDir() && isImportantFile(entry.Name()) && count < 8 {
-				fmt.Printf("    β€’ %s\n", entry.Name())
-				count++
-			}
+		if err == nil {
+			fmt.Print("\nπŸ€– Del: ")
+			d.streamResponse(ctx, finalResponse)
+			d.chatHistory = append(d.chatHistory, api.Message{Role: "assistant", Content: finalResponse})
 		}
+	} else {
+		// No tools, just stream the response
+		fmt.Print("πŸ€– Del: ")
+		d.streamResponse(ctx, fullResponse)
 	}
 	
-	fmt.Println("\nπŸ’‘ Del knows this is your working directory.")
-	fmt.Println("   Just say 'analyze the code' or 'scan for vulnerabilities'!")
-	fmt.Println()
-}
-
-func (d *Del) showTools() {
-	fmt.Println(`
-πŸ”§ Available Tools:
-`)
-	for name, tool := range d.tools {
-		fmt.Printf("  βœ“ %-18s %s\n", name, tool.Description)
-	}
 	fmt.Println()
 }
 
-func (d *Del) StartREPL(ctx context.Context) {
-	d.clearScreen()
+func (d *Del) Start(ctx context.Context) {
 	cwd, _ := os.Getwd()
-	fmt.Printf("🎀 Del the Funky Robosapien is ready!\n")
-	fmt.Printf("πŸ€– Powered by %s\n", d.aiProvider.Name())
+	fmt.Println("🎀 Del the Funky Robosapien (Claude Code Style)")
+	fmt.Printf("πŸ€– Powered by Ollama (%s)\n", d.model)
 	fmt.Printf("πŸ“ Working in: %s\n", cwd)
-	fmt.Println("πŸš€ Type 'help' for commands, 'quit' to exit, or just ask me anything!")
-	fmt.Println("πŸ’‘ Try: 'analyze the code', 'scan for vulnerabilities', 'show project structure'")
+	fmt.Println("πŸ’‘ Try: 'list files', 'read main.go', 'check git status', 'analyze the code'")
 	fmt.Println()
 	
 	scanner := bufio.NewScanner(os.Stdin)
@@ -1609,92 +397,22 @@ func (d *Del) StartREPL(ctx context.Context) {
 		if !scanner.Scan() {
 			break
 		}
+		
 		input := strings.TrimSpace(scanner.Text())
 		if input == "" {
 			continue
 		}
 		
-		// Handle quick commands
-		switch strings.ToLower(input) {
-		case "quit", "q", "exit":
-			fmt.Println("πŸ‘‹ Stay funky, keep coding!")
-			return
-		case "help", "h":
-			d.showHelp()
-			continue
-		case "clear", "cls":
-			d.clearScreen()
-			continue
-		case "context", "ctx":
-			d.showContext()
-			continue
-		case "tools":
-			d.showTools()
-			continue
-		case "safe":
-			d.safeMode = !d.safeMode
-			if d.safeMode {
-				fmt.Println("πŸ›‘οΈ  Safe mode ENABLED - dangerous operations will require confirmation")
-			} else {
-				fmt.Println("⚠️  Safe mode DISABLED - dangerous operations will execute without confirmation")
-			}
-			continue
-		case "unsafe":
-			d.safeMode = false
-			fmt.Println("⚠️  Safe mode DISABLED - BE CAREFUL!")
-			continue
-		}
-		
-		fmt.Print("πŸ€– Del: ")
-		d.chatHistory = append(d.chatHistory, api.Message{Role: "user", Content: input})
-		
-		// Stage 1: Get initial response from model (should contain tool calls)
-		response, err := d.aiProvider.Chat(ctx, d.chatHistory)
-		if err != nil {
-			fmt.Printf("\n⚠️  Error: %s\n\n", err)
-			continue
-		}
-		
-		// Check if there are tool calls to execute
-		hasTools, toolResults := d.handleToolCalls(ctx, response)
-		
-		if hasTools {
-			// Stage 2: Tool calls were found and executed, ask model for final response
-			d.chatHistory = append(d.chatHistory, api.Message{Role: "assistant", Content: response})
-			
-			fmt.Printf("\n● Providing tool results to model for final response...\n")
-			
-			// Create tool results message
-			toolResultsJSON, _ := json.MarshalIndent(toolResults, "", "  ")
-			toolMessage := fmt.Sprintf("Tool execution results:\n```json\n%s\n```\n\nPlease provide a natural response based on these results.", string(toolResultsJSON))
-			d.chatHistory = append(d.chatHistory, api.Message{Role: "user", Content: toolMessage})
-			
-			// Get final response with tool results
-			finalResponse, err := d.aiProvider.Chat(ctx, d.chatHistory)
-			if err != nil {
-				fmt.Printf("  ⎿  ❌ Error getting final response: %s\n\n", err)
-				continue
-			}
-			fmt.Printf("  ⎿  βœ… Generated natural response\n")
-			fmt.Printf("\nπŸ€– Del: %s", finalResponse)
-			d.chatHistory = append(d.chatHistory, api.Message{Role: "assistant", Content: finalResponse})
-		} else {
-			// No tool calls, just display the response normally
-			fmt.Print(response)
-			d.chatHistory = append(d.chatHistory, api.Message{Role: "assistant", Content: response})
+		if input == "quit" || input == "exit" || input == "q" {
+			fmt.Println("πŸ‘‹ Stay funky!")
+			break
 		}
 		
+		d.processMessage(ctx, input)
 		fmt.Println()
 	}
 }
 
-func createOllamaProvider(model string) *OllamaProvider {
-	if model == "" {
-		model = "deepseek-coder-v2:16b"
-	}
-	return NewOllamaProvider(model)
-}
-
 func main() {
 	var model = flag.String("model", "deepseek-coder-v2:16b", "Ollama model to use")
 	var help = flag.Bool("help", false, "Show help message")
@@ -1702,7 +420,7 @@ func main() {
 	flag.Parse()
 	
 	if *help {
-		fmt.Println(`🎀 Del the Funky Robosapien - Ultimate AI Coding Assistant
+		fmt.Println(`🎀 Del the Funky Robosapien - Claude Code Style AI Assistant
 
 Usage:
   del [flags]
@@ -1713,29 +431,20 @@ Flags:
 
 Popular Models:
   deepseek-coder-v2:16b    # Best for coding (default)
-  codellama:34b           # Meta's coding model
-  codegemma:7b           # Google's coding model
-  qwen2.5-coder:32b      # Alibaba's coding model
+  codellama:34b           # Meta's coding model  
+  qwen2.5-coder:32b       # Alibaba's coding model
 
 Examples:
   del                              # Use default model
   del --model codellama:34b        # Use CodeLlama
-  del --model qwen2.5-coder:32b    # Use Qwen Coder
 
-Interactive Commands:
-  help, h             Show available commands and tools
-  quit, q, exit       Exit Del
-  clear, cls          Clear screen
-  context             Show current project context
-
-Del automatically uses tools based on your requests:
-  "scan for vulnerabilities", "read main.go", "analyze this code", etc.
+Del automatically uses tools based on your requests with Claude Code style progress indicators:
+  "list files", "read main.go", "check git status", "run ls -la", "analyze the code"
 `)
 		return
 	}
 	
 	ctx := context.Background()
-	provider := createOllamaProvider(*model)
-	assistant := NewDel(provider)
-	assistant.StartREPL(ctx)
-}
+	assistant := NewDel(*model)
+	assistant.Start(ctx)
+}
\ No newline at end of file
go.mod
@@ -2,10 +2,7 @@ module github.com/xlgmokha/deltron
 
 go 1.24.0
 
-require (
-	github.com/creack/pty v1.1.24
-	github.com/ollama/ollama v0.9.2
-)
+require github.com/ollama/ollama v0.9.2
 
 require (
 	golang.org/x/crypto v0.36.0 // indirect
go.sum
@@ -1,5 +1,3 @@
-github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
-github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=