/** * 上下文注入诊断日志(opt-in,**默认关闭**)。 * * 用途:排查「CoHub 注入的上下文是否真的到达了子代理」。 * 历史(见 CHANGELOG 1.4.0 / 1.5.1):曾连续出现「上下文未注入 / 详情未追加 / * 写入 description 而非 prompt」等 bug,该日志就是当时的排查手段,因此**保留字段与 * 默认路径不变**,只把「每次委派无条件同步写盘」改成「显式开启后才写」。 * * 开启方式(任一即可): * 1. 环境变量 `COHUB_CTX_DIAG=1`(`=0` 可强制关闭,优先级最高) * 2. 用户配置 `~/.config/opencode/oh-my-opencode-cohub.json` → `{ "diag": { "enabled": true } }` * 或项目配置 `.opencode/oh-my-opencode-cohub.json` → 同上 * * 设计要点(对比旧实现): * - 旧:每次委派 = statSync + appendFileSync(同步阻塞事件循环), * 且「超 50KB → 读全文 → 重写末 30 行 → 立刻又 append」形成**反复全量读+全量写**的循环。 * - 新:关闭时不产生任何 I/O;开启时用**异步串行队列** appendFile(不阻塞事件循环), * 仅在「自上次压缩以来累计写入 > MAX_BYTES」时触发一次压缩,且压缩**只读文件尾部窗口** * (不读全文),压缩后计数器归零 → 需要再累积 MAX_BYTES 才会再次压缩,循环被消除。 * - 文件创建时使用 mode 0o600(POSIX 收紧权限;Windows 上为 no-op)。 * * 任务生命周期诊断(Wave3 扩展): * - 新增 `appendTaskDiag(record, filePath)`:最小 task 诊断 record(白名单收窄, * 支持 call 关联 / event / duration / lastActivityAt / 宿主 retry / 限流 kind / * 注入预算估算),复用本文件同一异步串行队列与压缩/权限机制,不另建日志系统。 * - 关闭路径零新增 I/O:调用方须用 `ctxDiag.enabled` 门控(与 appendCtxDiag 一致)。 */ import type { RateLimitKind } from '../orchestration/rate-limit'; /** 诊断日志配置(全部可选,缺省即安全) */ export interface CtxDiagConfig { /** 是否开启上下文注入诊断日志(默认 false) */ enabled?: boolean; /** 自定义日志文件路径(默认 os.tmpdir()/opencode/ctx-diag.log,保持历史路径不变) */ path?: string; } /** 缺省配置:关闭。热路径零开销是缺省行为。 */ export declare const DEFAULT_CTX_DIAG_CONFIG: Required>; /** 解析后的诊断设置(在插件初始化时求值一次,热路径只读常量) */ export interface CtxDiagSettings { enabled: boolean; filePath: string; } /** * 是否开启诊断日志。 * 优先级:环境变量(1/true 开,0/false 关)> 配置 > 缺省(关)。 */ export declare function isCtxDiagEnabled(config?: Partial | null, env?: string): boolean; /** 诊断日志文件路径(默认保持历史 tmpdir 路径,可被配置覆盖) */ export declare function resolveCtxDiagPath(config?: Partial | null): string; /** 一次性解析设置(插件初始化时调用,避免热路径重复读 process.env) */ export declare function resolveCtxDiagSettings(config?: Partial | null, env?: NodeJS.ProcessEnv): CtxDiagSettings; /** * 追加一条诊断记录(异步,失败静默)。 * 调用方应先判断 `settings.enabled`;本函数自身不做开关判断,便于复用。 */ export declare function appendCtxDiag(record: unknown, filePath: string): void; /** 测试/诊断辅助:等待队列落盘 */ export declare function flushCtxDiag(): Promise; /** 测试辅助:重置进程内计数器 */ export declare function __resetCtxDiagState(): void; /** 供测试断言用的常量导出 */ export declare const CTX_DIAG_LIMITS: { readonly MAX_BYTES: number; readonly KEEP_LINES: 30; readonly TAIL_WINDOW: number; }; /** 诊断日志目录(供排查指引使用) */ export declare function ctxDiagDir(filePath?: string): string; /** 建议的任务生命周期事件值(record 白名单以字段为准,值仅作约定) */ export type TaskDiagEvent = 'task_started' | 'task_completed' | 'task_failed' | 'task_cancelled' | 'retry_scheduled' | 'rate_limit_detected' | 'state_changed'; /** * 任务诊断最小 record(白名单字段;调用方只允许传这些键, * 未知字段会在 sanitize 时被丢弃——天然阻断 apiKey/body/headers 等敏感内容)。 */ export interface TaskDiagRecord { /** 记录类型标记:task 诊断(区别于上下文注入诊断) */ t: 'task'; /** 调用关联标识(如 `(parentSessionID, callID)` 组合串) */ callID?: string; /** 会话 ID(建议调用方传入截断值) */ session?: string; /** 任务 alias */ alias?: string; /** 生命周期事件(见 TaskDiagEvent 约定值) */ event?: string; /** 引擎侧任务状态 */ status?: string; /** 任务耗时(毫秒) */ durationMs?: number; /** 最近活动时间戳(调用方传 Date.now(),不新增轮询 timer) */ lastActivityAt?: number; /** 宿主重试尝试次数 */ retryAttempt?: number; /** 宿主计划下次重试的等待毫秒 */ retryNextMs?: number; /** 限流分类(classifyRateLimit 的 kind) */ rateLimitKind?: RateLimitKind; /** 服务端 Retry-After 毫秒 */ retryAfterMs?: number; /** 注入预算估算(字符数,仅必要元数据) */ budgetChars?: number; /** 注入预算估算(token 数,仅必要元数据) */ budgetTokens?: number; } /** 白名单收窄:只保留允许字段并做类型/长度校验;非对象输入返回 null */ export declare function sanitizeTaskDiagRecord(input: unknown): TaskDiagRecord | null; /** * 追加一条任务生命周期诊断(异步串行,失败静默,复用 ctxDiag 队列)。 * 调用方须先判断 `settings.enabled`;无效输入直接返回(零 I/O)。 */ export declare function appendTaskDiag(record: unknown, filePath: string): void; //# sourceMappingURL=diag-log.d.ts.map