opencode-cursor-agent/internal/server/mount_hints.go

61 lines
1.7 KiB
Go

package server
import (
"regexp"
"sort"
"strings"
"github.com/daniel/cursor-adapter/internal/types"
)
// Cowork-style mount path: /sessions/<adjective>-<adjective>-<color>/mnt/<folder>
// (and any deeper subpath; we capture only the mount root).
var mountPathRe = regexp.MustCompile(`/sessions/[a-z][a-z0-9]*(?:-[a-z][a-z0-9]*)+/mnt/[^\s/'"]+`)
// extractMountHints walks all prior tool_result blocks in the conversation
// and returns any Cowork-style /sessions/<id>/mnt/<folder> mount roots
// they reveal, deduped & sorted.
//
// This is purely stateless — we re-derive the set from the request body
// every turn. No server-side cache to invalidate, and it survives proxy
// restarts because the caller (Claude Desktop) replays the full history
// on each request anyway.
func extractMountHints(req types.AnthropicMessagesRequest) []string {
seen := map[string]struct{}{}
for _, m := range req.Messages {
for _, b := range m.Content {
if b.Type != "tool_result" {
continue
}
for _, p := range mountPathRe.FindAllString(renderToolResultContent(b.Content), -1) {
seen[p] = struct{}{}
}
}
}
if len(seen) == 0 {
return nil
}
out := make([]string, 0, len(seen))
for p := range seen {
out = append(out, p)
}
sort.Strings(out)
return out
}
// renderMountHints turns a list of mount roots into a prompt section the
// brain can refer to. Returns "" when there are no hints.
func renderMountHints(hints []string) string {
if len(hints) == 0 {
return ""
}
var b strings.Builder
b.WriteString("Known host-mount paths (discovered earlier in this conversation, prefer these for any host file work):\n")
for _, h := range hints {
b.WriteString("- ")
b.WriteString(h)
b.WriteByte('\n')
}
return b.String()
}