feat(mcp): record SQL executions in query history

This commit is contained in:
ccq authored and GitHub committed 2026-09-18 22:50:26 +08:00
1 parent 1c47062cdd
commit 0f6db4b2c7
7 files changed
+264 -6

No files matched your search

@@ -16,6 +16,7 @@ import { canRollbackHistoryEntry } from "@/lib/history/historyAiAnalysis";
import { hasHistoryDateRange, historyDateRangeIsValid, type HistoryDateRange } from "@/lib/history/historyTimeRange";
import { HISTORY_ROW_HEIGHT, HISTORY_SCROLL_BUFFER, shouldVirtualizeHistory } from "@/lib/history/historyVirtualList";
import { historyConnectionHasSelectedDatabase } from "@/lib/history/historySearch";
import { historyEntrySource } from "@/lib/history/historyEntrySource";
import type { HistoryConnectionFilter, HistoryDatabaseFilter, HistoryEntry, HistorySearchRequest } from "@/lib/backend/api";
import { copyToClipboard } from "@/lib/common/clipboard";
import { executeWithProductionSqlGuard } from "@/lib/database/productionExecutionGuard";
@@ -605,6 +606,9 @@ onBeforeUnmount(() => {
{{ kindShortLabel(entry) }}
</span>
<span class="truncate font-medium">{{ entryTitle(entry) }}</span>
<span v-if="historyEntrySource(entry)" class="inline-flex h-5 shrink-0 items-center rounded border border-primary/30 bg-primary/5 px-1 text-[10px] font-medium text-primary">
{{ historyEntrySource(entry) }}
</span>
<span class="ml-auto shrink-0 text-muted-foreground">{{ formatTime(entry.executed_at) }}</span>
</div>
<div class="truncate font-mono text-muted-foreground">{{ entrySubtitle(entry) }}</div>
@@ -0,0 +1,14 @@
import { describe, expect, it } from "vitest";
import { historyEntrySource } from "@/lib/history/historyEntrySource";
describe("historyEntrySource", () => {
it("identifies MCP entries from history details", () => {
expect(historyEntrySource({ details_json: '{"source":"mcp"}' })).toBe("MCP");
});
it("ignores other, missing, or invalid details", () => {
expect(historyEntrySource({ details_json: '{"source":"desktop"}' })).toBeNull();
expect(historyEntrySource({ details_json: null })).toBeNull();
expect(historyEntrySource({ details_json: "{" })).toBeNull();
});
});
@@ -0,0 +1,11 @@
import type { HistoryEntry } from "@/lib/backend/api";
export function historyEntrySource(entry: Pick<HistoryEntry, "details_json">): "MCP" | null {
if (!entry.details_json) return null;
try {
const details = JSON.parse(entry.details_json) as { source?: unknown };
return details.source === "mcp" ? "MCP" : null;
} catch {
return null;
}
}