Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

88 lines
3.1 KiB
Go

package persistence
import (
"fmt"
"time"
)
// PromotedToolEntry is one workspace-learned tool promotion: a tool that
// was deferred behind tools_search but has been promoted into the eager
// surface for this repo/workspace after use. Persisted so the learned
// surface survives daemon restarts. last_used_epoch drives demotion — a
// promotion unused for N session epochs is dropped back to deferred.
type PromotedToolEntry struct {
Tool string
WorkspaceID string
PromotedEpoch int64
LastUsedEpoch int64
UseCount int64
UpdatedAt time.Time
}
// LoadPromotedTools reads every learned promotion for a repo_key.
func (s *SidecarStore) LoadPromotedTools(repoKey string) ([]PromotedToolEntry, error) {
rows, err := s.db.Query(`
SELECT tool, workspace_id, promoted_epoch, last_used_epoch, use_count, updated_at
FROM promoted_tools WHERE repo_key = ?
ORDER BY tool ASC`, repoKey)
if err != nil {
return nil, fmt.Errorf("persistence: query promoted_tools: %w", err)
}
defer rows.Close()
var out []PromotedToolEntry
for rows.Next() {
var e PromotedToolEntry
var updatedAt int64
if err := rows.Scan(&e.Tool, &e.WorkspaceID, &e.PromotedEpoch,
&e.LastUsedEpoch, &e.UseCount, &updatedAt); err != nil {
return out, fmt.Errorf("persistence: scan promoted_tool: %w", err)
}
e.UpdatedAt = fromUnix(updatedAt)
out = append(out, e)
}
return out, rows.Err()
}
// UpsertPromotedTool writes (or replaces) one learned promotion.
func (s *SidecarStore) UpsertPromotedTool(repoKey string, e PromotedToolEntry) error {
s.writeMu.Lock()
defer s.writeMu.Unlock()
_, err := s.db.Exec(`
INSERT OR REPLACE INTO promoted_tools
(repo_key, tool, workspace_id, promoted_epoch, last_used_epoch, use_count, updated_at)
VALUES (?,?,?,?,?,?,?)`,
repoKey, e.Tool, e.WorkspaceID, e.PromotedEpoch, e.LastUsedEpoch,
e.UseCount, unixOrZero(e.UpdatedAt))
if err != nil {
return fmt.Errorf("persistence: upsert promoted_tool: %w", err)
}
return nil
}
// DeletePromotedTool drops one learned promotion (demotion). Missing rows
// are not errors.
func (s *SidecarStore) DeletePromotedTool(repoKey, tool string) error {
s.writeMu.Lock()
defer s.writeMu.Unlock()
_, err := s.db.Exec(`DELETE FROM promoted_tools WHERE repo_key = ? AND tool = ?`, repoKey, tool)
return err
}
// BumpSessionEpoch increments and returns the repo_key's session epoch — a
// monotonic counter advanced once per server startup, so "unused for N
// sessions" can be measured against last_used_epoch.
func (s *SidecarStore) BumpSessionEpoch(repoKey string) (int64, error) {
s.writeMu.Lock()
defer s.writeMu.Unlock()
if _, err := s.db.Exec(`
INSERT INTO tool_surface_meta (repo_key, session_epoch) VALUES (?, 1)
ON CONFLICT(repo_key) DO UPDATE SET session_epoch = session_epoch + 1`, repoKey); err != nil {
return 0, fmt.Errorf("persistence: bump session epoch: %w", err)
}
var epoch int64
if err := s.db.QueryRow(`SELECT session_epoch FROM tool_surface_meta WHERE repo_key = ?`, repoKey).Scan(&epoch); err != nil {
return 0, fmt.Errorf("persistence: read session epoch: %w", err)
}
return epoch, nil
}