Backup AI usage history on reset

This commit is contained in:
rcourtman 2025-12-12 12:14:13 +00:00
parent 4df04970ea
commit 1294a66f56
3 changed files with 34 additions and 5 deletions

View file

@ -55,7 +55,7 @@ export class AIAPI {
return apiFetchJSON(`${this.baseUrl}/ai/cost/reset`, {
method: 'POST',
body: JSON.stringify({}),
}) as Promise<{ ok: boolean }>;
}) as Promise<{ ok: boolean; backup_file?: string }>;
}
// Start OAuth flow for Claude Pro/Max subscription

View file

@ -187,10 +187,14 @@ export const AICostDashboard: Component = () => {
};
const resetHistory = async () => {
if (!confirm('Reset AI usage history? This clears the stored token/cost history.')) return;
if (!confirm('Reset AI usage history? A backup will be created in the Pulse config directory.')) return;
try {
await AIAPI.resetCostHistory();
notificationStore.success('AI usage history reset');
const result = await AIAPI.resetCostHistory();
if (result.backup_file) {
notificationStore.success(`AI usage history reset (backup: ${result.backup_file})`);
} else {
notificationStore.success('AI usage history reset');
}
await loadSummary(days());
} catch (err) {
logger.error('[AICostDashboard] Failed to reset AI cost history:', err);

View file

@ -6,6 +6,8 @@ import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"time"
@ -2460,13 +2462,36 @@ func (h *AISettingsHandler) HandleResetAICostHistory(w http.ResponseWriter, r *h
return
}
backupFile := ""
if h.persistence != nil {
configDir := h.persistence.DataDir()
if strings.TrimSpace(configDir) != "" {
usagePath := filepath.Join(configDir, "ai_usage_history.json")
if _, err := os.Stat(usagePath); err == nil {
ts := time.Now().UTC().Format("20060102-150405")
backupFile = fmt.Sprintf("ai_usage_history.json.bak-%s", ts)
backupPath := filepath.Join(configDir, backupFile)
if err := os.Rename(usagePath, backupPath); err != nil {
log.Error().Err(err).Str("path", usagePath).Msg("Failed to backup AI usage history before reset")
http.Error(w, "Failed to backup AI usage history", http.StatusInternalServerError)
return
}
}
}
}
if err := h.aiService.ClearCostHistory(); err != nil {
log.Error().Err(err).Msg("Failed to clear AI cost history")
http.Error(w, "Failed to clear AI cost history", http.StatusInternalServerError)
return
}
if err := utils.WriteJSONResponse(w, map[string]any{"ok": true}); err != nil {
resp := map[string]any{"ok": true}
if backupFile != "" {
resp["backup_file"] = backupFile
}
if err := utils.WriteJSONResponse(w, resp); err != nil {
log.Error().Err(err).Msg("Failed to write clear cost history response")
}
}