Skip to content

Commit f220cfe

Browse files
committed
feat(history): 代理完成后抢先刷新历史索引
技术变更: - 在 electron/indexer.ts 增加快速刷新队列与增量 upsert 逻辑,统一处理按文件和按根目录的轻量刷新请求。 - 补充 transcriptPath 的可访问路径规范化,兼容 WSL 路径与 UNC 路径互转。 - 在 Claude、Gemini 通知桥接中透传 transcriptPath,在 Codex 通知桥接中触发小范围近期会话扫描。 - 为索引器增加窗口 getter 缓存以及快速刷新状态清理,避免重启或热更新后残留定时器和闭包。 产品行为: - Agent 完成一轮对话后,历史侧栏可以更早显示新会话或最新摘要。 - 不再完全依赖原有 800ms 文件监听去抖链路,同时保留 watcher 与重扫作为兜底。 测试: - 已通过:npm run build:electron - 已通过:npm run test Signed-off-by: Lulu <58587930+lulu-sk@users.noreply.github.com>
1 parent 917773f commit f220cfe

File tree

4 files changed

+424
-22
lines changed

4 files changed

+424
-22
lines changed

electron/claude/notifications.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { BrowserWindow } from "electron";
77
import { perfLogger } from "../log";
88
import { uncToWsl, type SessionsRootCandidate } from "../wsl";
99
import { getClaudeRootCandidatesFastAsync } from "../agentSessions/claude/discovery";
10+
import { requestHistoryFastRefresh } from "../indexer";
1011

1112
const CLAUDE_HOOK_FILENAME = "codexflow_stop_notify.js";
1213
const CLAUDE_HOOK_TIMEOUT_MS = 5000;
@@ -635,10 +636,17 @@ function readClaudeNotifyEntries(source: ClaudeNotifySource): ClaudeNotifyEntry[
635636
}
636637

637638
/**
638-
* 中文说明:将 Claude 通知事件转发给渲染进程。
639+
* 中文说明:将 Claude 通知事件转发给渲染进程,并用 transcriptPath 触发精确历史刷新
639640
*/
640-
function emitClaudeNotify(entry: ClaudeNotifyEntry): void {
641+
function emitClaudeNotify(entry: ClaudeNotifyEntry, sourcePath?: string): void {
641642
const win = claudeNotifyWindowGetter ? claudeNotifyWindowGetter() : null;
643+
try {
644+
requestHistoryFastRefresh({
645+
providerId: "claude",
646+
filePath: entry.transcriptPath,
647+
sourcePath,
648+
});
649+
} catch {}
642650
if (!win) return;
643651
const providerId = String(entry.providerId || "claude").toLowerCase();
644652
if (providerId && providerId !== "claude") return;
@@ -668,7 +676,7 @@ async function pollClaudeNotifyFiles(): Promise<void> {
668676
for (const source of Array.from(claudeNotifySources.values())) {
669677
const entries = readClaudeNotifyEntries(source);
670678
if (!entries.length) continue;
671-
for (const entry of entries) emitClaudeNotify(entry);
679+
for (const entry of entries) emitClaudeNotify(entry, source.filePath);
672680
}
673681
} finally {
674682
claudeNotifyPolling = false;

electron/codex/notifications.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import path from "node:path";
66
import { BrowserWindow } from "electron";
77
import { perfLogger } from "../log";
88
import { getCodexRootsFastAsync } from "../wsl";
9+
import { requestHistoryFastRefresh } from "../indexer";
910

1011
const CODEX_NOTIFY_FILENAME = "codexflow_after_agent_notify.jsonl";
1112
const CODEX_NOTIFY_POLL_INTERVAL_MS = 1200;
@@ -165,10 +166,16 @@ function readCodexNotifyEntries(source: CodexNotifySource): CodexNotifyEntry[] {
165166
}
166167

167168
/**
168-
* 中文说明:将 Codex 通知事件转发给渲染进程。
169+
* 中文说明:将 Codex 通知事件转发给渲染进程,并提示索引器抢先刷新最近历史
169170
*/
170-
function emitCodexNotify(entry: CodexNotifyEntry): void {
171+
function emitCodexNotify(entry: CodexNotifyEntry, sourcePath?: string): void {
171172
const win = codexNotifyWindowGetter ? codexNotifyWindowGetter() : null;
173+
try {
174+
requestHistoryFastRefresh({
175+
providerId: "codex",
176+
sourcePath,
177+
});
178+
} catch {}
172179
if (!win) return;
173180
const providerId = String(entry.providerId || "codex").toLowerCase();
174181
if (providerId && providerId !== "codex") return;
@@ -198,7 +205,7 @@ async function pollCodexNotifyFiles(): Promise<void> {
198205
for (const source of Array.from(codexNotifySources.values())) {
199206
const entries = readCodexNotifyEntries(source);
200207
if (!entries.length) continue;
201-
for (const entry of entries) emitCodexNotify(entry);
208+
for (const entry of entries) emitCodexNotify(entry, source.filePath);
202209
}
203210
} finally {
204211
codexNotifyPolling = false;

electron/gemini/notifications.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { BrowserWindow } from "electron";
77
import { perfLogger } from "../log";
88
import { uncToWsl, type SessionsRootCandidate } from "../wsl";
99
import { getGeminiRootCandidatesFastAsync } from "../agentSessions/gemini/discovery";
10+
import { requestHistoryFastRefresh } from "../indexer";
1011

1112
const GEMINI_HOOK_FILENAME = "codexflow_after_agent_notify.js";
1213
const GEMINI_NOTIFY_FILENAME = "codexflow_after_agent_notify.jsonl";
@@ -796,10 +797,17 @@ function readGeminiNotifyEntries(source: GeminiNotifySource): GeminiNotifyEntry[
796797
}
797798

798799
/**
799-
* 中文说明:将 Gemini 通知事件转发给渲染进程。
800+
* 中文说明:将 Gemini 通知事件转发给渲染进程,并用 transcriptPath 触发精确历史刷新
800801
*/
801-
function emitGeminiNotify(entry: GeminiNotifyEntry): void {
802+
function emitGeminiNotify(entry: GeminiNotifyEntry, sourcePath?: string): void {
802803
const win = geminiNotifyWindowGetter ? geminiNotifyWindowGetter() : null;
804+
try {
805+
requestHistoryFastRefresh({
806+
providerId: "gemini",
807+
filePath: entry.transcriptPath,
808+
sourcePath,
809+
});
810+
} catch {}
803811
if (!win) return;
804812
const providerId = String(entry.providerId || "gemini").toLowerCase();
805813
if (providerId && providerId !== "gemini") return;
@@ -829,7 +837,7 @@ async function pollGeminiNotifyFiles(): Promise<void> {
829837
for (const source of Array.from(geminiNotifySources.values())) {
830838
const entries = readGeminiNotifyEntries(source);
831839
if (!entries.length) continue;
832-
for (const entry of entries) emitGeminiNotify(entry);
840+
for (const entry of entries) emitGeminiNotify(entry, source.filePath);
833841
}
834842
} finally {
835843
geminiNotifyPolling = false;

0 commit comments

Comments
 (0)