第四部分:基础设施与客户端模块群
以下为 dsh 基础设施与客户端模块群的深度分析,涵盖 session/session-query/storage/settings/credentials/identity/interaction/guard/hooks/todo/plan/goal/feedback/schedule/jobs/spill/runtime-diagnostics/boot/bundle/preset/api/sdk/typert/client/host/extensions/acp/attachment/context/workspace/util 三十一个模块。
目录
- session — 持久化会话数据
- session-query — 会话查询
- storage — 存储能力
- settings — 用户设置
- credentials — 凭证管理
- identity — 身份标识
- interaction — 交互/审批
- guard — 安全防护
- hooks — 钩子桥接
- todo — 待办工具
- plan — 计划模式
- goal — 目标管理
- feedback — 反馈
- schedule — 调度
- jobs — 后台任务
- spill — 溢出管理
- runtime-diagnostics — 运行时诊断
- boot — 启动引导
- bundle — 打包分发
- preset — 预设组合
- api — 远程 API 网关
- sdk — JSON-RPC 协议
- typert — 类型图
- client — 客户端
- host — 宿主
- extensions — 扩展
- acp — Agent Client Protocol
- attachment — 附件
- context — 上下文插件
- workspace — 工作区
- util — 工具库
- 基础设施协作总览
session
路径: packages/session/
核心作用: 事件溯源的会话持久化层,管理 Agent 会话的生命周期事件(turn/start, turn/end, user/message, assistant/message, tool/* 等),提供会话格式版本化、写后序列化链和检查点策略。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
Session | 类 | 会话实体,持有事件日志、表面节点(Surface)、头部元数据,提供 append() 追加事件 |
SessionHeader | 接口 | 会话元数据:id、cwd、createdAt、parentSession |
SessionEvent | 类型联合 | 事件溯源事件类型(user/message, assistant/message, turn/start, turn/end, tool/* 等) |
SessionId | 品牌类型 | Branded<'SessionId'>,跨包边界的编译时类型安全 |
SessionPersistence | 服务 | 持久化服务,提供 list() 枚举和会话加载 |
SessionProjection | 投影 | 会话事件折叠投影,通过 SessionProjectionMap 声明合并扩展 |
SessionTitle | 服务 | 会话标题生成服务,支持 LLM 提供商注册 |
CheckpointPolicy | 插件 | 语义检查点策略:模型请求前、工具分派前、步骤边界刷新持久化 |
SessionTelemetryCoordinator | 服务 | 遥测协调器,管理记录发射和共享策略 |
foldPlanMode() | 函数 | 从会话事件折叠计划模式状态(last-write-wins) |
registerSessionTitleLlmProvider() | 函数 | 注册 LLM 标题生成提供商 |
架构要点
- 事件溯源模式:所有状态变化以不可变事件追加到会话日志,投影通过折叠事件派生当前状态
- 格式版本化:
SessionFormatVersion标记日志格式版本,跨版本兼容通过格式迁移处理 - 写后序列化链:
Session.append()先在内存中追加事件,通过检查点策略在语义边界刷新到持久化后端 - 检查点策略:
session-checkpoint-policy在模型请求前(llm/stream)、工具分派前(tools/execute)、步骤边界(agent/pre-step)设置刷新门控,确保持久化完成后才执行副作用 - 遥测共享策略:
FULL/FEEDBACK_ONLY/DISABLED三级共享策略,feedback/record事件可触发反馈门控的会话前缀共享
session-query
路径: packages/session-query/
核心作用: 会话查询能力,提供跨会话搜索、事件搜索、会话谱系追踪和事件读取工具,支持工作区访问控制。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
SessionSearchHit | 接口 | 会话搜索结果项,包含头部、最佳匹配事件、可用性状态 |
SessionEventSearchHit | 接口 | 事件搜索结果项,包含 seq、类型、片段 |
SessionLineageTrace | 接口 | 会话谱系追踪,祖先和后代关系 |
SessionEventTraceObservation | 接口 | 事件追踪观察,替换链、派生事件 |
SessionEventWindow | 接口 | 事件窗口,目标事件及前后邻居 |
formatSessionSearch() | 函数 | 渲染会话搜索结果为模型可读文本 |
formatEventSearch() | 函数 | 渲染事件搜索结果 |
formatSessionTrace() | 函数 | 渲染会话谱系追踪 |
workspaceAccess | 对象 | 工作区访问控制:读取标题、授权后代访问 |
架构要点
- 工作区访问控制:通过
workspaceAccess模块实现工作区边界检查,祖先/后代访问需要工作区授权 - 模型文本渲染:
Presentation模块将查询结果格式化为模型可读的结构化文本,包含序号、时间戳、片段 - 三层查询:会话搜索(跨会话)、事件搜索(单会话内)、事件读取(单事件+上下文窗口)
storage
路径: packages/storage/
核心作用: 存储能力枢纽,提供命名后端注册表和挂载的数据形式(KV 等),自身不执行 IO——后端拥有介质,数据形式拥有语义。
架构图
chmentError | 类 | 附件错误,携带稳定错误码(INVALID_IMAGE/IMAGE_TOO_LARGE/ATTACHMENT_CORRUPT等) | |ImageAttachmentRef| 接口 | 持久化图像引用:attachmentId、mediaType、bytes、width、height | |ImageAttachmentLimits| 接口 | 部署解析的限制:maxImageBytes、maxImagesPerMessage 等 | |SaveImageAttachment| 接口 | 保存请求:data、mediaType、name | |StoredImageAttachment| 接口 | 存储结果:ref + data | |LocalAttachmentStore| 类 | 本地后端,基于DSH_HOME/attachments/v1| |detectImage()| 函数 | 完全解码光栅图像,返回格式和尺寸 | |probeImage()| 函数 | 仅解析头部,不完整解码像素 | |saveImageFile()| 函数 | 保存图像:哈希→暂存→link→目录同步 | |readImageFile()| 函数 | 读取图像:读取→哈希验证→头部验证 | |validateImageFile()| 函数 | 验证图像不持久化 | |ensureDurableHome()| 函数 | 确保 DSH_HOME 目录持久性 | |ensureDurableDirectory()| 函数 | 确保目录及其祖先持久性 | |syncDirectory()` | 函数 | 同步目录条目(fsync) |
架构要点
- 内容寻址:对象按
sha256:<hash>存储,相同内容自动去重(link EEXIST 时验证) - 不可变存储:写入后不可修改,读取时验证哈希完整性
- 持久性保证:写入后 fsync 文件和目录,确保崩溃后条目持久
- 两阶段写入:暂存文件→link 到目标→同步目录→清理暂存
- 双重验证:写入时完全解码(
detectImage),读取时仅探头部(probeImage) - 进程级持久性证明:
ensureDurableHome每进程独立执行一次 DSH_HOME 持久性证明 - 显示名清洗:剥离路径分隔符(
/和\),防止本地路径泄露到引用和会话日志
context
路径: packages/context/
核心作用: 上下文插件群,包含 agent-instructions(工作区指令加载器)、session-reference(会话引用)、time-context(时间上下文)和 tmux-context(tmux 上下文)。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
apply() | 函数 | 挂载工作区指令加载器 |
loadBaselineInstructions() | 函数 | 发现、读取、渲染基线指令链 |
loadBaselineInstructionSet() | 函数 | 加载基线+保留的文件 |
discoverBaselineInstructionFiles() | 函数 | 发现主机可见的指令候选 |
findProjectRoot() | 函数 | 向上查找项目根(标记文件) |
ancestorChain() | 函数 | 构建根到 cwd 的目录链 |
dedupInstructionFilesByDirectory() | 函数 | 按目录去重(trimmed 内容摘要) |
renderWorkspaceContext() | 函数 | 渲染基线指令链 |
renderWorkspaceInstructionSet() | 函数 | 渲染基线+保留文件 |
renderInstructionChanges() | 函数 | 渲染对账批次 |
reconcileInstructionContext() | 函数 | 对账指令上下文 |
baselineInstructionState() | 函数 | 将基线文件转为比较和元数据状态 |
probeScopeInstruction() | 函数 | 探测指令作用域 |
readScopeInstruction() | 函数 | 读取已探测的指令 |
instructionContentSha1() | 函数 | 计算内容 SHA-1 |
trimmedInstructionDigest() | 函数 | 计算修剪内容摘要(去空白) |
workspaceBaselineIdentity() | 函数 | 基线身份标识 |
candidateScopeKey() | 函数 | 每候选作用域键 |
instructionScopeKey() | 函数 | 指令作用域键 |
Config | 配置 | dshHome、projectRootMarkers、maxBytes、instructionFileCandidates 等 |
InstructionVersionCache | 类型 | WeakMap<Session, Map> 每会话元数据缓存 |
AgentInstructionChange | 接口 | 指令变更:set/replace/remove |
AgentInstructionSource | 接口 | 指令来源声明(合并到 MessageSourceMap) |
架构要点
- 三层指令发现:用户全局(
$DSH_HOME/AGENTS.md)→ 项目根到 cwd 的目录链 → 每目录候选文件(AGENTS.md、CLAUDE.md+.local覆盖) - 字节预算:
maxBytes限制渲染后文本长度,超出时从最不特定开始省略,最特定文件二分截断 - 内容去重:按目录修剪内容摘要去重,同目录相同内容的不同候选只保留首个
- 动态对账:文件工具触碰(read/write/edit)后异步重新加载和对账指令上下文
- 步骤边界:步骤内触碰延迟到
step/end后投影,步骤外立即投影 - 投影排队:通过
projectionTailsWeakMap 确保同 Agent 投影串行执行 - system-reminder 框架:渲染文本包裹在
<system-reminder>标签中,框架在消息内容中烘焙 - 版本缓存:
InstructionVersionCache通过 WeakMap 隔离每会话的元数据缓存 - 基线替换:配置变更时通过
replacePreviousBaseline标记完整替换前序基线
session-reference 架构要点
- 会话引用投影:将会话引用结构投影到模型上下文
- URI 标识:通过 URI 标识会话引用目标
- 序列化:支持会话引用的序列化和反序列化
time-context 架构要点
- 时间戳:为模型提供当前时间戳上下文
- 请求时区:
request-zone处理请求的时区信息
workspace
路径: packages/workspace/
核心作用: 工作区实体注册表(ctx.workspaceRegistry),管理工作区记录、稳定的注册表顺序和经头部验证的会话成员关系。基于存储域数据形式,通过 fs.realpath 规范化路径作为唯一标识。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
WorkspaceRegistry | 服务 | 工作区注册表 ctx.workspaceRegistry,依赖 storageDomain 和 sessionPersistence |
WorkspaceEntity | 类 | 单个 Workspace 实现,持有记录快照,所有写入通过私有 mutate() |
WorkspaceEntityHost | 接口 | 实体宿主:table()/sessionPath()/readSessionHeader()/rememberSessionPath() |
Workspace | 接口 | 消费者接口:id、path、title、sessionIds、setTitle/attachSession/insertSessionBefore/detachSession/status |
WorkspaceId | 品牌类型 | Branded<'WorkspaceId'>,生成的 UUID |
WorkspaceRecord | Zod 推断 | 持久化记录:path、title、sessionIds、createdAt、updatedAt |
WorkspaceDomainState | Zod 推断 | 域状态:initialized、workspaceIds、archivedSessionIds、pendingMutation |
workspaceDomainSpec | 域规格 | defineDomain({ name: 'workspace', version: 2, ... }) |
realpathNormalize() | 函数 | 通过 fs.realpath 规范化目录路径 |
WorkspaceMoveInvalidError | 类 | 移动会话时引用了不在账户中的会话 |
WorkspaceUnknownSessionError | 类 | 归档时引用了未知的会话 |
WorkspaceOrderInvalidError | 类 | 重排序时引用了未知的工作区 |
架构要点
- realpath 唯一标识:工作区路径通过
fs.realpath规范化作为唯一标识——尾斜杠、..和符号链接都被解析 - 头部验证成员关系:会话成员关系需要同时满足:id 在账户中 AND 会话头部的规范化 cwd 等于工作区路径
- 待定变更恢复:
pendingMutation标记在域状态中,启动时恢复未完成的创建/删除操作 - 操作序列化:
enqueueOperation()确保所有注册表写操作串行执行 - Bootstrap:首次启动时从会话头部按 cwd 分组创建工作区记录
- 过滤候选修剪:每次接受的变更都执行持久化的过滤候选修剪(移除无效 sessionIds)
- 不变量检查:域变更事件验证注册表缓存与域表的一致性——删除时缓存必须已移除,写入时缓存必须已存在
- 归档集:归档会话保留 sessionIds 槽位,取消归档恢复位置
util
路径: packages/util/
核心作用: 共享工具库集合,提供品牌类型、原生命令执行、启动环境快照、DSH 路径解析、超时算术、输出保留和原子写入等基础能力。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
Branded<B> | 类型 | 编译时品牌类型原语,零运行时成本 |
runNativeCommand() | 函数 | 无 shell 的 execFile 执行器,utf8 stdio + abort 传播 + Windows 隐藏 |
LaunchEnvironmentSnapshot | 接口 | 不可变启动环境快照,按层级信任顺序解析变量 |
createLaunchEnvironmentSnapshot() | 函数 | 从各层内容构建快照 |
launchEnvironmentOf() | 函数 | 从上下文获取启动环境快照 |
resolveDshHome() | 函数 | 解析 DSH 主目录:配置 > $DSH_HOME > ~/.dsh |
defaultDshHome() | 函数 | 默认 DSH 主目录:~/.dsh |
expandHomePath() | 函数 | 展开 ~/~//~\ 前缀 |
canonicalizeWatchPath() | 函数 | 为文件监视器规范化路径(最深存在祖先 realpath + 缺失后缀) |
dshHomeDisplay() | 函数 | 用户友好显示形式(~/.dsh 或 $DSH_HOME) |
dshHomePath() | 函数 | 在 DSH 主目录下拼接路径段 |
deadline() | 函数 | 融合上游取消和可识别超时,返回 Deadline(信号 + 清理) |
idleWatchdog() | 函数 | 可重武装的空闲看门狗,计时器仅在 next() 待出时存在 |
clampTimeout() | 函数 | 验证、默认、钳制超时值 |
TimeoutReason | 类 | 超时原因:携带能力拥有的 code 和 timeoutMs |
timeoutOf() | 函数 | 从信号或原因载体恢复超时原因 |
MAX_TIMER_DELAY_MS | 常量 | Node 计时器不钳制为 1ms 的最大延迟 |
ItemRetainer<T> | 类 | 有序逻辑单元保留器,head 策略 |
TextRetainer | 类 | 字节导向文本流保留器,head/tail/headTail 策略 |
RetainedItems<T> | 接口 | 项保留结果 |
RetainedText | 接口 | 文本保留结果 |
formatRetentionNotice() | 函数 | 格式化保留通知(标准化省略子句 + 工具恢复指导) |
describeOmitted() | 函数 | 标准化省略措辞 |
writeFileAtomic() | 函数 | 原子文件替换:随机后缀兄弟文件 + rename |
withFileLock() | 函数 | 跨进程写入锁:wx 创建 .lock 兄弟文件 |
WriteFileAtomicOptions | 接口 | 写入选项:mode(必需)+ dirMode(可选) |
架构要点
- 品牌类型原语:
Branded<B>是纯类型工具,零运行时代码,各包品牌自己拥有的 ID - 层级信任顺序:启动环境按
process>project-env>user-env信任顺序解析,Windows 大小写折叠 - 冻结快照:启动环境快照在构建后不可变,后续 chdir/工作区切换/会话恢复观察相同值
- 超时融合:
AbortSignal.any融合上游取消和超时,竞速解析为单个原因 - UTF-8 边界安全:
TextRetainer.finish()在切割处修剪部分 UTF-8 序列,永不发出替换字符 - 原子写入:
wx标志独占创建防止符号链接植入,同目录兄弟 rename 确保原子性 - 跨进程锁:指数退避重试(20ms→200ms),2 秒超时,从不移除现有锁(文件年龄不能证明所有者已停止)
基础设施协作总览
DeepSeek Harness 的基础设施模块群通过分层协作支撑整个 AI Agent 运行时。以下总览图展示了核心基础设施模块之间的协作关系:
协作说明
-
启动与存储初始化:
Boot阶段首先通过LaunchEnvironment捕获启动环境快照,通过HomePaths解析 DSH 主目录,然后初始化Storage枢纽。Storage挂载后端(JSON/SQLite),StorageDomain在后端之上构建领域抽象(DomainGlobal、KvTable)。 -
会话持久化链:
Session实体通过SessionPersistence持久化到存储后端。CheckpointPolicy在语义边界(模型请求前、工具分派前、步骤边界)调用sessions.flush()确保持久化完成。SessionQuery在持久化会话之上提供跨会话搜索和谱系追踪。 -
配置与预设:
Settings和Credentials通过Storage持久化。Preset从Session事件折叠旋钮状态(沙箱模式、审批策略),通过derive()匹配预设规格。 -
安全与交互:
Guard提供沙箱模式控制,Interaction提供审批瀑布和用户问题。Attachment提供内容寻址的不可变附件存储,通过Storage的本地后端持久化。 -
工作区管理:
WorkspaceRegistry依赖StorageDomain(域表)和SessionPersistence(会话头部索引),通过fs.realpath规范化路径作为工作区唯一标识。Context(agent-instructions)发现和渲染工作区指令,依赖Workspace的路径信息。Spill在DSH_HOME下管理溢出文件。 -
工具生态:
Hooks、Todo、Plan、Goal、Jobs、Schedule、Feedback等工具模块都通过Session追加事件,通过SessionProjection派生投影状态。Timeout为Jobs、Schedule、Hooks提供超时算术。OutputRetention为Spill提供有界输出保留。 -
通信与客户端:
API Gateway通过Typert生成的 Remote 命名空间暴露主机能力,SDK提供 JSON-RPC 传输层,ACP通过 stdio 暴露自动化接口。Client通过API连接主机,Host提供目录选择等宿主能力,Extensions管理动态插件。 -
诊断与遥测:
RuntimeDiagnostics聚合各子系统运行时状态,SessionTelemetry通过 OpenTelemetry 导出遥测数据,Feedback事件可触发反馈门控的会话共享。 -
工具库横切:
Brand为所有跨边界 ID 提供编译时类型安全;AtomicWrite为Settings、Credentials等提供原子文件替换和跨进程锁;NativeCommand为Host的原生集成提供无 shell 命令执行。 -
不变量伴生:每个包都有一个不变量伴生插件,通过
ctx.invariants.register()注册包级不变量检查,确保运行时状态一致性。大多数工具模块的不变量验证会话事件(如todo/write的列表完整性、plan/mode的布尔状态)。Workspace的不变量验证注册表缓存与域表的一致性。
本文档基于 DeepSeek Harness 项目源码分析生成,覆盖 31 个模块(
create包不存在,已跳过)。所有 Mermaid 图使用graph TB方向和classDef着色。分析日期:2026-08-18。
class Storage,BackendRegistry,Forms hub
class JsonBackend,SqliteBackend,KvFacet backend
class DomainLayer,DomainGlobal,KvTable,DefineDomain domain
### 关键类/函数表
| 名称 | 类型 | 职责 |
|------|------|------|
| `Storage` | 服务 | 存储枢纽,`ctx.storage`,管理后端注册和数据形式挂载 |
| `BackendRegistry` | 类 | 命名后端注册表,支持注册/解析/列表,防止重复注册 |
| `StorageBackend` | 接口 | 后端契约:拥有一种介质,暴露 KV 操作面和 `close()` |
| `KvFacet` | 接口 | KV 操作面:`open()` 打开单元,返回 `KvUnit` |
| `KvUnit` | 接口 | 已打开单元:`loadAll()`、`putRecord()`、`deleteRecord()`、`setGlobal()`、`close()` |
| `KvUnitDescriptor` | 接口 | 单元描述符:名称、版本、表名列表、是否有全局单例 |
| `StorageError` | 类 | 存储错误类,携带稳定错误码 |
| `StorageErrorCode` | 类型 | 错误码联合:`backend-not-found`、`duplicate-backend`、`version-mismatch` 等 |
| `UNIT_NAME_RE` | 常量 | 单元/表名正则:`/^[a-z][a-z0-9_]*$/` |
| `storageBackendServiceKey()` | 函数 | 派生后端生命周期服务键 |
| `defineDomain()` | 函数 | 领域定义:名称、版本、全局模式、表规格 |
| `DomainGlobal<T>` | 接口 | 领域全局单例:`get()`/`set()` |
| `KvTable<K, V>` | 接口 | KV 表:`get()`/`put()`/`delete()`/`update()`/`entries()`/`size` |
### 架构要点
- **后端不可知**:存储枢纽自身不执行任何 IO,后端拥有介质(文件树、数据库文件),数据形式拥有语义
- **多后端共存**:多个后端可同时挂载,由消费者配置决定路由
- **单元版本化**:`KvUnitDescriptor.version` 在首次物化时标记介质,版本不匹配拒绝 `version-mismatch`
- **领域层**:`storage-domain` 在 KV 之上构建领域抽象——`DomainGlobal` 单例和 `KvTable` 表接口,通过 `defineDomain()` 声明领域规格
- **写链序列化**:领域层运行每单元一个写链,确保写操作顺序一致
---
## settings
**路径**: `packages/settings/`
**核心作用**: 用户设置管理,提供命名空间设置存储和配置读写能力。
### 架构图
```mermaid
graph TB
subgraph "settings 核心"
SettingsService[Settings<br/>设置服务]
Namespace[Namespace<br/>命名空间]
SettingsPath[SettingsPath<br/>设置路径]
end
subgraph "settings-local"
LocalBackend[LocalSettings<br/>本地设置后端]
JsonStore[JSON Store<br/>文件存储]
end
SettingsService --> Namespace
Namespace --> SettingsPath
SettingsService --> LocalBackend
LocalBackend --> JsonStore
classDef core fill:#4a90d9,stroke:#357abd,color:#fff
classDef local fill:#f5a623,stroke:#d48b0a,color:#fff
class SettingsService,Namespace,SettingsPath core
class LocalBackend,JsonStore local
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
Settings | 服务 | 设置服务 ctx.settings,提供命名空间读写 |
SettingsNamespaceView | 接口 | 命名空间视图,暴露路径操作和值读取 |
SettingsPathOpView | 接口 | 设置路径操作视图 |
LocalSettings | 类 | 本地设置后端,基于 JSON 文件存储 |
Config | 配置 | 设置插件配置 |
架构要点
- 命名空间隔离:设置按命名空间组织,每个命名空间独立管理其配置路径
- 原子写入:本地设置后端使用
writeFileAtomic实现原子替换,通过withFileLock序列化跨进程写入 - 客户端投影:通过
./client和./types双出口投影,零重复
credentials
路径: packages/credentials/
核心作用: 凭证管理,提供 API 密钥、令牌等敏感凭证的安全存储和读取能力。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
CredentialStore | 服务 | 凭证存储服务 ctx.credentials |
CredentialView | 接口 | 凭证客户端视图,包含提供商和模型信息 |
CredentialError | 类 | 凭证错误类 |
LocalCredentialStore | 类 | 本地凭证后端实现 |
架构要点
- 安全隔离:凭证通过独立服务管理,不混入通用设置
- 客户端安全投影:
CredentialView只暴露必要的非敏感信息给客户端 - 与设置分离:凭证独立于设置命名空间,避免意外泄露
identity
路径: packages/identity/
核心作用: 身份标识管理,提供匿名用户 ID 和会话身份追踪能力。
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
getOrCreateAnonymousUserId() | 函数 | 获取或创建匿名用户 ID,用于遥测和反馈 |
AnonymousUserId | 类型 | 匿名用户标识符 |
架构要点
- 匿名身份:为遥测和反馈提供匿名用户标识,不泄露个人信息
- 持久化:匿名 ID 持久化存储在 DSH_HOME 下
interaction
路径: packages/interaction/
核心作用: 交互与审批能力,提供用户问题、审批请求和交互式决策的框架。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
ApprovalRequest | 接口 | 审批请求:代理、工具调用 ID、选项列表 |
ApprovalWaterfall | 机制 | 审批瀑布:多个监听器依次处理审批请求 |
ApprovalPolicy | 类型 | 审批策略:never/always/on-failure 等 |
UserQuestion | 服务 | 用户问题服务,支持多选/单选问题 |
UserQuestionError | 类 | 用户问题错误 |
架构要点
- 审批瀑布:多个审批提供者通过
ctx.on('approval/request', ...)串联,依次评估审批请求 - 一次性审批:ACP 桥接器提供
allow-once/reject-once选项,从不推断持久授权 - 问题服务:支持向用户提出结构化问题并等待回答
guard
路径: packages/guard/
核心作用: 安全防护层,提供沙箱模式控制和工具执行防护。
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
Guard | 服务 | 安全防护服务 |
SandboxMode | 类型 | 沙箱模式:off/workspace/full |
GuardPolicy | 接口 | 防护策略配置 |
架构要点
- 沙箱模式:控制 Agent 工具执行的范围限制
- 与预设联动:沙箱模式是预设匹配的关键维度之一
hooks
路径: packages/hooks/
核心作用: 钩子桥接系统,将 Claude Code 和 Codex 的命令钩子适配到 dsh 的扩展点。hook-protocol 提供共享执行和解析层,hooks-claude-code 和 hooks-codex 是提供者特定的桥接器。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
runHook() | 函数 | 执行单个命令钩子,带超时和 abort 传播 |
matchesMatcher() | 函数 | 匹配器评估:正则匹配工具名/参数 |
mergeHookOutputs() | 函数 | 合并多个钩子输出为单个决策 |
createDetachedRuns() | 函数 | 创建分离运行的钩子(不阻塞主流程) |
appendHookInvoked() | 函数 | 追加钩子调用事件到会话日志 |
appendHookResult() | 函数 | 追加钩子结果事件 |
MatcherGroup | 接口 | 匹配器组:matcher + hooks 列表 |
HookOutput | 接口 | 钩子输出:stdout、stderr、退出码 |
MergedHookOutcome | 接口 | 合并后的钩子决策 |
parseClaudeCodeConfig() | 函数 | 解析 CC 钩子配置为匹配器组 |
substituteCommand() | 函数 | 替换 ${CLAUDE_PLUGIN_ROOT} 和 ${CLAUDE_PROJECT_DIR} |
架构要点
- 共享执行层:
hook-protocol提供编解码、匹配、执行、合并的通用实现,桥接器只需处理提供者特定格式 - CC 事件映射:支持 SessionStart、UserPromptSubmit、PreToolUse、PostToolUse、Stop、SubagentStart、SubagentStop 七种事件
- 变量替换:在解析时对命令字符串进行变量替换,而非运行时
- 分离运行:
createDetachedRuns支持不阻塞主流程的钩子执行 - 匹配器诊断:无效正则表达式在配置解析时即抛出
SyntaxError
todo
路径: packages/todo/
核心作用: 模型可见的整列表替换待办工具。每次调用追加 todo/write 快照到会话日志,重放为 last-write-wins。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
defineTool('todo_write') | 工具 | 模型面向的待办写入工具 |
toTodoList() | 函数 | 规范化模型输入为 TodoItem[]:去空白、去重、并行策略检查 |
TodoItem | 接口 | 待办项:content + status(pending/in_progress/completed) |
validateTodos() | 函数 | 不变量验证:数组、非空内容、去重、合法状态 |
Config | 配置 | allowParallelInProgress:是否允许多个 in_progress |
SessionProjectionMap.todos | 声明合并 | todos 投影键声明 |
架构要点
- 整列表替换:每次调用携带完整替换列表,无增量更新
- 并行策略:
allowParallelInProgress配置控制是否允许多个in_progress项 - 投影声明合并:通过
SessionProjectionMap声明合并扩展todos投影键 - 双出口投影:
./types供主机消费者,./client供客户端聚合,零内容重复
plan
路径: packages/plan/
核心作用: 计划模式是按 Agent 记录的协作状态。激活时,部署拥有的指导段落包含在每个模型请求中,exit_plan_mode 工具呈现完成计划供用户审查。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
PlanModeController | 服务 | 计划模式控制器 ctx.planMode |
PlanModeConfig | 接口 | 配置:section 指导段落 |
PlanProjection | 接口 | 投影:active + pending |
EXIT_PLAN_MODE | 常量 | 退出工具名称 'exit_plan_mode' |
SessionEventMap['plan/mode'] | 声明合并 | 计划模式事件:{ active: boolean } |
SessionProjectionMap.plan | 声明合并 | 计划投影键声明 |
resolveConfig() | 函数 | 验证部署指导配置 |
foldPlanMode() | 函数 | 从事件折叠计划模式状态 |
架构要点
- 日志状态:计划模式状态记录在会话日志中(
plan/mode事件),恢复和分叉无需活动镜像 - 待定状态:用户选择在下一个接受的回合前步骤前保持待定
- 工具目录稳定:
exit_plan_mode工具在计划模式未激活时也保持注册,模式切换只改变提示段落 - 审查交互:退出工具通过用户问题服务呈现审查选择(批准/继续计划)
goal
路径: packages/goal/
核心作用: 目标管理工具,提供 get_goal、create_goal、update_goal 模型面向工具,支持目标创建、完成和阻塞的状态管理。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
goalToolExecution() | 函数 | 认证调用代理和驱动边界 |
requireDirectHuman() | 函数 | 要求直接人类输入权限 |
completionAuthority() | 函数 | 解析完成权限:直接人类或目标回合 |
GoalToolAuthority | 类型 | 权限联合:direct-human |
renderWrapupContext() | 函数 | 渲染终端自主目标更新的收尾指令 |
GoalView | 接口 | 目标视图:id、revision、roundsStarted |
GoalId | 品牌类型 | Branded<'GoalId'> |
架构要点
- 权限模型:目标操作需要权限——直接人类输入或当前目标回合
- 驱动边界检查:
goalToolExecution()验证调用代理是当前活动驱动发起者 - 收尾指令:自主目标回合结束后注入收尾上下文,让模型向用户致辞
- 回合匹配:通过
isMatchingGoalRound()验证当前回合是否为目标许可回合
feedback
路径: packages/feedback/
核心作用: 会话反馈机制,包括 /feedback 命令(追加 feedback/record 事件)和消息级反馈(持久化到存储域)。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
recordFeedback() | 函数 | 记录反馈到会话日志(feedback/record 事件) |
executeFeedbackCommand() | 函数 | 执行 /feedback 命令:验证、记录、确认 |
sharingDisclosure() | 函数 | 生成共享策略披露文本 |
MessageFeedbackItem | 接口 | 消息反馈项:messageId、rating、note、version |
MessageFeedbackRating | 类型 | 评分:positive |
messageFeedbackRowSchema | Zod 模式 | 消息反馈行持久化模式 |
messageFeedbackItemSchema | Zod 模式 | 反馈项模式,含时间戳一致性验证 |
架构要点
- 双层反馈:会话级反馈(
feedback/record事件,追加到会话日志)和消息级反馈(独立存储域 sidecar) - 共享披露:
/feedback确认包含会话共享策略状态(full/feedback-only/disabled) - 匿名用户:反馈确认包含匿名用户 ID
- 消息反馈存储域:消息级反馈使用独立存储域,按会话生命周期隔离
schedule
路径: packages/schedule/
核心作用: 调度系统,为根 Agent 提供一次性提醒和重复提醒能力。使用实时计时器投影和事务序列化确保调度一致性。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
ScheduleRuntime | 类 | 一次性实时计时器投影,驱动到期决策 |
runScheduleTransaction() | 函数 | Agent 级事务序列化 |
foldScheduleEvents() | 函数 | 折叠调度事件为当前状态 |
resolveEveryOccurrence() | 函数 | 解析重复调度的下一次发生 |
renderReminderFraming() | 函数 | 渲染提醒框架文本 |
renderEveryReminderBatchFraming() | 函数 | 渲染批量提醒框架 |
flushSchedulePersistence() | 函数 | 刷新调度持久化 |
ScheduleLogError | 类 | 调度日志错误 |
FoldedSchedules | 接口 | 折叠后的调度状态:active 列表 |
DueDecision | 类型 | 到期决策:one-shot/every/wait |
MAX_TIMER_DELAY_MS | 常量 | Node 计时器最大延迟 |
架构要点
- Agent 级序列化:通过
WeakMap<Agent, Promise>实现每 Agent 事务串行化 - 到期决策:
dueDecision()按优先级选择到期的一次性调度、批量到期重复调度、或等待下一次唤醒 - 合并触发:多个触发合并到一次驱动循环,避免重复计算
- 计时器管理:实时计时器投影,到期前清除并重设
- 提醒框架:提醒消息使用 framing 文本包装,注入到 Agent inbox
jobs
路径: packages/jobs/
核心作用: 后台任务能力,提供进程内作业注册表,支持任务启动、取消、等待和输出读取。
架构图
关键类/函数表
| 名称 | 类型 | 职责 |
|---|---|---|
JobRegistry | 抽象服务 | 作业注册表 ctx.jobs |
LocalJobRegistry | 类 | 进程内实现,内存存储所有记录 |
JobId | 品牌类型 | Branded<'JobId'> |
JobSnapshot | 接口 | 不可变快照:id、kind、label、status、output |
JobStart | 接口 | 启动规格:kind、label、owner、run()、outputLimitBytes |
JobStatus | 类型 | running/stopping/completed/killed/failed |
JobKind | 类型 | 作业类型字符串 |
JobOutcome | 类型 | 作业结果 |
JobDoneListener | 类型 | 完成监听器 |
JobsChangedListener | 类型 | 变更监听器 |
TrackedTask | 接口 | 内部追踪记录(不对外暴露) |
JobLayer | 类 | 作用域层:控制器、监听器、变更通知 |
ScopedLayers | 类 | 作用域分层管理 |
TASK_WAIT_TIMEOUT | 常量 | 等待超时码 |
DEFAULT_MAX_CONCURRENT_TASKS_PER_OWNER | 常量 | 默认每 owner 最大并发:10 |
架构要点
- 作用域分层:作业控制器和监听器按注册上下文的作用域分层,读取是 owner 相对的
- 快照隔离:
snapshot()只返回不可变快照,永不返回活动状态 - 并发限制:每 owner 最大并发作业数限制,超出拒绝
- 生命周期独立:注册表记录比生产者和控制器光纤寿命更长
- 清理钩子:Agent 或服务销毁时取消活动工作并等待合规生产者

417

被折叠的 条评论
为什么被折叠?



