Why: the completion doc's N2 requires skills validated per the open spec; today frontmatter was a description-only line hack with silent skips, no name field, and no error surface. Evidence: GOWORK=off go vet + go test -count=1 ./... green; parser units cover all field forms and reject malformed shapes with located errors; the validation matrix covers kebab-case/name-equals-dir/ required description/limits; Store.Diagnostics surfaces per-skill reasons and Load returns the located validation error for same-named invalid skills; existing fixtures updated to spec form. Impact: stricter by design — skills without name/description or with unknown frontmatter keys now produce located errors instead of silently loading or silently skipping; ValidateSkillDocument is exported so the product plugin/seed paths share the same validator. Refs: Agent-System-Documents#42 (N2 plan WP4)
73 lines
2.2 KiB
Go
73 lines
2.2 KiB
Go
package resources
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"agent-native/runtime/skills"
|
|
"agent-native/runtime/tools"
|
|
)
|
|
|
|
func TestContextAndPromptAndTrust(t *testing.T) {
|
|
root := t.TempDir()
|
|
proj := filepath.Join(root, "proj")
|
|
if err := os.MkdirAll(proj, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(root, "AGENTS.md"), []byte("root-agents"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(proj, "SYSTEM.md"), []byte("sys"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
text, err := ContextFiles(proj)
|
|
if err != nil || !strings.Contains(text, "root-agents") || !strings.Contains(text, "sys") {
|
|
t.Fatalf("context: %s %v", text, err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(proj, "greet.md"), []byte("hello {{name}}"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := Expand("say /greet", proj, map[string]string{"name": "Ada"})
|
|
if err != nil || got != "say hello Ada" {
|
|
t.Fatalf("expand: %q %v", got, err)
|
|
}
|
|
if ProjectTrusted(TrustAsk, false, false) {
|
|
t.Fatal("ask is not trusted without approve")
|
|
}
|
|
if !ProjectTrusted(TrustNever, true, false) {
|
|
t.Fatal("approve overrides never")
|
|
}
|
|
if ProjectTrusted(TrustAlways, false, true) {
|
|
t.Fatal("no-approve wins")
|
|
}
|
|
}
|
|
|
|
func TestPiAliasesFilterAndSkillCommand(t *testing.T) {
|
|
reg := tools.WorkspaceTools(t.TempDir())
|
|
reg.RegisterPiAliases()
|
|
if !reg.Has("read") || !reg.Has("ls") || !reg.Has("read_file") {
|
|
t.Fatal("aliases missing")
|
|
}
|
|
if err := reg.Filter(tools.FilterOptions{Exclude: []string{"read"}, NoBuiltin: false}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if reg.Has("read") || !reg.Has("read_file") {
|
|
t.Fatal("exclude should drop only the alias")
|
|
}
|
|
dir := t.TempDir()
|
|
skillDir := filepath.Join(dir, "review")
|
|
if err := os.MkdirAll(skillDir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(skillDir, "SKILL.md"), []byte("---\nname: review\ndescription: 评审技能\n---\n\nbe thorough"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
store := skills.NewStore(dir)
|
|
out, err := store.ExpandCommands("use /skill:review now")
|
|
if err != nil || !strings.Contains(out, "be thorough") {
|
|
t.Fatalf("skill expand: %q %v", out, err)
|
|
}
|
|
}
|