CrossRelay stage 0+1: Go gateway with Anthropic<->Chat Completions relay, Tauri shell, bilingual management UI

- Go gateway (stdlib only): /v1/messages non-stream + SSE, /v1/messages/count_tokens,
  management API /api/* (providers CRUD, apply/restore, settings, backups, logs)
- Protocol conversion: Anthropic Messages <-> Chat Completions with a streaming
  state machine keyed by content block index (text, tool_use, parallel calls)
- ~/.claude/settings.json guarded read/write: timestamped backups, managed env
  keys only, one-click restore
- Tauri 2 shell: spawns the gateway sidecar, parses the random port from stdout,
  stdin pipe watchdog prevents orphans, kills the child on exit
- React frontend: Dashboard/Providers/Settings, zh-CN + en-US, TanStack Query
- Tests: Go table-driven + httptest integration (all green), vitest + RTL
This commit is contained in:
kate522 committed 2026-10-18 17:19:13 +08:00
1 parent 8ee5e98ea3
commit f8acf31ebc
71 files changed
+15727 -1

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
package gateway
import "sync"
// logRing keeps the most recent log entries in memory.
type logRing struct {
mu sync.Mutex
entries []LogEntry
cap int
}
func newLogRing(capacity int) *logRing {
return &logRing{cap: capacity}
}
func (r *logRing) add(entry LogEntry) {
r.mu.Lock()
defer r.mu.Unlock()
r.entries = append(r.entries, entry)
if len(r.entries) > r.cap {
r.entries = r.entries[len(r.entries)-r.cap:]
}
}
// list returns entries newest first.
func (r *logRing) list() []LogEntry {
r.mu.Lock()
defer r.mu.Unlock()
out := make([]LogEntry, len(r.entries))
for i, e := range r.entries {
out[len(r.entries)-1-i] = e
}
return out
}