Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save miketheprogrammer/8e84ecfaa17fa73a8ae58467c19b5446 to your computer and use it in GitHub Desktop.

Select an option

Save miketheprogrammer/8e84ecfaa17fa73a8ae58467c19b5446 to your computer and use it in GitHub Desktop.
asd
package main
import (
"bufio"
"context"
"encoding/json"
"fmt"
"log"
"os"
"os/exec"
"strings"
"sync"
"sync/atomic"
)
var requestCounter atomic.Int64
func nextRequestID() string {
n := requestCounter.Add(1)
return fmt.Sprintf("req_%d", n)
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
cmd := exec.CommandContext(ctx, "claude",
"--output-format", "stream-json",
"--input-format", "stream-json",
"--include-partial-messages",
"--verbose",
"--setting-sources", "",
"--permission-mode", "acceptEdits",
)
stdin, err := cmd.StdinPipe()
if err != nil {
log.Fatalf("stdin pipe: %v", err)
}
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatalf("stdout pipe: %v", err)
}
stderr, err := cmd.StderrPipe()
if err != nil {
log.Fatalf("stderr pipe: %v", err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
var stdinMu sync.Mutex
sendJSON := func(v interface{}) {
b, _ := json.Marshal(v)
stdinMu.Lock()
_, writeErr := fmt.Fprintf(stdin, "%s\n", b)
stdinMu.Unlock()
if writeErr != nil {
fmt.Fprintf(os.Stderr, "[ERROR] write to stdin: %v\n", writeErr)
}
fmt.Fprintf(os.Stderr, "[SENT] %s\n", b)
}
// Drain stderr
go func() {
scanner := bufio.NewScanner(stderr)
scanner.Buffer(make([]byte, 0), 1*1024*1024)
for scanner.Scan() {
fmt.Fprintf(os.Stderr, "[claude stderr] %s\n", scanner.Text())
}
}()
// Channels for coordination
initDone := make(chan struct{}, 1) // handshake complete, can send first message
turnDone := make(chan struct{}, 1) // current turn complete, can send next message
var sessionID string
// Read NDJSON from stdout
go func() {
defer func() {
// Unblock anything waiting
select {
case initDone <- struct{}{}:
default:
}
select {
case turnDone <- struct{}{}:
default:
}
}()
scanner := bufio.NewScanner(stdout)
scanner.Buffer(make([]byte, 0), 10*1024*1024)
for scanner.Scan() {
line := scanner.Bytes()
fmt.Fprintf(os.Stderr, "[RECV] %s\n", string(line))
var msg map[string]interface{}
if err := json.Unmarshal(line, &msg); err != nil {
fmt.Fprintf(os.Stderr, "[WARN] parse error: %v\n", err)
continue
}
msgType, _ := msg["type"].(string)
switch msgType {
case "system":
subtype, _ := msg["subtype"].(string)
if sid, ok := msg["session_id"].(string); ok {
sessionID = sid
}
fmt.Fprintf(os.Stderr, "[INFO] system subtype=%q session=%q\n", subtype, sessionID)
case "rate_limit_event":
info, _ := msg["rate_limit_info"].(map[string]interface{})
status, _ := info["status"].(string)
if sid, ok := msg["session_id"].(string); ok && sessionID == "" {
sessionID = sid
}
fmt.Fprintf(os.Stderr, "[INFO] rate_limit: status=%q\n", status)
// CLI responds to our initialize request
case "control_response":
fmt.Fprintf(os.Stderr, "[INFO] control_response received (init handshake complete)\n")
select {
case initDone <- struct{}{}:
default:
}
// CLI asks us for permissions, hooks, etc.
case "control_request":
reqID, _ := msg["request_id"].(string)
request, _ := msg["request"].(map[string]interface{})
subtype, _ := request["subtype"].(string)
fmt.Fprintf(os.Stderr, "[INFO] control_request subtype=%q id=%q\n", subtype, reqID)
switch subtype {
case "can_use_tool":
sendJSON(map[string]interface{}{
"type": "control_response",
"request_id": reqID,
"response": map[string]interface{}{
"behavior": "allow",
},
})
default:
sendJSON(map[string]interface{}{
"type": "control_response",
"request_id": reqID,
"response": map[string]interface{}{},
})
}
case "stream_event":
event, _ := msg["event"].(map[string]interface{})
eventType, _ := event["type"].(string)
if eventType == "content_block_delta" {
delta, _ := event["delta"].(map[string]interface{})
if delta["type"] == "text_delta" {
text, _ := delta["text"].(string)
fmt.Print(text)
}
}
case "assistant":
// With --include-partial-messages, text already printed
// via stream_event. Log tool use here.
message, _ := msg["message"].(map[string]interface{})
if message != nil {
content, _ := message["content"].([]interface{})
for _, block := range content {
b, _ := block.(map[string]interface{})
if b["type"] == "tool_use" {
name, _ := b["name"].(string)
fmt.Fprintf(os.Stderr, "\n[TOOL] %s\n", name)
}
}
}
case "user":
fmt.Fprintf(os.Stderr, "[INFO] user message (tool result)\n")
case "result":
fmt.Println()
subtype, _ := msg["subtype"].(string)
costUSD, _ := msg["total_cost_usd"].(float64)
fmt.Fprintf(os.Stderr, "[INFO] result: subtype=%q cost=$%.4f\n", subtype, costUSD)
fmt.Printf("--- Done (cost: $%.4f) ---\n", costUSD)
select {
case turnDone <- struct{}{}:
default:
}
default:
fmt.Fprintf(os.Stderr, "[DEBUG] unhandled: %q\n", msgType)
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintf(os.Stderr, "[ERROR] stdout scanner: %v\n", err)
}
fmt.Fprintf(os.Stderr, "[INFO] stdout closed\n")
}()
// ── Initialize handshake ─────────────────────────────────────
fmt.Println("Claude CLI Streaming Test")
fmt.Println("Sending initialize handshake...")
sendJSON(map[string]interface{}{
"type": "control_request",
"request_id": nextRequestID(),
"request": map[string]interface{}{
"subtype": "initialize",
},
})
// Wait for the control_response (init ack)
<-initDone
fmt.Printf("Initialized! session=%s\n", sessionID)
fmt.Println("Type a message and press Enter. 'quit' to exit.\n")
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("> ")
text, err := reader.ReadString('\n')
if err != nil {
break
}
text = strings.TrimSpace(text)
if text == "" {
continue
}
if text == "quit" || text == "exit" {
fmt.Println("Bye!")
break
}
sendJSON(map[string]interface{}{
"type": "user",
"session_id": sessionID,
"parent_tool_use_id": nil,
"message": map[string]interface{}{
"role": "user",
"content": text,
},
})
// Wait for the result message before accepting next input
<-turnDone
}
stdin.Close()
cmd.Wait()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment