claude-code: set shared agent text at the controller's terminal, for now
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.
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
package main
|
||||
|
||||
// The shared text the operator sets at the controller's terminal (novox/hq issue 340, the operator's decision of
|
||||
// 2026-10-09): instruction sections, output styles, skills, commands and subagents for every node or some. They are
|
||||
// keys of this module's settings, which the controller takes at its terminal alone. A setting holds no line break
|
||||
// (issue 339), so each text is a list of its lines; a one-line text may be a string.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Lines is a text as a setting holds it: a list of its lines, or one line as a string.
|
||||
type Lines string
|
||||
|
||||
// UnmarshalJSON takes a string or a list of strings, joined by line breaks.
|
||||
func (l *Lines) UnmarshalJSON(raw []byte) error {
|
||||
var one string
|
||||
if json.Unmarshal(raw, &one) == nil {
|
||||
*l = Lines(one)
|
||||
return nil
|
||||
}
|
||||
var many []string
|
||||
if err := json.Unmarshal(raw, &many); err != nil {
|
||||
return errors.New("a text is a list of its lines, or one line")
|
||||
}
|
||||
*l = Lines(strings.Join(many, "\n") + "\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
// SharedText is the text keys of this module's settings.
|
||||
type SharedText struct {
|
||||
Instructions map[string]Lines `json:"instructions"`
|
||||
OutputStyles map[string]Lines `json:"output_styles"`
|
||||
Agents map[string]Lines `json:"agents"`
|
||||
Commands map[string]Lines `json:"commands"`
|
||||
Skills map[string]map[string]Lines `json:"skills"`
|
||||
}
|
||||
|
||||
// TerminalItems are the items the operator's settings hold, as the plugin and the instruction file take them, and
|
||||
// what was left out and why: an item that is not well formed (a name, a path, a skill without its SKILL.md). What
|
||||
// the text asks of a session is the operator's to say there, so it is not judged.
|
||||
func TerminalItems(text SharedText) ([]Item, []string) {
|
||||
var out []Item
|
||||
var left []string
|
||||
add := func(it Item) {
|
||||
it.Scope, it.By = ScopeMesh, "the controller's terminal"
|
||||
if problem := it.shapeProblem(); problem != "" {
|
||||
left = append(left, it.Kind+" "+it.Name+": "+problem)
|
||||
return
|
||||
}
|
||||
out = append(out, it)
|
||||
}
|
||||
for kind, texts := range map[string]map[string]Lines{KindInstructions: text.Instructions,
|
||||
KindOutputStyle: text.OutputStyles, KindAgent: text.Agents, KindCommand: text.Commands} {
|
||||
for name, body := range texts {
|
||||
add(Item{Kind: kind, Name: name, Files: map[string]string{name + ".md": string(body)}})
|
||||
}
|
||||
}
|
||||
for name, files := range text.Skills {
|
||||
it := Item{Kind: KindSkill, Name: name, Files: map[string]string{}}
|
||||
for rel, body := range files {
|
||||
it.Files[rel] = string(body)
|
||||
}
|
||||
add(it)
|
||||
}
|
||||
sort.Slice(out, func(i, j int) bool {
|
||||
if out[i].Kind != out[j].Kind {
|
||||
return out[i].Kind < out[j].Kind
|
||||
}
|
||||
return out[i].Name < out[j].Name
|
||||
})
|
||||
sort.Strings(left)
|
||||
return out, left
|
||||
}
|
||||
|
||||
// terminalText reads the shared text from this module's settings file.
|
||||
func terminalText(p Paths) ([]Item, []string) {
|
||||
var text SharedText
|
||||
if raw, err := os.ReadFile(p.Settings); err == nil {
|
||||
if err := json.Unmarshal(raw, &text); err != nil {
|
||||
return nil, []string{"the shared text in this module's settings could not be read: " + err.Error()}
|
||||
}
|
||||
}
|
||||
return TerminalItems(text)
|
||||
}
|
||||
Reference in New Issue
Block a user