Files
tutti/packages/agent/store-sqlite/migrations_session_title_text.go
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

164 lines
3.9 KiB
Go

// Frozen title helpers preserve the historical migration transform without
// making store-sqlite depend on the Host application layer. Live title
// derivation belongs exclusively to packages/agent/host.
package storesqlite
import (
"strings"
"unicode/utf8"
canonical "github.com/tutti-os/tutti/packages/agent/store-sqlite/canonical"
)
const maxMigratedSessionTitleRunes = 120
func normalizeMigratedSessionTitle(value string) string {
value = strings.TrimSpace(value)
if value == "" {
return ""
}
var output strings.Builder
for index := 0; index < len(value); {
labelStart, hrefStart, hrefEnd, ok := migratedTitleMarkdownLinkAt(value, index)
if !ok {
output.WriteByte(value[index])
index++
continue
}
output.WriteString(unescapeMigratedTitleMarkdownLabel(value[labelStart : hrefStart-2]))
index = hrefEnd + 1
}
return strings.Join(strings.Fields(strings.TrimSpace(output.String())), " ")
}
func deriveMigratedSessionTitle(currentTitle string, visiblePrompt string) string {
if strings.TrimSpace(currentTitle) != "" {
return ""
}
title := normalizeMigratedSessionTitle(visiblePrompt)
if title == "" {
return ""
}
if utf8.RuneCountInString(title) <= maxMigratedSessionTitleRunes {
return title
}
const suffix = "..."
runes := []rune(title)
suffixRunes := utf8.RuneCountInString(suffix)
return strings.TrimSpace(string(runes[:maxMigratedSessionTitleRunes-suffixRunes])) + suffix
}
func isLegacyMigratedSessionTitlePlaceholder(value string, provider string, targetAliases ...string) bool {
title := normalizeMigratedTitleIdentity(value)
provider = normalizeMigratedTitleIdentity(provider)
if title == "" || title == provider {
return true
}
for _, candidate := range targetAliases {
if title == normalizeMigratedTitleIdentity(candidate) {
return true
}
}
descriptor, ok := canonical.FindProviderIdentity(provider)
if !ok {
return false
}
for _, candidate := range append(
[]string{descriptor.ID, descriptor.DisplayName},
descriptor.Aliases...,
) {
if title == normalizeMigratedTitleIdentity(candidate) {
return true
}
}
return false
}
func normalizeMigratedTitleIdentity(value string) string {
return strings.ToLower(strings.TrimSpace(value))
}
func migratedTitleMarkdownLinkAt(value string, start int) (labelStart, hrefStart, hrefEnd int, ok bool) {
if start >= len(value) || value[start] != '[' {
return 0, 0, 0, false
}
labelEnd := findMigratedTitleUnescaped(value, start+1, ']')
if labelEnd < 0 || labelEnd+1 >= len(value) || value[labelEnd+1] != '(' {
return 0, 0, 0, false
}
hrefEnd = findMigratedTitleBalancedHrefEnd(value, labelEnd+2)
if hrefEnd < 0 {
return 0, 0, 0, false
}
return start + 1, labelEnd + 2, hrefEnd, true
}
func findMigratedTitleUnescaped(value string, start int, target byte) int {
escaped := false
for index := start; index < len(value); index++ {
if escaped {
escaped = false
continue
}
if value[index] == '\\' {
escaped = true
continue
}
if value[index] == target {
return index
}
}
return -1
}
func findMigratedTitleBalancedHrefEnd(value string, start int) int {
depth := 0
escaped := false
for index := start; index < len(value); index++ {
if escaped {
escaped = false
continue
}
switch value[index] {
case '\\':
escaped = true
case '(':
depth++
case ')':
if depth == 0 {
return index
}
depth--
}
}
return -1
}
func unescapeMigratedTitleMarkdownLabel(value string) string {
var output strings.Builder
escaped := false
for index := 0; index < len(value); index++ {
char := value[index]
if escaped {
if strings.ContainsRune(`\\[]()`, rune(char)) {
output.WriteByte(char)
} else {
output.WriteByte('\\')
output.WriteByte(char)
}
escaped = false
continue
}
if char == '\\' {
escaped = true
continue
}
output.WriteByte(char)
}
if escaped {
output.WriteByte('\\')
}
return output.String()
}