Initial MVP implementation of Claudia Docs CLI

- Auth commands: login, logout, status
- Document commands: create, list, get, update, delete
- Project commands: list, get
- Folder commands: list, create
- Tag commands: list, create, add
- Search command
- Reasoning save command
- JSON output format with --output text option
- Viper-based configuration management
- Cobra CLI framework
This commit is contained in:
Claudia CLI Bot
2026-03-31 01:25:15 +00:00
commit aca95d90f3
17 changed files with 3270 additions and 0 deletions

110
internal/api/client.go Normal file
View File

@@ -0,0 +1,110 @@
package api
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/claudia/docs-cli/internal/config"
"github.com/claudia/docs-cli/pkg/types"
)
// Client is the API client
type Client struct {
BaseURL string
Token string
HTTPClient *http.Client
Timeout time.Duration
}
// NewClient creates a new API client
func NewClient() (*Client, error) {
cfg := config.GetConfig()
if cfg == nil {
cfg = &config.Config{Server: "http://localhost:8000", Timeout: "30s"}
}
timeout, err := time.ParseDuration(cfg.Timeout)
if err != nil {
timeout = 30 * time.Second
}
return &Client{
BaseURL: cfg.Server + "/api/v1",
Token: cfg.Token,
HTTPClient: &http.Client{
Timeout: timeout,
},
Timeout: timeout,
}, nil
}
// SetToken sets the authentication token
func (c *Client) SetToken(token string) {
c.Token = token
}
// doRequest performs an HTTP request
func (c *Client) doRequest(method, path string, body interface{}) (*http.Response, error) {
var reqBody io.Reader
if body != nil {
jsonData, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("failed to marshal request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonData)
}
url := c.BaseURL + path
req, err := http.NewRequest(method, url, reqBody)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
}
return c.HTTPClient.Do(req)
}
// DoRequest performs an HTTP request (exported for auth package)
func (c *Client) DoRequest(method, path string, body interface{}) (*http.Response, error) {
return c.doRequest(method, path, body)
}
// Response parses the API response
type Response struct {
Success bool
Data interface{}
Error *types.ErrorInfo
}
func parseResponse(resp *http.Response) (*types.Response, error) {
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
var apiResp types.Response
if err := json.Unmarshal(body, &apiResp); err != nil {
return nil, fmt.Errorf("failed to parse response JSON: %w", err)
}
return &apiResp, nil
}
func handleError(resp *http.Response, body []byte) error {
var apiResp types.Response
if err := json.Unmarshal(body, &apiResp); err != nil {
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
}
if apiResp.Error != nil {
return fmt.Errorf("%s: %s", apiResp.Error.Code, apiResp.Error.Message)
}
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
}