ONNX
security
malware-detection
File size: 3,770 Bytes
d2507b5
 
 
 
 
 
 
a2a3348
d2507b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package parser

import (
	"fmt"
	"os"
	"strings"

	"huggingface.co/turenlabs/Vigil/source/pkg/types"
)

// Parse reads a Claude Code skill markdown file and extracts frontmatter + body.
func Parse(filePath string) (*types.SkillFile, error) {
	raw, err := os.ReadFile(filePath)
	if err != nil {
		return nil, fmt.Errorf("reading skill file: %w", err)
	}
	return ParseBytes(raw, filePath)
}

// ParseBytes parses skill file content from bytes.
func ParseBytes(raw []byte, filePath string) (*types.SkillFile, error) {
	content := string(raw)

	frontmatter, body, bodyStartLine, err := splitFrontmatter(content)
	if err != nil {
		return nil, fmt.Errorf("parsing frontmatter: %w", err)
	}

	sf := &types.SkillFile{
		RawContent:    content,
		FilePath:      filePath,
		Body:          body,
		BodyStartLine: bodyStartLine,
	}

	if frontmatter != "" {
		parseFrontmatterFields(frontmatter, sf)
	}

	return sf, nil
}

// splitFrontmatter splits a markdown file into YAML frontmatter and body.
// Frontmatter is delimited by --- on the first line and a closing ---.
// bodyStartLine is the 1-based line number where the body begins in the original content.
func splitFrontmatter(content string) (frontmatter, body string, bodyStartLine int, err error) {
	trimmed := strings.TrimSpace(content)
	if !strings.HasPrefix(trimmed, "---") {
		return "", content, 1, nil
	}

	// Count leading blank lines that TrimSpace removed
	leadingLines := 0
	for i, ch := range content {
		if ch == '\n' {
			leadingLines++
		} else if ch != ' ' && ch != '\t' && ch != '\r' {
			_ = i
			break
		}
	}

	rest := trimmed[3:]
	rest = strings.TrimLeft(rest, " \t")
	if len(rest) > 0 && rest[0] == '\n' {
		rest = rest[1:]
	} else if len(rest) > 1 && rest[0] == '\r' && rest[1] == '\n' {
		rest = rest[2:]
	}

	// Handle empty frontmatter: starts with closing ---
	if strings.HasPrefix(rest, "---") {
		body = strings.TrimLeft(rest[3:], " \t\r\n")
		// Opening --- (1) + closing --- (1) + leadingLines
		bodyStartLine = leadingLines + 3
		return "", body, bodyStartLine, nil
	}

	idx := strings.Index(rest, "\n---")
	if idx == -1 {
		return "", content, 1, nil
	}

	frontmatter = rest[:idx]
	body = strings.TrimLeft(rest[idx+4:], " \t\r\n")

	// Count lines: leading blank + opening --- line + frontmatter lines + closing --- line
	fmLines := strings.Count(frontmatter, "\n") + 1
	bodyStartLine = leadingLines + 1 + fmLines + 1 // opening--- + fm lines + closing---

	// Account for blank lines trimmed between closing --- and body start
	afterClosing := rest[idx+4:]
	for _, ch := range afterClosing {
		if ch == '\n' {
			bodyStartLine++
		} else if ch != ' ' && ch != '\t' && ch != '\r' {
			break
		}
	}

	return frontmatter, body, bodyStartLine, nil
}

// parseFrontmatterFields extracts known fields from simple YAML frontmatter.
// Handles flat key: value pairs and simple list items (- value).
func parseFrontmatterFields(fm string, sf *types.SkillFile) {
	lines := strings.Split(fm, "\n")
	var currentKey string

	for _, line := range lines {
		trimmed := strings.TrimRight(line, " \t\r")

		// List item under current key
		if strings.HasPrefix(trimmed, "  - ") || strings.HasPrefix(trimmed, "  - ") {
			val := strings.TrimSpace(trimmed[strings.Index(trimmed, "- ")+2:])
			if currentKey == "triggers" {
				sf.Triggers = append(sf.Triggers, val)
			}
			continue
		}

		// Key: value pair
		colonIdx := strings.Index(trimmed, ":")
		if colonIdx > 0 {
			key := strings.TrimSpace(trimmed[:colonIdx])
			val := strings.TrimSpace(trimmed[colonIdx+1:])
			currentKey = key

			switch key {
			case "name":
				sf.Name = val
			case "description":
				sf.Description = val
			case "type":
				sf.Type = val
			case "triggers":
				// Value comes on subsequent lines as list items
			}
		}
	}
}