初始化仓库

This commit is contained in:
2026-06-02 23:14:41 +08:00
commit 0bc3f02670
520 changed files with 191097 additions and 0 deletions
+543
View File
@@ -0,0 +1,543 @@
package core
import (
"fmt"
"path/filepath"
"regexp"
"sort"
"strings"
"unicode/utf8"
)
type ReferenceRenderCfg struct {
NormalizeAgents []string
RenderPlatforms []string
DisplayPath string
MarkerStyle string
EnclosureStyle string
}
type placeholderReplacement struct {
placeholder string
ref *localReference
keepText string
}
var (
reFenceBlock = regexp.MustCompile("(?s)```.*?```")
reInlineCodeSpan = regexp.MustCompile("`([^`\n]+)`")
reBareURL = regexp.MustCompile(`https?://[^\s<>()]+`)
reAbsOrFileRef = regexp.MustCompile(`file:///[^\s` + "`" + `<>\[\](),,、;;。!?!?]+|/[^\s` + "`" + `<>\[\](),,、;;。!?!?]+`)
reRelativeRef = regexp.MustCompile(`(?:\.\.?/|[A-Za-z0-9_.-]+/)[^\s` + "`" + `<>\[\](),,、;;。!?!?]+`)
reBasenameFileRef = regexp.MustCompile(`\b[A-Za-z0-9_.-]+\.[A-Za-z0-9_.-]+(?:#L\d+(?:C\d+)?|:\d+(?::\d+)?|:\d+-\d+)?\b`)
)
func DefaultReferenceRenderCfg() ReferenceRenderCfg {
return ReferenceRenderCfg{
DisplayPath: "dirname_basename",
MarkerStyle: "emoji",
EnclosureStyle: "code",
}
}
func normalizeReferenceRenderCfg(cfg ReferenceRenderCfg) ReferenceRenderCfg {
n := DefaultReferenceRenderCfg()
if strings.TrimSpace(cfg.DisplayPath) != "" {
n.DisplayPath = strings.ToLower(strings.TrimSpace(cfg.DisplayPath))
}
if strings.TrimSpace(cfg.MarkerStyle) != "" {
n.MarkerStyle = strings.ToLower(strings.TrimSpace(cfg.MarkerStyle))
}
if strings.TrimSpace(cfg.EnclosureStyle) != "" {
n.EnclosureStyle = strings.ToLower(strings.TrimSpace(cfg.EnclosureStyle))
}
n.NormalizeAgents = normalizeReferenceScope(cfg.NormalizeAgents, supportedReferenceNormalizeAgents)
n.RenderPlatforms = normalizeReferenceScope(cfg.RenderPlatforms, supportedReferenceRenderPlatforms)
return n
}
var supportedReferenceNormalizeAgents = []string{"codex", "claudecode"}
var supportedReferenceRenderPlatforms = []string{"feishu", "weixin"}
func normalizeReferenceScope(values []string, supported []string) []string {
if len(values) == 0 {
return nil
}
supportedSet := make(map[string]struct{}, len(supported))
for _, v := range supported {
supportedSet[v] = struct{}{}
}
hasAll := false
seen := map[string]struct{}{}
out := make([]string, 0, len(values))
for _, v := range values {
key := strings.ToLower(strings.TrimSpace(v))
if key == "" {
continue
}
if key == "all" {
hasAll = true
continue
}
if _, ok := supportedSet[key]; !ok {
continue
}
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
out = append(out, key)
}
if hasAll {
return append([]string(nil), supported...)
}
return out
}
func (cfg ReferenceRenderCfg) renderEnabled(agentName, platformName string) bool {
if len(cfg.NormalizeAgents) == 0 || len(cfg.RenderPlatforms) == 0 {
return false
}
agentName = strings.ToLower(strings.TrimSpace(agentName))
platformName = strings.ToLower(strings.TrimSpace(platformName))
if !containsFolded(cfg.NormalizeAgents, agentName) {
return false
}
return containsFolded(cfg.RenderPlatforms, platformName)
}
func containsFolded(values []string, want string) bool {
for _, v := range values {
if strings.EqualFold(strings.TrimSpace(v), want) {
return true
}
}
return false
}
func TransformLocalReferences(text string, cfg ReferenceRenderCfg, agentName, platformName, workspaceDir string) string {
cfg = normalizeReferenceRenderCfg(cfg)
if !cfg.renderEnabled(agentName, platformName) || strings.TrimSpace(text) == "" {
return text
}
parts := splitWithMatches(text, reFenceBlock)
var out strings.Builder
for _, part := range parts {
if part.matched {
out.WriteString(part.text)
continue
}
out.WriteString(transformTextOutsideFence(part.text, cfg, workspaceDir))
}
return out.String()
}
func transformTextOutsideFence(text string, cfg ReferenceRenderCfg, workspaceDir string) string {
parts := splitWithMatches(text, reInlineCodeSpan)
replacements := make([]placeholderReplacement, 0)
var out strings.Builder
for _, part := range parts {
if !part.matched {
transformed, reps := transformNonCodeText(part.text, cfg, workspaceDir)
if len(replacements) > 0 && len(reps) > 0 {
offset := len(replacements)
for i := range reps {
oldPlaceholder := reps[i].placeholder
newPlaceholder := makeReferencePlaceholder(offset + i)
transformed = strings.ReplaceAll(transformed, oldPlaceholder, newPlaceholder)
reps[i].placeholder = newPlaceholder
}
}
out.WriteString(transformed)
replacements = append(replacements, reps...)
continue
}
match := reInlineCodeSpan.FindStringSubmatch(part.text)
if len(match) < 2 {
out.WriteString(part.text)
continue
}
ref, ok := parseLocalReference(match[1], workspaceDir)
if !ok {
out.WriteString(part.text)
continue
}
placeholder := makeReferencePlaceholder(len(replacements))
replacements = append(replacements, placeholderReplacement{placeholder: placeholder, ref: ref})
out.WriteString(placeholder)
}
return replaceReferencePlaceholders(out.String(), replacements, cfg)
}
func transformNonCodeText(text string, cfg ReferenceRenderCfg, workspaceDir string) (string, []placeholderReplacement) {
replacements := make([]placeholderReplacement, 0)
text = replaceProtectedWebMarkdownLinks(text, &replacements)
text = replaceProtectedLinks(text, reBareURL, &replacements)
text = replaceMarkdownLinks(text, &replacements, workspaceDir)
text = replaceLocalReferenceCandidates(text, reAbsOrFileRef, &replacements, workspaceDir)
text = replaceLocalReferenceCandidates(text, reRelativeRef, &replacements, workspaceDir)
text = replaceLocalReferenceCandidates(text, reBasenameFileRef, &replacements, workspaceDir)
return text, replacements
}
func replaceProtectedLinks(text string, re *regexp.Regexp, replacements *[]placeholderReplacement) string {
matches := re.FindAllStringIndex(text, -1)
if len(matches) == 0 {
return text
}
var out strings.Builder
last := 0
for _, m := range matches {
out.WriteString(text[last:m[0]])
token := text[m[0]:m[1]]
placeholder := makeReferencePlaceholder(len(*replacements))
*replacements = append(*replacements, placeholderReplacement{placeholder: placeholder, keepText: token})
out.WriteString(placeholder)
last = m[1]
}
out.WriteString(text[last:])
return out.String()
}
func replaceProtectedWebMarkdownLinks(text string, replacements *[]placeholderReplacement) string {
matches := reMarkdownLink.FindAllStringSubmatchIndex(text, -1)
if len(matches) == 0 {
return text
}
var out strings.Builder
last := 0
for _, m := range matches {
target := text[m[4]:m[5]]
if !isWebURL(target) {
continue
}
out.WriteString(text[last:m[0]])
token := text[m[0]:m[1]]
placeholder := makeReferencePlaceholder(len(*replacements))
*replacements = append(*replacements, placeholderReplacement{placeholder: placeholder, keepText: token})
out.WriteString(placeholder)
last = m[1]
}
out.WriteString(text[last:])
return out.String()
}
func replaceMarkdownLinks(text string, replacements *[]placeholderReplacement, workspaceDir string) string {
matches := reMarkdownLink.FindAllStringSubmatchIndex(text, -1)
if len(matches) == 0 {
return text
}
var out strings.Builder
last := 0
for _, m := range matches {
out.WriteString(text[last:m[0]])
target := text[m[4]:m[5]]
suffix := ""
if m[6] >= 0 {
suffix = text[m[6]:m[7]]
}
ref, ok := parseLocalReference(target+suffix, workspaceDir)
if !ok {
out.WriteString(text[m[0]:m[1]])
last = m[1]
continue
}
placeholder := makeReferencePlaceholder(len(*replacements))
*replacements = append(*replacements, placeholderReplacement{placeholder: placeholder, ref: ref})
out.WriteString(placeholder)
last = m[1]
}
out.WriteString(text[last:])
return out.String()
}
func replaceLocalReferenceCandidates(text string, re *regexp.Regexp, replacements *[]placeholderReplacement, workspaceDir string) string {
matches := re.FindAllStringIndex(text, -1)
if len(matches) == 0 {
return text
}
var out strings.Builder
last := 0
for _, m := range matches {
out.WriteString(text[last:m[0]])
token := text[m[0]:m[1]]
if re == reAbsOrFileRef && !isValidAbsoluteReferenceBoundary(text, m[0]) {
out.WriteString(token)
last = m[1]
continue
}
if re == reRelativeRef && !isValidRelativeReferenceBoundary(text, m[0]) {
out.WriteString(token)
last = m[1]
continue
}
ref, ok := parseLocalReference(token, workspaceDir)
if !ok {
out.WriteString(token)
last = m[1]
continue
}
placeholder := makeReferencePlaceholder(len(*replacements))
*replacements = append(*replacements, placeholderReplacement{placeholder: placeholder, ref: ref})
out.WriteString(placeholder)
last = m[1]
}
out.WriteString(text[last:])
return out.String()
}
func isValidAbsoluteReferenceBoundary(text string, start int) bool {
if start <= 0 {
return true
}
prev, _ := utf8.DecodeLastRuneInString(text[:start])
switch {
case prev == ' ', prev == '\n', prev == '\t', prev == '\r':
return true
case strings.ContainsRune("([<{\"'`、,,;;。!?!?:", prev):
return true
default:
return false
}
}
func isValidRelativeReferenceBoundary(text string, start int) bool {
if start <= 0 {
return true
}
prev, _ := utf8.DecodeLastRuneInString(text[:start])
switch {
case prev == ' ', prev == '\n', prev == '\t', prev == '\r':
return true
case strings.ContainsRune("([<{\"'`、,,;;。!?!?:", prev):
return true
default:
return false
}
}
func replaceReferencePlaceholders(text string, replacements []placeholderReplacement, cfg ReferenceRenderCfg) string {
if len(replacements) == 0 {
return text
}
basenameCounts := make(map[string]int)
for _, rep := range replacements {
if rep.ref == nil {
continue
}
base := refBaseName(rep.ref)
if base != "" {
basenameCounts[base]++
}
}
sort.SliceStable(replacements, func(i, j int) bool {
return len(replacements[i].placeholder) > len(replacements[j].placeholder)
})
for _, rep := range replacements {
replacement := rep.keepText
if rep.ref != nil {
replacement = renderLocalReference(rep.ref, cfg, basenameCounts)
}
text = strings.ReplaceAll(text, rep.placeholder, replacement)
}
return text
}
type splitPart struct {
text string
matched bool
}
func splitWithMatches(text string, re *regexp.Regexp) []splitPart {
matches := re.FindAllStringIndex(text, -1)
if len(matches) == 0 {
return []splitPart{{text: text}}
}
parts := make([]splitPart, 0, len(matches)*2+1)
last := 0
for _, m := range matches {
if m[0] > last {
parts = append(parts, splitPart{text: text[last:m[0]]})
}
parts = append(parts, splitPart{text: text[m[0]:m[1]], matched: true})
last = m[1]
}
if last < len(text) {
parts = append(parts, splitPart{text: text[last:]})
}
return parts
}
func makeReferencePlaceholder(idx int) string {
return fmt.Sprintf("\x00REF_%03d\x00", idx)
}
func refBaseName(ref *localReference) string {
if ref == nil {
return ""
}
p := referenceDisplaySource(ref, "basename")
if p == "" {
return ""
}
return strings.TrimSuffix(p, "/")
}
func renderLocalReference(ref *localReference, cfg ReferenceRenderCfg, basenameCounts map[string]int) string {
body := referenceDisplaySource(ref, cfg.DisplayPath)
if cfg.DisplayPath == "smart" {
base := refBaseName(ref)
if basenameCounts[base] <= 1 {
body = referenceDisplaySource(ref, "basename")
} else {
body = referenceDisplaySource(ref, "dirname_basename")
if body == base {
body = referenceDisplaySource(ref, "relative")
}
}
}
body += renderReferenceLocation(ref)
body = applyReferenceEnclosure(cfg.EnclosureStyle, body)
return applyReferenceMarker(cfg.MarkerStyle, ref.kind, body)
}
func referenceDisplaySource(ref *localReference, mode string) string {
mode = strings.ToLower(strings.TrimSpace(mode))
switch mode {
case "absolute":
if ref.pathAbs != "" {
return appendDirSuffix(ref.pathAbs, ref.kind)
}
return appendDirSuffix(cleanDisplayPath(ref.pathOriginal), ref.kind)
case "relative":
if ref.pathRel == "." {
if ref.kind == referenceKindDir {
return "./"
}
return "."
}
if rel := sanitizeRelativeDisplay(ref.pathRel); rel != "" {
return appendDirSuffix(rel, ref.kind)
}
if ref.isRelative {
return appendDirSuffix(cleanDisplayPath(ref.pathOriginal), ref.kind)
}
if ref.pathAbs != "" {
return appendDirSuffix(ref.pathAbs, ref.kind)
}
return appendDirSuffix(cleanDisplayPath(ref.pathOriginal), ref.kind)
case "basename":
return appendDirSuffix(pathTail(ref, 1), ref.kind)
case "dirname_basename":
return appendDirSuffix(pathTail(ref, 2), ref.kind)
case "smart":
return appendDirSuffix(pathTail(ref, 1), ref.kind)
default:
return appendDirSuffix(pathTail(ref, 2), ref.kind)
}
}
func sanitizeRelativeDisplay(rel string) string {
rel = filepath.ToSlash(strings.TrimSpace(rel))
if rel == "" || rel == "." || rel == ".." || strings.HasPrefix(rel, "../") {
return ""
}
return rel
}
func pathTail(ref *localReference, segs int) string {
source := sanitizeRelativeDisplay(ref.pathRel)
if source == "" {
if ref.isRelative {
source = cleanDisplayPath(ref.pathOriginal)
} else if ref.pathAbs != "" {
source = filepath.ToSlash(ref.pathAbs)
} else {
source = cleanDisplayPath(ref.pathOriginal)
}
}
source = strings.TrimSuffix(source, "/")
parts := strings.Split(filepath.ToSlash(source), "/")
if len(parts) == 0 {
return source
}
if segs <= 0 || len(parts) <= segs {
return source
}
return strings.Join(parts[len(parts)-segs:], "/")
}
func cleanDisplayPath(path string) string {
if path == "" {
return ""
}
path = filepath.ToSlash(path)
path = strings.TrimPrefix(path, "./")
return strings.TrimSpace(path)
}
func appendDirSuffix(path string, kind referenceKind) string {
path = filepath.ToSlash(strings.TrimSpace(path))
if path == "" {
return path
}
if kind == referenceKindDir && !strings.HasSuffix(path, "/") {
return path + "/"
}
return strings.TrimSuffix(path, "/")
}
func renderReferenceLocation(ref *localReference) string {
switch ref.locationFormat {
case referenceLocationColonLine:
return fmt.Sprintf(":%d", ref.lineStart)
case referenceLocationColonLineCol:
return fmt.Sprintf(":%d:%d", ref.lineStart, ref.column)
case referenceLocationColonRange:
return fmt.Sprintf(":%d-%d", ref.lineStart, ref.lineEnd)
case referenceLocationHashLine:
return fmt.Sprintf("#L%d", ref.lineStart)
case referenceLocationHashLineCol:
return fmt.Sprintf("#L%dC%d", ref.lineStart, ref.column)
default:
return ""
}
}
func applyReferenceMarker(style string, kind referenceKind, body string) string {
switch strings.ToLower(strings.TrimSpace(style)) {
case "ascii":
if kind == referenceKindDir {
return "[DIR] " + body
}
if kind == referenceKindFile {
return "[FILE] " + body
}
return body
case "emoji":
if kind == referenceKindDir {
return "📁 " + body
}
if kind == referenceKindFile {
return "📄 " + body
}
return body
default:
return body
}
}
func applyReferenceEnclosure(style, body string) string {
switch strings.ToLower(strings.TrimSpace(style)) {
case "bracket":
return "[" + body + "]"
case "angle":
return "<" + body + ">"
case "fullwidth":
return "【" + body + "】"
case "code":
return "`" + body + "`"
default:
return body
}
}