From 3896b3db434f4decb141efb48491a5faec7b6ed1 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Wed, 11 Mar 2026 09:07:05 +0100 Subject: [PATCH] Assist: add Comments view for beads; add read_bead_comments.sh tool --- cmd/Assist/main.go | 74 +++++++++++++++++++++++++++++++++- mcptools/read_bead_comments.sh | 17 ++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100755 mcptools/read_bead_comments.sh diff --git a/cmd/Assist/main.go b/cmd/Assist/main.go index 2eb531c..99c0703 100644 --- a/cmd/Assist/main.go +++ b/cmd/Assist/main.go @@ -2341,7 +2341,7 @@ func openViewBeadWindow(beadID string, mount string) error { } w.Name(fmt.Sprintf("/AnviLLM/Tasks/%s", beadID)) - w.Write("tag", []byte("Get Put New Blocks ")) + w.Write("tag", []byte("Get Put New Blocks Comments ")) go handleViewBeadWindow(w, beadID, mount) return nil @@ -2396,6 +2396,10 @@ func handleViewBeadWindow(w *acme.Win, beadID string, mount string) { } else if err := addBlocksDep(beadID, arg, mount); err != nil { fmt.Fprintf(os.Stderr, "Error adding blocks dep: %v\n", err) } + case "Comments": + if err := openCommentsWindow(beadID, mount); err != nil { + fmt.Fprintf(os.Stderr, "Error opening comments window: %v\n", err) + } default: w.WriteEvent(e) } @@ -2453,6 +2457,74 @@ func refreshViewBeadWindow(w *acme.Win, beadID string, mount string) { w.Ctl("show") } +func openCommentsWindow(beadID string, mount string) error { + w, err := acme.New() + if err != nil { + return err + } + w.Name(fmt.Sprintf("/AnviLLM/Tasks/%s/comments", beadID)) + w.Write("tag", []byte("Get ")) + + go handleCommentsWindow(w, beadID, mount) + return nil +} + +func handleCommentsWindow(w *acme.Win, beadID string, mount string) { + defer w.CloseFiles() + refreshCommentsWindow(w, beadID, mount) + + for e := range w.EventChan() { + switch e.C2 { + case 'x', 'X': + if string(e.Text) == "Get" { + refreshCommentsWindow(w, beadID, mount) + } else { + w.WriteEvent(e) + } + default: + w.WriteEvent(e) + } + } +} + +func refreshCommentsWindow(w *acme.Win, beadID string, mount string) { + data, err := readFile(filepath.Join("beads", mount, beadID, "comments")) + if err != nil { + w.Addr(",") + w.Write("data", []byte(fmt.Sprintf("Error reading comments: %v\n", err))) + w.Ctl("clean") + return + } + + var comments []struct { + Author string `json:"author"` + Body string `json:"body"` + CreatedAt string `json:"created_at"` + } + if err := json.Unmarshal(data, &comments); err != nil { + w.Addr(",") + w.Write("data", []byte(fmt.Sprintf("Error parsing comments: %v\n", err))) + w.Ctl("clean") + return + } + + var buf strings.Builder + if len(comments) == 0 { + buf.WriteString("No comments.\n") + } else { + for _, c := range comments { + buf.WriteString(fmt.Sprintf("--- %s (%s) ---\n%s\n\n", c.Author, c.CreatedAt, c.Body)) + } + } + + w.Addr(",") + w.Write("data", []byte(buf.String())) + w.Ctl("clean") + w.Addr("0") + w.Ctl("dot=addr") + w.Ctl("show") +} + func getBead(beadID string, mount string) (*Bead, error) { if !isConnected() { return nil, fmt.Errorf("not connected to anvilsrv") diff --git a/mcptools/read_bead_comments.sh b/mcptools/read_bead_comments.sh new file mode 100755 index 0000000..e91955c --- /dev/null +++ b/mcptools/read_bead_comments.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# capabilities: beads +# description: Read comments for a bead +# Usage: read_comments.sh +set -euo pipefail + +if cat /etc/shadow >/dev/null 2>&1; then + echo "Error: This script must be run via execute_code tool" >&2 + exit 1 +fi + +if [ $# -lt 2 ]; then + echo "usage: read_comments.sh " >&2 + exit 1 +fi + +9p read "agent/beads/$1/$2/comments" 2>/dev/null || echo "[]"