/** * G3 (2026-08-13): 操作级审计日志(借鉴 devtool audit.jsonl,附录 F.3)。 * * 修复 devtool 的 writeFile read-modify-write 并发竞态(workflowAutomation.ts:267) * ——改用 fs/promises.appendFile(O_APPEND 内核原子,; }): boolean; /** audit 条目(对齐 devtool AuditEntry 5 字段 + enhanced 适配 trace_id/risk/ok)。 */ export interface AuditEntry { timestamp: string; trace_id: string; tool: string; action: string; risk: RiskLevel; ok: boolean; project_path: string; changed_files: string[]; duration_ms: number; caller?: string; details?: { before_values?: Record; batch?: boolean; truncated?: boolean; confirmed?: boolean; [key: string]: unknown; }; } /** 批4-T3(五维评估 P1): 工具→审计上报通道。约定:工具可在 result.structuredContent._audit * 放 { before_values?: Record }(写前旧值,供 suggest_rollback 的 * project.godot 恢复分支消费)。本函数提取 hint 并返回剥离 _audit 键后的 result—— * after hook 的返回值会传回 MCP 客户端,剥离防 _audit 成为半公共 API。 * 非法形态(非对象/无 before_values)静默忽略返回原 result(审计提示是 best-effort,不阻断工具)。 * structuredContent 约束为 unknown 而非 Record:SDK CallToolResult 的该字段是具体 * union 类型,过窄约束会与真实 ToolResult 不兼容(批4 实测)。 */ export interface AuditHint { before_values?: Record; } export declare function extractAuditHint(result: T): { hint: AuditHint | undefined; result: T; }; /** * 原子追加一条 audit(appendFile O_APPEND,修复 devtool writeFile 竞态)。 * 审计失败应由调用方 catch(默认 best-effort 不影响工具结果,对齐 G2 catch 哲学; * ⚠️ 1A STRICT 例外:GODOT_MCP_AUDIT_STRICT=true 时调用方将操作判失败——见 isAuditStrict)。 * 空白 projectPath 拒绝(2026-10-01):join 相对路径会在 CWD 建怪名目录落"项目级"审计 * (实证:ToolDispatcher 测试的 ' ' project_path 每轮全量测试在仓库根积 ' /.godot'); * 此处 throw 交调用方既有 catch(recordAuditWriteFailure 可观测),绝不静默建目录。 */ export declare function appendAuditLine(projectPath: string, entry: AuditEntry): Promise; /** 轮转阈值与保留代数(可测试性:模块常量,测试以小文件触发需另造大文件或直接测 * rotateIfNeeded 的行为契约——阈值本身不 mock,10MB 造文件成本可控)。 */ export declare const AUDIT_ROTATE_SIZE: number; export declare const AUDIT_ROTATE_KEEP = 3; /** 超 AUDIT_ROTATE_SIZE 时链式轮转:.3 删(最老)→.2→.3→.1→.2→主文件→.1。 * 文件不存在/小于阈值 no-op;轮转失败不阻断追加(best-effort——追加是主路径, * 轮转失败仅意味着继续增长,下次再试)。 */ export declare function rotateIfNeeded(filePath: string): Promise; export declare function getExternalAuditDir(): string; /** 外置副本路径:按项目绝对路径 sha256 前 16 hex 命名(一项目一文件;文件名不含项目 * 名/用户名 PII。分隔符归一防 D:\a\b 与 D:/a/b 分裂;I-1(审查)Windows 大小写归一防 * D:\GitHub\Demo 与 d:\github\demo 分裂——分裂不仅丢条目,还会让 compareAuditSources 的 * divergence(projectEntries < externalEntries)恒 false,真实删行篡改漏报。 * 仅 win32 小写:Linux 文件系统大小写敏感,无条件小写会让不同项目碰撞同一外置文件)。 */ export declare function getExternalAuditFile(projectPath: string): string; export interface AuditDivergence { projectEntries: number; externalEntries: number; /** 两副本任何不一致(行数差或同位行内容不同)均为 true(批5-T11 从"单向行数比对"升级)。 */ diverged: boolean; /** 批5-T11: 首个不一致行号(两副本 1-based 共同前缀之后;行数差且前缀全等时=较短方长度+1)。 */ firstDivergentLine?: number; /** 批5-T11: 'length'(行数不一致)|'content'(行数一致但某行内容不同——改字段不删行的 * 篡改形态,批4 前不可检测)。 */ divergenceKind?: 'length' | 'content'; } /** 项目内副本 vs 外置副本逐行内容比对(批5-T11 升级:原仅 `projectEntries < externalEntries` * 单向行数比对,"改字段不删行"的篡改不可检测;两副本由 appendAuditLine 双写同一 line * 字符串,行内容应完全一致,任何同位行差异即篡改信号)。 * 检测力边界(诚实):双删两份副本(行数等且内容等)仍不可检测——需 hash 链/签名,见 * 方案 §4 不做裁决(跨进程并发写断链误报);外置副本自身被同权限进程删改不检(参照系 * 假设,与 THREAT_MODEL 诚实边界一致)。 */ export declare function compareAuditSources(projectPath: string): Promise; /** audit 回放只读统计(不真重放执行,对齐 devtool buildAuditReplay)。 */ export interface AuditReplaySummary { totalEntries: number; timeRange: { first?: string; last?: string; }; operationCounts: Record; changedFileCounts: Record; riskHighlights: { index: number; entry: AuditEntry; reason: string; }[]; parseErrors: number; entries: (AuditEntry & { index: number; })[]; /** 批5-T12: 主文件旁的轮转代(.1~.N)计数——回放只覆盖主文件,轮转代需手动查。 */ rotatedFiles: number; } /** 读 audit.jsonl + 只读统计。limit 取末尾 N 条;since 过滤时间。 * 2A: external=true 读外置副本(防篡改参照,见 getExternalAuditFile)。 */ export declare function readAuditLog(projectPath: string, opts?: { limit?: number; since?: string; external?: boolean; }): Promise; /** * 从 args 推断 changed_files(阶段1 MVP)。 * 限制:project_replace/create_project 批量场景只能给主路径 + batch 标记, * 完整文件集要阶段2(工具显式上报 ToolContext.audit 收集器)。 */ export declare function inferChangedFiles(tool: string, action: string, args: Record, projectPath?: string): { files: string[]; batch: boolean; }; export interface RollbackSuggestion { supported: boolean; suggestions: string[]; } /** 对单条 audit entry 生成诚实回滚建议(不自动执行,对齐 devtool suggestRollback)。 */ export declare function suggestRollback(entry: AuditEntry): RollbackSuggestion; /** 机器级审计文件:~/.godot-mcp/machine-audit.jsonl(机器级目录惯例)。 */ export declare function getMachineAuditFile(): string; /** 追加一条机器级审计行(timestamp 由本函数补)。 */ export declare function appendMachineAuditLine(entry: Omit): Promise;