package cli import ( "encoding/json" "iop/apps/node/internal/runtime" ) // --- claude-json emitter --- type claudeJSONEmitter struct{} func (claudeJSONEmitter) Name() string { return "claude-json" } func (e claudeJSONEmitter) Emit(line string) ([]runtime.RuntimeEvent, error) { var ev struct { Type string `json:"type"` Event struct { Type string `json:"type"` Delta struct { Type string `json:"type"` Text string `json:"text"` } `json:"delta"` } `json:"event"` IsError bool `json:"is_error"` Result string `json:"result"` } if err := json.Unmarshal([]byte(line), &ev); err != nil { return nil, nil } switch ev.Type { case "stream_event": if ev.Event.Type == "content_block_delta" && ev.Event.Delta.Type == "text_delta" && ev.Event.Delta.Text != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeDelta, Delta: ev.Event.Delta.Text, }}, nil } return nil, nil case "result": if ev.IsError && ev.Result != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeError, Error: ev.Result, }}, nil } return nil, nil } return nil, nil } // --- codex-json emitter --- type codexJSONEmitter struct{} func (codexJSONEmitter) Name() string { return "codex-json" } func (e codexJSONEmitter) Emit(line string) ([]runtime.RuntimeEvent, error) { var ev struct { Type string `json:"type"` Item struct { Type string `json:"type"` Text string `json:"text"` Delta string `json:"delta"` Message struct { Content []struct { Type string `json:"type"` Text string `json:"text"` } `json:"content"` } `json:"message"` } `json:"item"` Delta string `json:"delta"` Text string `json:"text"` Message string `json:"message"` Error struct { Message string `json:"message"` } `json:"error"` Content []struct { Type string `json:"type"` Text string `json:"text"` } `json:"content"` } if err := json.Unmarshal([]byte(line), &ev); err != nil { return nil, nil } switch ev.Type { case "item.delta", "item.updated", "response.output_text.delta", "output_text.delta": if delta := codexDeltaText(ev); delta != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeDelta, Delta: delta, }}, nil } return nil, nil case "item.completed": if ev.Item.Type == "agent_message" && ev.Item.Text != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeDelta, Delta: ev.Item.Text, }}, nil } if delta := codexDeltaText(ev); delta != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeDelta, Delta: delta, }}, nil } return nil, nil case "error": return []runtime.RuntimeEvent{{ Type: runtime.EventTypeError, Error: ev.Message, }}, nil case "turn.failed": return []runtime.RuntimeEvent{{ Type: runtime.EventTypeError, Error: ev.Error.Message, }}, nil } return nil, nil } func codexDeltaText(ev struct { Type string `json:"type"` Item struct { Type string `json:"type"` Text string `json:"text"` Delta string `json:"delta"` Message struct { Content []struct { Type string `json:"type"` Text string `json:"text"` } `json:"content"` } `json:"message"` } `json:"item"` Delta string `json:"delta"` Text string `json:"text"` Message string `json:"message"` Error struct { Message string `json:"message"` } `json:"error"` Content []struct { Type string `json:"type"` Text string `json:"text"` } `json:"content"` }) string { if ev.Item.Delta != "" { return ev.Item.Delta } if ev.Delta != "" { return ev.Delta } if ev.Text != "" { return ev.Text } for _, part := range ev.Item.Message.Content { if part.Type == "output_text" && part.Text != "" { return part.Text } } for _, part := range ev.Content { if part.Type == "output_text" && part.Text != "" { return part.Text } } return "" } // --- opencode-json emitter --- type opencodeJSONEmitter struct{} func (opencodeJSONEmitter) Name() string { return "opencode-json" } func (e opencodeJSONEmitter) Emit(line string) ([]runtime.RuntimeEvent, error) { var ev struct { Type string `json:"type"` Error struct { Name string `json:"name"` Data struct { Message string `json:"message"` } `json:"data"` } `json:"error"` Part struct { Type string `json:"type"` Text string `json:"text"` } `json:"part"` } if err := json.Unmarshal([]byte(line), &ev); err != nil { return nil, nil } switch ev.Type { case "text": if ev.Part.Type == "text" && ev.Part.Text != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeDelta, Delta: ev.Part.Text, }}, nil } return nil, nil case "error": msg := ev.Error.Data.Message if msg == "" { msg = ev.Error.Name } if msg != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeError, Error: msg, }}, nil } return nil, nil } return nil, nil } // --- cline-json emitter --- type clineJSONEmitter struct{} func (clineJSONEmitter) Name() string { return "cline-json" } func (e clineJSONEmitter) Emit(line string) ([]runtime.RuntimeEvent, error) { var ev struct { Type string `json:"type"` Say string `json:"say"` Ask string `json:"ask"` Text string `json:"text"` Message string `json:"message"` Status string `json:"status"` Error string `json:"error"` } if err := json.Unmarshal([]byte(line), &ev); err != nil { return nil, nil } switch { case ev.Type == "say" && ev.Say == "text" && ev.Text != "": return []runtime.RuntimeEvent{{ Type: runtime.EventTypeDelta, Delta: ev.Text, }}, nil case ev.Type == "say" && ev.Say == "error": msg := ev.Text if msg == "" { msg = ev.Message } if msg != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeError, Error: msg, }}, nil } return nil, nil case ev.Type == "completion" && ev.Status == "error": msg := ev.Error if msg == "" { msg = ev.Message } if msg == "" { msg = "cline task failed" } return []runtime.RuntimeEvent{{ Type: runtime.EventTypeError, Error: msg, }}, nil case ev.Type == "ask" && ev.Ask == "api_req_failed": msg := ev.Text if msg == "" { msg = ev.Message } if msg != "" { return []runtime.RuntimeEvent{{ Type: runtime.EventTypeError, Error: msg, }}, nil } return nil, nil } return nil, nil }