Screens 2 and 3: new-task form, live log and diff; measured the merge gap they expose
This commit is contained in:
@@ -57,17 +57,104 @@ func New() (*Client, error) {
|
||||
func (c *Client) UsingUserKey() bool { return os.Getenv("PAPERCLIP_BOARD_KEY") != "" }
|
||||
|
||||
type Issue struct {
|
||||
ID string `json:"id"`
|
||||
Identifier string `json:"identifier"`
|
||||
Title string `json:"title"`
|
||||
Status string `json:"status"`
|
||||
Priority string `json:"priority"`
|
||||
ProjectID string `json:"projectId"`
|
||||
ParentID string `json:"parentId"`
|
||||
AssigneeAgent string `json:"assigneeAgentId"`
|
||||
AssigneeUser string `json:"assigneeUserId"`
|
||||
ExecutionState string `json:"-"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description"`
|
||||
Identifier string `json:"identifier"`
|
||||
Title string `json:"title"`
|
||||
Status string `json:"status"`
|
||||
Priority string `json:"priority"`
|
||||
ProjectID string `json:"projectId"`
|
||||
ParentID string `json:"parentId"`
|
||||
AssigneeAgent string `json:"assigneeAgentId"`
|
||||
AssigneeUser string `json:"assigneeUserId"`
|
||||
UpdatedAt string `json:"updatedAt"`
|
||||
|
||||
// Workspace is where Paperclip put this task's own copy of the code. It is
|
||||
// null when the instance does not make worktrees.
|
||||
Workspace *struct {
|
||||
CWD string `json:"cwd"`
|
||||
Branch string `json:"branchName"`
|
||||
BaseRef string `json:"baseRef"`
|
||||
Strategy string `json:"strategyType"`
|
||||
} `json:"currentExecutionWorkspace"`
|
||||
}
|
||||
|
||||
// Run is one heartbeat run: when it started, how it ended, what it cost.
|
||||
type Run struct {
|
||||
ID string `json:"runId"`
|
||||
Status string `json:"status"`
|
||||
Source string `json:"invocationSource"`
|
||||
AgentID string `json:"agentId"`
|
||||
StartedAt string `json:"startedAt"`
|
||||
FinishedAt string `json:"finishedAt"`
|
||||
ErrorCode string `json:"errorCode"`
|
||||
}
|
||||
|
||||
// Activity is one structural event on a task.
|
||||
type Activity struct {
|
||||
ID string `json:"id"`
|
||||
ActorType string `json:"actorType"`
|
||||
Action string `json:"action"`
|
||||
CreatedAt string `json:"createdAt"`
|
||||
}
|
||||
|
||||
// Runs returns a task's run history, newest first.
|
||||
func (c *Client) Runs(issueID string) ([]Run, error) {
|
||||
var out []Run
|
||||
err := c.do("GET", "/api/issues/"+issueID+"/runs", nil, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Activity returns a task's structural events, newest first.
|
||||
func (c *Client) Activity(issueID string) ([]Activity, error) {
|
||||
var out []Activity
|
||||
err := c.do("GET", "/api/issues/"+issueID+"/activity", nil, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// CreateTask creates a task, unassigned. Blockers are never accepted at
|
||||
// creation: they must be a separate call, or the write is ignored.
|
||||
type NewTask struct {
|
||||
Title string
|
||||
Description string
|
||||
ProjectID string
|
||||
}
|
||||
|
||||
func (c *Client) CreateTask(t NewTask) (Issue, error) {
|
||||
if !c.UsingUserKey() {
|
||||
return Issue{}, errors.New("refusing to write with the agent key: set PAPERCLIP_BOARD_KEY")
|
||||
}
|
||||
var out Issue
|
||||
body := map[string]any{
|
||||
"title": t.Title,
|
||||
"description": t.Description,
|
||||
"projectId": t.ProjectID,
|
||||
"status": "todo",
|
||||
}
|
||||
err := c.do("POST", "/api/companies/"+c.Company+"/issues", body, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// SetBlockers replaces a task's blocked-by list.
|
||||
func (c *Client) SetBlockers(issueID string, blockerIDs []string) (Issue, error) {
|
||||
if !c.UsingUserKey() {
|
||||
return Issue{}, errors.New("refusing to write with the agent key: set PAPERCLIP_BOARD_KEY")
|
||||
}
|
||||
var out Issue
|
||||
err := c.do("PATCH", "/api/issues/"+issueID, map[string]any{"blockedByIssueIds": blockerIDs}, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Assign gives a task to an agent. It is always a separate call from creation:
|
||||
// an assigned task is claimed by that agent's run within seconds, and the run
|
||||
// then owns the task's fields.
|
||||
func (c *Client) Assign(issueID, agentID string) (Issue, error) {
|
||||
if !c.UsingUserKey() {
|
||||
return Issue{}, errors.New("refusing to write with the agent key: set PAPERCLIP_BOARD_KEY")
|
||||
}
|
||||
var out Issue
|
||||
err := c.do("PATCH", "/api/issues/"+issueID, map[string]any{"assigneeAgentId": agentID}, &out)
|
||||
return out, err
|
||||
}
|
||||
|
||||
type Project struct {
|
||||
|
||||
Reference in New Issue
Block a user