diff --git a/anvillm b/anvillm new file mode 100755 index 0000000..06ac269 Binary files /dev/null and b/anvillm differ diff --git a/anvilwebgw b/anvilwebgw new file mode 100755 index 0000000..f7d35a0 Binary files /dev/null and b/anvilwebgw differ diff --git a/cmd/Assist/main.go b/cmd/Assist/main.go index 8d424b0..9c35351 100644 --- a/cmd/Assist/main.go +++ b/cmd/Assist/main.go @@ -1334,7 +1334,7 @@ func openArchiveWindow(owner, date string) error { } else { w.Name(fmt.Sprintf("/AnviLLM/%s/archive", owner)) } - w.Write("tag", []byte("Get ")) + w.Write("tag", []byte("Get Search ")) go handleArchiveWindow(w, owner, date) return nil @@ -1357,7 +1357,9 @@ func handleArchiveWindow(w *acme.Win, owner, date string) { for e := range w.EventChan() { switch e.C2 { case 'x', 'X': - switch string(e.Text) { + cmd := string(e.Text) + arg := strings.TrimSpace(string(e.Arg)) + switch cmd { case "Get": // Re-read date from window name tag, _ := w.ReadAll("tag") @@ -1369,6 +1371,50 @@ func handleArchiveWindow(w *acme.Win, owner, date string) { messages, _, loadErr = listMessages(owner + "/completed") } refreshArchiveWindowWithMessages(w, messages, owner, date, loadErr) + case "Search": + if arg == "" { + w.WriteEvent(e) + continue + } + out, err := exec.Command("bash", "-c", fmt.Sprintf("bash <(9p read anvillm/tools/mail_search.sh) --agent-id user --pattern %q", arg)).CombinedOutput() + if err != nil { + w.Addr(",") + w.Write("data", []byte(fmt.Sprintf("Search error: %v\n%s", err, out))) + w.Ctl("clean") + continue + } + var searchResults []Message + for _, line := range strings.Split(string(out), "\n") { + line = strings.TrimSpace(line) + if line == "" { + continue + } + var entry struct { + Ts int64 `json:"ts"` + Data struct { + ID string `json:"id"` + From string `json:"from"` + To string `json:"to"` + Type string `json:"type"` + Subject string `json:"subject"` + Body string `json:"body"` + } `json:"data"` + } + if err := json.Unmarshal([]byte(line), &entry); err != nil { + continue + } + searchResults = append(searchResults, Message{ + ID: entry.Data.ID, + From: entry.Data.From, + To: entry.Data.To, + Type: entry.Data.Type, + Subject: entry.Data.Subject, + Body: entry.Data.Body, + Timestamp: entry.Ts, + }) + } + messages = searchResults + refreshArchiveWindowWithMessages(w, messages, owner, "", nil) default: w.WriteEvent(e) } diff --git a/mcptools/mail_history.sh b/mcptools/mail_history.sh index 94cd613..fc49b62 100755 --- a/mcptools/mail_history.sh +++ b/mcptools/mail_history.sh @@ -38,8 +38,4 @@ if [[ ${#FILES[@]} -eq 0 ]]; then exit 0 fi -cat "${FILES[@]}" | jq -rs 'sort_by(.ts) | .[] | -"\(.ts | strftime("%Y-%m-%d %H:%M:%S")) [\(.data.type)] \(.data.from) → \(.data.to) - Subject: \(.data.subject) - \(.data.body | split("\n") | join("\n ")) -"' +cat "${FILES[@]}" | jq -cs 'sort_by(.ts) | .[]' diff --git a/mcptools/mail_search.sh b/mcptools/mail_search.sh index 17c415d..dba203e 100755 --- a/mcptools/mail_search.sh +++ b/mcptools/mail_search.sh @@ -21,7 +21,22 @@ if [[ -z "$AGENT_ID" ]] || [[ -z "$PATTERN" ]]; then exit 1 fi -DATE_FLAG="" -[[ -n "$DATE" ]] && DATE_FLAG="--date $DATE" +MAIL_DIR="$HOME/.local/share/anvillm/mail/$AGENT_ID" -bash <(9p read anvillm/tools/mail_history.sh) --agent-id "$AGENT_ID" $DATE_FLAG | grep -E "$PATTERN" +shopt -s nullglob +if [[ -n "$DATE" ]]; then + SENT="$MAIL_DIR/${DATE}-sent.jsonl" + RECV="$MAIL_DIR/${DATE}-recv.jsonl" + FILES=() + [[ -f "$SENT" ]] && FILES+=("$SENT") + [[ -f "$RECV" ]] && FILES+=("$RECV") +else + FILES=("$MAIL_DIR"/*-sent.jsonl "$MAIL_DIR"/*-recv.jsonl) +fi +shopt -u nullglob + +if [[ ${#FILES[@]} -eq 0 ]]; then + exit 0 +fi + +cat "${FILES[@]}" | grep -E "$PATTERN"