package cli import ( "bufio" "encoding/json" "fmt" "io" "os" "github.com/spf13/cobra" "github.com/thepeterstone/claudomator/internal/storage" ) type executionStore interface { GetExecution(id string) (*storage.Execution, error) } func newLogsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "logs ", Short: "Show logs for an execution", Args: cobra.ExactArgs(1), SilenceErrors: true, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { store, err := storage.Open(cfg.DBPath) if err != nil { return fmt.Errorf("opening db: %w", err) } defer store.Close() return renderLogs(args[0], store, cmd.OutOrStdout()) }, } return cmd } type streamMessage struct { Type string `json:"type"` Message *assistantMsg `json:"message,omitempty"` } type assistantMsg struct { Content []contentBlock `json:"content"` } type contentBlock struct { Type string `json:"type"` Text string `json:"text,omitempty"` Name string `json:"name,omitempty"` Input json.RawMessage `json:"input,omitempty"` } func renderLogs(execID string, store executionStore, w io.Writer) error { exec, err := store.GetExecution(execID) if err != nil { fmt.Fprintf(w, "execution %s not found\n", execID) return fmt.Errorf("execution %s not found", execID) } if exec.StdoutPath == "" { fmt.Fprintln(w, "no output recorded") return nil } fi, err := os.Stat(exec.StdoutPath) if err != nil || fi.Size() == 0 { fmt.Fprintln(w, "no output recorded") return nil } f, err := os.Open(exec.StdoutPath) if err != nil { fmt.Fprintln(w, "no output recorded") return nil } defer f.Close() scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Bytes() if len(line) == 0 { continue } var msg streamMessage if err := json.Unmarshal(line, &msg); err != nil { continue } if msg.Type != "assistant" || msg.Message == nil { continue } for _, block := range msg.Message.Content { switch block.Type { case "text": fmt.Fprintln(w, block.Text) case "tool_use": summary := string(block.Input) if len(summary) > 80 { summary = summary[:80] } fmt.Fprintf(w, " > %s (%s)\n", block.Name, summary) } } } fmt.Fprintf(w, "Cost: $%.4f Exit: %d\n", exec.CostUSD, exec.ExitCode) return nil }