shell: support Windows cmd /C; normalize date/time; allow all commands; add tests

This commit is contained in:
2026-03-05 17:44:19 +08:00
parent 47b6059773
commit e2f806edb3
19 changed files with 989 additions and 350 deletions

View File

@@ -14,6 +14,21 @@ type Skill struct {
Source string
}
type SkillSummary struct {
DirName string
Name string
Description string
Source string
}
type scannedSkill struct {
dirName string
name string
description string
content string
source string
}
func LoadSoul(path string) (string, error) {
b, err := os.ReadFile(path)
if err != nil {
@@ -27,6 +42,39 @@ func LoadSoul(path string) (string, error) {
}
func LoadSkillSet(dir string) ([]Skill, error) {
scanned, err := scanSkills(dir)
if err != nil {
return nil, err
}
out := make([]Skill, 0, len(scanned))
for _, s := range scanned {
out = append(out, Skill{
Name: s.name,
Content: s.content,
Source: s.source,
})
}
return out, nil
}
func LoadSkillSummaries(dir string) ([]SkillSummary, error) {
scanned, err := scanSkills(dir)
if err != nil {
return nil, err
}
out := make([]SkillSummary, 0, len(scanned))
for _, s := range scanned {
out = append(out, SkillSummary{
DirName: s.dirName,
Name: s.name,
Description: s.description,
Source: s.source,
})
}
return out, nil
}
func scanSkills(dir string) ([]scannedSkill, error) {
entries, err := os.ReadDir(dir)
if err != nil {
return nil, fmt.Errorf("read skills dir failed: %w", err)
@@ -40,7 +88,7 @@ func LoadSkillSet(dir string) ([]Skill, error) {
}
sort.Strings(skillDirs)
out := make([]Skill, 0, len(skillDirs))
out := make([]scannedSkill, 0, len(skillDirs))
for _, skillDir := range skillDirs {
file := filepath.Join(dir, skillDir, "skill.md")
b, err := os.ReadFile(file)
@@ -54,12 +102,16 @@ func LoadSkillSet(dir string) ([]Skill, error) {
if content == "" {
continue
}
name := extractSkillName(skillDir, content)
out = append(out, Skill{
Name: name,
Content: content,
Source: file,
name, description := parseSkillNameDescription(skillDir, content)
if strings.TrimSpace(name) == "" {
continue
}
out = append(out, scannedSkill{
dirName: skillDir,
name: name,
description: description,
content: content,
source: file,
})
}
@@ -88,3 +140,74 @@ func extractSkillName(fileName, markdown string) string {
}
return base
}
func parseSkillNameDescription(fileName, markdown string) (string, string) {
name := ""
description := ""
fm := parseFrontMatter(markdown)
if v, ok := fm["name"]; ok {
name = strings.TrimSpace(v)
}
if v, ok := fm["description"]; ok {
description = strings.TrimSpace(v)
}
if name == "" {
name = extractSkillName(fileName, markdown)
}
if description == "" {
description = extractSkillDescription(markdown)
}
return name, description
}
func parseFrontMatter(markdown string) map[string]string {
lines := strings.Split(markdown, "\n")
out := map[string]string{}
if len(lines) < 3 {
return out
}
if strings.TrimSpace(lines[0]) != "---" {
return out
}
for i := 1; i < len(lines); i++ {
line := strings.TrimSpace(lines[i])
if line == "---" {
break
}
idx := strings.Index(line, ":")
if idx <= 0 {
continue
}
k := strings.ToLower(strings.TrimSpace(line[:idx]))
v := strings.TrimSpace(line[idx+1:])
v = strings.Trim(v, "\"'")
if k != "" && v != "" {
out[k] = v
}
}
return out
}
func extractSkillDescription(markdown string) string {
lines := strings.Split(markdown, "\n")
for _, raw := range lines {
line := strings.TrimSpace(raw)
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "---") {
continue
}
if strings.Contains(line, ":") {
parts := strings.SplitN(line, ":", 2)
if len(parts) == 2 {
left := strings.ToLower(strings.TrimSpace(parts[0]))
if left == "name" || left == "description" || left == "source" || left == "generated_at" {
continue
}
}
}
if len(line) > 200 {
line = line[:200]
}
return line
}
return ""
}