update the archive options
This commit is contained in:
81
go-api/internal/definition/curated.go
Normal file
81
go-api/internal/definition/curated.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package definition
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CuratedIDs reads the agent specs that ship with the deployment and returns
|
||||
// the set of definition ids they declare.
|
||||
//
|
||||
// # WHY THIS EXISTS
|
||||
//
|
||||
// An agent is "built-in" when the product ships its spec. There is no column
|
||||
// saying so and deliberately none is added here: `importagents` publishes these
|
||||
// same files into `agent_definitions` as ordinary `organization` rows, so a
|
||||
// curated agent and a tenant-authored shared agent are indistinguishable in the
|
||||
// table. The distinguishing fact lives on disk, in the directory the importer
|
||||
// publishes FROM — which is the same fact the frontend uses, where `isShipped`
|
||||
// tests membership of the ids bundled from `src/agents/**/*.md`.
|
||||
//
|
||||
// Reading the directory rather than listing ids in configuration keeps the
|
||||
// protected set and the published set the same set by construction. Adding a
|
||||
// ninth agent protects it; removing one stops protecting it; neither needs a
|
||||
// code change, and neither can drift.
|
||||
//
|
||||
// The ids are parsed out of the frontmatter with the same parser the importer
|
||||
// uses, NOT taken from the filename. A file named `analytics-agent.md` whose
|
||||
// frontmatter says `id: analytics` publishes as `analytics`, and protecting the
|
||||
// filename would protect nothing.
|
||||
//
|
||||
// A missing directory returns an empty set and no error: development checkouts
|
||||
// and test binaries run from working directories that have no `agents/`, and
|
||||
// this is a protection list rather than something to serve from. A directory
|
||||
// that exists but holds a spec that will not parse IS an error — that same file
|
||||
// would fail the importer, and staying quiet about it would leave an agent
|
||||
// unprotected for a reason nobody could see.
|
||||
func CuratedIDs(dir string) (map[string]bool, error) {
|
||||
entries, err := os.ReadDir(dir)
|
||||
if os.IsNotExist(err) {
|
||||
return map[string]bool{}, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read curated agents in %s: %w", dir, err)
|
||||
}
|
||||
|
||||
ids := make(map[string]bool, len(entries))
|
||||
for _, e := range entries {
|
||||
name := e.Name()
|
||||
// README.md is documentation, not a spec — skipped by name, the same
|
||||
// way cmd/importagents skips it, so that a parse failure always means
|
||||
// something is actually wrong.
|
||||
if e.IsDir() || !strings.HasSuffix(name, ".md") || name == "README.md" {
|
||||
continue
|
||||
}
|
||||
raw, err := os.ReadFile(filepath.Join(dir, name))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read %s: %w", name, err)
|
||||
}
|
||||
parsed, err := ParseAgent(string(raw), Options{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", name, err)
|
||||
}
|
||||
if parsed.ID != "" {
|
||||
ids[parsed.ID] = true
|
||||
}
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
// SortedIDs renders a set as a stable list, for logging.
|
||||
func SortedIDs(set map[string]bool) []string {
|
||||
out := make([]string, 0, len(set))
|
||||
for id := range set {
|
||||
out = append(out, id)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user