Merge pull request 'chore: Go 1.26 modernization' (#17) from chore/go-1.26-modernization into main
This commit is contained in:
commit
c8b32cc1a1
26 changed files with 136 additions and 174 deletions
4
pkg/cache/cache.go
vendored
4
pkg/cache/cache.go
vendored
|
|
@ -67,7 +67,7 @@ func (c *Cache) Path(key string) string {
|
|||
}
|
||||
|
||||
// Get retrieves a cached item if it exists and hasn't expired.
|
||||
func (c *Cache) Get(key string, dest interface{}) (bool, error) {
|
||||
func (c *Cache) Get(key string, dest any) (bool, error) {
|
||||
path := c.Path(key)
|
||||
|
||||
dataStr, err := c.medium.Read(path)
|
||||
|
|
@ -98,7 +98,7 @@ func (c *Cache) Get(key string, dest interface{}) (bool, error) {
|
|||
}
|
||||
|
||||
// Set stores an item in the cache.
|
||||
func (c *Cache) Set(key string, data interface{}) error {
|
||||
func (c *Cache) Set(key string, data any) error {
|
||||
path := c.Path(key)
|
||||
|
||||
// Ensure parent directory exists
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package coredeno
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -14,7 +15,7 @@ func (s *Sidecar) Start(ctx context.Context, args ...string) error {
|
|||
defer s.mu.Unlock()
|
||||
|
||||
if s.cmd != nil {
|
||||
return fmt.Errorf("coredeno: already running")
|
||||
return errors.New("coredeno: already running")
|
||||
}
|
||||
|
||||
// Ensure socket directory exists with owner-only permissions
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package coredeno
|
|||
|
||||
import (
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -25,20 +26,10 @@ func CheckPath(path string, allowed []string) bool {
|
|||
|
||||
// CheckNet returns true if the given host:port is in the allowed list.
|
||||
func CheckNet(addr string, allowed []string) bool {
|
||||
for _, a := range allowed {
|
||||
if a == addr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(allowed, addr)
|
||||
}
|
||||
|
||||
// CheckRun returns true if the given command is in the allowed list.
|
||||
func CheckRun(cmd string, allowed []string) bool {
|
||||
for _, a := range allowed {
|
||||
if a == cmd {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(allowed, cmd)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"embed"
|
||||
goio "io"
|
||||
"slices"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
|
|
@ -29,12 +30,7 @@ type Features struct {
|
|||
|
||||
// IsEnabled returns true if the given feature is enabled.
|
||||
func (f *Features) IsEnabled(feature string) bool {
|
||||
for _, flag := range f.Flags {
|
||||
if flag == feature {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
return slices.Contains(f.Flags, feature)
|
||||
}
|
||||
|
||||
// Option is a function that configures the Core.
|
||||
|
|
@ -44,15 +40,15 @@ type Option func(*Core) error
|
|||
// Message is the interface for all messages that can be sent through the Core's IPC system.
|
||||
// Any struct can be a message, allowing for structured data to be passed between services.
|
||||
// Used with ACTION for fire-and-forget broadcasts.
|
||||
type Message interface{}
|
||||
type Message any
|
||||
|
||||
// Query is the interface for read-only requests that return data.
|
||||
// Used with QUERY (first responder) or QUERYALL (all responders).
|
||||
type Query interface{}
|
||||
type Query any
|
||||
|
||||
// Task is the interface for requests that perform side effects.
|
||||
// Used with PERFORM (first responder executes).
|
||||
type Task interface{}
|
||||
type Task any
|
||||
|
||||
// TaskWithID is an optional interface for tasks that need to know their assigned ID.
|
||||
// This is useful for tasks that want to report progress back to the frontend.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
|
@ -27,7 +28,7 @@ func newServiceManager() *serviceManager {
|
|||
// It also appends to startables/stoppables if the service implements those interfaces.
|
||||
func (m *serviceManager) registerService(name string, svc any) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf("core: service name cannot be empty")
|
||||
return errors.New("core: service name cannot be empty")
|
||||
}
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package help
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"regexp"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
|
@ -158,11 +159,11 @@ func (i *searchIndex) Search(query string) []*SearchResult {
|
|||
}
|
||||
|
||||
// Sort by score (highest first)
|
||||
sort.Slice(results, func(a, b int) bool {
|
||||
if results[a].Score != results[b].Score {
|
||||
return results[a].Score > results[b].Score
|
||||
slices.SortFunc(results, func(a, b *SearchResult) int {
|
||||
if a.Score != b.Score {
|
||||
return cmp.Compare(b.Score, a.Score) // descending
|
||||
}
|
||||
return results[a].Topic.Title < results[b].Topic.Title
|
||||
return cmp.Compare(a.Topic.Title, b.Topic.Title)
|
||||
})
|
||||
|
||||
return results
|
||||
|
|
@ -285,24 +286,15 @@ func extractSnippet(content string, res []*regexp.Regexp) string {
|
|||
if matchPos == -1 {
|
||||
// No match found, use start of content
|
||||
start = 0
|
||||
end = snippetLen
|
||||
if end > runeLen {
|
||||
end = runeLen
|
||||
}
|
||||
end = min(snippetLen, runeLen)
|
||||
} else {
|
||||
// Convert byte position to rune position
|
||||
matchRunePos := len([]rune(content[:matchPos]))
|
||||
|
||||
// Extract snippet around match (rune-based)
|
||||
start = matchRunePos - 50
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
start = max(matchRunePos-50, 0)
|
||||
|
||||
end = start + snippetLen
|
||||
if end > runeLen {
|
||||
end = runeLen
|
||||
}
|
||||
end = min(start+snippetLen, runeLen)
|
||||
}
|
||||
|
||||
snippet := string(runes[start:end])
|
||||
|
|
@ -357,11 +349,11 @@ func highlight(text string, res []*regexp.Regexp) string {
|
|||
}
|
||||
|
||||
// Sort matches by start position
|
||||
sort.Slice(matches, func(i, j int) bool {
|
||||
if matches[i].start != matches[j].start {
|
||||
return matches[i].start < matches[j].start
|
||||
slices.SortFunc(matches, func(a, b match) int {
|
||||
if a.start != b.start {
|
||||
return cmp.Compare(a.start, b.start)
|
||||
}
|
||||
return matches[i].end > matches[j].end
|
||||
return cmp.Compare(b.end, a.end) // descending
|
||||
})
|
||||
|
||||
// Merge overlapping or adjacent matches
|
||||
|
|
@ -370,9 +362,7 @@ func highlight(text string, res []*regexp.Regexp) string {
|
|||
curr := matches[0]
|
||||
for i := 1; i < len(matches); i++ {
|
||||
if matches[i].start <= curr.end {
|
||||
if matches[i].end > curr.end {
|
||||
curr.end = matches[i].end
|
||||
}
|
||||
curr.end = max(curr.end, matches[i].end)
|
||||
} else {
|
||||
merged = append(merged, curr)
|
||||
curr = matches[i]
|
||||
|
|
|
|||
|
|
@ -18,14 +18,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -101,7 +103,7 @@ func findProjectRoot() (string, error) {
|
|||
}
|
||||
parent := filepath.Dir(dir)
|
||||
if parent == dir {
|
||||
return "", fmt.Errorf("could not find go.mod in any parent directory")
|
||||
return "", errors.New("could not find go.mod in any parent directory")
|
||||
}
|
||||
dir = parent
|
||||
}
|
||||
|
|
@ -507,11 +509,11 @@ func printReport(result ValidationResult) {
|
|||
fmt.Printf("-------------\n")
|
||||
|
||||
// Sort by file then line
|
||||
sort.Slice(result.MissingKeys, func(i, j int) bool {
|
||||
if result.MissingKeys[i].File != result.MissingKeys[j].File {
|
||||
return result.MissingKeys[i].File < result.MissingKeys[j].File
|
||||
slices.SortFunc(result.MissingKeys, func(a, b KeyUsage) int {
|
||||
if a.File != b.File {
|
||||
return cmp.Compare(a.File, b.File)
|
||||
}
|
||||
return result.MissingKeys[i].Line < result.MissingKeys[j].Line
|
||||
return cmp.Compare(a.Line, b.Line)
|
||||
})
|
||||
|
||||
for _, usage := range result.MissingKeys {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package i18n
|
|||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path"
|
||||
|
|
@ -118,7 +119,7 @@ func NewWithLoader(loader Loader, opts ...Option) (*Service, error) {
|
|||
// Load all available languages
|
||||
langs := loader.Languages()
|
||||
if len(langs) == 0 {
|
||||
return nil, fmt.Errorf("no languages available from loader")
|
||||
return nil, errors.New("no languages available from loader")
|
||||
}
|
||||
|
||||
for _, lang := range langs {
|
||||
|
|
@ -223,7 +224,7 @@ func (s *Service) SetLanguage(lang string) error {
|
|||
}
|
||||
|
||||
if len(s.availableLangs) == 0 {
|
||||
return fmt.Errorf("no languages available")
|
||||
return errors.New("no languages available")
|
||||
}
|
||||
|
||||
matcher := language.NewMatcher(s.availableLangs)
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@
|
|||
package datanode
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
goio "io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -359,8 +360,8 @@ func (m *Medium) List(p string) ([]fs.DirEntry, error) {
|
|||
}
|
||||
}
|
||||
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
return entries[i].Name() < entries[j].Name()
|
||||
slices.SortFunc(entries, func(a, b fs.DirEntry) int {
|
||||
return cmp.Compare(a.Name(), b.Name())
|
||||
})
|
||||
|
||||
return entries, nil
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ package node
|
|||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"cmp"
|
||||
goio "io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -335,8 +336,8 @@ func (n *Node) ReadDir(name string) ([]fs.DirEntry, error) {
|
|||
}
|
||||
}
|
||||
|
||||
sort.Slice(entries, func(i, j int) bool {
|
||||
return entries[i].Name() < entries[j].Name()
|
||||
slices.SortFunc(entries, func(a, b fs.DirEntry) int {
|
||||
return cmp.Compare(a.Name(), b.Name())
|
||||
})
|
||||
|
||||
return entries, nil
|
||||
|
|
|
|||
|
|
@ -103,10 +103,7 @@ func (x *XORObfuscator) deriveKeyStream(entropy []byte, length int) []byte {
|
|||
h.Write(blockBytes[:])
|
||||
block := h.Sum(nil)
|
||||
|
||||
copyLen := len(block)
|
||||
if offset+copyLen > length {
|
||||
copyLen = length - offset
|
||||
}
|
||||
copyLen := min(len(block), length-offset)
|
||||
copy(stream[offset:], block[:copyLen])
|
||||
offset += copyLen
|
||||
blockNum++
|
||||
|
|
@ -222,10 +219,7 @@ func (s *ShuffleMaskObfuscator) deriveMask(entropy []byte, length int) []byte {
|
|||
h.Write(blockBytes[:])
|
||||
block := h.Sum(nil)
|
||||
|
||||
copyLen := len(block)
|
||||
if offset+copyLen > length {
|
||||
copyLen = length - offset
|
||||
}
|
||||
copyLen := min(len(block), length-offset)
|
||||
copy(mask[offset:], block[:copyLen])
|
||||
offset += copyLen
|
||||
blockNum++
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
package collector
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -126,8 +127,11 @@ func (i *InfluxDB) Collect(ctx context.Context) error {
|
|||
for _, r := range runSet {
|
||||
data.Runs = append(data.Runs, r)
|
||||
}
|
||||
sort.Slice(data.Runs, func(i, j int) bool {
|
||||
return data.Runs[i].Model < data.Runs[j].Model || (data.Runs[i].Model == data.Runs[j].Model && data.Runs[i].RunID < data.Runs[j].RunID)
|
||||
slices.SortFunc(data.Runs, func(a, b lab.BenchmarkRun) int {
|
||||
if c := cmp.Compare(a.Model, b.Model); c != 0 {
|
||||
return c
|
||||
}
|
||||
return cmp.Compare(a.RunID, b.RunID)
|
||||
})
|
||||
|
||||
i.store.SetBenchmarks(data)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"math"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
|
|
@ -60,25 +62,15 @@ func LossChart(points []lab.LossPoint) template.HTML {
|
|||
yMin, yMax := allPts[0].Loss, allPts[0].Loss
|
||||
for _, p := range allPts {
|
||||
x := float64(p.Iteration)
|
||||
if x < xMin {
|
||||
xMin = x
|
||||
}
|
||||
if x > xMax {
|
||||
xMax = x
|
||||
}
|
||||
if p.Loss < yMin {
|
||||
yMin = p.Loss
|
||||
}
|
||||
if p.Loss > yMax {
|
||||
yMax = p.Loss
|
||||
}
|
||||
xMin = min(xMin, x)
|
||||
xMax = max(xMax, x)
|
||||
yMin = min(yMin, p.Loss)
|
||||
yMax = max(yMax, p.Loss)
|
||||
}
|
||||
|
||||
// Add padding to Y range.
|
||||
yRange := yMax - yMin
|
||||
if yRange < 0.1 {
|
||||
yRange = 0.1
|
||||
}
|
||||
yRange = max(yRange, 0.1)
|
||||
yMin = yMin - yRange*0.1
|
||||
yMax = yMax + yRange*0.1
|
||||
if xMax == xMin {
|
||||
|
|
@ -102,13 +94,7 @@ func LossChart(points []lab.LossPoint) template.HTML {
|
|||
}
|
||||
|
||||
// X axis labels.
|
||||
nGridX := 6
|
||||
if int(xMax-xMin) < nGridX {
|
||||
nGridX = int(xMax - xMin)
|
||||
}
|
||||
if nGridX < 1 {
|
||||
nGridX = 1
|
||||
}
|
||||
nGridX := max(min(6, int(xMax-xMin)), 1)
|
||||
for i := 0; i <= nGridX; i++ {
|
||||
xVal := xMin + float64(i)*(xMax-xMin)/float64(nGridX)
|
||||
x := scaleX(xVal)
|
||||
|
|
@ -118,7 +104,7 @@ func LossChart(points []lab.LossPoint) template.HTML {
|
|||
|
||||
// Draw train loss line (dimmed).
|
||||
if len(trainPts) > 1 {
|
||||
sort.Slice(trainPts, func(i, j int) bool { return trainPts[i].Iteration < trainPts[j].Iteration })
|
||||
slices.SortFunc(trainPts, func(a, b lab.LossPoint) int { return cmp.Compare(a.Iteration, b.Iteration) })
|
||||
sb.WriteString(`<polyline points="`)
|
||||
for i, p := range trainPts {
|
||||
if i > 0 {
|
||||
|
|
@ -134,7 +120,7 @@ func LossChart(points []lab.LossPoint) template.HTML {
|
|||
|
||||
// Draw val loss line (accent).
|
||||
if len(valPts) > 1 {
|
||||
sort.Slice(valPts, func(i, j int) bool { return valPts[i].Iteration < valPts[j].Iteration })
|
||||
slices.SortFunc(valPts, func(a, b lab.LossPoint) int { return cmp.Compare(a.Iteration, b.Iteration) })
|
||||
sb.WriteString(`<polyline points="`)
|
||||
for i, p := range valPts {
|
||||
if i > 0 {
|
||||
|
|
@ -232,7 +218,7 @@ func ContentChart(points []lab.ContentPoint) template.HTML {
|
|||
if !ok || len(pts) < 2 {
|
||||
continue
|
||||
}
|
||||
sort.Slice(pts, func(i, j int) bool { return pts[i].Iteration < pts[j].Iteration })
|
||||
slices.SortFunc(pts, func(a, b lab.ContentPoint) int { return cmp.Compare(a.Iteration, b.Iteration) })
|
||||
|
||||
// Average duplicate iterations.
|
||||
averaged := averageByIteration(pts)
|
||||
|
|
@ -285,7 +271,7 @@ func CapabilityChart(points []lab.CapabilityPoint) template.HTML {
|
|||
overall = append(overall, p)
|
||||
}
|
||||
}
|
||||
sort.Slice(overall, func(i, j int) bool { return overall[i].Iteration < overall[j].Iteration })
|
||||
slices.SortFunc(overall, func(a, b lab.CapabilityPoint) int { return cmp.Compare(a.Iteration, b.Iteration) })
|
||||
|
||||
if len(overall) == 0 {
|
||||
return template.HTML(`<div class="empty">No overall capability data</div>`)
|
||||
|
|
@ -532,21 +518,14 @@ func DomainChart(stats []lab.DomainStat) template.HTML {
|
|||
if len(stats) == 0 {
|
||||
return ""
|
||||
}
|
||||
limit := 25
|
||||
if len(stats) < limit {
|
||||
limit = len(stats)
|
||||
}
|
||||
limit := min(25, len(stats))
|
||||
items := stats[:limit]
|
||||
|
||||
maxCount := 0
|
||||
for _, d := range items {
|
||||
if d.Count > maxCount {
|
||||
maxCount = d.Count
|
||||
}
|
||||
}
|
||||
if maxCount == 0 {
|
||||
maxCount = 1
|
||||
maxCount = max(maxCount, d.Count)
|
||||
}
|
||||
maxCount = max(maxCount, 1)
|
||||
|
||||
barH := 18
|
||||
gap := 4
|
||||
|
|
@ -561,10 +540,7 @@ func DomainChart(stats []lab.DomainStat) template.HTML {
|
|||
|
||||
for i, d := range items {
|
||||
y := i*(barH+gap) + 5
|
||||
barW := int(float64(d.Count) / float64(maxCount) * float64(barAreaW))
|
||||
if barW < 2 {
|
||||
barW = 2
|
||||
}
|
||||
barW := max(int(float64(d.Count)/float64(maxCount)*float64(barAreaW)), 2)
|
||||
fmt.Fprintf(&b, `<text x="%d" y="%d" fill="var(--muted)" font-size="11" text-anchor="end" dominant-baseline="middle">%s</text>`,
|
||||
labelW-8, y+barH/2, template.HTMLEscapeString(d.Domain))
|
||||
fmt.Fprintf(&b, `<rect x="%d" y="%d" width="%d" height="%d" fill="var(--accent)" rx="2" opacity="0.8"/>`,
|
||||
|
|
@ -585,13 +561,9 @@ func VoiceChart(stats []lab.VoiceStat) template.HTML {
|
|||
|
||||
maxCount := 0
|
||||
for _, v := range stats {
|
||||
if v.Count > maxCount {
|
||||
maxCount = v.Count
|
||||
}
|
||||
}
|
||||
if maxCount == 0 {
|
||||
maxCount = 1
|
||||
maxCount = max(maxCount, v.Count)
|
||||
}
|
||||
maxCount = max(maxCount, 1)
|
||||
|
||||
barW := 50
|
||||
gap := 8
|
||||
|
|
@ -607,10 +579,7 @@ func VoiceChart(stats []lab.VoiceStat) template.HTML {
|
|||
|
||||
for i, v := range stats {
|
||||
x := i*(barW+gap) + gap + 5
|
||||
barH := int(float64(v.Count) / float64(maxCount) * float64(chartHeight))
|
||||
if barH < 2 {
|
||||
barH = 2
|
||||
}
|
||||
barH := max(int(float64(v.Count)/float64(maxCount)*float64(chartHeight)), 2)
|
||||
y := topPad + chartHeight - barH
|
||||
|
||||
fmt.Fprintf(&b, `<rect x="%d" y="%d" width="%d" height="%d" fill="var(--green)" rx="2" opacity="0.7"/>`,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"sort"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -72,10 +73,7 @@ func NewWebHandler(s *lab.Store) *WebHandler {
|
|||
if cores <= 0 {
|
||||
return "0"
|
||||
}
|
||||
pct := load / float64(cores) * 100
|
||||
if pct > 100 {
|
||||
pct = 100
|
||||
}
|
||||
pct := min(load/float64(cores)*100, 100)
|
||||
return fmt.Sprintf("%.0f", pct)
|
||||
},
|
||||
"fmtGB": func(v float64) string {
|
||||
|
|
@ -376,11 +374,14 @@ func buildModelGroups(runs []lab.TrainingRunStatus, benchmarks lab.BenchmarkData
|
|||
}
|
||||
result = append(result, *g)
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if result[i].HasTraining != result[j].HasTraining {
|
||||
return result[i].HasTraining
|
||||
slices.SortFunc(result, func(a, b ModelGroup) int {
|
||||
if a.HasTraining != b.HasTraining {
|
||||
if a.HasTraining {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
}
|
||||
return result[i].Model < result[j].Model
|
||||
return cmp.Compare(a.Model, b.Model)
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package manifest
|
|||
import (
|
||||
"crypto/ed25519"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
|
@ -29,7 +30,7 @@ func Sign(m *Manifest, priv ed25519.PrivateKey) error {
|
|||
// Verify checks the ed25519 signature in m.Sign against the public key.
|
||||
func Verify(m *Manifest, pub ed25519.PublicKey) (bool, error) {
|
||||
if m.Sign == "" {
|
||||
return false, fmt.Errorf("manifest.Verify: no signature present")
|
||||
return false, errors.New("manifest.Verify: no signature present")
|
||||
}
|
||||
sig, err := base64.StdEncoding.DecodeString(m.Sign)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ func (i *Installer) cloneRepo(ctx context.Context, org, repo, version, dest stri
|
|||
|
||||
cmd := exec.CommandContext(ctx, "gh", args...)
|
||||
if output, err := cmd.CombinedOutput(); err != nil {
|
||||
return fmt.Errorf("%s: %s", err, strings.TrimSpace(string(output)))
|
||||
return fmt.Errorf("%w: %s", err, strings.TrimSpace(string(output)))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
package plugin
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"slices"
|
||||
|
||||
core "forge.lthn.ai/core/go/pkg/framework/core"
|
||||
"forge.lthn.ai/core/go/pkg/io"
|
||||
|
|
@ -34,8 +35,8 @@ func (r *Registry) List() []*PluginConfig {
|
|||
for _, cfg := range r.plugins {
|
||||
result = append(result, cfg)
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
return result[i].Name < result[j].Name
|
||||
slices.SortFunc(result, func(a, b *PluginConfig) int {
|
||||
return cmp.Compare(a.Name, b.Name)
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package process
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -104,7 +104,7 @@ func (r *Runner) RunAll(ctx context.Context, specs []RunSpec) (*RunAllResult, er
|
|||
Name: name,
|
||||
Spec: remaining[name],
|
||||
Skipped: true,
|
||||
Error: fmt.Errorf("circular dependency or missing dependency"),
|
||||
Error: errors.New("circular dependency or missing dependency"),
|
||||
})
|
||||
}
|
||||
break
|
||||
|
|
@ -136,7 +136,7 @@ func (r *Runner) RunAll(ctx context.Context, specs []RunSpec) (*RunAllResult, er
|
|||
Name: spec.Name,
|
||||
Spec: spec,
|
||||
Skipped: true,
|
||||
Error: fmt.Errorf("skipped due to dependency failure"),
|
||||
Error: errors.New("skipped due to dependency failure"),
|
||||
}
|
||||
} else {
|
||||
result = r.runSpec(ctx, spec)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
package repos
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
|
@ -146,7 +147,7 @@ func FindRegistry(m io.Medium) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("repos.yaml not found")
|
||||
return "", errors.New("repos.yaml not found")
|
||||
}
|
||||
|
||||
// ScanDirectory creates a Registry by scanning a directory for git repos.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -54,7 +55,7 @@ type contentBlock struct {
|
|||
Text string `json:"text,omitempty"`
|
||||
Input json.RawMessage `json:"input,omitempty"`
|
||||
ToolUseID string `json:"tool_use_id,omitempty"`
|
||||
Content interface{} `json:"content,omitempty"`
|
||||
Content any `json:"content,omitempty"`
|
||||
IsError *bool `json:"is_error,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -156,8 +157,8 @@ func ListSessions(projectsDir string) ([]Session, error) {
|
|||
sessions = append(sessions, s)
|
||||
}
|
||||
|
||||
sort.Slice(sessions, func(i, j int) bool {
|
||||
return sessions[i].StartTime.After(sessions[j].StartTime)
|
||||
slices.SortFunc(sessions, func(a, b Session) int {
|
||||
return b.StartTime.Compare(a.StartTime) // descending
|
||||
})
|
||||
|
||||
return sessions, nil
|
||||
|
|
@ -340,7 +341,7 @@ func extractToolInput(toolName string, raw json.RawMessage) string {
|
|||
}
|
||||
|
||||
// Fallback: show raw JSON keys
|
||||
var m map[string]interface{}
|
||||
var m map[string]any
|
||||
if json.Unmarshal(raw, &m) == nil {
|
||||
var parts []string
|
||||
for k := range m {
|
||||
|
|
@ -353,21 +354,21 @@ func extractToolInput(toolName string, raw json.RawMessage) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func extractResultContent(content interface{}) string {
|
||||
func extractResultContent(content any) string {
|
||||
switch v := content.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []interface{}:
|
||||
case []any:
|
||||
var parts []string
|
||||
for _, item := range v {
|
||||
if m, ok := item.(map[string]interface{}); ok {
|
||||
if m, ok := item.(map[string]any); ok {
|
||||
if text, ok := m["text"].(string); ok {
|
||||
parts = append(parts, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(parts, "\n")
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
if text, ok := v["text"].(string); ok {
|
||||
return text
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
|
@ -10,7 +11,7 @@ import (
|
|||
// RenderMP4 generates an MP4 video from session events using VHS (charmbracelet).
|
||||
func RenderMP4(sess *Session, outputPath string) error {
|
||||
if _, err := exec.LookPath("vhs"); err != nil {
|
||||
return fmt.Errorf("vhs not installed (go install github.com/charmbracelet/vhs@latest)")
|
||||
return errors.New("vhs not installed (go install github.com/charmbracelet/vhs@latest)")
|
||||
}
|
||||
|
||||
tape := generateTape(sess, outputPath)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package webview
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -191,7 +192,7 @@ func (a HoverAction) Execute(ctx context.Context, wv *Webview) error {
|
|||
}
|
||||
|
||||
if elem.BoundingBox == nil {
|
||||
return fmt.Errorf("element has no bounding box")
|
||||
return errors.New("element has no bounding box")
|
||||
}
|
||||
|
||||
x := elem.BoundingBox.X + elem.BoundingBox.Width/2
|
||||
|
|
@ -234,7 +235,7 @@ func (a DoubleClickAction) Execute(ctx context.Context, wv *Webview) error {
|
|||
y := elem.BoundingBox.Y + elem.BoundingBox.Height/2
|
||||
|
||||
// Double click sequence
|
||||
for i := 0; i < 2; i++ {
|
||||
for i := range 2 {
|
||||
for _, eventType := range []string{"mousePressed", "mouseReleased"} {
|
||||
_, err := wv.client.Call(ctx, "Input.dispatchMouseEvent", map[string]any{
|
||||
"type": eventType,
|
||||
|
|
@ -495,7 +496,7 @@ func (wv *Webview) DragAndDrop(sourceSelector, targetSelector string) error {
|
|||
return fmt.Errorf("source element not found: %w", err)
|
||||
}
|
||||
if source.BoundingBox == nil {
|
||||
return fmt.Errorf("source element has no bounding box")
|
||||
return errors.New("source element has no bounding box")
|
||||
}
|
||||
|
||||
target, err := wv.querySelector(ctx, targetSelector)
|
||||
|
|
@ -503,7 +504,7 @@ func (wv *Webview) DragAndDrop(sourceSelector, targetSelector string) error {
|
|||
return fmt.Errorf("target element not found: %w", err)
|
||||
}
|
||||
if target.BoundingBox == nil {
|
||||
return fmt.Errorf("target element has no bounding box")
|
||||
return errors.New("target element has no bounding box")
|
||||
}
|
||||
|
||||
// Calculate center points
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package webview
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
|
@ -42,7 +43,7 @@ func (ah *AngularHelper) waitForAngular(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
if !isAngular {
|
||||
return fmt.Errorf("not an Angular application")
|
||||
return errors.New("not an Angular application")
|
||||
}
|
||||
|
||||
// Wait for Zone.js stability
|
||||
|
|
@ -278,13 +279,13 @@ func (ah *AngularHelper) GetRouterState() (*AngularRouterState, error) {
|
|||
}
|
||||
|
||||
if result == nil {
|
||||
return nil, fmt.Errorf("could not get router state")
|
||||
return nil, errors.New("could not get router state")
|
||||
}
|
||||
|
||||
// Parse result
|
||||
resultMap, ok := result.(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid router state format")
|
||||
return nil, errors.New("invalid router state format")
|
||||
}
|
||||
|
||||
state := &AngularRouterState{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package webview
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -121,7 +122,7 @@ func NewCDPClient(debugURL string) (*CDPClient, error) {
|
|||
}
|
||||
|
||||
if wsURL == "" {
|
||||
return nil, fmt.Errorf("no WebSocket URL available")
|
||||
return nil, errors.New("no WebSocket URL available")
|
||||
}
|
||||
|
||||
// Connect to WebSocket
|
||||
|
|
@ -306,7 +307,7 @@ func (c *CDPClient) NewTab(url string) (*CDPClient, error) {
|
|||
}
|
||||
|
||||
if target.WebSocketDebuggerURL == "" {
|
||||
return nil, fmt.Errorf("no WebSocket URL for new tab")
|
||||
return nil, errors.New("no WebSocket URL for new tab")
|
||||
}
|
||||
|
||||
// Connect to new tab
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ package webview
|
|||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -122,7 +123,7 @@ func New(opts ...Option) (*Webview, error) {
|
|||
|
||||
if wv.client == nil {
|
||||
cancel()
|
||||
return nil, fmt.Errorf("no debug URL provided; use WithDebugURL option")
|
||||
return nil, errors.New("no debug URL provided; use WithDebugURL option")
|
||||
}
|
||||
|
||||
// Enable console capture
|
||||
|
|
@ -222,7 +223,7 @@ func (wv *Webview) Screenshot() ([]byte, error) {
|
|||
|
||||
dataStr, ok := result["data"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid screenshot data")
|
||||
return nil, errors.New("invalid screenshot data")
|
||||
}
|
||||
|
||||
data, err := base64.StdEncoding.DecodeString(dataStr)
|
||||
|
|
@ -263,7 +264,7 @@ func (wv *Webview) GetURL() (string, error) {
|
|||
|
||||
url, ok := result.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid URL result")
|
||||
return "", errors.New("invalid URL result")
|
||||
}
|
||||
|
||||
return url, nil
|
||||
|
|
@ -281,7 +282,7 @@ func (wv *Webview) GetTitle() (string, error) {
|
|||
|
||||
title, ok := result.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid title result")
|
||||
return "", errors.New("invalid title result")
|
||||
}
|
||||
|
||||
return title, nil
|
||||
|
|
@ -306,7 +307,7 @@ func (wv *Webview) GetHTML(selector string) (string, error) {
|
|||
|
||||
html, ok := result.(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("invalid HTML result")
|
||||
return "", errors.New("invalid HTML result")
|
||||
}
|
||||
|
||||
return html, nil
|
||||
|
|
@ -520,7 +521,7 @@ func (wv *Webview) evaluate(ctx context.Context, script string) (any, error) {
|
|||
return nil, fmt.Errorf("JavaScript error: %s", description)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("JavaScript error")
|
||||
return nil, errors.New("JavaScript error")
|
||||
}
|
||||
|
||||
// Extract result value
|
||||
|
|
@ -541,12 +542,12 @@ func (wv *Webview) querySelector(ctx context.Context, selector string) (*Element
|
|||
|
||||
root, ok := docResult["root"].(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid document root")
|
||||
return nil, errors.New("invalid document root")
|
||||
}
|
||||
|
||||
rootID, ok := root["nodeId"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid root node ID")
|
||||
return nil, errors.New("invalid root node ID")
|
||||
}
|
||||
|
||||
// Query selector
|
||||
|
|
@ -576,12 +577,12 @@ func (wv *Webview) querySelectorAll(ctx context.Context, selector string) ([]*El
|
|||
|
||||
root, ok := docResult["root"].(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid document root")
|
||||
return nil, errors.New("invalid document root")
|
||||
}
|
||||
|
||||
rootID, ok := root["nodeId"].(float64)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid root node ID")
|
||||
return nil, errors.New("invalid root node ID")
|
||||
}
|
||||
|
||||
// Query selector all
|
||||
|
|
@ -595,7 +596,7 @@ func (wv *Webview) querySelectorAll(ctx context.Context, selector string) ([]*El
|
|||
|
||||
nodeIDs, ok := queryResult["nodeIds"].([]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid node IDs")
|
||||
return nil, errors.New("invalid node IDs")
|
||||
}
|
||||
|
||||
elements := make([]*ElementInfo, 0, len(nodeIDs))
|
||||
|
|
@ -622,7 +623,7 @@ func (wv *Webview) getElementInfo(ctx context.Context, nodeID int) (*ElementInfo
|
|||
|
||||
node, ok := descResult["node"].(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid node description")
|
||||
return nil, errors.New("invalid node description")
|
||||
}
|
||||
|
||||
tagName, _ := node["nodeName"].(string)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ package ws
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
|
@ -220,7 +221,7 @@ func (h *Hub) Broadcast(msg Message) error {
|
|||
select {
|
||||
case h.broadcast <- data:
|
||||
default:
|
||||
return fmt.Errorf("broadcast channel full")
|
||||
return errors.New("broadcast channel full")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -424,7 +425,7 @@ func (c *Client) writePump() {
|
|||
|
||||
// Batch queued messages
|
||||
n := len(c.send)
|
||||
for i := 0; i < n; i++ {
|
||||
for range n {
|
||||
w.Write([]byte{'\n'})
|
||||
w.Write(<-c.send)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue