/** * Guardian 状态引擎:监听 session/event,驱动三个触发线 * (断言计数 / 无反馈环 / 编辑审查队列),状态存两层 storage。 * * 状态以内存为权威(Map + 数组),turn 结算时 flush 到 JSON 存储。 * 多会话并发安全:状态按 sessionId 分桶;提醒注入取「最近活跃会话」 * (DSH web 典型场景单会话活跃,跨会话串扰后果轻微且可接受)。 * @module @max-null/dsh-guardian/engine */ import { Service, type Context } from '@deepseek-ai/cordis'; import { type GuardianConfig, type GuardianSessionState, type GuardianSnapshot } from './types.ts'; /** * Guardian 引擎服务(服务名 `guardian`)。 * 暴露 snapshot() 给 UI(SSiD 侧栏同进程直读)。 */ export declare class GuardianEngine extends Service { private readonly config; static inject: string[]; private readonly rules; private readonly reviewMax; private readonly noFeedbackThreshold; private unit; private readonly sessions; private reviewQueue; /** callId → 待确认的编辑(filePath + 归属),tool/result 成功时入队。 */ private readonly pendingEdits; /** 最近收到事件的会话 id(提醒注入的近似目标)。 */ private activeSessionId; /** 串行化磁盘写(KvUnit 不序列化并发写)。 */ private writeChain; /** 被吞掉的失败累计次数(诊断用:连续增长说明存储或环境有问题)。 */ private failureCount; constructor(ctx: Context, config?: GuardianConfig); /** 当前会话状态(无则空态,不落盘)。 */ sessionState(sessionId: string): GuardianSessionState; /** UI 快照:最近活跃会话的状态 + 审查队列。 */ snapshot(): GuardianSnapshot; /** 断言提醒(供 systemPrompt.context 动态求值)。 */ assertionReminder(): string; /** 无反馈环警告(供 systemPrompt.context 动态求值)。 */ noFeedbackWarning(): string; /** 审查提醒(供 systemPrompt.context 动态求值)。 */ reviewReminder(): string; protected [Service.init](): Promise; /** * 注册 `session/event` 监听。 * * 监听器是同步回调,不能 await 事件处理,因此包装层必须自己吞掉失败 * (见 `handleEventSafely`)——`void` 掉一个会 reject 的 promise 等于 * 把未处理的 rejection 交给进程。 */ private bindSessionEvents; /** * 事件入口的安全包装:任何失败都不得逃逸为未处理的 rejection。 * * Node 默认把未处理的 rejection 当作致命错误,所以一次存储写失败就足以 * 终止承载全部会话的内核进程。guardian 的状态(断言计数、审查队列)都是 * **可重建的提示性状态**,正确的后果是「丢一次本次更新」,而不是进程退出。 */ private handleEventSafely; /** * 记录并吞掉一次不应逃逸到进程的失败。 * * 走 stderr 而不是 `ctx.logger`:`ctx.logger.warn` 的默认阈值是 1(只放行 * error/info),warn 的消息连 cordis 的内存 buffer 都进不去,更不会到任何 * 文件——等于静默吞掉。宿主侧 stderr 才是落地的:SSiD 壳把内核子进程的 * stderr 落进 `~/.ssid/kernel-child.log`。同类先例见 `dsh-ssid-pwsh-retry`。 * @param scope — 失败环节,用于日志定位 * @param error — 原始错误(只取 message,状态本身可重建) */ private absorbFailure; /** 事件分发:按类型推进三个触发线,turn/end 时结算 + flush。 */ private handleEvent; /** * 序列化写一条会话状态。 * * `catch` 不可省略:`writeChain` 一旦 rejected 就**保持** rejected,链上 * 后续写入会立即失败,`turn/end` 的 `await` 还会把它冒泡到事件入口。 * 吞掉失败后链始终可用,下一次写入照常尝试。 */ private flushSession; /** 序列化写审查队列(global slot)。吞掉失败的理由同 `flushSession`。 */ private flushQueue; } export default GuardianEngine;