Files
ely-eye/ely-eye-mcp/internal/store/proofs.go
T
ZacharyZhang-NY 4cd29f91e5 Add Ely-Eye MCP server
Local read-only Model Context Protocol server (Go) exposing the .ely_eye memory
store to coding agents such as Codex and Claude Code: nine tools over status,
cartridges, Evidence Atoms, compiled evidence packs, proof suites, and HashHop
proofs. One-line cross-platform install (no Docker), with a prebuilt-binary
release workflow.
2026-05-30 23:51:45 -04:00

105 lines
2.5 KiB
Go

package store
import (
"context"
"encoding/json"
"errors"
"os"
"path/filepath"
"sort"
"time"
"github.com/ZacharyZhang-NY/ely-eye/ely-eye-mcp/internal/domain"
)
type proofDir struct {
name string
modTime time.Time
}
func (s *Store) ListProofSuites(ctx context.Context, limit int, includePayload bool) ([]domain.ProofSuite, error) {
if err := ctx.Err(); err != nil {
return nil, err
}
if limit <= 0 || limit > 100 {
limit = 20
}
root := filepath.Join(s.cfg.ElyEyeHome, "data", "eval_proofs")
entries, err := os.ReadDir(root)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return []domain.ProofSuite{}, nil
}
return nil, err
}
dirs := sortedProofDirs(entries)
proofs := make([]domain.ProofSuite, 0, limit)
for _, dir := range dirs {
if err := ctx.Err(); err != nil {
return nil, err
}
path := filepath.Join(root, dir.name, "proof_suite.json")
data, err := os.ReadFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
continue
}
return nil, err
}
var header struct {
ProofID string `json:"proof_id"`
CartridgeID string `json:"cartridge_id"`
Status string `json:"status"`
CreatedAt string `json:"created_at"`
}
if err := json.Unmarshal(data, &header); err != nil {
return nil, err
}
proof := domain.ProofSuite{
ProofID: header.ProofID,
CartridgeID: header.CartridgeID,
Status: header.Status,
CreatedAt: header.CreatedAt,
Path: path,
}
if includePayload {
value, err := readJSONValue(data)
if err != nil {
return nil, err
}
proof.Payload = value
}
proofs = append(proofs, proof)
if len(proofs) == limit {
break
}
}
return proofs, nil
}
// sortedProofDirs resolves each directory's mod time once and orders newest
// first. The store mutates underneath the read-only server, so a directory may
// be removed between ReadDir and Info; an Info error yields a zero time that
// sorts last rather than dereferencing a nil FileInfo. Names break ties for a
// stable order.
func sortedProofDirs(entries []os.DirEntry) []proofDir {
dirs := make([]proofDir, 0, len(entries))
for _, entry := range entries {
if !entry.IsDir() {
continue
}
modTime := time.Time{}
if info, err := entry.Info(); err == nil {
modTime = info.ModTime()
}
dirs = append(dirs, proofDir{name: entry.Name(), modTime: modTime})
}
sort.Slice(dirs, func(i int, j int) bool {
if !dirs[i].modTime.Equal(dirs[j].modTime) {
return dirs[i].modTime.After(dirs[j].modTime)
}
return dirs[i].name < dirs[j].name
})
return dirs
}