extractFilePaths returns a deduplicated, forward-slash-normalized list of file-path tokens present in the input. It looks at three sources: 1. `@file ` commands (existing chatcli syntax) 2. `@./foo/bar.go` path mentions (pathMentionRe) 3. Bare file tokens like "pkg/foo/bar_test.go" or "main.g
(input string)
| 41 | // files, only to match glob patterns, so non-existent paths are kept (a skill |
| 42 | // author might want to match on paths the user is *planning* to create). |
| 43 | func extractFilePaths(input string) []string { |
| 44 | if input == "" { |
| 45 | return nil |
| 46 | } |
| 47 | seen := make(map[string]bool) |
| 48 | var out []string |
| 49 | add := func(p string) { |
| 50 | p = strings.TrimSpace(p) |
| 51 | if p == "" { |
| 52 | return |
| 53 | } |
| 54 | p = strings.ReplaceAll(p, "\\", "/") |
| 55 | // Strip surrounding punctuation commonly found in prose. |
| 56 | p = strings.Trim(p, ".,;:()[]{}\"'`") |
| 57 | if p == "" { |
| 58 | return |
| 59 | } |
| 60 | if seen[p] { |
| 61 | return |
| 62 | } |
| 63 | seen[p] = true |
| 64 | out = append(out, p) |
| 65 | } |
| 66 | |
| 67 | // 1. @file <path> extraction (reuse existing regex). |
| 68 | // We purposely do not require the path to exist on disk — skills can |
| 69 | // match prospective paths. |
| 70 | fileCmdRe := regexp.MustCompile(`@file\s+([\w./_~\-*]+/?[\w.\-*]*)`) |
| 71 | for _, m := range fileCmdRe.FindAllStringSubmatch(input, -1) { |
| 72 | if len(m) > 1 { |
| 73 | add(m[1]) |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | // 2. @path mentions (existing pathMentionRe lives in path_mentions.go). |
| 78 | for _, m := range pathMentionRe.FindAllStringSubmatch(input, -1) { |
| 79 | if len(m) > 1 { |
| 80 | add(m[1]) |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | // 3. Bare tokens with a slash or known extension. |
| 85 | for _, tok := range filePathTokenRe.FindAllString(input, -1) { |
| 86 | add(tok) |
| 87 | } |
| 88 | |
| 89 | return out |
| 90 | } |
| 91 | |
| 92 | // buildSkillInjectionBlock formats a slice of auto-activated skills into the |
| 93 | // system-prompt block that gets appended as a ContentBlock. Returns an empty |
no outgoing calls