feat(tui-go): idea board viewer
OverlayIdeas (opened with I, global/cross-session) lists the idea board in the artifact-viewer shell: ↑↓ to move, x/d to remove (sends DiscardIdea, optimistic drop), esc to close. Pull-based via ListIdeas -> idea.list.
This commit is contained in:
@@ -149,6 +149,21 @@ func TestDecodeGoldenServerFrames(t *testing.T) {
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "idea.list carries the cross-session board",
|
||||
json: `{"type":"idea.list","ideas":[{"ideaId":"i1","text":"cache the repo map","capturedAtMs":1000},` +
|
||||
`{"ideaId":"i2","text":"add --dry-run","capturedAtMs":2000}]}`,
|
||||
wantType: TypeIdeaList,
|
||||
eventBear: false,
|
||||
check: func(t *testing.T, m ServerMessage) {
|
||||
if len(m.Ideas) != 2 {
|
||||
t.Fatalf("idea.list ideas: %+v", m.Ideas)
|
||||
}
|
||||
if m.Ideas[0].IdeaID != "i1" || m.Ideas[0].Text != "cache the repo map" || m.Ideas[0].CapturedAtMs != 1000 {
|
||||
t.Fatalf("idea.list idea[0]: %+v", m.Ideas[0])
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "workflow.proposed carries candidate workflows",
|
||||
json: `{"type":"workflow.proposed","sessionId":"s1","proposalId":"prop-1","prompt":"Run one?",` +
|
||||
@@ -233,6 +248,16 @@ func TestEncodeGoldenClientFrames(t *testing.T) {
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DiscardIdea carries the ideaId",
|
||||
frame: DiscardIdea("i1"),
|
||||
wantType: clientPrefix + "DiscardIdea",
|
||||
check: func(t *testing.T, raw map[string]any) {
|
||||
if raw["ideaId"] != "i1" {
|
||||
t.Fatalf("DiscardIdea ideaId: %+v", raw)
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ClarificationResponse carries ids + answers",
|
||||
frame: ClarificationResponse("s1", "analyst", "req-1",
|
||||
|
||||
@@ -54,6 +54,7 @@ const (
|
||||
TypeArtifactList = "artifact.list"
|
||||
TypeConfigSnapshot = "config.snapshot"
|
||||
TypeSessionStats = "session.stats"
|
||||
TypeIdeaList = "idea.list"
|
||||
)
|
||||
|
||||
// ServerMessage is a flat decode of every server->client variant. Field names
|
||||
@@ -146,6 +147,16 @@ type ServerMessage struct {
|
||||
Prompt string `json:"prompt"`
|
||||
OriginalRequest string `json:"originalRequest"`
|
||||
Candidates []ProposedWorkflowDto `json:"candidates"`
|
||||
|
||||
// idea.list — the cross-session idea board
|
||||
Ideas []IdeaDto `json:"ideas"`
|
||||
}
|
||||
|
||||
// IdeaDto is one idea on the cross-session board. Mirrors the Kotlin IdeaDto.
|
||||
type IdeaDto struct {
|
||||
IdeaID string `json:"ideaId"`
|
||||
Text string `json:"text"`
|
||||
CapturedAtMs int64 `json:"capturedAtMs"`
|
||||
}
|
||||
|
||||
// ProposedWorkflowDto is one candidate workflow the router suggests, with a short
|
||||
@@ -385,6 +396,16 @@ func GetConfig() []byte {
|
||||
return encode("GetConfig", map[string]any{})
|
||||
}
|
||||
|
||||
// ListIdeas requests the cross-session idea board (replied to with an idea.list).
|
||||
func ListIdeas() []byte {
|
||||
return encode("ListIdeas", map[string]any{})
|
||||
}
|
||||
|
||||
// DiscardIdea removes an idea from the board (server tombstones it; replies with a fresh idea.list).
|
||||
func DiscardIdea(ideaID string) []byte {
|
||||
return encode("DiscardIdea", map[string]any{"ideaId": ideaID})
|
||||
}
|
||||
|
||||
// UpdateConfig asks the server to apply and persist a config patch (key -> string value).
|
||||
func UpdateConfig(patch map[string]string) []byte {
|
||||
return encode("UpdateConfig", map[string]any{"patch": patch})
|
||||
|
||||
Reference in New Issue
Block a user