Why: The library had no process entry, and the product backend still called the loop directly. Evidence: go test -count=1 ./... Impact: exec.Backend keeps the same request and result. Execute now goes through AgentSession. Extensions and packages are not a sandbox. Refs: feature/pi-headless N6 N7 Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
1.1 KiB
Go
55 lines
1.1 KiB
Go
package rpc
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"encoding/json"
|
|
"io"
|
|
)
|
|
|
|
// Client is the Go SDK for the JSONL RPC mode.
|
|
type Client struct {
|
|
in io.Writer
|
|
out *bufio.Reader
|
|
}
|
|
|
|
// NewClient wraps a bidirectional pipe. Commands are one JSON object per line.
|
|
func NewClient(in io.Writer, out io.Reader) *Client {
|
|
return &Client{in: in, out: bufio.NewReader(out)}
|
|
}
|
|
|
|
// Call sends one command and reads the matching response.
|
|
func (c *Client) Call(ctx context.Context, req Request) (Response, error) {
|
|
raw, err := json.Marshal(req)
|
|
if err != nil {
|
|
return Response{}, err
|
|
}
|
|
if _, err := c.in.Write(append(raw, '\n')); err != nil {
|
|
return Response{}, err
|
|
}
|
|
type result struct {
|
|
resp Response
|
|
err error
|
|
}
|
|
ch := make(chan result, 1)
|
|
go func() {
|
|
line, err := c.out.ReadBytes('\n')
|
|
if err != nil {
|
|
ch <- result{err: err}
|
|
return
|
|
}
|
|
var resp Response
|
|
if err := json.Unmarshal(line, &resp); err != nil {
|
|
ch <- result{err: err}
|
|
return
|
|
}
|
|
ch <- result{resp: resp}
|
|
}()
|
|
select {
|
|
case <-ctx.Done():
|
|
return Response{}, ctx.Err()
|
|
case got := <-ch:
|
|
return got.resp, got.err
|
|
}
|
|
}
|