cleanup: remove unused functions and fix tests

Remove unused Go code identified through systematic analysis:

Removed Functions:
- BashRun() in claudetool/bash.go - legacy testing function
- ContentToString() in claudetool/util.go - unused utility function
- GetActiveTunnels() in dockerimg/tunnel_manager.go - unused getter method

Removed Types:
- baseResponse struct in claudetool/browse/browse.go - unused response type

Test Updates:
- Replaced BashRun tests with direct Bash.Run calls in bash_test.go
- Removed ContentToString test from agent_test.go (testing unused function)
- Updated tunnel manager tests to access internal activeTunnels map directly
- Fixed all compilation errors caused by removed functions

All tests now pass and the codebase is cleaner with reduced maintenance burden.
The removed functions had no references in production code and were only
used in tests, which have been updated or removed as appropriate.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s2cac4b024f877682k
diff --git a/claudetool/bash.go b/claudetool/bash.go
index ce27ec7..a62892f 100644
--- a/claudetool/bash.go
+++ b/claudetool/bash.go
@@ -324,12 +324,6 @@
 	}, nil
 }
 
-// BashRun is the legacy function for testing compatibility
-func BashRun(ctx context.Context, m json.RawMessage) ([]llm.Content, error) {
-	// Use the default Bash tool which has no permission callback
-	return Bash.Run(ctx, m)
-}
-
 // checkAndInstallMissingTools analyzes a bash command and attempts to automatically install any missing tools.
 func (b *BashTool) checkAndInstallMissingTools(ctx context.Context, command string) error {
 	commands, err := bashkit.ExtractCommands(command)
diff --git a/claudetool/bash_test.go b/claudetool/bash_test.go
index 45dd4fe..6904447 100644
--- a/claudetool/bash_test.go
+++ b/claudetool/bash_test.go
@@ -11,20 +11,19 @@
 	"time"
 )
 
-func TestBashRun(t *testing.T) {
+func TestBashTool(t *testing.T) {
 	// Test basic functionality
 	t.Run("Basic Command", func(t *testing.T) {
 		input := json.RawMessage(`{"command":"echo 'Hello, world!'"}`)
 
-		result, err := BashRun(context.Background(), input)
+		result, err := Bash.Run(context.Background(), input)
 		if err != nil {
 			t.Fatalf("Unexpected error: %v", err)
 		}
 
 		expected := "Hello, world!\n"
-		resultStr := ContentToString(result)
-		if resultStr != expected {
-			t.Errorf("Expected %q, got %q", expected, resultStr)
+		if len(result) == 0 || result[0].Text != expected {
+			t.Errorf("Expected %q, got %q", expected, result[0].Text)
 		}
 	})
 
@@ -32,15 +31,14 @@
 	t.Run("Command With Arguments", func(t *testing.T) {
 		input := json.RawMessage(`{"command":"echo -n foo && echo -n bar"}`)
 
-		result, err := BashRun(context.Background(), input)
+		result, err := Bash.Run(context.Background(), input)
 		if err != nil {
 			t.Fatalf("Unexpected error: %v", err)
 		}
 
 		expected := "foobar"
-		resultStr := ContentToString(result)
-		if resultStr != expected {
-			t.Errorf("Expected %q, got %q", expected, resultStr)
+		if len(result) == 0 || result[0].Text != expected {
+			t.Errorf("Expected %q, got %q", expected, result[0].Text)
 		}
 	})
 
@@ -58,15 +56,14 @@
 			t.Fatalf("Failed to marshal input: %v", err)
 		}
 
-		result, err := BashRun(context.Background(), inputJSON)
+		result, err := Bash.Run(context.Background(), inputJSON)
 		if err != nil {
 			t.Fatalf("Unexpected error: %v", err)
 		}
 
 		expected := "Completed\n"
-		resultStr := ContentToString(result)
-		if resultStr != expected {
-			t.Errorf("Expected %q, got %q", expected, resultStr)
+		if len(result) == 0 || result[0].Text != expected {
+			t.Errorf("Expected %q, got %q", expected, result[0].Text)
 		}
 	})
 
@@ -84,7 +81,7 @@
 			t.Fatalf("Failed to marshal input: %v", err)
 		}
 
-		_, err = BashRun(context.Background(), inputJSON)
+		_, err = Bash.Run(context.Background(), inputJSON)
 		if err == nil {
 			t.Errorf("Expected timeout error, got none")
 		} else if !strings.Contains(err.Error(), "timed out") {
@@ -96,7 +93,7 @@
 	t.Run("Failed Command", func(t *testing.T) {
 		input := json.RawMessage(`{"command":"exit 1"}`)
 
-		_, err := BashRun(context.Background(), input)
+		_, err := Bash.Run(context.Background(), input)
 		if err == nil {
 			t.Errorf("Expected error for failed command, got none")
 		}
@@ -106,7 +103,7 @@
 	t.Run("Invalid JSON Input", func(t *testing.T) {
 		input := json.RawMessage(`{"command":123}`) // Invalid JSON (command must be string)
 
-		_, err := BashRun(context.Background(), input)
+		_, err := Bash.Run(context.Background(), input)
 		if err == nil {
 			t.Errorf("Expected error for invalid input, got none")
 		}
@@ -224,14 +221,14 @@
 			t.Fatalf("Failed to marshal input: %v", err)
 		}
 
-		result, err := BashRun(context.Background(), inputJSON)
+		result, err := Bash.Run(context.Background(), inputJSON)
 		if err != nil {
 			t.Fatalf("Unexpected error: %v", err)
 		}
 
 		// Parse the returned JSON
 		var bgResult BackgroundResult
-		resultStr := ContentToString(result)
+		resultStr := result[0].Text
 		if err := json.Unmarshal([]byte(resultStr), &bgResult); err != nil {
 			t.Fatalf("Failed to unmarshal background result: %v", err)
 		}
@@ -282,14 +279,14 @@
 			t.Fatalf("Failed to marshal input: %v", err)
 		}
 
-		result, err := BashRun(context.Background(), inputJSON)
+		result, err := Bash.Run(context.Background(), inputJSON)
 		if err != nil {
 			t.Fatalf("Unexpected error: %v", err)
 		}
 
 		// Parse the returned JSON
 		var bgResult BackgroundResult
-		resultStr := ContentToString(result)
+		resultStr := result[0].Text
 		if err := json.Unmarshal([]byte(resultStr), &bgResult); err != nil {
 			t.Fatalf("Failed to unmarshal background result: %v", err)
 		}
@@ -340,14 +337,14 @@
 		}
 
 		// Start the command in the background
-		result, err := BashRun(context.Background(), inputJSON)
+		result, err := Bash.Run(context.Background(), inputJSON)
 		if err != nil {
 			t.Fatalf("Unexpected error: %v", err)
 		}
 
 		// Parse the returned JSON
 		var bgResult BackgroundResult
-		resultStr := ContentToString(result)
+		resultStr := result[0].Text
 		if err := json.Unmarshal([]byte(resultStr), &bgResult); err != nil {
 			t.Fatalf("Failed to unmarshal background result: %v", err)
 		}
diff --git a/claudetool/browse/browse.go b/claudetool/browse/browse.go
index 2918abb..f600c72 100644
--- a/claudetool/browse/browse.go
+++ b/claudetool/browse/browse.go
@@ -141,11 +141,6 @@
 	return b.browserCtx, nil
 }
 
-// All tools return this as a response when successful
-type baseResponse struct {
-	Status string `json:"status,omitempty"`
-}
-
 func successResponse() string {
 	return `{"status":"success"}`
 }
diff --git a/claudetool/util.go b/claudetool/util.go
index 88136e4..5715f79 100644
--- a/claudetool/util.go
+++ b/claudetool/util.go
@@ -1,13 +1 @@
 package claudetool
-
-import (
-	"sketch.dev/llm"
-)
-
-// ContentToString extracts text from []llm.Content if available
-func ContentToString(content []llm.Content) string {
-	if len(content) == 0 {
-		return ""
-	}
-	return content[0].Text
-}