diff --git a/cmd/Assist/main.go b/cmd/Assist/main.go index ff5cd7e..ab4f6da 100644 --- a/cmd/Assist/main.go +++ b/cmd/Assist/main.go @@ -2301,7 +2301,7 @@ func openViewBeadWindow(beadID string, mount string) error { } w.Name(fmt.Sprintf("/AnviLLM/Tasks/%s", beadID)) - w.Write("tag", []byte("Get Put New Blocks Comments ")) + w.Write("tag", []byte("Get Put New Blocks Comments Comment ")) go handleViewBeadWindow(w, beadID, mount) return nil @@ -2360,6 +2360,10 @@ func handleViewBeadWindow(w *acme.Win, beadID string, mount string) { if err := openCommentsWindow(beadID, mount); err != nil { fmt.Fprintf(os.Stderr, "Error opening comments window: %v\n", err) } + case "Comment": + if err := openCommentWindow(beadID, mount); err != nil { + fmt.Fprintf(os.Stderr, "Error opening comment window: %v\n", err) + } default: w.WriteEvent(e) } @@ -2429,6 +2433,50 @@ func openCommentsWindow(beadID string, mount string) error { return nil } +func openCommentWindow(beadID string, mount string) error { + w, err := acme.New() + if err != nil { + return err + } + w.Name(fmt.Sprintf("/AnviLLM/Tasks/%s/comment", beadID)) + w.Write("tag", []byte("Put ")) + + go handleCommentWindow(w, beadID, mount) + return nil +} + +func handleCommentWindow(w *acme.Win, beadID string, mount string) { + defer w.CloseFiles() + for e := range w.EventChan() { + switch e.C2 { + case 'x', 'X': + if string(e.Text) == "Put" { + body, err := w.ReadAll("body") + if err != nil { + fmt.Fprintf(os.Stderr, "Error reading body: %v\n", err) + continue + } + text := strings.TrimSpace(string(body)) + if text == "" { + continue + } + cmd := fmt.Sprintf("comment %s '%s'", beadID, text) + if err := writeFile(filepath.Join("beads", mount, "ctl"), []byte(cmd)); err != nil { + fmt.Fprintf(os.Stderr, "Error adding comment: %v\n", err) + } else { + w.Addr(",") + w.Write("data", nil) + w.Ctl("clean") + } + } else { + w.WriteEvent(e) + } + default: + w.WriteEvent(e) + } + } +} + func handleCommentsWindow(w *acme.Win, beadID string, mount string) { defer w.CloseFiles() refreshCommentsWindow(w, beadID, mount) @@ -2458,7 +2506,7 @@ func refreshCommentsWindow(w *acme.Win, beadID string, mount string) { var comments []struct { Author string `json:"author"` - Body string `json:"body"` + Text string `json:"text"` CreatedAt string `json:"created_at"` } if err := json.Unmarshal(data, &comments); err != nil { @@ -2473,7 +2521,7 @@ func refreshCommentsWindow(w *acme.Win, beadID string, mount string) { 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)) + buf.WriteString(fmt.Sprintf("--- %s (%s) ---\n%s\n\n", c.Author, c.CreatedAt, c.Text)) } } diff --git a/internal/p9/beads.go b/internal/p9/beads.go index 207b020..29c3b5e 100644 --- a/internal/p9/beads.go +++ b/internal/p9/beads.go @@ -16,6 +16,7 @@ import ( "time" bd "github.com/steveyegge/beads" + "github.com/google/uuid" "go.uber.org/zap" ) @@ -337,7 +338,7 @@ func (b *BeadsFS) Write(path string, data []byte, sessionID string) error { return fmt.Errorf("usage: mount [name]") } cwd := args[0] - name := filepath.Base(cwd) + name := uuid.New().String()[:8] if len(args) >= 2 { name = args[1] } diff --git a/scripts/anvillm-supervisor b/scripts/anvillm-supervisor old mode 100644 new mode 100755 index de1eda7..5072e77 --- a/scripts/anvillm-supervisor +++ b/scripts/anvillm-supervisor @@ -1,27 +1,43 @@ #!/bin/bash -# Periodic worker health check: orphan bead recovery and idle worker nudging. -# Usage: anvillm-worker-check [--orphans] [--nudge] +# Periodic worker health check: orphan bead recovery, idle worker nudging, auto-mount. +# Usage: anvillm-supervisor [--orphans] [--nudge] [--auto-mount ] set -euo pipefail -LOG_PREFIX="[worker-check $(date '+%Y-%m-%d %H:%M:%S')]" +LOG_PREFIX="[supervisor $(date '+%Y-%m-%d %H:%M:%S')]" log() { echo "$LOG_PREFIX $*"; } DO_ORPHANS=0 DO_NUDGE=0 +AUTO_MOUNT_DIR="" while [[ $# -gt 0 ]]; do case "$1" in --orphans) DO_ORPHANS=1; shift ;; --nudge) DO_NUDGE=1; shift ;; + --auto-mount) AUTO_MOUNT_DIR="$2"; shift 2 ;; *) echo "unknown argument: $1" >&2; exit 1 ;; esac done -if [ "$DO_ORPHANS" -eq 0 ] && [ "$DO_NUDGE" -eq 0 ]; then - echo "usage: anvillm-worker-check [--orphans] [--nudge]" >&2 +if [ "$DO_ORPHANS" -eq 0 ] && [ "$DO_NUDGE" -eq 0 ] && [ -z "$AUTO_MOUNT_DIR" ]; then + echo "usage: anvillm-supervisor [--orphans] [--nudge] [--auto-mount ]" >&2 exit 1 fi +# --- Auto-mount beads for workdir --- +if [ -n "$AUTO_MOUNT_DIR" ]; then + MTAB=$(9p read anvillm/beads/mtab 2>/dev/null || true) + EXISTING=$(echo "$MTAB" | awk -F'\t' -v dir="$AUTO_MOUNT_DIR" '$2 == dir {print $1; exit}') + if [ -n "$EXISTING" ]; then + echo "error: already mounted as $EXISTING" >&2 + exit 1 + fi + echo "mount $AUTO_MOUNT_DIR" | 9p write anvillm/beads/ctl + # Read back the mount name from mtab + 9p read anvillm/beads/mtab 2>/dev/null | awk -F'\t' -v dir="$AUTO_MOUNT_DIR" '$2 == dir {print $1; exit}' + exit 0 +fi + SESSIONS=$(9p read anvillm/list 2>/dev/null || true) # --- Orphan recovery ---