feat: 升级至 v0.3.16 — 工单修复 51 项 + 审查修复 30 项(安全加固/适配器/工具系统/数据层/前端)
This commit is contained in:
@@ -324,8 +324,21 @@ export class ConfirmationHook implements PreToolHook {
|
||||
return new Promise<boolean>((resolve) => {
|
||||
const expiresAt = Date.now() + this.confirmationTimeoutMs;
|
||||
|
||||
// #18 修复: 超时与用户确认的竞态条件防护
|
||||
// 场景:超时 setTimeout 回调已进入事件循环队列但尚未执行时,用户点击确认,
|
||||
// resolveConfirmation 中 clearTimeout 无法取消已排队的回调,
|
||||
// 导致用户已确认但仍弹出"超时 toast"等副作用。
|
||||
// 使用 settled 标志确保超时分支与确认分支互斥,先到者赢,另一分支直接 return。
|
||||
let settled = false;
|
||||
const safeResolve = (v: boolean) => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
resolve(v);
|
||||
};
|
||||
|
||||
// 设置超时
|
||||
const timer = setTimeout(() => {
|
||||
if (settled) return; // 已被 resolveConfirmation 处理,跳过超时副作用
|
||||
this.pendingConfirmations.delete(request.toolCallId);
|
||||
// 超时发送 toast 通知用户(3 秒节流,防止并行工具风暴)
|
||||
if (this.mainWindow && !this.mainWindow.isDestroyed()) {
|
||||
@@ -343,11 +356,11 @@ export class ConfirmationHook implements PreToolHook {
|
||||
});
|
||||
}
|
||||
}
|
||||
resolve(false); // 超时视为拒绝
|
||||
safeResolve(false); // 超时视为拒绝
|
||||
}, this.confirmationTimeoutMs);
|
||||
|
||||
this.pendingConfirmations.set(request.toolCallId, {
|
||||
resolve,
|
||||
resolve: safeResolve,
|
||||
timer,
|
||||
toolName: request.toolName,
|
||||
expiresAt,
|
||||
|
||||
@@ -20,16 +20,24 @@ export class AuditLogHook implements PostToolHook {
|
||||
constructor(private auditService: AuditService) {}
|
||||
|
||||
async afterExecute(toolCall: MetonaToolCall, result: MetonaToolResult, sessionId: string): Promise<void> {
|
||||
this.auditService.logToolCall({
|
||||
sessionId,
|
||||
iteration: toolCall.iteration,
|
||||
toolName: toolCall.name,
|
||||
args: toolCall.args,
|
||||
outcome: result.success ? 'success' : 'error',
|
||||
result: result.result,
|
||||
error: result.error,
|
||||
durationMs: result.durationMs,
|
||||
});
|
||||
// #17 修复: AuditHook 应为 "fire and forget",hook 失败不应影响工具执行链
|
||||
// 虽然 AuditService.log() 内部已 try-catch,但 hook 层再加一层防御,
|
||||
// 确保任何意外异常(如 getDB 抛错、JSON.stringify 失败)都不会冒泡到 ToolRegistry
|
||||
try {
|
||||
this.auditService.logToolCall({
|
||||
sessionId,
|
||||
iteration: toolCall.iteration,
|
||||
toolName: toolCall.name,
|
||||
args: toolCall.args,
|
||||
outcome: result.success ? 'success' : 'error',
|
||||
result: result.result,
|
||||
error: result.error,
|
||||
durationMs: result.durationMs,
|
||||
});
|
||||
} catch (err) {
|
||||
log.error('[AuditLogHook] Failed to log audit:', err);
|
||||
// 不抛出,让工具执行链继续
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user