69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
package session
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// SessionName returns a stable tmux session name for the given workspace.
|
|
// Format: ctask-<category>-<slug>-<hash6>.
|
|
//
|
|
// category and slug are sanitized to [A-Za-z0-9_-]; characters outside that
|
|
// set become '_'; runs of '_' collapse; both are lowercased. slug is
|
|
// truncated to 30 characters maximum (after sanitization). hash6 is the
|
|
// first six lowercase-hex characters of sha256(canonical absolute path).
|
|
//
|
|
// On Windows the path is lowercased before hashing to match
|
|
// config.searchRootKey conventions for case-insensitive filesystems.
|
|
func SessionName(category, slug, absWsPath string) string {
|
|
cat := sanitizeNameComponent(category)
|
|
sl := sanitizeNameComponent(slug)
|
|
if len(sl) > 30 {
|
|
sl = sl[:30]
|
|
sl = strings.TrimRight(sl, "_")
|
|
}
|
|
clean := filepath.Clean(absWsPath)
|
|
if runtime.GOOS == "windows" {
|
|
clean = strings.ToLower(clean)
|
|
}
|
|
sum := sha256.Sum256([]byte(clean))
|
|
hash := hex.EncodeToString(sum[:])[:6]
|
|
return "ctask-" + cat + "-" + sl + "-" + hash
|
|
}
|
|
|
|
// sanitizeNameComponent replaces every char outside [A-Za-z0-9_-] with '_',
|
|
// collapses runs of '_', trims leading/trailing '_' and '-', and lowercases.
|
|
func sanitizeNameComponent(s string) string {
|
|
if s == "" {
|
|
return "_"
|
|
}
|
|
var b strings.Builder
|
|
b.Grow(len(s))
|
|
for _, r := range s {
|
|
switch {
|
|
case r >= 'a' && r <= 'z':
|
|
b.WriteRune(r)
|
|
case r >= 'A' && r <= 'Z':
|
|
b.WriteRune(r + ('a' - 'A'))
|
|
case r >= '0' && r <= '9':
|
|
b.WriteRune(r)
|
|
case r == '_' || r == '-':
|
|
b.WriteRune(r)
|
|
default:
|
|
b.WriteByte('_')
|
|
}
|
|
}
|
|
out := b.String()
|
|
for strings.Contains(out, "__") {
|
|
out = strings.ReplaceAll(out, "__", "_")
|
|
}
|
|
out = strings.Trim(out, "_-")
|
|
if out == "" {
|
|
return "_"
|
|
}
|
|
return out
|
|
}
|