feat: AI task API, token-based context windows, SSH password auth, sudo bypass detection

Replace message-count context windows with token-budget based ones for both
studio and shell. Add /api/ai/task endpoint for background tool
check/install/update. Enhance sudo blocking to catch piped/chained elevation
commands. Add SSH password support via sshpass and connection editing UI.
Remove realTokens persistence in favor of consumption tracking. Bump to 0.4.1.

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
Augustin
2026-04-26 20:06:20 +02:00
parent c9f2932147
commit d98110ce8a
16 changed files with 446 additions and 105 deletions

View File

@@ -26,18 +26,16 @@ type FeedMessage struct {
}
type Conversation struct {
Messages []FeedMessage `json:"messages"`
Summary string `json:"summary,omitempty"`
RealTokens int `json:"real_tokens,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
Messages []FeedMessage `json:"messages"`
Summary string `json:"summary,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
type ConversationStore struct {
mu sync.RWMutex
path string
conv *Conversation
realTokens int
mu sync.RWMutex
path string
conv *Conversation
}
type TokenCount struct {
@@ -87,7 +85,6 @@ func (cs *ConversationStore) load() {
conv.Messages = []FeedMessage{}
}
cs.conv = &conv
cs.realTokens = conv.RealTokens
}
func (cs *ConversationStore) save() error {
@@ -157,10 +154,8 @@ func (cs *ConversationStore) Clear() {
cs.conv.Messages = []FeedMessage{}
cs.conv.Summary = ""
cs.conv.RealTokens = 0
cs.conv.CreatedAt = time.Now().Format(time.RFC3339)
cs.conv.UpdatedAt = time.Now().Format(time.RFC3339)
cs.realTokens = 0
cs.save()
go cleanupImages(imageIDs)
@@ -184,23 +179,9 @@ func (cs *ConversationStore) TrimOld(keepCount int) {
}
func (cs *ConversationStore) ApproxTokenCount() int {
if cs.realTokens > 0 {
return cs.realTokens
}
return cs.ApproxTokenCountDetailed().total
}
// AddRealTokens accumulates actual token counts from the API response.
func (cs *ConversationStore) AddRealTokens(tokens int) {
if tokens <= 0 {
return
}
cs.mu.Lock()
cs.realTokens += tokens
cs.conv.RealTokens = cs.realTokens
cs.mu.Unlock()
}
func (cs *ConversationStore) ApproxTokenCountDetailed() TokenCount {
cs.mu.RLock()
defer cs.mu.RUnlock()