Files
goclaw/internal/providers/claude_cli_auth.go
T
viettranx b2c4d543aa feat(providers): add Claude CLI provider with MCP bridge (#61)
Add Claude CLI as an LLM provider (subscription-based, no API key needed).
The CLI manages session history, tool execution, and context while GoClaw
forwards messages and streams responses.

Key features:
- Claude CLI provider with session persistence (--resume)
- MCP bridge server exposing GoClaw tools to CLI via streamable-http
- Security hooks (shell deny patterns, workspace path restrictions)
- Per-session mutex preventing concurrent CLI calls
- Onboard wizard for Claude CLI setup and auth verification
- Web UI for adding/managing Claude CLI provider with auth status
- Provider registry Close() for proper shutdown cleanup

Security:
- CLI path validation (only "claude" or absolute paths from DB)
- Token auth middleware for MCP bridge endpoint
- Shell injection prevention in hook scripts (single-quoted paths)
- Relative path resolution before workspace boundary checks
- Resource leak prevention on provider replace/unregister

Co-authored-by: nhokboo <nhokboo@users.noreply.github.com>
2026-03-07 02:06:39 +07:00

41 lines
1.1 KiB
Go

package providers
import (
"context"
"encoding/json"
"fmt"
"os/exec"
)
// ClaudeAuthStatus holds the parsed result of `claude auth status --json`.
type ClaudeAuthStatus struct {
LoggedIn bool `json:"loggedIn"`
Email string `json:"email,omitempty"`
SubscriptionType string `json:"subscriptionType,omitempty"`
}
// CheckClaudeAuthStatus runs `claude auth status --json` using the given CLI
// path and returns the parsed authentication status.
func CheckClaudeAuthStatus(ctx context.Context, cliPath string) (*ClaudeAuthStatus, error) {
if cliPath == "" {
cliPath = "claude"
}
resolvedPath, err := exec.LookPath(cliPath)
if err != nil {
return nil, fmt.Errorf("claude CLI binary not found at %q: %w", cliPath, err)
}
cmd := exec.CommandContext(ctx, resolvedPath, "auth", "status", "--json")
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("claude auth status failed: %w", err)
}
var status ClaudeAuthStatus
if err := json.Unmarshal(output, &status); err != nil {
return nil, fmt.Errorf("failed to parse auth status: %w", err)
}
return &status, nil
}