Instructions, output styles, skills, commands and subagents for every node or some reach every session as the mesh's own word, and the tools cannot tell an agent from the operator; the operator decided they are set at the terminal until a surface of their own updates them (hq issue 340). They are settings keys, each text a list of lines; the home scope stays free.
108 lines
3.3 KiB
Go
108 lines
3.3 KiB
Go
package main
|
|
|
|
// What a Claude Code session on the mesh runs or obeys, and where each came from (novox/hq issue 340): for the
|
|
// operator to review what is registered today, read-only.
|
|
|
|
import (
|
|
"encoding/json"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// ByIs says what a registration's `by` is: the node whose tool runner served the call, never the caller, whom the
|
|
// runner is not told.
|
|
const ByIs = "the node whose tool runner served the registering call; who called it was never recorded, because the runner is not told"
|
|
|
|
// Registrations is every registration on the mesh that reaches a session, read from the state, and what the
|
|
// operator set at the controller's terminal for this node: the tool servers (`servers`), the agent's
|
|
// configuration (`config`) with whether each is still rendered and, when not, why; and the `managed_settings`
|
|
// and `mcp_servers` this node's layers compose to.
|
|
func Registrations(p Paths, servers ServerState, config ConfigState) (map[string]any, error) {
|
|
serverKeys, err := servers.Keys()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sort.Strings(serverKeys)
|
|
registered := map[string]any{}
|
|
for _, key := range serverKeys {
|
|
raw, found, err := servers.Get(key)
|
|
if err != nil || !found {
|
|
continue
|
|
}
|
|
var entry map[string]any
|
|
if json.Unmarshal(raw, &entry) != nil {
|
|
continue
|
|
}
|
|
row := map[string]any{"entry": entry, "by": "not recorded: a tool server's registration kept only its entry"}
|
|
if _, name, ok := strings.Cut(key, "."); ok {
|
|
if problem := EntryProblem(name, entry); problem != "" {
|
|
row["rendered"] = "no: " + problem
|
|
} else {
|
|
row["rendered"] = "yes, on the nodes its key names"
|
|
}
|
|
}
|
|
registered[key] = row
|
|
}
|
|
|
|
configKeys, err := config.Keys()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sort.Strings(configKeys)
|
|
items := map[string]any{}
|
|
for _, key := range configKeys {
|
|
raw, found, err := config.Get(key)
|
|
if err != nil || !found {
|
|
continue
|
|
}
|
|
var it Item
|
|
if json.Unmarshal(raw, &it) != nil {
|
|
continue
|
|
}
|
|
_, node, _, _, ok := ParseKey(key)
|
|
if !ok {
|
|
continue
|
|
}
|
|
row := map[string]any{"kind": it.Kind, "scope": it.Scope, "by": it.By, "at": it.At}
|
|
files := make([]string, 0, len(it.Files))
|
|
for f := range it.Files {
|
|
files = append(files, f)
|
|
}
|
|
sort.Strings(files)
|
|
if len(files) > 0 {
|
|
row["files"] = files
|
|
}
|
|
switch it.Kind {
|
|
case KindHook:
|
|
row["event"], row["matcher"], row["command"] = it.Event, it.Matcher, it.Command
|
|
case KindSettings:
|
|
row["settings"] = it.Settings
|
|
}
|
|
switch problem := it.Problem(); {
|
|
case it.Key(node) != key:
|
|
row["rendered"] = "no: its key does not say what the item is"
|
|
case problem != "":
|
|
row["rendered"] = "no: " + problem
|
|
default:
|
|
row["rendered"] = "yes, as " + it.Scope + " " + it.Kind
|
|
}
|
|
items[key] = row
|
|
}
|
|
|
|
var settings Settings
|
|
_ = readJSON(p.Settings, &settings)
|
|
text, leftOut := terminalText(p)
|
|
shared := []string{}
|
|
for _, it := range text {
|
|
shared = append(shared, it.Kind+" "+it.Name)
|
|
}
|
|
return map[string]any{
|
|
"set at the controller's terminal, as this node composes it": map[string]any{
|
|
"managed_settings": settings.ManagedSettings, "mcp_servers": settings.MCPServers,
|
|
"shared text": shared, "shared text left out": leftOut},
|
|
"tool servers registered through this module": registered,
|
|
"configuration registered through this module": items,
|
|
"by": ByIs,
|
|
}, nil
|
|
}
|