Initial commit
diff --git a/claudetool/edit_regression_test.go b/claudetool/edit_regression_test.go
new file mode 100644
index 0000000..cb859fe
--- /dev/null
+++ b/claudetool/edit_regression_test.go
@@ -0,0 +1,152 @@
+package claudetool
+
+import (
+	"context"
+	"encoding/json"
+	"strings"
+	"testing"
+)
+
+// TestEmptyContentHandling tests handling of empty content in str_replace and related operations
+// This test specifically reproduces conditions that might lead to "index out of range [0]" panic
+func TestEmptyContentHandling(t *testing.T) {
+	// Create a file with empty content
+	emptyFile := setupTestFile(t, "")
+
+	// Test running EditRun directly with empty content
+	// This more closely simulates the actual call flow that led to the panic
+	input := map[string]any{
+		"command": "str_replace",
+		"path":    emptyFile,
+		"old_str": "nonexistent text",
+		"new_str": "new content",
+	}
+
+	inputJSON, err := json.Marshal(input)
+	if err != nil {
+		t.Fatalf("Failed to marshal input: %v", err)
+	}
+
+	// This should not panic but return an error
+	_, err = EditRun(context.Background(), inputJSON)
+	if err == nil {
+		t.Fatalf("Expected error for empty file with str_replace but got none")
+	}
+
+	// Make sure the error message is as expected
+	if !strings.Contains(err.Error(), "did not appear verbatim") {
+		t.Errorf("Expected error message to indicate missing string, got: %s", err.Error())
+	}
+}
+
+// TestNilParameterHandling tests error cases with nil parameters
+// This test validates proper error handling when nil or invalid parameters are provided
+func TestNilParameterHandling(t *testing.T) {
+	// Create a test file
+	testFile := setupTestFile(t, "test content")
+
+	// Test case 1: nil old_str in str_replace
+	input1 := map[string]any{
+		"command": "str_replace",
+		"path":    testFile,
+		// old_str is deliberately missing
+		"new_str": "replacement",
+	}
+
+	inputJSON1, err := json.Marshal(input1)
+	if err != nil {
+		t.Fatalf("Failed to marshal input: %v", err)
+	}
+
+	_, err = EditRun(context.Background(), inputJSON1)
+	if err == nil {
+		t.Fatalf("Expected error for missing old_str but got none")
+	}
+	if !strings.Contains(err.Error(), "parameter old_str is required") {
+		t.Errorf("Expected error message to indicate missing old_str, got: %s", err.Error())
+	}
+
+	// Test case 2: nil new_str in insert
+	input2 := map[string]any{
+		"command":     "insert",
+		"path":        testFile,
+		"insert_line": 1,
+		// new_str is deliberately missing
+	}
+
+	inputJSON2, err := json.Marshal(input2)
+	if err != nil {
+		t.Fatalf("Failed to marshal input: %v", err)
+	}
+
+	_, err = EditRun(context.Background(), inputJSON2)
+	if err == nil {
+		t.Fatalf("Expected error for missing new_str but got none")
+	}
+	if !strings.Contains(err.Error(), "parameter new_str is required") {
+		t.Errorf("Expected error message to indicate missing new_str, got: %s", err.Error())
+	}
+
+	// Test case 3: nil view_range in view
+	// This doesn't cause an error, but tests the code path
+	input3 := map[string]any{
+		"command": "view",
+		"path":    testFile,
+		// No view_range
+	}
+
+	inputJSON3, err := json.Marshal(input3)
+	if err != nil {
+		t.Fatalf("Failed to marshal input: %v", err)
+	}
+
+	// This should not result in an error
+	_, err = EditRun(context.Background(), inputJSON3)
+	if err != nil {
+		t.Fatalf("Unexpected error for nil view_range: %v", err)
+	}
+}
+
+// TestEmptySplitResult tests the specific scenario where strings.Split might return empty results
+// This directly reproduces conditions that might have led to the "index out of range [0]" panic
+func TestEmptySplitResult(t *testing.T) {
+	// Direct test of strings.Split behavior and our handling of it
+	emptyCases := []struct {
+		content string
+		oldStr  string
+	}{
+		{"", "any string"},
+		{"content", "not in string"},
+		{"\n\n", "also not here"},
+	}
+
+	for _, tc := range emptyCases {
+		parts := strings.Split(tc.content, tc.oldStr)
+
+		// Verify that strings.Split with non-matching separator returns a slice with original content
+		if len(parts) != 1 {
+			t.Errorf("Expected strings.Split to return a slice with 1 element when separator isn't found, got %d elements", len(parts))
+		}
+
+		// Double check the content
+		if len(parts) > 0 && parts[0] != tc.content {
+			t.Errorf("Expected parts[0] to be original content %q, got %q", tc.content, parts[0])
+		}
+	}
+
+	// Test the actual unsafe scenario with empty content
+	emptyFile := setupTestFile(t, "")
+
+	// Get the content and simulate the internal string splitting
+	content, _ := readFile(emptyFile)
+	oldStr := "nonexistent"
+	parts := strings.Split(content, oldStr)
+
+	// Validate that the defensive code would work
+	if len(parts) == 0 {
+		parts = []string{""} // This is the fix
+	}
+
+	// This would have panicked without the fix
+	_ = strings.Count(parts[0], "\n")
+}