Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b350fe967 | |||
| 1d770b45c9 |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*.exe
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
74
main.go
74
main.go
@@ -69,10 +69,11 @@ func main() {
|
|||||||
debugLog("Connecting to: %s", giteaURL)
|
debugLog("Connecting to: %s", giteaURL)
|
||||||
|
|
||||||
// Read JSON-RPC messages from stdin, forward to Gitea, write responses to stdout
|
// Read JSON-RPC messages from stdin, forward to Gitea, write responses to stdout
|
||||||
|
// Supports both raw JSON lines and Content-Length framed messages (Claude Code uses framing)
|
||||||
reader := bufio.NewReader(os.Stdin)
|
reader := bufio.NewReader(os.Stdin)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
line, err := reader.ReadBytes('\n')
|
line, err := readMessage(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
debugLog("EOF received, exiting")
|
debugLog("EOF received, exiting")
|
||||||
@@ -109,8 +110,8 @@ func main() {
|
|||||||
|
|
||||||
debugLog("Response: %s", string(response))
|
debugLog("Response: %s", string(response))
|
||||||
|
|
||||||
// Write response to stdout
|
// Write response to stdout with Content-Length framing
|
||||||
fmt.Println(string(response))
|
writeFramed(response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,9 +148,74 @@ func forwardToGitea(request []byte) ([]byte, error) {
|
|||||||
return body, nil
|
return body, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readMessage reads a JSON-RPC message from stdin.
|
||||||
|
// Handles both raw JSON lines and Content-Length framed messages.
|
||||||
|
// Claude Code sends: Content-Length: N\r\n\r\n{json}
|
||||||
|
func readMessage(reader *bufio.Reader) ([]byte, error) {
|
||||||
|
// Peek at first bytes to detect format
|
||||||
|
for {
|
||||||
|
line, err := reader.ReadBytes('\n')
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
trimmed := bytes.TrimSpace(line)
|
||||||
|
if len(trimmed) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it starts with '{', it's a raw JSON line
|
||||||
|
if trimmed[0] == '{' {
|
||||||
|
return trimmed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it starts with "Content-Length:", read the framed message
|
||||||
|
if bytes.HasPrefix(bytes.ToLower(trimmed), []byte("content-length:")) {
|
||||||
|
// Parse content length
|
||||||
|
parts := bytes.SplitN(trimmed, []byte(":"), 2)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lengthStr := bytes.TrimSpace(parts[1])
|
||||||
|
var contentLength int
|
||||||
|
fmt.Sscanf(string(lengthStr), "%d", &contentLength)
|
||||||
|
if contentLength <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read until empty line (end of headers)
|
||||||
|
for {
|
||||||
|
headerLine, err := reader.ReadBytes('\n')
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(bytes.TrimSpace(headerLine)) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read exactly contentLength bytes
|
||||||
|
body := make([]byte, contentLength)
|
||||||
|
_, err := io.ReadFull(reader, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("read body: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown line, skip
|
||||||
|
debugLog("Skipping unknown line: %s", string(trimmed))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func writeResponse(resp interface{}) {
|
func writeResponse(resp interface{}) {
|
||||||
data, _ := json.Marshal(resp)
|
data, _ := json.Marshal(resp)
|
||||||
fmt.Println(string(data))
|
writeFramed(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeFramed(data []byte) {
|
||||||
|
fmt.Fprintf(os.Stdout, "Content-Length: %d\r\n\r\n%s", len(data), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func debugLog(format string, args ...interface{}) {
|
func debugLog(format string, args ...interface{}) {
|
||||||
|
|||||||
Reference in New Issue
Block a user