- Introduce new MCP and Robot command groups in the CLI, allowing for better organization of package management commands. - Add corresponding command descriptions for MCP and Robot functionalities to improve user guidance. - Update the agent command group to include additional commands for enhanced agent management. - Modify .gitignore to exclude specific design markdown files from version control. - Add environment variable for test application path in GitHub workflows to streamline testing setup.
115 lines
3.2 KiB
Go
115 lines
3.2 KiB
Go
package robot
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
)
|
|
|
|
// RobotJSON represents the portable fields exported from a robot member record.
|
|
type RobotJSON struct {
|
|
DisplayName string `json:"display_name,omitempty"`
|
|
Bio *string `json:"bio,omitempty"`
|
|
SystemPrompt string `json:"system_prompt,omitempty"`
|
|
LanguageModel string `json:"language_model,omitempty"`
|
|
RobotConfig json.RawMessage `json:"robot_config,omitempty"`
|
|
Agents []string `json:"agents,omitempty"`
|
|
MCPServers []string `json:"mcp_servers,omitempty"`
|
|
}
|
|
|
|
// robotConfig is a partial parse of robot_config for dependency extraction.
|
|
type robotConfig struct {
|
|
Resources struct {
|
|
Phases map[string]string `json:"phases,omitempty"`
|
|
} `json:"resources,omitempty"`
|
|
}
|
|
|
|
// RobotDep represents a dependency extracted from a robot configuration.
|
|
type RobotDep struct {
|
|
PackageID string // "@scope/name"
|
|
Type string // "assistant" or "mcp"
|
|
}
|
|
|
|
// AnalyzeDeps extracts dependencies from a RobotJSON following DESIGN-ROBOT.md rules:
|
|
// - phases values: "yao.robot-host" → @yao/robot-host (assistant)
|
|
// - agents values: "yao.keeper.fetch" → @yao/keeper (first-layer assistant, take first 2 segments)
|
|
// - mcp_servers values: "ark.image.text2img" → @ark/image.text2img (mcp)
|
|
// - Excludes: __yao.* prefixed built-in agents
|
|
func AnalyzeDeps(robot *RobotJSON) []RobotDep {
|
|
seen := map[string]bool{}
|
|
var deps []RobotDep
|
|
|
|
addDep := func(pkgID, depType string) {
|
|
if seen[pkgID] {
|
|
return
|
|
}
|
|
seen[pkgID] = true
|
|
deps = append(deps, RobotDep{PackageID: pkgID, Type: depType})
|
|
}
|
|
|
|
// Extract from phases (all are assistants)
|
|
if len(robot.RobotConfig) > 0 {
|
|
var cfg robotConfig
|
|
if err := json.Unmarshal(robot.RobotConfig, &cfg); err == nil {
|
|
for _, yaoID := range cfg.Resources.Phases {
|
|
if isBuiltIn(yaoID) {
|
|
continue
|
|
}
|
|
pkgID := yaoIDToPackageID(yaoID)
|
|
if pkgID != "" {
|
|
addDep(pkgID, "assistant")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Extract from agents (first-layer assistant)
|
|
for _, yaoID := range robot.Agents {
|
|
if isBuiltIn(yaoID) {
|
|
continue
|
|
}
|
|
pkgID := agentYaoIDToPackageID(yaoID)
|
|
if pkgID != "" {
|
|
addDep(pkgID, "assistant")
|
|
}
|
|
}
|
|
|
|
// Extract from mcp_servers
|
|
for _, yaoID := range robot.MCPServers {
|
|
if isBuiltIn(yaoID) {
|
|
continue
|
|
}
|
|
pkgID := yaoIDToPackageID(yaoID)
|
|
if pkgID != "" {
|
|
addDep(pkgID, "mcp")
|
|
}
|
|
}
|
|
|
|
return deps
|
|
}
|
|
|
|
// isBuiltIn returns true for __yao.* prefixed IDs.
|
|
func isBuiltIn(yaoID string) bool {
|
|
return strings.HasPrefix(yaoID, "__yao.")
|
|
}
|
|
|
|
// yaoIDToPackageID converts "yao.robot-host" → "@yao/robot-host".
|
|
// First "." separates scope from name.
|
|
func yaoIDToPackageID(yaoID string) string {
|
|
idx := strings.Index(yaoID, ".")
|
|
if idx <= 0 || idx >= len(yaoID)-1 {
|
|
return ""
|
|
}
|
|
scope := yaoID[:idx]
|
|
name := yaoID[idx+1:]
|
|
return "@" + scope + "/" + name
|
|
}
|
|
|
|
// agentYaoIDToPackageID converts "yao.keeper.fetch" → "@yao/keeper".
|
|
// Takes the first two segments only (first-layer assistant).
|
|
func agentYaoIDToPackageID(yaoID string) string {
|
|
parts := strings.SplitN(yaoID, ".", 3)
|
|
if len(parts) < 2 || parts[0] == "" || parts[1] == "" {
|
|
return ""
|
|
}
|
|
return "@" + parts[0] + "/" + parts[1]
|
|
}
|