跳转至

MiniHarness 架构说明

说明 miniharness/ 如何组织:目录布局、与上游包的对应、依赖方向、公共 API 边界。 docs/report/ 解读上游「是什么、为什么」;docs/chapters/ 带你在 Python 里逐步实现;本页面向改代码或查归属时定位文件。

1.0 运行时主链

一次回合的数据路径:boot 经 loader/ 展开组合并激活插件 → Session 只追加 SessionEvent → derive_messages 等纯函数投影模型历史 → AgentLoop 在 turn/step 里经 LLM 扩展口与 ToolRegistry 执行工具 → 所有模型可见输入以 durable 事件写回日志(持久化插件异步订阅 session/event,见第 5 章)。web/ 与 protocol/ 是 L3 入口,读写同一份会话约定;webui/ 不 import Python 内核。

功能模块总图、Turn/Step 与审批控制面、章节与验收表见 system-map.md(Fig S1~S6)。本页 §1.2 目录树与 §2 映射表供改代码时查归属;手册章号与主测试文件与 system-map 功能模块表一致,映射表备注中亦可能出现「第 N 章」交叉引用。

1. 目录组织

1.1 原则:目录按上游包家族镜像

代码目录镜像上游的包族结构(packages/ 下的 core/、llm/、boot/、sandbox/……),镜像到家族这一级(两级子包),不镜像到每个包,也不按主题平铺:

  • 家族级镜像:约 20 个子包,维护成本低,"去哪个目录找什么"与上游一致;
  • 文件级镜像:只做约定密集处(session、llm、agent-loop),这几处上游"一个文件一个职责"本身就是知识点;
  • 为什么不是 1:1 镜像全部近 50 个包?Python 一个仓库分成 50 个目录,光 __init__.py 就有 50 个,对教学项目是过度工程;
  • 为什么不是主题平铺?平铺表达不了模块边界:无法声明"哪些是约定、哪些是实现细节",依赖方向无法用测试约束,环压力只能靠延迟导入绕。

1.2 目录树

miniharness/
├── __init__.py # 教学面再导出,只含约定层(__all__ == 28,见 §4)
├── core/ # packages/core
│ ├── session/ # Session 本体 + types/invariant/json/message/repair/surface/tool_history/seq_ranges/projections,__init__.py 聚合
│ │ │ # message.py 上游在 llm/llm/src/message.ts,mini 保留会话域(L0 不依赖 llm,简化标注)
│ │ ├── projections.py # message 投影(SessionMessageProjection):image/offload 的拆分校验 + 图片卸载覆盖表(对应 session/surface.ts + compaction-image-offload/projection.ts)
│ │ ├── zstd_frames.py # zstd 拼接帧容器扫描/解码/截断前缀恢复(python-zstandard)
│ │ ├── persistence.py # JSONL(zstd 帧容器/明文,V4 一行一事件;上游 session-persistence-jsonl) + SqlitePersistence(mini 载体,上游无 sqlite 会话持久化包)+ _find/list_headers 走多代解析
│ │ ├── generation.py # generation 读侧:canonical 文件名/目录多代选择/migrate-on-open(对应 session-persistence-jsonl/src/generation.ts)
│ │ └── released/ # released 只读词表 + v0~v4 codec + 相邻迁移链迁移器 + 深度校验层(对应 packages/session/session-format-* 与 session-format-catalog)
│ ├── session_store.py # SessionStore(ctx.sessions 服务:create/prepare/enter/announce + fork + flush)
│ ├── agents.py # AgentRegistry(ctx.agents:live 代理实例注册 + turn 归档准入;packages/core/agent)
│ ├── agent_default_model.py # AgentDefaultModel(ctx.agentDefaultModel:部署默认模型选择 + profile 持久化)
│ ├── scope.py # Context + RegistryService(vendor/cordis 语义)
│ ├── dsh_scope.py # dsh-scope 原语(scopeParents 图 + scopeTarget 载波 + createScope,对应 packages/core/scope)
│ ├── hmr.py # Cordis HMR 服务(vendor/hmr:register_config watch + 单飞刷新 + config-update-failed 外泄)
│ ├── schema.py # schemastery 配置引擎全量移植(vendor/schemastery)
│ ├── home_paths.py # harness 根解析($DSH_HOME > ~/.dsh;packages/util/home-paths)
│ ├── version.py # 单一版本来源(miniharness.__version__;pyproject dynamic version 与 web host.describe 读它)
│ ├── tool_timeout.py # 工具调用超时约定常量(TOOL_TIMEOUT / timeout_error_message,L0,packages/guard 的超时执行器共享面)
│ ├── code_language.py # 扩展名→语言共享表(packages/util/code-language)
│ ├── working_cwd.py # working_directory_of(有效工作目录的同步零 I/O 消费者面:投影态 ?? session.meta cwd,L0)
│ ├── output_retention.py # UTF-16 代理对安全截断(packages/util/output-retention)
│ ├── tools.py # 工具注册表 + 执行管线
│ ├── system_prompt.py # SystemPromptService(分节渲染,systemPrompt 服务)
│ └── agent_loop/ # agent.py(turn/step 状态机,V2 内嵌流写入磁盘)+ assistant_stream.py(AssistantStreamAttempt)+ resident_loop.py(常驻单循环)+ tool_calls.py(并行调度)+ inbox.py(双队列收件箱)+ projections.py(turnBoundary/inbox 会话投影单元)+ runtime_context.py(runtimeContext 投影:retained 快照 restore + 按追加序折叠)
├── llm/ # packages/llm
│ ├── protocol.py # StreamChunk / LlmAdapter / LlmFailure / BlockAssembler(协议层)
│ │ + 图像定价/模态/发现类型(LlmImageRequestPrice/Pricing 等)
│ ├── assistant_stream.py # AssistantStreamRecord codec:Accumulator 压缩 / expand 解码 / validate 校验(V2 流内嵌)
│ ├── deepseek.py # DeepSeek Messages API 适配器(httpx + 图片/Files 路径)
│ ├── deepseek_messages.py # Messages wire 序列化 + SSE 事件派发/翻译 + 错误映射
│ ├── fake.py # FakeLlmAdapter(教学扩展)
│ ├── retry_policy.py # retry policy 解析(normal/always)
│ ├── retry.py # agent/request-error 恢复 + 退避
│ ├── token_meter.py # TokenMeter 增量 fold + usage 折入锚
│ ├── pi_ai.py # 多 provider 协议适配器(M15:三协议 body/事件翻译 + apiKeyEnv 凭据;无 ctx.llm 注册表)
│ ├── deepseek_account.py # 账户路由 /models 目录(P0-6a:listing/modelOverrides/版本门控/AccountRoute)
│ ├── deepseek_extensions.py # DeepSeek 请求扩展注册表(P0-6d:ExtensionRegistry + prepare_request_extensions)
│ ├── plugin_package_inventory_deepseek.py # 活动插件包清单贡献(P0-6d:dsh_plugin_packages)
│ └── deepseek_files/ # DeepSeek Files API 执行簇(file-id/defaults/models/types/model-info/
│ # image-tokens/request-pricing/files-api/upload-index/file-store/request-files)
├── ptc_runtime/ # packages/ptc-runtime(seam + Python 后端,L1)
│ ├── types.py # PtcRunRequest/Spec/Result/Failure + 绑定契约(PtcBindingNamespace)
│ ├── service.py # PtcRuntime Service Definition + 保留名常量 + 绑定校验
│ └── runtime.py # PythonPtcRuntime(CPython 子进程 + 行 JSON 绑定协议)
├── ptc/ # packages/core/tools/src/ptc.ts(L2,tools-presentation seam)
│ └── run_code.py # run_code 工具(子派发 tool/ptc-dispatch* 事件 + 精心挑选外层结果)
├── attachment/ # packages/attachment(attachment + attachment-local)
│ ├── types.py # ImageAttachmentRef(含 originalDimensions)/ FileAttachmentRef / SaveImage·SaveFile·SaveFileStreamAttachment / ImageAttachmentLimits / ImageRequestTarget / RequestImageAttachment
│ ├── error.py # AttachmentError + 17 错误码(含 INVALID_FILE_BASE64 / ATTACHMENT_FILES_UNSUPPORTED)+ is_attachment_error
│ ├── encoding.py # 共享质量阶梯 [85,75,60] + encodeFirstWithinLimit 惰性候选执行
│ ├── normalization.py # provider 无关规范化管线(直通/总像素预算+长边封顶/按 alpha 分流编码)
│ ├── projection.py # requestImageDimensions 纯请求投影几何(上游抽到 seam 包)
│ ├── request_image.py # variantId 确定身份的请求图缓存版本(request-image-v6,按路由目标)
│ ├── admission.py # canonical base64 wire 受理入口(图片批次 + 文件单个)
│ ├── file_store.py # verbatim 文件内容寻址存储(files/<sha2>/<sha>/<name> 别名 + file-objects 规范对象)
│ ├── file_uploads.py # FileUploads(ctx.fileUploads:会话级 receipt + prompt 绑定/退休,packages/client/file-upload)
│ └── store.py # LocalAttachmentStore(规范化字节 sha256 内容寻址 + 完整性复验 + verbatim 文件族 + admit_prompt_content)
├── seams/session_checkpoint.py # 语义持久化检查点策略(packages/session/session-checkpoint-policy)
├── storage/ # packages/storage(storage hub + storage-domain + storage-json)
│ ├── hub.py # Storage hub(ctx.storage:backend 注册表 + 可挂载数据形态,不碰 IO)
│ ├── registry.py # BackendRegistry(具名 backend 表 + stale disposer 守卫)
│ ├── spec.py # 域声明(define_domain / domain_table / DomainSpec / descriptor_of)
│ ├── domain.py # DomainImpl + KvTable + DomainGlobal(单写链 + domain/changed 发射)
│ ├── facility.py # DomainFacility(route 解析 + open 校验 + backup-and-skip 政策)
│ ├── events.py # DomainChanged(put 带新值 / delete 无值)
│ ├── error.py # StorageError / DomainError 错误码闭集
│ └── jsonbackend/ # JSON 持久 medium:atomic.py / format.py / single_unit.py / per_record_unit.py
├── compaction/ # packages/compaction
│ ├── config.py # 压缩规格解析(threshold / headroom / reserved output / retain / retries)
│ ├── region.py # selectCompactableRange + 压缩事务(surface replace 检查点)
│ ├── summarizer.py # 前缀重放摘要 + 检查点框架
│ ├── tool_result_pruner.py # 可选 tool-result 裁剪阶段(ctx.toolResultPruner 消费者)
│ └── engine.py # BasicCompactionEngine(pre-step 压力 / request-error overflow 接线)
├── jobs/ # packages/jobs(seam + jobs-local + tool-jobs)
│ ├── types.py # 类型/常量 / JobDoneBox(done 的 Promise 替身)/ JobHandle
│ ├── view.py # JobView / JobChunk / JobChannel 投影(view.ts 等价)
│ ├── ring.py # OutputRing(绝对偏移 + 头部驱逐 + UTF-8 安全超块尾部)
│ ├── pump.py # 注册表自有 pull 泵(150ms cadence + 结算末次排干 + spill)
│ ├── events.py # JobEventHub / JobLayer(scope 分层路由 + 包含投递)
│ ├── archive_admission.py # job 家族并入 workspace session-activity/stop
│ ├── render.py # public_job / status_line / render_model_delta
│ ├── registry.py # LocalJobRegistry(ctx.jobs 服务 + owner 会话栅栏 + 结算/上限/teardown + events)
│ └── tools.py # job_output / job_list / job_kill + 完成 notice 投递 + 可见输出封顶(finalizeContent)
├── plan/ # packages/plan/plan-mode(状态机 + 审查 UI + 投影)
│ ├── config.py # plan-mode 规格解析(section 校验,fail loud)
│ ├── mode.py # PlanModeController(log-only plan/mode + plan:policy 节 + pre-step 提交)
│ ├── review.py # exit_plan_mode 工具 + /plan 命令 + userQuestions 审查通道
│ └── projection.py # plan 投影单元(command/run ↔ plan/mode 双事件折叠)
├── commands/ # packages/interaction/commands(命令约定)
│ └── __init__.py # CommandRegistry + command/run|done 配对 + parse/route
├── goal/ # packages/goal(goal + goal-round-driver + tool-goal + command-goal)
│ ├── domain.py # goal/change 事件严格重放 fold + GoalError
│ ├── service.py # GoalService(ctx.goals:compare-and-set 变更 + 激活)
│ ├── prompt.py # goal round 提示词
│ ├── driver.py # GoalDriver(pre-step reservation 校验 + continue_rounds + driver 模式事件驱动续跑)
│ ├── tools.py # get_goal / create_goal / update_goal + tool:goal 节
│ └── commands.py # /goal 命令表面
├── skills/ # packages/skill(skill + skill-filesystem + tool-skill + skill-office + tool-workspace-dependencies)
│ ├── registry.py # SkillRegistry(ctx.skills 服务 + 分层注册 + 渲染/digest)
│ ├── filesystem.py # FileSystemSkillProvider(六类根 + frontmatter)
│ ├── tool_skill.py # skill 工具 + /名字 手势 + durable catalog 注入
│ ├── office.py # dsh-office provider:office-docx/pptx/xlsx 三技能(LibreOffice Kit 降级)
│ ├── assets/ # office 三技能 SKILL.md + scripts/check_office.py(逐字节复用上游)
│ └── workspace_dependencies.py # load_workspace_dependencies:读 runtime.json + payload 校验/安装
├── guard/ # packages/guard(循环卫生守卫:超时执行器 + 重复调用提醒)
│ ├── timeout_policy.py # TimeoutPolicy 插件(上游 timeout-policy,仅注册超时执行器约定面)
│ └── repeat_tool_reminder.py # RepeatToolReminder(重复工具调用提醒:预拒绝计数 + 决策折叠)
├── identity/ # packages/identity/anonymous-user-id(harness-home 匿名用户 id)
├── telemetry/ # packages/session/{session-stats,session-telemetry,session-telemetry-otel} + packages/telemetry/otel + packages/llm/token-meter
│ ├── folds.py # fold_session_stats / fold_token_usage / derive_turn_token_usage(纯 fold)
│ ├── service.py # UsageStatsService(ctx.usageStats)+ projection_values 自由函数
│ ├── session_telemetry.py # SessionTelemetryBackend + Coordinator(live/on-demand 采集 + 脱敏 waterfall + sourceEvent 信封)
│ ├── session_telemetry_otel.py # OTel 后端(经共享 ctx.otel;FEEDBACK_ONLY/DISABLED)
│ ├── otel.py # 共享 ctx.otel 服务(event reporter 按条数 + session-log reporter 按字节)
│ ├── otel_transport.py # 显式 OTLP/JSON httpx transport(retry/redirect/响应上限/可中断等待)
│ └── product_telemetry_otel.py # 产品遥测适配器(经 ctx.otel event reporter + x-channel)
├── session_log_deepseek/ # packages/session/session-log-deepseek(L2)
│ └── __init__.py # dsh_session_log 请求字段(maxBytes 前缀界 + 已接受水位 fold)
├── session_query/ # packages/session-query(session-query + session-query-sqlite + tool-session-query)
│ ├── config.py # 配置常量 + SessionQueryError 错误码闭集
│ ├── extraction.py # 一方事件语义文本抽取
│ ├── documents.py # 事件记录 + 语义文档投影(surface 分类)
│ ├── sqlite.py # FTS5 检索索引(bm25 + snippet)
│ ├── service.py # SessionQuery(ctx.sessionQuery:search/search_events/read_event/trace_event/lineage)
│ └── tool.py # 模型侧五工具(session_search/event_search/trace/event_trace/event_read)
├── session_projection/ # packages/session/session-projection(投影注册 API v2,L1)
│ └── __init__.py # ProjectionDefinition + SessionProjectionRegistry(ctx.sessionProjections)
├── session_turn_outline/ # packages/session/session-turn-outline(M18,L2)
│ └── __init__.py # turnOutline 投影单元(turn/start 锚定 + 首人类 prompt + 落定回复)
├── session_title/ # packages/session/session-title + session-title-first-prompt-llm(M10,L2)
│ └── __init__.py # SessionTitleService + title/titleInput 投影 + fallback + first-prompt LLM 提供者
├── session_projection_cache/ # packages/session/session-projection-cache(M14,L2)
│ └── __init__.py # SessionProjectionCache(写后节流 + 身份匹配 + 冷读播种,storage domain)
├── working_directory/ # packages/session/working-directory + tool-working-directory(可变当前执行目录,L2)
│ └── __init__.py # WorkingDirectoryService(ctx.workingDirectory:get/ensure/set)+ workingDirectory 投影 + context working-directory:current + assemble prepend 准入 + working_directory 工具
├── workflow/ # packages/workflow/workflow(M13,L2)
│ └── __init__.py # WorkflowEngine 服务定义 + WorkflowError 码 + validate_meta + 六事件
├── workflow_ptc/ # packages/workflow/workflow-ptc(M13,L3)
│ ├── __init__.py # PtcWorkflowEngine:Python 工作流脚本经 PythonPtcRuntime 绑定面执行
│ └── meta.py # META_STATEMENT / assert_body_parses / resolve_subagent_provider
├── tool_workflow/ # packages/workflow/tool-workflow(M13,L3)
│ └── __init__.py # workflow 模型工具 + durable run-start/agent-start/agent-end/run-end 记录
├── subprocess/ # packages/subprocess(M17,L3)
│ └── __init__.py # ctx.subprocess 接缝服务(resolve_executable/terminal_environment/env 清洗收编)
├── deepseek_account/ # packages/credentials/deepseek-account + deepseek-account-platform(P1-21/ND-14,L3)
│ ├── __init__.py # ctx.deepseekAccount 服务定义 + 本地落空实现(恒 signed-out)+ resolve/reject token + 事件 + is_running_account_task
│ ├── protocol.py # Platform origin/header/cookie/browser URL + /auth-api/v0 envelope + 稳定错误
│ ├── details.py # profile/wallet/bonus 投影 + Platform detail 读取
│ ├── logout.py # 有界重试的 grant 撤销
│ └── platform.py # PlatformAccount:浏览器 PKCE 状态机 + OAuth 回调 + device/Platform session
├── terminal/ # packages/terminal/terminal 服务域(L1,仅依赖 core.scope)
│ ├── types.py # TerminalError 8 码闭集 + TerminalBackend/TerminalSession Protocol + _utf8_bytes(代理对感知)
│ ├── sanitize.py # TerminalSanitizer + normalize_terminal_text(terminal-bash/src/sanitize.ts)
│ ├── bounded_buffer.py # BoundedTextBuffer(双限链式 chunk,session.ts)+ read_scrollback + utf8_tail
│ ├── operation.py # LocalSendOperation(单飞 + owner 栅栏 + cancel 结算)
│ └── service.py # TerminalSessionService(ctx.terminals:spawn/kill/read/signal/start_send/list)+ install_terminals
├── terminal_bash/ # packages/terminal/terminal-bash(terminal 后端 P2,层 3 登记,拓扑同 shell)
│ ├── config.py # resolve_config 缺省(rows=40/cols=160)+ shell 探测
│ ├── environment.py # child_environment(owner.id+sessionId+UTF-8 preamble)+ bash/pwsh prompt 复盘(133;D marker / dsh> )
│ ├── emulator.py # 终端仿真器(CPR/DA2/DA1/DECRQM 应答 + 光标定位 + scrollback 视图/翻页)
│ ├── provider.py # TerminalHandle 契约(inspect_foreground/inspect_activity + write/signal/terminate 生命周期)+ 平台拆三(_posix.py / _winpty.py:pywinpty PtyProcess + reader 线程 + SubprocessOutcome)
│ ├── shell_activity.py # ShellActivity + prepare_shell_activity(bash --rcfile / zsh ZDOTDIR 私有状态文件,subprocess-local shell-activity.ts)
│ ├── session.py # LocalPtySession(poll_readiness 五判据 settle + interrupt + 增量 UTF-8 解码)
│ └── index.py # install_terminal_bash(幂等)+ apply(依赖 terminals 先装)
├── tool_terminal/ # packages/terminal/tool-terminal(六模型工具 P3,层 3 登记,消费 terminal + jobs)
│ ├── render.py # render_spawn/send/send_read/read/list + bound_terminal_text(逐字对齐 render.ts)
│ ├── tools.py # 六工具(terminal_open/send/read/signal/close/list)+ resolve_config + install_tool_terminal
│ └── __init__.py # 导出 + 上游插件形状常量 name/inject
├── terminal_controller/ # packages/api/terminal-controller(浏览器终端 P4,层 3 登记)
│ ├── types.py # 两错误码 + TerminalControlUnavailable/LimitReached + TerminalInput 判别联合/decode_terminal_input + resolve_config + frame_bytes
│ ├── stream.py # TerminalFollower(JSON 帧 UTF-8 字节预算 + 排空/分离)
│ ├── terminal.py # BrowserTerminal(pyte HistoryScreen 恢复屏 + attach/submit/ack + writable/require_controller 分支)
│ ├── shells.py # resolve_executable/shell + discover_shells + terminal_environment(subprocess-local 等价)
│ └── index.py # TerminalController(ctx.terminalController:environment/shells/list/create/attach/rename/close)
├── workspace_controller/ # packages/api/workspace-controller(工作区控制,层 3 登记)
│ └── __init__.py # WorkspaceController(ctx.workspaceController:十命令 + follow 代次)
├── workspace_files/ # packages/api/workspace-files(文件预览,层 3 登记)
│ └── __init__.py # WorkspaceFiles(ctx.workspaceFiles:read/readBytes(options)/stat/list + target-scoped changes)
├── workspace_changes/ # packages/deliverables/workspace-changes(回合变更摘要与比较,L2)
│ ├── __init__.py # WorkspaceChanges Service(ctx.workspaceChanges:summary/diff + 事件接线)
│ ├── recorder.py # TurnRecorder(基线快照 + 写意图捕获 + turn/end 记录 + 摘要/比较)
│ ├── git.py # 私有索引工作树快照 / diff-tree numstat / gitlink / check-ignore
│ ├── capture.py # 内容寻址副本 + 二进制/超限判定
│ ├── compare.py # Myers 行比较 + 统一 hunk(超时退整文件替换)
│ └── paths.py # canonical / 展示 / durable 路径与临时根
├── deliverables/ # packages/deliverables/tool-present
│ └── present.py # present 工具 + deliverables/presented 事件
├── settings_controller/ # packages/api/settings-controller(设置/凭据,层 3 登记)
│ └── __init__.py # SettingsController + CredentialsController(ctx.settingsController / credentialsController)
├── context/ # packages/context(请求上下文插件,层 2 登记)
│ ├── time_context.py # 每步时钟读数 + 浏览器时区策略 + timeContext 投影
│ ├── tmux_context.py # tmux 方位查询/变化抑制 + tmuxContext 投影
│ ├── file_reference.py # @file 词法 + FileReferenceService(ctx.fileReferences)
│ ├── file_reference_local.py # WorkspaceFileSearch 模糊索引 + 本地服务 + 提示节
│ ├── session_reference.py # dsh-session URI/提及 + 跨会话快照准备 + candidates
│ └── agent_instructions.py # AGENTS.md 发现/预算渲染/reconcile + pre-step/touch driver
├── boot/ # packages/boot
│ ├── boot.py # 启动 + patch overlay
│ ├── composition.py # YAML 配置 / !!js 插值 / dump 渲染
│ ├── profile.py # profile 目录机制(bundle/profile/home 补丁层序 + init_profile + compose_entries)
│ ├── config_editor.py # ConfigEditor(ctx.configEditor:把 profile 条目配置持久化到 cordis.patch.yml)
│ ├── plugin_manager.py # PluginManager(ctx.pluginManager:Loader 条目列举/启停写 profile 补丁)
│ ├── config_schema.py # profile 配置 schema 导出(compose 条目 → JSON Schema;CLI --dump-config-schema)
│ └── dotenv.py # .env 解析(parse_dotenv)
├── loader/ # vendor/loader + vendor/include(cordis 组件系统,L0)
│ ├── model.py # ENTRY_KEY / GROUP_KEY / SEP 载波键
│ ├── utils.py # !!js 求值 + baseUrl 上溯 + 瞬态事件循环结算
│ ├── patch.py # apply_entry_patches(replace / insert / name 门)
│ ├── entry.py # Entry(update / disabled / init)+ module 旧方言桥
│ ├── group.py # EntryGroup(一级子列表宿主)+ Group 插件
│ ├── tree.py # EntryTree(扁平 store + resolve / import_ / write)
│ ├── loader.py # Loader 服务(internal/config|update|plugin 钩子)
│ └── include.py # Include 子树(文件读写 + initial + !!js 原样回写)
├── fs/ # packages/fs(文件系统 seam + 本地/沙箱后端 + 模型侧工具)
│ ├── types.py # 目标/版本标识、元数据、写/编辑意图与结果、FsErrorCode 闭集
│ ├── service.py # FileSystem(ctx.fs 抽象契约,含 watch 默认拒绝)
│ ├── local.py # LocalFileSystem(realpath 身份 / 原子写 / 字面编辑 / watchdog watch)
│ ├── sandbox.py # SandboxedFileSystem(每次调用沙箱围栏)
│ ├── observation_policy.py # 观测态策略(fs/write-intent、fs/edit-intent、fs/observed)
│ ├── diff.py # write/edit 结果态 hunk diff + FsDiffMeta(operation)
│ ├── tools.py # read / write / edit 工具(tool-fs)
│ ├── str_replace_editor.py # str_replace_editor 工具
│ └── search.py # glob / grep 工具(stdlib 承载)
├── lsp/ # packages/lsp/lsp(LSP 能力 seam,L1)
│ └── __init__.py # Lsp(ctx.lsp:provider 注册原子预留 id+扩展名 + 每查询扩展名路由)+ LspError + final_extension
├── lsp_stdio/ # packages/lsp/lsp-stdio(通用 stdio 语言服务器后端,L2)
│ ├── framing.py # Content-Length JSON-RPC 编解码(头部/消息大小有界)
│ ├── abort.py # 信号鸭子类型(.aborted/.is_set)+ abortable(不取消底层 work)
│ ├── protocol.py # LSP wire 类型面(dict 承载,登记)
│ ├── translate.py # 纯协议翻译:能力判定 / Location/LocationLink/Hover 归一
│ ├── host.py # 经 ctx.fs 规范工作区 + 约束读源(完整文档字节上限)
│ ├── connection.py # 子进程上的 JSON-RPC 端点(server 请求应答 / stderr 有界尾 / 增级终止)
│ ├── instance.py # 一个服务端实例:握手 + 串行可取消查询队列 + 瞬态 open + 有界拆除
│ └── __init__.py # LocalLspProvider(按工作区池化)+ install_lsp_stdio(server 表)
├── tool_lsp/ # packages/lsp/tool-lsp(模型可见 lsp 工具,L2)
│ ├── render.py # 一基↔零基光标转换 / 位置渲染 / file:URI 解析 / UI 呈现
│ └── __init__.py # create_lsp_tool / install_tool_lsp(四操作只读工具 + tool:lsp prompt 节)
├── todo/ # packages/todo
│ └── __init__.py # to_todo_list / fold_todos / install_todo_tool(模型侧 todo_write)
├── schedule/ # packages/schedule/schedule + schedule/tool-schedule(dsh-v0.2.0-rc.2 推倒重写,L2)
│ ├── types.py # 六规则记录 + legacy 读侧词表 + 工具/错误码集
│ ├── domain.py # 纯域:daily/weekly/cron(Vixie)/every 求解 + DST + framing
│ ├── storage.py # schedule storage-domain 表(任务 schema + lastDelivery 精化)
│ ├── delivery_history.py # 投递历史 append/prune + 身份游标分页
│ ├── update.py # compare-and-update(expected 全记录)
│ ├── runtime.py # 单 Host 定时器 + 到期按会话批量唤醒
│ ├── tools.py # tool-schedule 等价包:register_schedule_tools + install_tool_schedule(唯一挂载入口)
│ ├── service.py # ScheduleService(ctx.schedule:list/catalog/history/delete/update + schedule/changed;不挂工具)
│ └── archive_admission.py # 归档准入读存储行
├── spill/ # packages/spill(spill + spill-local + spill-policy)
│ ├── __init__.py # SpillStore seam + LocalSpillStore + 大结果落盘策略(tools/post-execute)
│ └── retention.py # retain_content:text/image 有序 head/tail 保留(token 预算、整图不可切)
├── workspace/ # packages/workspace/workspace(工作区实体 + 注册表服务)
│ └── __init__.py # Workspace / WorkspaceService(ctx.workspaces)+ paths 规范化 + 归档准入/置顶/默认登记
├── settings/ # packages/settings(settings + settings-file)
│ └── __init__.py # SettingsProvider + SettingsScope + redact_secrets + 文件 provider
├── cli/ # apps/cli
│ ├── main.py # launcher 选项(profile / patch / dump)+ _web_main(boot/profile 驱动装配)
│ ├── headless.py # 一次性任务入口
│ ├── default_tools.py # headless 默认工具集(教学扩展)
│ ├── session_cmds.py # 会话 list / resume / delete / stats(教学扩展;stats 为遥测可视化终端)
│ ├── preset_cmds.py # presets list / show / select / delete(教学扩展,web Remote 等价本地入口)
│ ├── web_profile.yml # 默认 web 组合模板(种子进 profile include;Loader 不写此资产)
│ └── plugins/ # web 组合条目插件(loader 插件模块 apply(ctx, **config),每条目安装一服务)
│ ├── system_prompt.py / web.py / user_questions.py / sandbox_policy.py
│ ├── terminal_controller.py / fs.py / credentials.py / workspaces.py
│ ├── workspace_controller.py / workspace_files.py / session_projections.py
│ ├── usage_stats.py / turn_outline.py / command_feedback.py / message_feedback.py
│ ├── approval.py / permission_presets.py
│ ├── session_title.py / session_title_first_prompt_llm.py / deepseek_account.py
├── preset/ # packages/preset + apps/cli/config/agent-presets
│ ├── presets.py # shipped root / 分层 roster / 投影 / 锁 / cordis 翻译(数据目录 preset/{minimal,standard} 随迁)
├── extensions/ # packages/extensions
│ └── dynamic.py # 动态插件生命周期
├── interaction/ # packages/interaction
│ ├── approval.py # 审批服务(+ approval:policy 上下文 + setPolicy 通知)
│ ├── permission_presets.py # 权限预设(PermissionPresetService:预设表 + derive + 写路径 + /permission)
│ ├── user_questions.py # user-questions 服务(模型澄清 seam:UserQuestionError + ask 派发 + restore)
│ └── tool_ask_user.py # ask_user_question 工具(schema/execute/render,同 tool-ask-user)
├── feedback/ # packages/feedback(M12,L3)
│ ├── command_feedback.py # FEEDBACK_CATEGORIES + record_feedback + /feedback 命令 + sessionFeedback Remote
│ └── message_feedback.py # messageFeedback Remote(list/put/delete + 版本 CAS + 活/冷会话)
├── protocol/ # packages/{acp, sdk, hooks}
│ ├── acp.py # ACP 服务器子集
│ ├── sdk.py # JSON-RPC 信封 + 最小运行服务
│ └── hooks.py # hooks 桥(CC 配置 → 拦截决策)
├── seams/ # packages/{sandbox, credentials, authorization, subprocess, subagent, agent-team}
│ ├── sandbox_local.py # 真沙箱后端(平台链探测 / 失败即拒绝)
│ ├── sandbox_policy.py # 沙箱策略服务(部署缺省 + 会话日志覆盖决议)
│ ├── landlock_run.py # Landlock 自限制执行器(native/landlock-run 的 ctypes 载体)
│ ├── sandbox_windows_acl/ # Windows ACL 写限制沙箱(ctypes FFI 物化上游 windows-acl-restrict-poc;非 win32 import 即抛 OSError)
│ ├── credentials_local.py # 凭据四层 + CredentialsService(provide="credentials",发 credentials/record-updated)
│ ├── authorization.py # 授权服务(install_authorization opt-in;registerFlow/list/describe/cancel/begin + authorization/settled)
│ ├── agent_team/ # 实验族:implicit-root roster + durable peer mailbox + shared task DAG(packages/experimental/agent-team)
│ ├── subprocess_env.py # 子进程环境清洗切片(凭据形 + DSH_* 名剔除,packages/subprocess)
│ └── subagent/ # __init__ + descriptor + providers(三通道)+ worker(子进程)+ continuation(续跑管理)+ archive_admission(归档准入)+ tool(模型侧委托工具)
├── shell/ # packages/shell/{shell, bash-local, bash-sandbox, pwsh-local, pwsh-sandbox, shell-env}
│ ├── types.py # ShellExecution 句柄 / ShellExpiryPolicy / observed 偏移读 / settled_execution
│ ├── bash_local.py # 本地 bash 执行器(execute→ShellExecution,缺省 provider)
│ ├── bash_sandbox.py # 沙箱消费执行器(confine 包裹 + 三路归因 + result 装饰)
│ ├── pwsh_local.py # 本地 pwsh 执行器(-NoLogo -NoProfile -NonInteractive -Command + 编码前导 + 路径解析)
│ ├── pwsh_sandbox.py # 沙箱消费 pwsh 执行器(M16)
│ ├── env.py # ctx.shellEnv 注册表(DSH_* 内置 + 保留键 DSH_PROFILE[_DIR])
│ └── helpers.py # spawn 归因 / denial / runner 失败分类(helpers.ts)
├── tool_bash/ # packages/shell/tool-bash(模型面 bash 工具)
│ ├── index.py # bash 工具(前台/提升/后台三态 + jobs 集成 + stopped)
│ ├── background.py # process_outcome / process_sources / ring_delta
│ └── render.py # parse_exit_status / render_result / render_promoted / render_job_read
├── tool_pwsh/ # packages/shell/tool-pwsh(模型面 pwsh 工具,M16)
│ ├── index.py # pwsh 工具(三态 + jobs 集成 + kind:'pwsh')
│ └── render.py # render_pwsh_result / render_promoted / render_job_read
├── persistent_shell/ # packages/shell/tool-{bash,pwsh}-persistent 共享引擎(L2)
│ └── __init__.py # ShellDialect(bash/pwsh) + 标记包装/抽取 + 回滚/渲染 + PersistentShells + 工具工厂
├── tool_bash_persistent/ # packages/shell/tool-bash-persistent(持久 bash 工具,L3,opt-in)
│ └── __init__.py # create_persistent_bash / install_persistent_bash
├── tool_pwsh_persistent/ # packages/shell/tool-pwsh-persistent(持久 pwsh 工具,L3,opt-in)
│ └── __init__.py # create_persistent_pwsh / install_persistent_pwsh
├── mcp/ # packages/mcp/{mcp-client, mcp-resources}(mini 子集)
│ ├── types.py # Config schema / ReconnectConfig / RECONNECT_DEFAULTS / 常量
│ ├── client.py # apply(ctx, config) 同步门面:resolve 配置 → 链接生成
│ ├── connection.py # 代连接 supervisor(stdio / streamable-http)+ 重连 + 工具归属注册 + 生命线 ping
│ ├── transport.py # 传输工厂(stdio_client / streamable_http_client)
│ ├── server_context.py # MCP server 挂载(静态 server / CLI 定位 / 配置解析 → 联系请求)
│ ├── tools.py # sync_tools(公共工具名 hash / bridge 定义 / output 投影 / 图片受理)
│ ├── fixture_server.py # stdio 夹具(教学扩展,tests 用)
│ └── resources/ # packages/mcp/mcp-resources
│ ├── render.py # output render(手动 JSON 序列化的紧凑 JSON 投影)
│ ├── tools.py # list/read 三个共享资源工具(register_resource_tools)
│ └── runtime.py # ResourceRuntime(createResource → 生命周期 + disposer)
├── client/ # packages/client
│ └── trajectory.py # Trajectory 折叠引擎
├── web/ # packages/api/gateway + packages/client/connection + session-controller + remotes + host/frontend-static + host/webserver(mini 子集)
│ ├── envelope.py # 两信封 RPC(client-request / server-response,rpc-schema.ts:connection 层错误闭集 + transport_error 折叠)
│ ├── auth.py # 可选 token 门(/api/* 全域;未配置=无门,非回环裸听 fail loud;requestRejection 等价物)
│ ├── host.py # 监听地址分类(is_wildcard_host / is_loopback_host,按解析值;webserver index.ts 两谓词)
│ ├── attachments.py # unary 结果的二进制附件(bytes 叶子投影为 null 占位 + multipart 分帧 metadata + bytes-<i>)
│ ├── api.py # WebApi 会话服务(unary 方法 + 路由表)
│ ├── args.py # 路由层 `{args}` 边界校验(字段精确匹配 + 顶层 JSON 类型;gateway assertExactArguments/decode)
│ ├── stream_protocol.py # Remote 流 wire 语法(open/cancel/item/end/error 帧 exactKeys 闭合 + $events/result payload)
│ ├── uplink.py # 单流有界上行 inbox(字节上限 / end 半关 / end 后 item 与超限两违例)+ 方法侧 UplinkItems(逐项 codec 解码 + 失败折 gateway/input-invalid)
│ ├── mux.py # WS /api/remote.mux 单路径承载全部 Remote 流(RemoteStreamMuxConnection)
│ ├── events.py # $events 注册表(api-session/* 转发源 + waterfall + $events/result 结算)
│ ├── streams.py # GatewayStreams($events 装配 + session/terminal/workspace/files 流分发表)
│ ├── approvals.py # 审批桥(async tools/ask 闸门 ↔ approval/request waterfall + $events/result)
│ ├── questions.py # user-questions 桥(user-questions/request waterfall ↔ $events/result 结算)
│ ├── downloads.py # GET /api/session.export 会话日志导出(zip 打包 root + 后代 + 媒体)
│ ├── frontend.py # 静态服务约定(遍历 403 / SPA 回退 200 / MIME)
│ ├── inventory.py # pluginInventory/list 投影(Loader 条目四字段 + preset 组合行 flatten)
│ ├── static/ # vanilla SPA 教学参照前端(index.html / app.js / style.css,无构建步;消费旧 SSE wire,对新后端不工作——真实对接见仓库顶层 `webui/`)
│ ├── server.py # FastAPI 载体(unary {args} 解包 + $events/result 特判 + WS + 静态,stream-server.ts / handler.ts)
│ └── launcher.py # web profile 启动器(build_app / run_web)
├── web_tools/ # packages/web/{web,web-search-deepseek,web-fetch-http}+tool-web(模型可见 web 功能族,默认组合 dsh-base 挂载)
│ ├── runtime.py # WebRuntime(ctx.web:URL 策略 + 双 provider 注册表 + 执行期选择六分支 + 配置回落)
│ ├── network.py # 整址公网策略(答案集先整体校验再钉桩,防 DNS 重绑定)+ is_public_ip_address
│ ├── policy.py # 字节帽(声明超限拒绝/流式截断)+ 字符帽 + redirect 跟随/跨源拒绝
│ ├── fetch_http.py # 匿名公共抓取 provider(HttpFetchProvider + build_http_limits)
│ ├── search_deepseek.py # DeepSeek 搜索 provider(Anthropic /messages 协议 + citation_snippets + 3xx 拒绝)
│ ├── search_tool.py # web_search 工具(web_search_section_text + run_search_queries + round-robin 去重 merge)
│ ├── fetch_tool.py # web_fetch 工具(web_fetch_section_text + format_fetch_output 三段截断 + MAX_CONVERSION_DEPTH)
│ ├── trust.py # 信任域/信任来源判定
│ └── types.py # 契约类型(WebSearchResult/WebFetchResult + run_deadlined/is_set_signal)
├── demo.py # 端到端演示(教学入口,python -m miniharness.demo)
└── example_plugins.py # boot 演示插件(教学示例)

1.3 顶层再导出策略

  • miniharness/__init__.py 保留"教学再导出":from miniharness import Session 对学习者成立;
  • 子包 __init__.py 做族内再导出:from miniharness.llm import StreamChunk 与 from miniharness.llm.protocol import StreamChunk 等价。文档与示例写浅路径,业务代码写深路径(可被依赖方向测试检查);
  • 聚合器必须显式 __all__:无 __all__ 时 from .x import * 会把子模块命名空间的所有公开名复制进包——包括与子模块同名的属性(子模块属性遮蔽包引用),也包括子模块内部导入的 stdlib 名(如 json.py 里的 import json)。星号导入只应复制约定名,因此子包与其子模块各写显式 __all__;
  • 命名沿用上游:sdk.py 与上游包名一致;session_cmds.py 与 sessions.py 单复数混淆消除。

2. 模块 ↔ 上游映射

手册章号与每章主验收测试见 system-map.md#module-chapter-verify。下列各行「mini 模块 → 上游包」为改代码时的归属单源;报告 index.md 四维表的手册列只链本节,不复制行级章号。

2.0 mini 路径 → 手册章(前缀对照)

mini 路径前缀 / 包 手册章 说明
core/session/、core/session_store.py 01 事件日志、SessionStore
core/scope.py(Context/总线/Service) 02、13 02 总线;13 Service/intercept/Logger
core/tools.py、guard/ 03 工具管线与循环卫生守卫
core/agent_loop/、llm/ 04、09、12 04 loop;09 干预;12 并行调度
core/session/persistence.py、boot/ 05 持久化与 boot(loader 见 08)
seams/、shell/、ptc_runtime/ 等 06 能力扩展口与延伸域
cli/、web/、protocol/、webui/ 07 外部入口与 wire
loader/、preset/ 08 组合与 preset
interaction/approval.py 09 审批
client/trajectory.py 10 Trajectory 折叠
extensions/dynamic.py 11 动态插件
core/dsh_scope.py 14 载波与 scope 存储
core/schema.py 15 schemastery

映射表按行列出 mini 路径、手册章(第二列)、上游包与备注。章号与 system-map 功能模块表 一致;多章用顿号、节号用 §;与 §2.0 前缀对照不一致时以本表行为准。

| mini 路径 | 手册章 | 上游对应(唯一权威) | 备注 | |---|---|---| | core/session/(session/types/invariant/json/message/repair/surface/tool_history/seq_ranges + generation/persistence/zstd_frames 等) | 01 | packages/core/session/src/(types/invariant/surface/repair/seq-ranges/preparation/request-header/known-event-types/tool-history/index 10 文件)+ packages/llm/llm/src/message.ts + packages/session/session-format/src/json.ts | message 构造保留在会话域(L0 不依赖 llm,简化标注);上游 json.ts 在独立的 session-format 包(JSON 规范化/roundtrip),mini 并入会话域。dsh-v0.2.0-rc.2:repair.py 抽出 ToolCallRecovery(turn+step 钉住 pending call、仅 append 且匹配的 tool/result 确认、幂等 results),供失败 live step 与崩溃/fork 共用;新 tool_history.py(ToolHistoryProjection 折叠 header + developer 消息的工具增删,Session.tool_history 增量消费) | | core/session/persistence.py | 01、05 | packages/session/session-persistence-jsonl(+ session-format* 相邻迁移链) | 上游是独立包组,mini 并入会话域(简化标注);目录布局与上游 session-persistence-jsonl/src/format.ts 一致:root/--<projectKey(cwd)>--/<encodeSegment(id)>/session.v4.jsonl[.zstd](generation 版本化文件名,v0 旧名 session.jsonl 保留拒读;~XXXX 段转义、projectKey 分隔符折叠+251 截断、cwd 缺省 _no-cwd);默认载体 zstd 拼接帧容器(zstd_frames.py,一帧一记录,torn 末帧前缀恢复;可选明文 .jsonl),编码互斥、遗留平铺、重复 id、未知版本都直接拒绝读取(released 旧版本由上游相邻迁移链处理);V4 一行一事件(上游仅 v0→v1 迁移 codec 保留打包,assistant/message 内嵌流;V4 tool 角色平铺结果);头行与目录同源(header.cwd 回写);崩溃修复 closers 经 commit_repair 写入磁盘(与上游 commitRepair 一致),恢复构造 mode="restore";多代读侧:_find/list_headers 经 core/session/generation.py 解析 canonical 名、取最高代、migrate-on-open(确保代当前才回写,_ensure_generation_current)——v0/v1 released 旧制品读入时被相邻迁移(v0→v1→v2→v3→v4)转成 v3 后继发布,源文件不可变保留(os.replace 原子发布,.zstd 后缀=mini 载体约定,上游 .zst) | | core/session/released/(helpers/dispositions/codec/validate/validate_v2/validate_v3/validate_v4/payload_validation/relationships/migrate_v0_v1/migrate_v1_to_v2/migrate_v2_to_v3/migrate_v3_to_v4/catalog,共 15 文件) | 01、05 | packages/session/session-format-catalog + session-format-v0-to-v1 + session-format-v1-to-v2 + session-format-v2-to-v3 + session-format-v3-to-v4;词表 packages/core/session/src/known-event-types.ts(54 类型闭集);格式类型 packages/session/session-format/src/types.ts | 相邻迁移链整件纯函数移植(含 v2→v3、v3→v4);migrate_released_artifact 按版本选边 v0→v1→v2→v3→v4;载体差异(登记):v1 物理头 seedLength→isSeeded(seedLength:0 = seeded 零切割)、v1 user/message flat、chunk 流内嵌(assistant/message stream records / assistant/attempt);fork 切点重导出为 {inherited:true} marker(空种子合成 createdAt 时间);密集重映射拒绝指向已消费 chunk 的引用(绝不重定向,逐字文案);迁移不写任意目标(组装完整 AFTER + staged 校验 + 原子替换);深度校验层:54 类型逐字段 payload 语义(payload_validation.py,上游 payload-validation.ts ~1028 行)+ 跨事件关系状态机(relationships.py,上游 relationships.ts ~475 行,v2 assistant/attempt step 门经 (set,frozenset) 修复)+ artifact 编排(validate.py/validate_v2.py/validate_v3.py:内嵌流三事实 cross-check、marker/cut 双向、restore=信封级装载、v2 field 无引号方言);迁移链已切真实校验器(v0→v1 逐事件门 + 终态 artifact 双重门,v1→v2 目标门,v2→v3 目标 assertV3Event 全量校验);仅令牌/自性能隔离不随行移植 | | core/session_store.py | 01、07 | packages/core/session/src/index.ts(SessionStore 部分) | 内存会话服务:create/prepare/enter/announce 生命周期 + get/list/fork(五错误码)+ flush 检查点 + session/created|disposed|event|flush 四事件;create 与上游 generator effect 一致(enter 先 yield、announce 抛错自动回滚);事件派发经 scope_target 载波(carrier=scope_target(session, scope_of(owner_ctx or self.ctx)),与上游 enter 的 scopeTarget(session, scopeOf(store.ctx)) 一致);结构一致:SessionStore(Service),构造 super(ctx, "sessions") 即经 ctx.provide 自动登记、随拥有 fiber 自动注销(与上游 index.ts extends Service + super(ctx, 'sessions') 一致),install_sessions/web/api 手工 provide 已简化移除;无 typert lookup、flush 为同步近似(简化标注见模块 docstring) | | core/agents.py | 04、07 | packages/core/agent/src/index.ts(AgentRegistry)+ archive-admission.ts | 进程内 live 代理实例注册表(ctx.agents,L1):AgentRegistry(Service) 构造即 super(ctx, "agents") 登记、随拥有 fiber 注销;register(agent, owner=None)(id 与会话不符 / 同 id 已登记 fail-loud)、查询面 get/list/roots/is_owned_by、agent/created/agent/disposed(agent 自有载波,非会话日志事件;与上游 publish 时 enter+announce 公告一致,mini 单同步进程一键发布);install_agents(ctx) 幂等装配(生产 6 处 root 组合均接在 install_sessions 旁);模块级 assert_live_agent(agent)——装配即强制(无 agents 服务的裸装配 no-op)。另含 install_turn_archive_admission(ctx, lookup)(对齐上游 archive-admission.ts):注册表构造点安装 turn 归档准入家族——会话 Agent 运行中答 workspace/session-activity 的 {kind:'turn'}、workspace/session-stop 以 cancel('user')(不带 keep_inbox,排队输入随取消丢弃)停止该回合;家族键并入 workspace 的 SessionActivityKindMap。注册点 = AgentLoop.publish;goal _prepare_mutation 前置 assertLive 边界(陈旧/重复实例拒绝),jobs 访问面按 owner 会话 id 栅栏(rc.1 起不再断言 live 实例,owner 仅在 start 时解析为 live Agent,见 jobs 行)。载体差异:上游 initiator 用 AsyncLocalStorage 承载身份,走 enter+announce 两步;subagent 运行时 owner 链不承载(本节只登记 root/父子全部 live 实例) | | core/agent_default_model.py | 04、07 | packages/core/agent-default-model/src/index.ts | 部署默认模型选择(ctx.agentDefaultModel,L1):current_selection 返回分离的 {provider, model, reasoningEffort?};save_selection 经 ctx.configEditor 把完整选择持久化到同 id profile 条目(无 profile entry / 编辑器时 no-op),保存按提交顺序串行、失败只向调用者抛出且不阻塞后续保存;不校验目录成员资格。载体差异:上游 Config 为 live refs(patch 重应用即更新读取值),mini 插件 Config 是安装期 dict,保存成功后同步内存选择,profile patch 由 ConfigEditor 写入并在重载/重启后生效。web 组合默认挂载;session/selectModel 以 fire-and-forget 保存、session/initializeDefaultModel 等待保存,session/modelCatalog 的 default 读本服务 | | storage/(hub/registry/spec/domain/facility/events/error + jsonbackend/) | 06 | packages/storage/storage(index.ts:Storage 插件 + storageBackendServiceKey) + packages/storage/storage-domain(domain.ts/index.ts) + packages/storage/storage-json(single-unit/per-record-unit/format/atomic) | 非会话 KV 存储中心(ctx.storage,L1,不承载 storage-sqlite):hub 不碰 IO(backend 注册表 + 可挂载数据形态,storage.backend.<name> 生命周期服务键);domain 数据形态带 schema 校验(open 逐记录 validate_schema_value,invalid-record 带 fail-closed detail(table/key);invalid_records='backup-and-skip' 时坏记录 backup_record 移开 + 日志 + 跳过)、单写链(写先持久后改内存再发 domain/changed,put 带新值 / delete 无值;update 在链槽读改写 + missing-key 拒绝;close 排空已排队写照发事件、以 DomainError('closed') 拒绝新写);每域单开(already-open / reserved 释放);JSON backend:single 整文档 / per-record 一记录一文档(path-safe key、foreign 坏/过期文档读缺位、legacy 整文档 bootstrap 经版本接受集栅、.bak.<YYYYMMDDHHmm> 备份文件) | | core/scope.py | 02、13 | vendor/cordis + packages/core/scope | Context(服务仓库 + 事件总线 + 四种派发 + asyncio 变体)+ fiber 生命周期(对应 fiber.ts:状态机 PENDING/LOADING/ACTIVE/FAILED/UNLOADING/DISPOSED + internal/status;effect(execute, label) 上游形态——execute 立即执行、返回值按 None/callable/awaitable/生成器收集为 disposer;单发 + 可 await;注册先于执行 + setup barrier 重入保护;dispose 幂等 join 在途;同步立即逆序、异步并发 unload、错误 contained;装载半边 + 注册表——RegistryService(ctx.plugin 缩写 + 插件形态归一 + 运行记录按 callback 键控)、fiber 携带 inject 依赖 + epoch 重载(依赖变化卸载→重装)、restart/update(internal/update waterfall)、internal/config waterfall + schema 校验(resolve_config,core/schema.py)、internal/plugin 每次装载/卸载派发)+ create_scope fiber-backed 作用域(父销毁收回子 fiber)+ 服务仓库(reflect.ts 对应:按隔离标签键控的全局 store,ctx.get strict 缺省返回 None,ctx.isolate(name) 换标签,per-agent 的 tools/systemPrompt 经隔离不冲撞 root realm,重复提供同一标签 fail loud);另含 Service 基类(service.ts 对应:构造即经 ctx.provide 自动登记、随 fiber 注销、_invoke 可调用、_check/_init)、ctx.extend(meta)/ctx.intercept(name, config)(intercept 配置经 Service._resolve_config 沿祖先链近根优先合并)、内建 LoggerService(logger.ts 对应:ctx.logger(name) 铸具名 Logger 门面 + printf 格式 + exporter 注册/级别过滤/默认缓冲导出器,ctx.logger 属性为绑定访问方 ctx 的视图);dsh-scope 对应:事件派发模型改上游形态——on 双写 root _flat_hooks(全局 Hook 表)+ 祖先链 _listeners,dispatch 系加 this_arg 载波参数(有载波走扁平表按载波键过滤,无载波保留祖先链);create_scope 返回 Scope 包装 + 自动绑父 scope;scope_key = scope_of(self)(scopeParents 图);残余简化标注见模块 docstring | | core/schema.py | 15 | vendor/schemastery/src/index.ts(902 行单文件) | schemastery 引擎全量移植:可调用 Schema 节点 + resolve 分发 + 17 类 resolver(any/never/const/string/number/boolean/function/is/bitset/array/dict/tuple/object/union/intersect/transform/lazy + date/regExp/arrayBuffer 复合体)+ meta 克隆语义 + from/extend + ValidationError($path 前缀) + Options(autofix/ignore/path/strict) + toString 全 formatter + toJSON(uid+refs 共享序列化) + i18n(mergeDesc) + simplify(deepEqual dict-aware);S.from_/is_/reg_exp/array_buffer 等 pythonic 命名(上游名映射进 docstring);cordis fiber 适配层(resolve_config/ValidationError 聚合消息)保留文件尾部;L0 叶零内部依赖,cosmokit 助手(deepEqual/isNullable/isPlainObject/clone/valueMap/pick/Binary)内联;callback 不做字符串求值、date/regExp/arrayBuffer 锚定 Python 对应物(载体差异标注) | | core/dsh_scope.py | 14 | packages/core/scope/src/index.ts + store.ts | dsh-scope 协议本尊(纯库,L0):ScopeKey 弱引用身份键、scopeParents 图(bind/link/rebind + 环检测)、scope_parent_of/scope_chain_of(nearest-first)、scope_target/_ScopeCarrier/is_scope_carrier/carrier_key_of、scope_of(parent 链)、NamedEntries/AnonymousEntries/ScopedLayers 对应 store.ts;Context.create_scope 返回 Scope 包装(delegation 包装,__slots__ 无 __dict__) | | core/hmr.py | 02、13 | vendor/hmr/src/index.ts + packages/boot/hmr/src/index.ts | Cordis HMR 服务:Hmr(Service) provide="hmr";register_config(filename, refresh)——findWatchRoot walk-up 根定位(realpath+depth+缺盘拒绝)、重复注册拒绝、初扫已存在目标即刷(chokidar ignoreInitial=false 语义:缺文件无初扫)、disposer 注销+关 watcher+join 在飞刷新;refresh_config(key) 单飞+dirty 合并循环、失败 logger.warn + hmr/config-update-failed 并行事件外泄不毒化循环;run_exclusive(operation) 串行事务队列(对齐 packages/boot/hmr runExclusive:嵌套拒绝 'HMR transactions cannot be nested'、关闭拒绝 'HMR is disposed';config-editor/plugin-manager 类宿主写路径与自动重载共用锚);销毁期注册归一 CordisError(INACTIVE_EFFECT)。载体 watchdog(上游 chokidar);Node ESM 模块图热重载(ModuleLoader/externals/accepted)不适用 Python 载体;Windows 短路径两侧 normcase+realpath 归一 | | core/tools.py | 03 | packages/core/tools | 作用域化注册表(ScopedLayers/NamedEntries 存储:注册即 effect 归目标 fiber、fiber 销毁即自动注销;resolve/names 缺省取注册表 root 的 scope 键,显式 scope 沿键父链最近者胜 + 全局层兜底)+ 守卫执行管线(pre/execute/post waterfall + schema 校验 + 超时);注册项可选 when(step 级激活条件),resolve_activation 逐步解析(对齐 upstream ToolsService.resolve);schema_of/schemas 白名单投影 name/description/parameters +(存在时)deferLoading 标记;执行管线的规范化结果在 tools/post-execute 政策前经 project_content(上游 projectContent)安装内容,finalize_content 在结算前收口 | | core/tool_timeout.py | 03 | packages/util(超时常量)→ 被 packages/guard/timeout-policy 消费 | 工具调用超时约定叶(L0,零内部依赖):TOOL_TIMEOUT = "TOOL_TIMEOUT"、timeout_error_message(timeout_ms);被 core/tools.py(管线超时替换 error_info={name:'ToolTimeoutError', code:TOOL_TIMEOUT})与 guard/timeout_policy.py 两侧共享——guard 超时执行器是 packages/core/tools 超时语义的消费方 | | guard/ | 03 | packages/guard(timeout-policy + repeat-tool-reminder) | 循环卫生守卫:repeat_tool_reminder.py —— 重复工具调用提醒:Config(thresholds: [3,5,8] fail-loud 校验、include/exclude 通配符、argumentsPreviewChars 默认 500);per-agent WeakKeyDictionary 链,agent/pre-step 任一 user 消息清链;pre-execute 监听器对下行 {kind:'deny'} 决策计数并把提醒挂到 exec_.additional_contexts(mini deny 短路 post-execute);post-execute observe 在委派前执行,提醒 prepend 到下游决策 additionalContexts(accept 路径 {kind:'accept', additionalContexts:[reminder]},block 路径保留 kind:'block');提醒消息 source {kind:'plugin', plugin:'repeat-tool-reminder', form:'notice', summary:'{tool} × {count}'};timeout_policy.py —— 只 import L0 core.tool_timeout 再导出 TOOL_TIMEOUT(超时执行器本体在 core/tools.py 管线,timer-wins),装配面 opt-in install_timeout_policy/install_repeat_tool_reminder。载体差异登记:上游 post-execute 决策 PostToolDecision {kind, feedback?, additionalContexts?}(tools/src/index.ts)——mini 管线读取 kind(旧 action 别名已统一);上游 pre 侧 deny-vote 计数在 post-execute 决策里反馈,mini 因 deny 短路改为挂 exec | | core/agent_loop/agent.py | 04 | packages/core/agent-loop/src/agent.ts + index.ts | 单一 async 泵(_pump_async/_run_step_async)+ followup/steer 同步门面(经常驻单事件循环驱动,见下行 resident_loop)+ 协作式取消(_cancel_event 每轮新建 + call_soon_threadsafe 跨线程置位——对应上游 agent.ts 每 phase 新建 AbortController);aborted_cancel_cause 裁剪 abort 原因(对齐 agent.ts:只保留 {kind},hook 类另带 reason),cancel 与 _close_turn 落 turn/end 前经它过滤,杜绝 live fetch/AbortSignal 的额外字段(如 stack)进入日志;max_parallel_tool_calls 为经校验的普通配置值(对齐上游 Volatile 配置 + getter 读取,非 settings 服务);agent/pre-step 决策经 awaterfall;publish/dispose 生命周期(enter+announce+agent/session-start / cancel(disposed)+scope.dispose+detach,会话店成员资格归 loop)+ agent/* 事件载波派发(scopeTarget(agent, loop scope 键),兄弟作用域隔离)+ turn/step 编号 1 起经 _replayed_next_turn 从会话日志续号(对应 invariant.ts nextTurn:turn/end 闭合后 +1、尾部未闭合停在当前号;resume 冷重建 loop 不重置回合号);V2 流结算(agent.ts):正常完成 settle assistant/message(内嵌 stream、content=原始 assembler 块)、finish error/aborted 与异常先 settle assistant/attempt 再走 request-error waterfall、取消定稿 interruptedBlocks 前缀(空则 attempt) | | core/agent_loop/resident_loop.py | 04 | (无独立文件:Node 进程固有单事件循环) | 教学扩展:进程级懒加载单例循环(守护线程 run_forever);run_on_resident 阻塞提交协程、异常冒泡、主线程 Ctrl+C 协作取消在途泵;同步门面由此驱动后跨调用共享同一循环,与上游形态一致 | | core/agent_loop/tool_calls.py | 04、12 | packages/core/agent-loop/src/tool-calls.ts | 工具调用调度器(真并行):exclusive 单元素屏障 + parallel 有界滚动池(max_parallel 上限,读取经 AgentLoop.max_parallel_tool_calls getter;上游读 config.maxParallelToolCalls.get)、pre-execute 按模型序有序 await、execute 体真并行、结果按模型序提交;abort 时未启动调用按模型序补 TOOL_ABORTED_BEFORE_DISPATCH 合成错误 | | core/agent_loop/inbox.py | 09 | packages/core/agent-loop/src/inbox.ts | 双队列(followup→next-turn / steer→next-step)+ agent/inbox/spliced 持久化 | | core/agent_loop/projections.py | 04 | packages/core/agent-loop/src/index.ts(turnBoundaryProjectionDefinition)+ inbox.ts(inboxProjectionDefinition) | AgentLoop 拥有的会话投影单元:turnBoundary(host-only,stateVersion 2,消费 turn/start·end、step/start·end)+ inbox(wire,stateVersion 1,从 agent/inbox/spliced fold 双队列,wire 值即 fold 状态);AgentLoop 构造在有 sessionProjections(M7)时注册,dispose 随作用域回滚——session/projections 暴露 inbox 单元,host-only 的 turnBoundary 不进客户端 cut(对齐上游 session-projection snapshot 的 wire 门) | | core/agent_loop/assistant_stream.py | 04 | packages/core/agent-loop/src/assistant-stream.ts | AssistantStreamAttempt:一次模型 attempt 的压缩 + 组装 + 终态结算封装(attemptId/revision/start/push/settle/abandon;settle 在持久事件 append 成功后发 committed、失败 abandon;push 同时喂 Accumulator 与 BlockAssembler);V2 assistant/message.stream 内嵌与 assistant/attempt 的生产端 | | llm/assistant_stream.py | 04 | packages/llm/llm/src/assistant-stream.ts | AssistantStreamRecord codec:AssistantStreamAccumulator 游程压缩(text/reasoning/tool-call delta 连续段 + 不可压缩原样 chunk,dt 硬性规定)、expand_assistant_stream 逐 delta 边界还原、validate_record exactKeys fail-closed;V2 seed 边界展开验证(_assert_current_assistant_stream)消费同 codec | | core/agent_loop/runtime_context.py | 04 | packages/core/agent-loop/src/runtime-context.ts | loop 侧运行时上下文投影:retained 三态(undefined/null/{seq,text})restore(倒序找最近一条仍在 surface 的 owned 快照)+ 按追加序惰性消化新事件;project(current, sections) 文本相等去重、变化铸快照 user 消息(sections 非空带 form:'snapshot' 归因,空即 CLEARED 哨兵不带归因);SOURCE/CLEARED 逐字一致;接线在 _run_step_async pre-step waterfall 前(默认进入把快照追加在 claimed 之后,显式 enter 决策整体接管) | | core/system_prompt.py | 04 | packages/core/system-prompt/src/ | assemble waterfall + contexts/tools/variables 提供器 + {{variable}} 严格插值 + render_context_sections/join_context_sections 节渲染面(上游 renderContextSections/joinContextSections);scope 层叠、assembly.tools→请求工具集成未复现(简化标注见模块 docstring) | | llm/protocol.py | 04 | packages/llm/llm/src/ | stream(messages, tools, signal, session_id, purpose) async 约定(sessionId/purpose 对齐 types.ts)+ StreamAborted + _aiter_raced(异步迭代与 abort 事件竞速,asyncio 原生载体) | | llm/deepseek.py | 04 | packages/llm/llm-deepseek/src/{adapter,config,defaults,models,host}.ts + packages/llm/llm-deepseek-account + packages/llm/llm-deepseek-api-key | DeepSeek 官方 Anthropic 兼容 Messages 适配器:httpx 异步传输(原生 asyncio,abort 置位即关闭连接、真取消)+ per-read idle 300s watchdog(与上游 fetch 一致)+ catalog 能力解析 + image-capable 请求路径(Files API file-id 优先 → inline base64 回退 → stale-id 有界重试)+ dsh-v0.2.0-rc.2 认证 seam:auth 选择器(deepseek-official = x-api-key / deepseek-account = x-dsh-auth-token,无交叉回退)+ reject_token 回调(401 → ACCOUNT_TOKEN_INVALID)+ 402/带内 quota → ACCOUNT_QUOTA + 签出 → ACCOUNT_SIGN_IN_REQUIRED;工具变更请求按需拼 anthropic-beta: mid-conversation-tool-changes-2026-07-01;base 缺省 https://api.deepseek.com/anthropic,POST messagesApiRoot(base)/messages | | llm/deepseek_messages.py | 04 | packages/llm/llm-deepseek/src/{serialize,translate,sse,messages-api,transport}.ts | Messages wire 层:harness 消息 → Anthropic content blocks(text/image/thinking/tool_use/tool_result)+ 请求体 {model,max_tokens,system?,messages,tools?,stream,thinking,output_config?,…} + SSE 事件派发(message_start/content_block_/message_delta/message_stop/ping/error,message_stop 为完成点)+ 响应翻译(tool_use→tool-call、thinking→reasoning、stop_reason/usage 映射)+ HTTP/带内错误码映射 | | llm/deepseek_files/ | 04 | packages/llm/llm-deepseek/src/{common,file-store,files-api,upload-index}.ts | Files API 执行簇:file-id/defaults/models/types/model-info(能力解析)+ image-tokens(vision-token 计算器)+ request-pricing(路由目标 ImageRequestTarget + 请求图定价)+ files-api(Messages /v1/files httpx 传输)+ upload-index(files-v3.json + filelock)+ file-store(单飞共享上传 + 配额恢复)+ request-files(解析 + stale-id 重试 + 规范化图片诊断) | | llm/deepseek_account.py | 04 | packages/llm/llm-deepseek-account/src/{catalog,listing,resolve-catalog,config,index}.ts | 账户路由 /models 目录(P0-6a):listing 解码(api_capabilities.anthropic_messages + 文本输出/输入模态/容量校验 + client_requirements[APP_IDENTITY.product].min_version)+ modelOverrides 显式 resolve(models 不再可配)+ 版本门控(CLIENT_UPGRADE_REQUIRED/MODEL_UNSUPPORTED)+ asyncio 缓存(单飞 + 后台刷新 + last-known-good)+ AccountRoute(admit/discover_models,未登录 → 空目录)。载体差异:httpx 代 fetch、取消归入 TIMEOUT/TRANSPORT(登记 verified-diffs) | | llm/deepseek_extensions.py | 04 | packages/llm/deepseek-llm-api-extensions/src/index.ts + packages/llm/llm-deepseek/src/request-extensions.ts | DeepSeek 官方请求顶层扩展注册表(P0-6d):ExtensionRegistry(字段名非空且无首尾空白 + 不可重复 + disposer;prepare 逐字段调 provider,None 省略/抛错或不可 JSON → 逐字段告警一次后省略、值 JSON 深拷贝隔离)+ prepare_request_extensions(合并顶层、冲突/准备失败 → REQUEST_EXTENSION、合并体不可序列化 → 退回基础请求体、2xx 后 accept 且失败上报不使请求失败)。载体差异:同步 prepare 代异步 Service、JSON 深拷贝代 Object.freeze、构造参数代 Service 注入(登记 verified-diffs) | | llm/plugin_package_inventory_deepseek.py | 04 | packages/llm/plugin-package-inventory-deepseek/src/{index,types}.ts | 活动插件包清单贡献(P0-6d):collect_active_plugin_packages(ACTIVE fiber 注册项 → callback.__module__ → importlib.metadata.packages_distributions 发行版 → {name, version?};版本可选/容错、松散模块跳过、去重排序)+ install_plugin_package_inventory(注册 dsh_plugin_packages={version:1,packages:[...]})。载体差异:inventory 只收活动注册项,不并入 agentPresets 常驻组合条目(P0-4a 已落子代理侧选择) | | llm/fake.py | 04 | 无 | 教学扩展 | | attachment/(types + error + image + encoding + normalization + projection + request_image + admission + file_store + store) | 07 | packages/attachment/attachment(seam + types + error + admission + request-projection)+ packages/attachment/attachment-local(store + image + encoding + normalization + request-image + file-store) | sharp→Pillow(权威全量解码/EXIF 定向/重编码);规范化管线(总像素预算 + 长边封顶 + 共享质量阶梯按 alpha 分流)与 variantId 请求图缓存(request-image-v6,路由目标 ImageRequestTarget)与上游一致;verbatim 文件族与上游一致(file_store.py:file_leaf_name 清洗 / files/<sha2>/<sha>/<name> 别名 + file-objects 规范对象 / save·save_stream·read_stream 摘要验证;AttachmentStore 七方法含 admit_prompt_content 实例方法);file_uploads.py 复现 packages/client/file-upload 的会话级 receipt(stage/resolve/bindPrompt/retirePrompt,按 sessionId 而非弱引用键);CompressionLimiter 并发闸与 SharedRequest 单飞登记架构不适用(同步载体天然串行);显式 root(上游 DSH_HOME/attachments/v1) | | llm/retry_policy.py | 04 | packages/llm/llm/src/retry-policy.ts | | | llm/retry.py | 04 | packages/llm/llm-retry/src/ | async 恢复决策(派发前熔合信号检查 + always 派发后复查中止胜过决策)+ 事件驱动多信号竞速可取消等待(等价 AbortSignal.any;裸测试替身信号回退轮询)+ 插件 effect teardown(注销监听器 + lifetime.abort + 排干在途恢复) | | llm/token_meter.py | 04 | packages/llm/token-meter/src/ | | | llm/pi_ai.py | 04 | packages/llm/llm-pi-ai/src/{adapter,config}.ts | 多 provider 协议适配器(M15,§2.91):profile 解析/校验(deployment headers 按 Fetch 规则拒绝不可表示条目,requestHeaders 归因按大小写不敏感胜)+ 三协议 body/事件翻译 + apiKeyEnv 凭据;无 ctx.llm 注册表与 dormant→live(载体差异 §2.91) | | compaction/(config + region + summarizer + engine + tool_result_pruner + image_offload) | 04 §4.9 | packages/compaction/compaction-basic/src/ + compaction-tool-result-pruner/src/ + compaction-image-offload/src/(config / region / summarizer / index.ts / projection.ts) | 前缀重放无 KV cache 语义;toolResultPruner 可选阶段已与上游一致(compaction/tool_result_pruner.py,上游注入 ctx.toolResultPruner,mini 经 ctx.get('toolResultPruner') 取用);image_offload.py 镜像 compaction-image-offload——offload_oldest_images + agent/request-error 上的 IMAGE_OFFLOAD_REQUIRED surface 修复(install_compaction 一并安装)+ compaction/summary-error 恢复 waterfall(摘要失败 → 取消即抛 → 恢复监听卸载最旧 occurrence → 重选区间重试,见 region.py 的恢复循环)、两监听均带取消门(region.aborted)(install_compaction 一并安装),投影经 core/session/projections.py。配置对齐上游:headroomTokens 缺省 65536,maxTokens 缺省取 headroomTokens(不再固定 8192);resolve_spec(policy, contextWindow, reservedCompletionTokens) 压力预算 = 窗口 − 预留输出 − headroom,保留预算按「窗口 − 预留输出」缩放;reservedCompletionTokens 取请求信封 maxTokens 或适配器 defaultMaxTokens。摘要指令消息为无 source 的原始 user 请求消息(深冻结) | | jobs/(types + view + ring + pump + events + archive_admission + render + registry + tools) | 04、12 | packages/jobs/(seam + jobs-local + tool-jobs) | rc.1 重写:JobSpec.run(JobHandle)(append/updateProgress)+ pull 源(JobOutputSource)按 cadence 泵入 ring + JobOutcome.result;read 消费模型游标 / readAt 非消耗;JobEvents.subscribe(filter,listener)({owner}/{owners:'all'\|'scope'})替代 onJobDone/onJobsChanged;限界 OutputRing(绝对偏移 + 头部驱逐 + UTF-8 安全超块尾部);controller/订阅按注册 scope 分层;canonical value + render 分离;finalizeContent 可见输出二次封顶;owner 是 SessionId(经 ctx.agents 解析 live Agent;assert_live_agent 台账面已随 rc.1 移除);run_in_background 触发入口经模型侧 subagent 工具复现(简化标注见模块 docstring 与 verified-diffs §2.67/§3.44);注册表发号 <kind>-<16 位 hex uuid>(碰撞重试),并在 owner 会话追加 job/registered/job/settled(含创建它的 toolCall 与 producerReported) | | plan/(config + mode + review + projection) | 07、report/04 §8 | packages/plan/plan-mode/src/ | 状态机 + plan:policy 节 + 审查 UI(exit_plan_mode / /plan / userQuestions)+ plan 投影;canonical value + Tool.render 已与上游一致(approved 无 const——审查被收回时返 ToolResult(value={approved:false}, concludes_turn=True) 并结束回合,render 按真假两支文案)。详见 verified-diffs §2.136/§3.75 | | commands/ | 07、report/04 §8 | packages/interaction/commands/src/ | 命令注册/派发 + command/run|done 配对 + commands/change 通知 + normalizeResult fail-loud;handler 签名 (agent, raw) 为教学扩展(简化标注见模块 docstring) | | goal/(domain + service + prompt + driver + tools + commands) | 07、report/04 §8 | packages/goal/(goal + goal-round-driver + tool-goal + command-goal) | Typert remote(上游命令由 human UI 表面派发,mini 用 /goal 命令承载);_prepare_mutation 前置 assert_live_agent(R4 agent registry);driver 模式事件驱动续跑(同步门面保留 continue_rounds);权威判定近似;三工具 canonical value + render 已与上游一致。idle 结算含 parked 撤回(仍 queued 的预约从 inbox 撤回)与 pause fence。载体差异:同步驱动无 waitForChildren/agent/error disarm/restoreOtherClaimed(§3.75) | | skills/(registry + filesystem + tool_skill) | 07、report/04 §10 | packages/skill/(skill + skill-filesystem + tool-skill) | 无 chokidar watch、无 ctx.fs 适配;skill 工具 canonical value + render 已与上游一致(简化标注见模块 docstring) | | skills/office.py + skills/assets/ | 07、report/04 §10 | packages/skill/skill-office | 内置 dsh-office provider:七技能(office / office-docx / office-pptx / office-xlsx / office-render / office-recalculate / office-export-pdf;assets 逐字节复用上游 SKILL.md,含 office/references/sidecar.md);get 只对渲染三技能追加 "LibreOffice Kit is disabled in this deployment."(上游 cli:false 降级分支);resourceBase.path 归一 POSIX;上游已删 scripts/check_office.py(mini 同步删除该资产与启动校验)。载体差异:无 @deepseek-ai/libreoffice-kit(Node CLI + LibreOffice 二进制)——渲染/PDF/公式重算登记触发条件;装配 sdk-app 门控(DSH_PRIMARY_RUNTIME),install_office_skills 幂等 | | skills/workspace_dependencies.py | 07、report/04 §10 | packages/skill/tool-workspace-dependencies | load_workspace_dependencies 工具:读 runtime.json(PrimaryRuntimeManifest 校验:platform/arch/python/node/pnpm/pythonPackages)+ dependencies/ 路径推导 + payload 原位校验/安装(staging cp → 原子 swap + .previous 树)。载体差异:mini 无捆绑运行时,未配置 payload 时回落运行中 Python(sys.executable + site-packages + 已安装分布);sdk-app 门控装配 | | telemetry/(folds + service) | 04 §4.9 | packages/session/session-stats/src/(projection)+ packages/llm/token-meter/src/(usage-projection + turn-usage) | sessionStats/tokenUsage 投影 fold + derive_turn_token_usage(fail-closed)+ opt-in UsageStatsService(ctx.usageStats);register_telemetry_projections 把两单元注册进 ctx.sessionProjections(M7),projection_values 优先读注册表快照、否则服务镜像/现场折叠;contextPressure 与 telemetry-capture 不承载 | | telemetry/session_telemetry.py + telemetry/session_telemetry_otel.py | 04 §4.9 | packages/session/session-telemetry + session-telemetry-otel + packages/telemetry/otel | 会话遥测(L2):SessionTelemetryBackend(ctx.sessionTelemetry)seam + SessionTelemetryCoordinator(live 订阅 session/created|event|disposed|flush + agent/error 并清扫在世会话 / on-demand 读 canonical log;每条事件经 session-telemetry/record waterfall 脱敏,本包无规则;SessionTelemetryRecord.source_event 携带去 data 的 canonical 信封;模块级 handoff cursor 防重放;contain 单步异常)+ OTel 后端(共享 ctx.otel 服务;FEEDBACK_ONLY 按反馈 on-demand 采集、DISABLED 仅告警;sharing 模式;shutdown 期限;maxRequestBytes 界;sourceEvent 被脱敏移除则 withholds 该记录)。载体差异:Node @opentelemetry/sdk-logs → 自持 OTLP/JSON over httpx(无 Python OTel SDK,因按条数/字节界处理器与 retry/redirect/响应上限契约无等价物);匿名 user.id 经 identity;feedback/committed 面板与 Session.fromRestore 采集路径不承载(mini 无 feedback 提交面板) | | telemetry/otel.py + telemetry/otel_transport.py + telemetry/product_telemetry_otel.py | 04 §4.9 | packages/telemetry/otel + packages/host/product-telemetry-otel | 共享 OTel 服务(L2):ctx.otel 双通道——create_event_reporter(按条数界普通事件,OTelEventRecord{eventName,body,timestamp,severityNumber?,attributes?})+ create_session_log_reporter(按字节界,SESSION_LOG_MAX_REQUEST_BYTES=4_000_000,OTLP log record eventName:'session-log' + attributes{sessionId, content:JSON(event)},超限记录拒绝不截断、queue-full 拒绝、export 超时 watchdog 不释放槽)+ 显式 OTLP/JSON httpx transport(trust_env=False、429/502/503/504 retry limit 5、4 MiB 响应上限、follow_redirects=False、可选 gzip、可中断 retry 等待)+ 产品遥测适配器(x-channel 头,shutdown 经 AbortController + reporter.shutdown(signal)) | | session_log_deepseek/__init__.py | 07 | packages/session/session-log-deepseek/src/{index,types}.ts | dsh_session_log 请求字段(L2):enabled 活读 volatile + maxBytes(缺省 8 MiB,min 1);prepare 构造 {version:1, sessionFormatVersion, session: wireHeader, afterSeq} 并按 jsonBytes 取最长前缀(含 throughSeq 位数)≤ maxBytes;首条事件即超限或不可序列化 → 返回 undefined(不写字段)并告警 needs a N-byte dsh_session_log field, above maxBytes ... / too large to serialize ...,水位不退;accepted_through 读 session-log-deepseek/delivery-accepted 事件推进已接受后缀。install_session_log_deepseek(ctx, registry) 把本模块接进 llm/deepseek_extensions.py 的扩展注册表(provider 按 request.sessionId 经 ctx.sessions 解析会话,直连/过期会话省略字段);prepare_field 亦可由宿主直接在请求组装 seam 调用 | | llm/deepseek.py(扩展) | 04 | packages/llm/llm-deepseek/src/adapter.ts(prepareExtensions) | 构造参数 extensions=(ExtensionRegistry):_iter_chunks 发请求前 prepare_request_extensions,json=payload,HTTP <400 后 accept_extensions(准备省略/接受失败只告警) | | session_projection/__init__.py | 01、10 | packages/session/session-projection/src/{types,index}.ts | 会话投影注册 API v2(L1):ProjectionDefinition(key / init(header, inherited_event_count) / apply(state, event) / 可选 view + state_version)+ SessionProjectionRegistry(ctx.sessionProjections):订阅 session/created(新会话初始化 cell)与 session/event(eager drive),cell 惰性构建 + 按 is 变更门通知 on_changed;读面 state_of/snapshot/cached_snapshot/checkpoint/restore_floor/view_checkpoint/restore/hydrate。载体差异:merge-extensible 类型表 + zod schema → 运行时可选 state_schema/view_schema 可调用对象;上游 session.header → mini session.meta;WeakMap → WeakKeyDictionary。telemetry 经 register_telemetry_projections 把 sessionStats/tokenUsage 注册为单元,projection_values 返回注册表快照全部 wire 单元(含 inbox/title/turnOutline/permissions 等) | | session_turn_outline/__init__.py | 01、10 | packages/session/session-turn-outline/src/{projection,types}.ts | turnOutline 投影单元(M18,L2):preview 文本块 space-join + 空白折叠 + 预算截断省略号(50/120)+ turnOutlineProjectionDefinition(stateVersion 2,fold turn/start 锚定 + 人类 prompt 首块即胜 + draft 缓冲到 turn/end,wire view = turns 数组,state_schema 严格递增 turn) | | session_title/__init__.py | 01、10 | packages/session/session-title/src/{index,normalize,types}.ts + session-title-first-prompt-llm | 会话标题(M10,L2):clean_title_text/truncate_title_utf8/normalize_title/fallback_title + fold_session_title + SessionTitleService(get/rename 用户钉扎/refresh 取消钉扎/register 提供者;自动 first-prompt 调度——fallback 先落、request/header 后执行提供者)+ titleInput(stateVersion 3)/title(stateVersion 1)投影 + register_first_prompt_llm_provider(系统提示词 framing + 输入字节上限 + max-tokens/error 映射 + provider 自持 reasoningEffort 的 per-call 覆盖 + 提供者请求带 currentTitle)。载体差异:上游 llm/stream 事件与 async 微任务/AbortSignal 竞争 → mini 同步门面在 request/header 后触发;LLM 调用经 run_on_resident 驱动适配器流;fake/pi-ai 无 per-call 档位通道(§3.77) | | session_projection_cache/__init__.py | 01、10 | packages/session/session-projection-cache/src/{index,spec}.ts | 持久投影缓存(M14,L2):SessionProjectionCache(ctx.sessionProjectionCache)——写后节流(turn/end/create/dispose 强制 + count threshold + interval 惰性定时)落盘 session_projcache domain(per-record、version 7、backup-and-skip)+ 身份匹配(lifecycle + formatVersion + unseeded cut 守卫)+ 零 I/O cached_snapshot/跨格式边 cached_predecessor_title/hydrate_prepared/cold_snapshot 写回 + 无损 JSON 校验。载体差异:上游 async 持久化 + handle 级逐条读回验证 → mini 经 run_on_resident 同步驱动 storage domain 单写链 | | workflow/__init__.py | 06 | packages/workflow/workflow/src/{index,types,runtime-types}.ts | 工作流接缝(M13,L2):WorkflowEngine(ctx.workflowEngine)服务定义 + WorkflowError 11 码闭集(缺省 fatal)+ validate_meta(违规聚合 META_INVALID)+ 六事件(workflow/start、phase、log、agent-start、agent-end、end)+ WorkflowRunId 品牌 | | workflow_ptc/__init__.py | 06 | packages/workflow/workflow-ptc/src/{index,host,guest,runtime,realm,meta}.ts | Python 工作流引擎(M13,L3):PtcWorkflowEngine.start(meta/脚本解析/provider/maxTotalAgents 前置校验)→ PtcWorkflowRun(host 侧:guest 程序经 PythonPtcRuntime 绑定面执行,workflowHost 绑定 begin/startChild/childResult/disposeChild/progress;六脚本全局 agent/parallel/pipeline/phase/log/args;FIFO 并发槽 + 总 agent/items caps + schema 子集选项 + 结果物化 + 取消/拆解)。沙箱强制门(对齐上游 workflow-ptc):guest 执行前把当前 sandboxPolicy 决议经 PythonPtcRuntime.resolve 透传;运行时声明 sandbox_mode 时 read-only/workspace-write 经 LocalSandboxProvider.confine 包裹 worker,无可用 sandbox 后端则 fail-closed(如 sandbox-unavailable);运行时不声明 sandbox_mode 而部署挂了受限策略 → 拒跑并给可诊断错误;取消窗口折 cancelled。载体差异:脚本语言 JS→Python(同 run_code flavor);子代理 structured 输出无载体(schema 子代理按上游「缺 structured = 失败 → null」语义);子代理经 continuation manager 启动 | | tool_workflow/__init__.py | 06 | packages/workflow/tool-workflow/src/{index,record,types}.ts | workflow 模型工具(M13,L3):workflow 工具(script/meta/args/run_in_background 参数、前台/后台结局、渲染)+ durable 记录(tool-workflow/run-start/agent-start/agent-end/run-end)顶层传输执行 + 后台作业集成 | | subprocess/__init__.py | 06 | packages/subprocess/subprocess/src/index.ts | subprocess 接缝服务(M17,L3):ctx.subprocess(resolve_executable/terminal_environment/scrubbed_parent_env 收编既有实现,无复制)。载体差异:Windows Job/systemd scope/execve runner 平台专属 containment 无 Python 等价(Popen 近似);spill 收集器以内存缓冲承载 | | deepseek_account/{__init__,protocol,details,logout,platform}.py | 07 | packages/credentials/deepseek-account/src/{index,types,account-tasks}.ts + deepseek-account-platform/src/{index,protocol,details,logout,types}.ts | 账户服务定义(P1-21/ND-14,L3):ctx.deepseekAccount 抽象 + PlatformAccount(浏览器 PKCE attempt 状态机、固定宿主 /oauth/callback、auth_init/exchange/cancel、grant/device 存储、Platform profile/wallet/bonus/logout、safe links、session)+ LocalAccountService(无 credentials/authorization 或 platformOrigin 时的 signed-out 兜底)+ resolve_token/reject_token + 事件 deepseek-account/signed-out/session-expired/model-sign-in-required + is_running_account_task(account/signOut 时取消运行中的账户路由 Agent,keep_inbox,cause {kind:'hook', reason:'deepseek-account/signed-out'})+ account/* Remote wire(getState/getProfile/getBalance/startSignIn/cancelSignIn/signOut + 元数据/getUnnotifiedBonuses/ackBonusNotified/hasRunningAccountTasks/stream watch/watchExpiry)。载体差异:authorization 同步接缝 + daemon worker/Event;detail 以 generation 失效而非 abort 在途请求;httpx 有界流;watch 由服务推送改为短轮询投影等价发布;见 verified-diffs §2.151/§3.82/§2.152 | | session_query/(config/extraction/documents/sqlite/service/tool) | 07 | packages/session-query/{session-query,session-query-sqlite,tool-session-query} | 会话检索(L2):extract_event_text(一方事件语义文本)+ build_search_documents(surface 分类 current/shadowed/log-only)+ SqliteSearchIndex(FTS5 bm25 + snippet;查询当数据)+ SessionQuery(ctx.sessionQuery:search 跨会话最佳命中 / search_events 会话内 / read_event 原始窗口 / trace_event 替换来源 / lineage 世系;活会话经 ctx.sessions、持久化经注入 persistence)+ 五模型工具。载体差异:上游 tracing 提供方分层与 observation/lease 不承载(现场解析日志);授权/workpace 作用域(workspace-access + sessionProjections)不承载(无 workspace 实体,M5);session-log-export 由 web/downloads.py 承载 | | todo/__init__.py | 03 | packages/todo | 待办清单(L2):to_todo_list(工具入参校验,措辞逐字对齐)+ fold_todos(todo/write 最新胜出、turn/start 清空)+ install_todo_tool(模型侧 todo_write;事件 todo/write 为 log-only,已入 core/session/types.py KNOWN_TYPES)。载体差异:上游投影单元经 ctx.sessionProjections 注册,mini 无投影注册表(随 M7),当前以纯函数 fold + 工具结果承载 | | spill/(__init__.py + retention.py) | 03 | packages/spill/{spill,spill-local,spill-policy}(spill-policy/notice.ts / retention.ts) | 大结果落盘(L2):SpillStore(ctx.spillStore)seam + LocalSpillStore(每会话私有目录、0600 文件、注入式根)+ install_spill_policy(tools/post-execute prepend:可保留内容(text/image)的估算 token 超 maxInlineTokens 时把完整文本(图片位置写成可读附件地址)落盘、替换为有界 head/tail 预览 + 取回提示;图片整块保留或省略,提示报告 Omitted N images.;嵌套 PTC 复合结果省略整图时经 source {kind:'ptc-mode'} 的 user 消息重注 additionalContexts(ptc/run_code.py 转发);best-effort,失败绝不改写成功结果)。载体差异:上游策略依赖 dsh-output-retention(TextRetainer/describeOmitted),mini 内联预览与 describeOmitted 文案;上游按 UTF-16 码元切分并在代理对中间回退,Python str 以码点为原子单位,天然不在代理对中间切分,retention.ts 的代理保护不承载;上游 tools/ptc-dispatch-log 次臂不承载(mini 由 run_code 的 tool/ptc-dispatch 承载,post-execute 对嵌套结果照常保留) | | workspace/__init__.py | 07 | packages/workspace/workspace | 工作区实体(L2):fully_qualified_workspace_path/default_workspace_title/realpath_normalize(realpath 为唯一性 canon)+ Workspace(稳定 uuid、目录路径、标题、有序会话账户:setTitle/attachSession/insertSessionBefore/detachSession/status)+ WorkspaceService(ctx.workspaces:create/create_now/initialize_default/resolve_by_path/list/get/remove/delete/insert_before + 全局归档会话集 archive_session/unarchive_session/workspace/session-activity waterfall 准入(活跃则 WorkspaceActiveSessionError)+stopActivity 写后派发 workspace/session-stop/归档丢 pin + 全局置顶会话集 pinnedSessionIds/pin_session/unpin_session(WorkspaceArchivedSessionPinError,pin 顺序最近在前)+ SessionActivity/SessionActivityItem/SessionActivityKind(Map) 类型 + 首用默认登记 initializeDefault/defaultWorkspaceId + workspace/changed 变更通知)。载体差异:上游经 ctx.storage.domain(storage-domain 表 + 双写恢复标记 + 单写链)持久化并做 header-validated 账户过滤/归档集,mini 以 JSON 注册表(含 order/archivedSessionIds/pinnedSessionIds/defaultWorkspaceId 字段,缺省回填空)+ os.replace 原子发布承载(无显式 domain version;无 pendingMutation 恢复标记;change 通知以自有 workspace/changed 承载;SessionActivityKindMap 以 {"turn": object, "job": object} 承载上游可合并类型表——本包声明随默认组合装载的 turn/job 家族,其余由各自 provider 合并;typert RPC 视图未承载)。详见 verified-diffs §2.63/§2.65/§3.40 | | settings/__init__.py | 07 | packages/settings/{settings,settings-file} | 用户设置(L2):SettingsProvider(ctx.settings:命名空间注册 + 解析值 = schema 默认 → composition base → 用户文档 section)+ SettingsScope(get/watch/update/replace/mutate)+ 写路径 monotonic revision(陈旧写 SettingsConflictError/SETTINGS_CONFLICT)+ settings/updated(深度相等门控)与 settings/document-updated + redact_secrets(schema 声明 secret 位置只报 set 状态)+ SettingsFileProvider(JSON 文档原子写 + document_path/prepare_document + watchdog 外部改动重载,provider 源提交)。载体差异:上游 schema 用 schemastery(role('secret') + toJSON 线视图),mini 以纯 dict 默认值 + 显式 secret 路径集承载;typert RPC 描述视图未承载(settings-controller 以 schema:{} 占位)。rc.1 核心(settings/forms.py):SettingsForms(无注册机制、命名空间 = configEditor.entries 唯一 profile entry id、读 configuration 三层 value/base/user、写经 configEditor.edit 持久化 cordis.patch.yml、revision 追踪、configure({auto}) 页面策略、legacy settings.yaml 导入)+ install_settings_forms(幂等装配,要求 ctx.configEditor 在场);生产装配:web profile 已迁 boot/profile 驱动——cli/plugins/* 组合条目 + install_config_editor + install_settings_forms 装配,SettingsForms 成为 web profile 的 ctx.settings(命名空间 = web 组合条目 id,写经 config-editor 持久化 profile cordis.patch.yml);headless 手写装配仍维持 SettingsFileProvider 既有载体 | | boot/boot.py | 05、08 | packages/boot/app-boot | mount_root_include(Loader 服务 + 根 Include 条目,并登记 _BOOTSTRAP_INCLUDES WeakMap)+ boot(装载根配置→依序补丁→审计未激活条目 fail loud,ACTIVE/FAILED/PENDING 三态对齐 auditStartupEntries)+ load_optional_patches(缺文件→空层、坏文件 fail loud)+ reconcile_profile_patches(对齐 app-boot reconcileProfilePatches:快照 previousFailures 四元 → entry.update 应用补丁世代 → 等旧 fiber 结算 + await_all → introduced 判定(requiredIds 点名或与 previous 不一致的新失败)→ 抛 / 旧 fiber 被拒未失败原样重抛 → emit app-boot/config-reload)+ watch_user_patches(经 HMR watch 用户补丁层 → reconcile 对账重挂)。载体:旧 {replace|insert} 叠层补丁在 boot 侧转成 applyEntryPatches 形态(_overlay_to_entry_patches,不做表达式求值);对账的 fiber 结算为同步等价(internal/update waterfall 内完成卸载/重装,无 Promise.allSettled) | | boot/composition.py | 05、08 | packages/boot/app-boot + apps/cli/src/args.ts | load_dotenv_file 与上游 readEnvLayer 一致:ENOENT 静默/其它 warn/已存在不覆盖/bootstrap-only 物化前整体拒绝;home= 为 harness-home 时 HOME_LAYER_PROXY_NAMES(HTTP_PROXY/HTTPS_PROXY/ALL_PROXY/NO_PROXY)豁免、代理名错误文案明说 home .env 第二条出路(index.ts) | | boot/dotenv.py | 05、08 | packages/boot/app-boot(loadEnv) | bootstrap-only 名单/前缀与 BOOTSTRAP_NAMES/PREFIXES 一致;HOME_LAYER_PROXY_NAMES 同款;豁免判定在 load_dotenv_file(同上游 readEnvLayer) | | boot/profile.py | 05、08 | packages/boot/app-boot/src/{profile,profile-context}.ts | profile 目录机制:resolve_profile_dir(名字校验 + $MINIHARNESS_HOME/profiles/<name>)+ init_profile(manifest + 空 cordis.patch.yml 模板)+ load_profile_directory(读 dsh.profile.bundles + 用户补丁层)+ bundle_patch_files(dsh.bundle.patch 单文件/列表)+ compose_entries(空根或 base 单次 applyEntryPatches)+ read_profile_patches(层序:bundle → profile cordis.patch.yml → home 级 → overlays,后压先)。载体差异:mini 无 npm bundle 包(dsh-base/web-app)与 pnpm 安装面——bundle 层解析与 plugin-manager 子进程族登记架构不适用/触发条件;headless/web 是 Python 组合入口(非 bundle 装载插件树),用户自定义 profile 的 CLI 全接线随该差异登记 | | boot/config_editor.py | 05、08 | packages/boot/config-editor/src/index.ts | ConfigEditor(ctx.configEditor):profile 活动条目的配置编辑持久化到 cordis.patch.yml——documentPath/entries(根 Include 树唯一 id)/configuration(inherited + override)/edit(entry, change)(filelock 锁锚 profile package.json → reconcile 磁盘现状 → Fiber._resolve_config 验证 → ruamel round-trip 注释保留改写 → effective 验证 → 原子写 → reconcile requiredIds,失败写回旧文本再 reconcile 回滚;全程 hmr.run_exclusive)。载体差异:schemastery Config 校验经 _resolve_config(有 schema 时);filelock + 本地原子写 | | boot/plugin_manager.py | 05、08 | packages/boot/plugin-manager/src/{index,patch}.ts | PluginManager(ctx.pluginManager):当前 profile 的插件列举与启停——list_plugins 在 pluginInventory 四字段上按组合行给 patchId(唯一 id/name 匹配且根 Include 所有)或 readOnlyReason: unaddressable;set_plugin_enabled(id, enabled) 把 disabled 意图写入 profile cordis.patch.yml(ruamel 注释保留)→ effective 组合验证(home/overlay 覆盖拒绝)→ 原子写 → reconcile_profile_patches 应用,失败回写旧文本并回滚;成功后 emit plugin-manager/changed {reason}。载体差异:npm/pnpm 安装卸载与 package.json 锁文件版本豁免无 Python bundle 等价;pluginInventory/list 只在服务在场时加 managementAvailable:true;上游 restart-required 分支不适用(Loader 对账同步应用) | | boot/plugin_market.py + boot/plugin_market_index.py | 05、08 | packages/boot/plugin-market/src/index.ts | PluginMarket(ctx.pluginMarket):Remote listIndexes/setIndexes/search/readEntryDetail + pluginRegistryProbe/fastest 探测;HTTP(S) 索引抓取与 TTL 缓存;搜索 npm/git 形索引,install 字段支持 Python 扩展 source.type: python(经 config-editor 写 profile,不执行 pnpm)。载体差异:上游 npm 安装子进程族不承载;GitHub release 安装简化登记 | | boot/config_schema.py | 05、08 | packages/boot/app-boot/src/config-schema/ | profile 配置 schema 导出:generate_config_schema(compose 条目 → 逐插件 Config 投影 → JSON Schema 2020-12 文档 ConfigSchemaDump,含 $defs loaderExpression/entryMetadata/entry/entryList/patchList/patch/unknownConfig/includeConfig/includePatch/configN + x-cordis 注解 profile/complete/entries/diagnostics/patchSchema)+ collect_config_schemas(boot-free 走行、模块导入读 Config、group/include 子树递归)+ project_native_schema(schemastery → JSON Schema 投影器:object/dict/array/tuple/union/intersect/transform/string/number/boolean/const/any/never + 值位置 !!js 包裹 + x-cordis 注解 + partial limitation)。消费面:CLI --dump-config-schema(cli/main.py)。载体差异:mini 插件 config 多无 schemastery Config 声明 → 条目投影 unknownConfig(对齐上游无 schema 行为);lazy builder 执行一次;无法静态投影标 partial | | loader/(model/utils/patch/entry/group/tree/loader/isolate/include) | 05、08 | vendor/loader/src/{index,internal,config/{entry,group,isolate,tree,utils}}.ts + vendor/include/src/index.ts | cordis 组件系统活树:EntryTree 扁平 store + entries/resolve/import_/write;Entry 生命周期(update/disabled/init、loader/partial-dispose、internal/plugin 归属)+ module 旧方言 apply 桥;EntryGroup 一级子列表宿主(create/remove/update/stop)+ Group 插件;Loader 服务(internal/config 树载体字面/普通条目 interpolate、internal/update 写回 + 重载日志、internal/plugin 自销毁回写 disabled、[Service.check] 的 intercept.await 门控、envData/exit)+ apply_entry_patches + isolate/intercept 条目选项(isolate.py:Local/Global realm + loader/patch-context waterfall 迁实现 + loader/partial-dispose realm GC)+ Include(文件读写/initial/dump !!js 原样、rename 重试)。方言:条目 YAML 用上游 entryListSchema(JSON_SCHEMA + !!js)。载体/适配(登记 §3):同步门面 + ctx.plugin(parent=) 显式归属、baseUrl 沿 ctx 父链上溯、settle_gathered 瞬态 loop 结算、getOuterStack 数据面。不适用:internal.ts(Node ESM 内部加载器) | | fs/(types/service/local/sandbox/observation_policy/diff/tools/str_replace_editor/search) | 03、06 | packages/fs/fs + fs-local + fs-sandbox + fs-observation-policy + tool-fs + tool-str-replace-editor + tool-fs-search | 文件系统域(L1):FileSystem(ctx.fs)seam(含 watch 抽象契约,基类默认拒绝 FS_IO_ERROR)+ LocalFileSystem(realpath 身份、严格 UTF-8 + NUL 二进制拒绝、原子 staging、createIfAbsent 硬链接 no-replace、replaceIfVersion 陈旧守卫、字面编辑 LF/CRLF、watch 经 watchdog)+ SandboxedFileSystem(每次调用 read-only/workspace-write/danger-full-access 围栏)+ ObservedStateGate(fs/write-intent/fs/edit-intent/fs/observed)+ 模型侧 read/read_image/write/edit(注册开关 read/read_image/write/edit,缺省 true;read_image 仅在挂 attachment store 时注册)、str_replace_editor、glob/grep;变更结果以 canonical ctx.fs.process_path 暴露 path 并统一 emit fs/observed(mutationResult);read_image 供 PNG/JPEG/WebP/GIF 按签名/扩展名判定媒体类型、限额经 attachment store、路由须声明 image 输入。上游 tool-present 的 present 工具由 deliverables/ 承载(见下)。载体差异:AbortSignal→取消句柄;win32 DACL 复制/替换不承载;glob/grep 以 stdlib os.walk+re 替代打包 ripgrep(tool-fs-search);watch 以 watchdog 承载、无 chokidar ready 事件(observer 启动即返回,signal 只在 stat 前后检查);read_image 无 ctx.llm,路由事实取调用 Agent 的适配器模型信息。详见 verified-diffs §2.45/§2.46/§2.64/§3.41 | | lsp/ | 03、06 | packages/lsp/lsp | LSP 能力 seam(L1):ctx.lsp 提供语言服务 provider 注册表 + 按文件末段扩展名的每查询、顺序无关选择,暴露四语义操作(goToDefinition/findReferences/goToImplementation/hover)无 JSON-RPC 逃生口;register_provider 原子预留 id+扩展名(非法/冲突不发布,fail-loud)+ 返回 disposer;LspError 稳定码闭集 + final_extension。载体差异:上游 provider id 是品牌类型,mini 以 str 承载 | | lsp_stdio/ | 03、06 | packages/lsp/lsp-stdio | 通用 stdio 语言服务器后端(L2):framing(Content-Length JSON-RPC 编解码,头部/消息大小有界)+ translate(能力判定/Location/LocationLink/Hover 归一,纯函数)+ host(经 ctx.fs 规范工作区 + 约束读源)+ connection(子进程上的 JSON-RPC 端点:server→client 请求应答 + stderr 有界尾 + 增级终止)+ instance(握手 + 串行可取消查询队列 + 瞬态 didOpen→request→didClose + 有界拆除)+ LocalLspProvider(按规范工作区池化惰性单飞,传输失败透明重试一次)+ install_lsp_stdio(server 表)。载体差异:ctx.subprocess.spawn→asyncio.create_subprocess_exec(无 OS 级受管范围/进程树 containment);Web AbortSignal→鸭子类型信号 + 短轮询(abortable 不取消底层 work);AggregateError→单失败重抛/RuntimeError | | tool_lsp/ | 03、06 | packages/lsp/tool-lsp | 模型可见 lsp 只读工具(L2):四操作;一基 UTF-16 光标→seam 零基位置;要求会话工作区 cwd(否则 LSP_WORKSPACE_REQUIRED);位置渲染(按文件分组、file: URI→工作区相对/绝对、maxLocations 省略标记、完整结果 maxResultChars 封顶)+ hover 渲染;tool:lsp prompt 节(order 2200,文本逐字)。载体差异:上游 apply(ctx,config) 经 ctx.tools.register + inject tools/lsp/systemPrompt;mini 以 install_tool_lsp(ctx, registry, config) 由 default_tools 在 ctx.lsp 在场时条件注册 | | cli/main.py | 07 | apps/cli/src/args.ts | launcher 选项解析 + 组合验证/dump/--dump-config-schema;_web_main(--profile web)为 boot/profile 驱动装配:首次把默认 web 组合模板(cli/web_profile.yml)种子进 $DSH_HOME/profiles/web/cordis.yml → 读 profile/home/overlay 补丁层 → boot 组合(条目 = cli/plugins/* 插件)→ 装配 config-editor + SettingsForms + settings-controller → default_tools + agentPreset 投影 → web/launcher.run_web。对齐上游 web-app bundle 的插件组合面 | | cli/plugins/* | 07 | packages/bundle/web-app(插件条目) | web 组合条目插件:每条目 apply(ctx, **config) 安装一个 web 服务(install_* 既有函数);permission-presets/session-title-first-prompt-llm 声明 inject 依赖(approval/sessionTitle),session-title 读 boot env ctx.adapter;条目 config 必须整节透传给服务(permission-presets 的 defaultPreset 即设置对话框「权限」行的写目标,丢弃会让写入持久化却不生效) | | cli/headless.py | 07 | packages/bundle/headless + apps/cli | | | cli/default_tools.py | 00、07 | 无 | 教学扩展(上游是工具插件注册) | | cli/session_cmds.py | 00、07 | 无 | 教学扩展(上游会话管理在 web 表层) | | cli/preset_cmds.py | 00、07 | 无 | 教学扩展(上游 preset 管理是 web 表层 Remote:list/read/deletePreset/selectPreset)——miniharness presets 子命令,投影/锁/删除语义一致,不写 agent-preset/selected | | preset/presets.py | 08 | packages/preset + apps/cli/config/agent-presets | shipped root(system) + 多根 first-root-wins roster、project_preset/project_session_agent_preset 投影、PresetLockedError、PresetNotWritableError、mount 作用域审计;YAML 翻译(agent.cordis.yml → Preset);数据目录 preset/{minimal,standard};rc.1 声明式 registry 面——make_agent_preset_projection/register_agent_preset_projection(agentPreset 会话投影单元,stateVersion 1)+ roster rows(AgentPresetRow 形态含 isDefault/broken)供 agentPresets Remote list/read/select 消费 | | preset/registry.py | 08 | packages/preset/agent-preset-registry/src/{index,definition,composition-inventory,mount}.ts | 声明式载体:AgentPresetRegistry(register(definition) 幂等 + 重复拒绝 + unregister disposer、composition_inventory 声明态行投影 AgentPresetComposition、resolve_composition(id) 活组合解析 {id,tools,persona},roster 接线时以目录 roster 为唯一工具/persona 解析面)+ definition_composition/entry_list_problem/flatten_rows(声明行 flatten:组行跳过、组 disabled 继承、!!js 求值被拒→'conditional')+ install_agent_preset_registry(ctx, roster=...)(幂等装配 ctx.agentPresets)。组合行 flat 工具与 web/inventory.py 共享(单一实现,web→preset 显式例外)。载体差异:无 live fiber 常驻挂载(PresetTree/EntryTree 激活态行),mini 只提供声明态行 + 活组合数据(挂载树载体差异延续 §2.77) | | extensions/dynamic.py | 11 | packages/extensions/* | | | interaction/approval.py | 07、09 | packages/interaction/user-approval | 审批服务(ApprovalService):策略两档 + 审计对 + approval:policy 系统提示词上下文 + set_policy(agent, policy) 注入模型可见变更通知 | | interaction/permission_presets.py | 07、09 | packages/interaction/permission-presets | 权限预设(M11):PermissionPresetService(预设表捆绑 sandbox 模式 + 审批策略、derive/current/resolve/option_of、set 写 permission/preset 在前 + 只写变更旋钮、pin_initial_permission 会话钉扎、Auto 集成、permissions 投影 stateVersion 2、/permission 命令、catalog Remote);组合缺省读 ctx.shell.sandbox_mode/sandboxPolicy + approval 配置 | | interaction/user_questions.py | 07、09 | packages/interaction/user-questions/src/{index,projection,timed-wait,types}.ts | UserQuestionError(name + 稳定 code)、ask 校验序逐字 + waterfall 派发(user-questions/request + no-answerer fail-loud → NO_PROVIDER)、restore_user_question_error、取消归一(signal aborted → ASK_ABORTED);dsh-v0.2.0-rc.2 timed 面:userQuestions 投影单元(stateVersion 2,按 header 是否含 timeout 参数区分 timed/legacy,fold tool/call/tool/result/tool/ptc-dispatch/user-question-reply,LEGACY 调用永不追踪、TOOL_OUTCOME_UNKNOWN 仍可答)、TimedQuestionWait(Host 期限仅无客户端认领时计时)、服务方法 answer(steer user-question-reply + 关投影)/attach_wait({remainingMs} 帧)/ask_timed(ASK_TIMED_OUT → {pending, callId})。载体差异:waterfall base 经 core/scope.py awaterfall 承载 | | interaction/tool_ask_user.py | 07、09 | packages/interaction/tool-ask-user/src/{index,timed}.ts | ask_user_question 工具(legacy 默认 schema 逐字 + canonical {"answers":[...]})+ timed 面(mode='legacy'\|'timed' 配置、timeout 参数默认 120 / -1=必须回答、oneOf {pending,callId,message}\|{answers} 输出)。仅装配 userQuestions 服务后注册 | | schedule/(types/domain/runtime/tools/storage/delivery_history/update/service/archive_admission) | 07 | packages/schedule/schedule/src/{types,domain,index,runtime,update,delivery-history,storage}.ts + packages/schedule/tool-schedule/src/index.ts | 定时任务域(L2,dsh-v0.2.0-rc.2 推倒重写):六规则 after\|at\|every\|daily\|weekly\|cron(Vixie cron 语义、DST earlier/跳过、latest-only 触发);title 必填(≤120,历史事件仍可无 title 读入);权威存储改 storage-domain 表(Host 全局、单 Host 定时器、到期唤醒原会话、deliveryMode:'host'),删旧 session 事件投影/transaction;schedule_update compare-and-update;新 Remote list/catalog/history/delete/update + cordis 事件 schedule/changed;delivery-history 身份游标分页(默认 30 天/200 条);删 persistence_uncertain/corrupt_schedule_log 码。工具与服务已拆分(对齐上游 dsh-tool-schedule 独立包):install_tool_schedule(ctx, service) 是唯一挂载入口(service.py 不挂工具);委派子代理经 subagent_session 双门拒绝(工具层 A delegated subagent cannot use reminders.;服务层 create 抛错 / update 返非变更结果,This Session belongs to subagent routing, which never receives reminder delivery.)。载体差异:schedule/change 会话事件仅 legacy 读/回放;时区经 zoneinfo(别名拼写保留,与 Intl 解析差异登记);冷恢复经宿主 session-controller(mini 用 ctx.agents/注入 resolve);web 入口在传入 schedule_root 时由 WebApi 装配 install_host_schedule(storage-domain 任务表 + Host 定时器);headless/demo 手写组合未默认挂载 schedule 服务时 Remote 返回 gateway/invocation-unavailable | | core/code_language.py | 03 | packages/util/code-language/src/index.ts | 扩展名→语言共享表(L0):language_for_path/read_lang_hint_for_path(短名表 43 旧值逐字保留 + 新 ps1/csv/bat/env/log/proto/tf/tex/jl/v/gradle 等);fs/tools.py 的 lang_from_path 经此;读卡片 read_presentation_meta 持久化 lang | | core/output_retention.py | 03 | packages/util/output-retention/src/index.ts | UTF-16 代理对安全截断 truncate_without_splitting_surrogate_pair(L0),供 str-replace-editor / 持久 shell 输出截断 | | core/working_cwd.py | 03 | —(mini 消费者共享面) | working_directory_of(agent_or_session)(L0):有效工作目录的同步零 I/O 读取——存在 ctx.workingDirectory 时取 get(session)(投影态),否则回退 session.meta["cwd"]。fs/shell/terminal/lsp/skill/context/workflow-ptc/run_code 消费者共用,避免 L1 模块反向依赖 L2 服务 | | working_directory/__init__.py | 07 | packages/session/working-directory/src/index.ts + packages/session/tool-working-directory/src/index.ts | 可变当前执行目录(dsh-v0.2.1-rc.2,L2):WorkingDirectoryService(ctx.workingDirectory)——get(session)=投影态 ?? defaultDirectory;ensure(agent,signal) 校验存在、失效恢复 header.cwd ?? defaultDirectory 并落通知;set(agent,path,signal) 相对基于当前 cwd、canonical=processPath、空/非目录/非绝对 defaultDirectory 各报错;per-session serialize 链 + 提交早于兑现 + 通知失败仅 warn。workingDirectory 投影单元(init=header.cwd ?? null、stateVersion 1)+ 系统提示 context working-directory:current(order=100、required、interpolate=false)+ system-prompt/assemble prepend 准入(ensure + 写回 contribution)+ 模型工具 working_directory({cd?})。载体差异:消费者取同步 get(准入期 ensure 已覆盖校验,verified-diffs §3.52);生命周期拆解同步化(§3.53) | | feedback/command_feedback.py | 07 | packages/feedback/command-feedback | 会话级人工反馈(M12):FEEDBACK_CATEGORIES + record_feedback(feedback/record log-only 事件,trim/省略空 text/无 category)+ /feedback 命令(recordInput:false,空输入拒绝,成功两行 ack 含匿名用户 id)+ sessionFeedback Remote(record,session-not-found)。载体差异:Remote 经 Service + web/api.py 代理(上游 TypertRemoteService) | | feedback/message_feedback.py | 07 | packages/feedback/message-feedback | 消息级反馈(M12):MessageFeedbackService(list/put/delete)——note 校验先于一切(note-blank/note-too-large)、目标校验(append-origin 非空 assistant/message)、版本 CAS(version-conflict + ifVersion)、无操作不追加事件、note/category 省略丢键、delete 幂等恒 {absent:true}、活/冷会话路径(live flush 参与 / persistence load+append+flush)。载体差异:上游 open/stat/read 句柄与逐条持久化验证不承载 | | client/trajectory.py | 10 | packages/client/ui-trajectory | | | mcp/types.py | 06 | packages/mcp/mcp-client/src/{connection,index}.ts | ReconnectConfig / RECONNECT_DEFAULTS / Config schema 默认值(serverName 模式 [A-Za-z0-9_-]{1,32}、toolCallTimeoutMs 60000、maxInstructionBytes 32768、GENERATION_CLOSE_TIMEOUT_MS 5000);resolve_reconnect_policy / resolve_mcp_config 以显式解析承载上游 Schemastery loader 的 fail-loud 归一校验 | | mcp/client.py | 06 | packages/mcp/mcp-client/src/index.ts | apply(ctx, config):scope-session 化 serverName 保留集 + resolve → 链接生成;McpServerConnection 同步门面 | | mcp/connection.py | 06 | packages/mcp/mcp-client/src/connection.ts | 代连接 supervisor:stdio / streamable-http 统一,简历过期扫描 + 重连(初始/上限延迟、预算耗尽即停),工具归属注册(_RESOURCE_KEY / _TOOLS_OFFSET 预算集)与 sync_tools 换代、tools/list_changed 重同步、server instructions 字节上限 fail-loud、失败即拒绝(failOnStartupError 直抛);载体差异(SDK 2.2):SDK stdio 传输在子进程退出时不投递 EOF/异常(_drain_stdout 永久阻塞、read_stream 不关闭)——mini 以「握手/工具 RPC 有界竞速(_run_rpc,5s,对 generation.lost 中止)+ 常驻生命线 ping(watchdog,15s 心跳 / 3s 超时)」替代上游 within 取消令牌,杜绝子进程退出后握手流程阻塞挂起;代关闭屏障(GENERATION_CLOSE_TIMEOUT_MS)超时 fail-closed 防重叠子进程 | | mcp/transport.py | 06 | packages/mcp/mcp-client/src/transport.ts | 传输工厂 + stdio 子进程 env 组装(复用 seams.subprocess_env 净身切片的 L3 例外,见 §3 规则 1) | | mcp/server_context.py | 06 | packages/mcp/mcp-client/src/{server-context,mcp-servers.ts} | server 挂载点 / CLI 定位(-m module、script、绝对路径)/ MCP_SERVERS_ORDER | | mcp/tools.py | 06 | packages/mcp/mcp-client/src/tools.ts | sync_tools:${server}.${name}#${hash} 公共工具名(stringHash32 → base36 → MCP 前缀截断)、darkfrozen 手写 JSON 序列化等价(frost_equal / create_output)、LLM 输入/输出/图片受理投影(admit 门 + variantId 请求图缓存);图片投影经 project_content 政策前安装(对齐上游 projectContent:三条件一致才返回,post-execute 政策仍可替换/阻止) | | mcp/resources/render.py | 06 | packages/mcp/mcp-resources/src/render.ts | render_resource_result:手动 JSON 序列化紧凑 JSON + blob 掩码(8 base64 字符不泄漏原文) | | mcp/resources/tools.py | 06 | packages/mcp/mcp-resources/src/tools.ts | list_mcp_resources / list_mcp_resource_templates / read_mcp_resource 三工具定义(server/cursor/uri 参数约定 + Render 双参) | | mcp/resources/runtime.py | 06 | packages/mcp/mcp-resources/src/index.ts | McpResourceRuntime(createResource 生命周期、资源请求经关联连接、disposer 注销)+ install_mcp_resources(ctx) 装配 | | mcp/fixture_server.py | 06 | 无 | 教学扩展(tests 的 stdio/HTTP 夹具,--die-after 自毁模拟崩溃) | | web/envelope.py | 07 | packages/client/connection/src/{rpc-schema,rpc}.ts | 两信封消息联合(client-request / server-response)+ 连接层错误闭集(含 R3 新增 gateway/input-invalid);transport_error 折叠兜底码 ‘internal’ | | web/attachments.py | 07 | packages/api/gateway/src/index.ts(encodeRpcResult / encodeRuntimeResult)+ packages/client/connection/src/rpc-host.ts(fullResponse)+ client/rpc.ts(parseBinaryResponse) | unary 结果的二进制附件:bytes 叶子投影为 null 占位 + {path, codec:'bytes', part} 描述(循环引用 → gateway: circular RPC result)、result_response 分帧(失败/纯 JSON → application/json;有附件 → multipart/form-data 的 metadata + bytes-<i> 流式出体)、dumps 解冻后 wire 序列化;客户端重组在 webui/src/wire/rpc.ts | | web/upload.py | 07 | packages/client/file-upload/src/{http-route,protocol}.ts | 原始字节上传 POST /api/session/uploadFileBinary(先于 /api/{path} 兜底注册):405/415/400 载体拒绝 + 恒 200 业务结果;asyncio 队列 + 线程 generator 流式落盘(不聚合、不 base64);子代理 subagent/attachment-invalid;base64 回退 fileUploads/upload 在 web/api.py | | web/api.py | 07 | packages/api/session-controller/src/index.ts(session 域辅助入口)+ packages/preset/agent-preset-registry/src/index.ts(agentPresets Remote 面)+ packages/api/job-controller/src/index.ts(job/kill)+ packages/goal/goal(goals Remote)+ session-controller/src/{skill-catalog,file-references}.ts | WebApi unary 方法(list/search/create/selectModel/modelCatalog/canOpenWorkspacePath/openWorkspacePath/rename/fork/prompt/attachment/updateQueue/cancel/page)+ 路由表;session/queue placement 三态经 session/control 投影;agentPresets list/read/select(声明式 roster + turnBoundary 首回合锁 + durable agent-preset/selected);job/kill(栅栏折 job/not-found);host-plane goals/get|create|edit|pause|resume|complete|clear、skills/list、fileReferences/list(interface-wire §4.12)、llm/listProviders|listConfigurableProviders|discoverModels、commands/list|execute、directoryPicker/list|createDirectory|pick(§4.13) | | web/args.py | 07 | packages/api/gateway/src/index.ts(assertExactArguments:1112 / decode:1140)+ remote-error-codes.ts | 路由层 {args} 边界校验:每方法字段集合精确匹配(missing/unexpected → gateway/arguments-invalid)+ 顶层 JSON 类型(错型 → gateway/input-invalid);TypertGatewayFaultDetails{endpoint, field?};枚举/范围/非空/跨字段语义留 handler(业务码) | | web/stream_protocol.py | 07 | packages/api/gateway/src/stream-protocol.ts | Remote 流 wire 语法:open/cancel/item/end/error 帧(客户端四型与宿主三型都 exactKeys 闭合,多一个键即拒)、$events 打开与 $events/result payload 解析、无损 JSON 判定(dict 键须 str、float 有限非 -0) | | web/uplink.py | 07 | packages/api/gateway/src/stream-server.ts(UplinkInbox)+ index.ts(GatewayInvocation.uplink 的 UplinkDecoder:1214-1285 / decode:1493-1514 / streamInboxBytes @default 262144) | 单条逻辑流的有界单消费者上行 inbox:整帧 UTF-8 字节记账、end 半关、end 后 item → gateway/protocol、超限 → gateway/uplink-overflow(违例带 {endpoint} details 并中止该流)、fail 先到先得、释放后丢帧;方法侧 UplinkItems 逐项过该 endpoint 声明的 codec(未声明走无损 JSON 校验 + 解码结果复校),被拒项折 gateway/input-invalid(消息 wire field "uplink" failed boundary validation,details {endpoint, field})并中止整条逻辑流 | | web/mux.py | 07 | packages/api/gateway/src/create-mux-websocket.ts(RemoteStreamMuxConnection)+ stream-server.ts | 单条 /api/remote.mux WebSocket 承载全部 Remote 流;open/cancel/item/end/error 帧往返,二进制 1003/非法 1008/重复 open 1008 关闭码,隔离单流失败;每条 open 先建自己的 inbox(紧跟 open 的 item 排队不丢),item 违例以 Remote failure 中止该流并发终态 error 帧,$events 网关自有流 open 即释放 inbox | | webui/src/wire/mux.ts + webui/src/wire/json-value.ts | 07 | packages/typert/protocol/src/types.ts(RemoteStreamHandle:93-121)+ packages/api/gateway/src/client/{stream-client,index}.ts(ClientStreamHandle / pump / failAll)+ packages/typert/protocol/src/json-value.ts(isRemoteUplinkItem) | 客户端一条逻辑流:openStream 拿到的 StreamHandle 发上行 item(先过无损 JSON 校验)、endUplink 半关、close 取消、next 取下行帧;终态帧或断连(failAll)后 send 抛错并让挂起的 next 失败;streamId 由客户端铸非空字符串(crypto.randomUUID,上游 stream-client.ts) | | webui/src/wire/terminal.ts | 07 | packages/api/terminal-controller/src/client/index.ts + packages/api/gateway/src/client/stream-client.ts | 终端服务面:unary environment/shells/create/rename/close 用 agentId,list 用 sessionId;流 retain({args:{sessionId,id}})与双工 attach({args:{agentId:sessionId,id}})。TerminalConnection 维护写/尺寸上行序号、按 ack 放行(窗口内字节),snapshot 重置屏幕,终态与断连分 ended/closed/error | | webui/src/wire/workspace.ts | 07 | packages/api/workspace-files/src/{index,changes}.ts + packages/client/ui-sidebar-files/src/client/{face,directory-node}.ts | workspaceFiles/list|stat|read + /api/file URL;createWorkspaceServices.watch 绑 workspaceFiles/changes——前端为根目录与每个展开目录各开一条流,change 只重列该层,同层请求在途时合并 | | webui/src/ui/{TerminalPanel,TerminalScreen,FilesPanel,RightDock}.tsx + webui/src/app/rightDock.ts | 07 | packages/client/ui-sidebar-terminal + ui-sidebar-files + ui-sidebar-right + ui-dockkit | 多终端 tab/重命名/关闭/重连(xterm 只在动态加载的 TerminalScreen)、文件树懒展开与变更刷新、右侧栏三 tab 与 per-session 布局(宽度拖拽/键盘、收起、<768px 自动全屏、中央「侧栏」展开);dockkit 插槽/多 pane 未移植(FE-7) | | webui/src/wire/{settings,credentials,permissions}.ts | 07 | packages/api/settings-controller/src/{index,credentials}.ts + packages/interaction/permission-presets/src/index.ts(catalog) | 设置/凭据/权限目录三面:describe 回脱敏三层视图(secrets 只报 set)、update/replace/mutate 带 expectedRevision 围栏、settings/conflict 投影为 {ns, expected, actual};openSettingsDocument 如实上抛部署无打开器;credentials 值只进不出;permissionPresets/catalog 读 {options, defaultOptions, defaultPreset} | | webui/src/app/{useSettings,uiPreferences,usePreferences}.ts + webui/src/ui/{SettingsDialog,SettingsGeneral,SettingsNamespaceForm}.tsx | 07 | packages/client/ui-settings(SettingsRoot/config-form)+ ui-settings-general(GeneralSection)+ ui-permission-presets(PermissionRow) | 设置对话框:导航只列已实现分节;常规页权限行写 permission-presets.defaultPreset(danger-full-access 需风险确认),浏览器偏好(主题/字号/代码视图/忙碌发送)写 dsh.uiPrefs.v1 并即时生效;插件命名空间按值类型渲染(schema 恒 {}),路径 op 即时提交、冲突横幅 + 重读、document-updated 自动刷新,secret 只显存在性与清除 | | webui/src/wire/{account,session}.ts | 07 | packages/api/account-controller/src/index.ts + packages/api/session-controller/src/index.ts(initializeDefaultModel) | 账户面:account/watch 投影流 + getState/getProfile/getBalance/getUnnotifiedBonuses/ackBonusNotified/hasRunningAccountTasks/startSignIn/cancelSignIn/signOut 与 AccountClientMetadata;登录成功沿初始化默认模型。watch 在服务无订阅面时以 50ms 短轮询投影 + 深度相等门控等价发布 | | webui/src/app/{useAccount,useQuotaNotice}.ts + webui/src/ui/{AccountMenu,AccountSection,AccountAvatar,SignInDialog,SignOutDialog,BonusNotice,QuotaNotice,TurnNotice}.tsx | 07 | packages/client/ui-settings-account/src/client + packages/client/ui-chat/src/client/{apply.ts,chat/MessageItem.tsx} | 账号编排(revision 围栏、profile/balance 重读、头像加载、赠金确认退避、浏览器登录 tab 归属)、状态栏账号菜单与登录/退出对话框、设置「账号与余额」分节;额度提示只消费实时追加的 turn/end;TurnNotice 把 max-tokens/error/stopped 折成轨迹 notice 行并纳入检索 | | webui/src/wire/{goals,plan}.ts + webui/src/app/useGoal.ts | 07 | packages/goal/goal + packages/plan/plan-mode/src/index.ts + mini miniharness/plan/projection.py / miniharness/goal/service.py | goals/get|create|edit|pause|resume|complete|clear(CAS expectedVersion);invocation-unavailable 不当成有目标。plan 投影:pending 优先于 active,chip 目标 = pending ? !active : active;无投影时 fold 轨迹 | | webui/src/ui/GoalBar.tsx + webui/src/composer/PlanChip.tsx | 07 | packages/client/ui-goal/src/client/GoalBar.tsx + packages/client/ui-plan/src/client/PlanModeControl.tsx | GoalBar 读 goals/get:无目标/complete 不渲染;相位文案;pause/resume/edit/clear(无 complete 按钮)。PlanChip 仅 target 为真时显示,点击 /plan off;审批 takeover 时 GoalBar 一并隐藏 | | webui/src/wire/{questions,plan-review,question-draft,question-wait}.ts + webui/src/ui/{PlanReviewPanel,QuestionComposer,CommandCard}.tsx | 07 | packages/client/ui-user-questions(planReviewOf / PlanReviewPanel / QuestionComposer / PendingQuestion)+ packages/client/ui-chat GenericCommandCard + packages/api/remotes user-questions/request + packages/interaction/user-questions timed 面 | planReviewOf 命中走计划审查(批准 = asker label,讨论修改 = dismiss);未命中走 QuestionComposer(分页、单选/多选/自定义/跳过、推荐徽章、IME/换行、进程内草稿、timed 倒计时 / Take time / hide 座 / 超时后 userQuestions/answer)。轨迹折 command/run+command/done 为 CommandCard。审批 > 计划审查 > 通用提问 takeover | | web/events.py | 07 | packages/api/gateway/src/index.ts(remote-event)+ packages/api/session-controller(api-session/)+ packages/api/remotes | $events 注册表:open 首帧 ready → 转发 emit/waterfall/cancel;api-session/* 转发源(created/disposed/status/error/activity)+ settings/document-updated(emit,转发 {ns, revision},对齐 remote-events.ts);waterfall 经 $events/result 结算(approval/request 与 user-questions/request,result/next/rejected/cancelled),未知 clientId fail-closed | | web/streams.py | 07 | packages/api/session-controller/src/{index,remote-events}.ts + packages/api/terminal-controller/src/{index,retention}.ts + packages/api/workspace-controller/src/feed.ts + packages/api/workspace-files/src/index.ts + packages/api/job-controller/src/{rows,observe}.ts + packages/api/gateway/src/index.ts(GatewayInvocation:1287-1335) | GatewayStreams Remote 方法面:session/follow(快照 snapshot{header,cursor,records,hasMore,projections} + 逐条 event)+ session/control(baseline{projections} + 实时 projection 替换帧;rc.1 已去 queues/jobs)+ terminal/retain(一帧 retained 后保持到取消/身份关闭)+ terminal/attach(snapshot{sequence,screen,info,writable,inputWindow?} + 有序 output/state/ack;双工上行 TerminalInput=write/resize,序列连续编号)+ workspace/follow(baseline{items,archivedSessionIds,pinnedSessionIds} + upsert/remove/order/archived/pinned)+ workspaceFiles/changes(ready + change)+ job/list({type:'rows', jobs} 整集替换,纯 output 追加不刷新)+ job/follow(opened → output{chunks,next,lossy?} 按 64 KiB 软预算切帧 → 终态 status 后关流)+ $events 装配;每个流方法收一个 StreamInvocation(uplink 一次 + 下行结束 close 释放上行 + signal),声明的 codec 走 uplink_codecs(唯 terminal/attach 声明强类型 In=TerminalInput,其余 In = never,故出厂只含该项);跨堆非阻塞唤醒线程安全。活体 event 载体 = ≤50ms 短轮询批量提取(_poll_new_events,seq >= cursor,0 基 seq 不吞首帧);terminal/workspace/files/job 四条流 = 控制器同步对象的非阻塞 pop 经 10ms 短轮询桥接;wire 无 since(重连=重开全量) | | web/approvals.py | 07 | packages/interaction/user-approval + packages/api/remotes(last-resort approval 转发)| 审批桥:async tools/ask 闸门 → approval/request waterfall($events)+ $events/result 结算; outcome 映射 result∈APPROVAL_OUTCOMES(否则 unavailable fail-closed)/rejected→unavailable/next→nxt/cancelled;审计对 approval/asked+decided;接线点在工具闸门(上游在 approval/request,教学简化) | | web/questions.py | 07 | packages/bundle/client-ui-user-questions(应答面)+ packages/api/remotes(waterfall)| user-questions 桥:install 挂 async answerer 到会话 loop.ctx 的 user-questions/request;wire {questions, agent: agent.id, wait?}(agent 投影为 id;timed 的 wait:{callId,timed} 原样保留);kind result 原样 value / next→await nxt / rejected→_restore_wire_error(dict name/message/code 均有 str → UQE,否则 RuntimeError)/ cancelled→aborted_question | | web/server.py | 07 | packages/api/gateway/src/{stream-server,index}.ts(WS mux + 升级拒绝)+ packages/client/connection/src/{rpc.ts,rpc-host.ts}(unary 载体语义 + 响应分帧) | FastAPI 载体:unary POST {args} 严格解包(/api/<endpoint>)+ $events/result 特判;载体状态码 404/415/400(token 门配置时 /api/* 另有 401,web/auth.py——上游 requestRejection 等价物),业务错误恒 200 + result.ok=false + server-response 信封(含二进制的结果经 web/attachments.py 分帧);WS /api/remote.mux;GET /api/session.export 载体(query 校验→400、调 build_session_export);GET/HEAD /api/file(web/media.py,先于 /api/{path} 注册);未鉴权 GET /oauth/callback 在 /api/{path} 兜底前转 deepseekAccount.handle_callback;SPA 静态 fallback;无 CORS(上游同款:靠 415 状态码挡跨站写入) | | web/downloads.py | 07 | packages/session-query/session-log-export/src/{archive,index}.ts(导出域)+ api/session-controller(下载端点约定面) | 会话日志导出:parse_export_query(sessionId/includeDescendants)、SessionLogExportDeps、safe_session_id_segment、session_log_zip_filename、build_session_export(zip 条目序:根制品逐字原始文件名→后代 BFS+seen-set 去重→媒体、压缩等级缺省 6、私有错误安全壳);测试 tests/test_web_export.py | | web/media.py | 07 | packages/api/session-controller/src/media-references.ts | 文件展示路由 GET/HEAD /api/file?path=:连接层认证 + 绝对路径校验(缺失/空→400 missing path;NUL/相对→400 absolute path required);GET 经 ctx.fs.resolve + read_bytes(maxBytes) 返回原始字节,HEAD 仅 stat;成功头 Cache-Control: private, no-store、X-Content-Type-Options: nosniff、Content-Security-Policy: sandbox; default-src 'none';MIME 按路径(未知 octet-stream);上限取 ctx.attachments.image_limits.maxImageBytes;FsError 映射 403/404/413/499/500;未注册 fs/attachments → 404 | | web/frontend.py | 07 | packages/host/frontend-static | 静态服务约定:遍历 403 / SPA 回退 200 / MIME 按扩展 / 未知扩展 octet-stream;index taps 恒 identity(无 boot-manifest);DIST_ROOT 默认 web/static/,经 MINIHARNESS_WEBUI_DIST 可指向产品化前端构建产物(webui/dist/),约定不变 | | web/inventory.py | 07 | packages/host/plugin-inventory/src/{index,types}.ts + packages/preset/agent-presets/src/composition-inventory.ts + discovery.ts(entryListProblem) | pluginInventory/list 投影:entries_snapshot(Loader 非 group 条目四字段 {entryId,moduleName,enabled,fiberPhase},无 loader 服务→空)、file_composition/composition_inventory/build_inventory(preset 组合行 flatten 经 preset/registry.py 单一实现:组行跳过、组 disabled 继承、!!js 求值被拒→'conditional' + condition 原文、无 roster→省略 agentPresets 键)、PluginInventoryService(ctx.pluginInventory);JSON-schema 方言与 !!js 求值子集同 loader。载体差异:preset.json 载体无插件行→rows: [] | | web/static/(index.html + app.js + style.css) | 07 | packages/bundle/web-app + packages/client | 教学参照 vanilla SPA(无构建步):消费旧 SSE wire(events.mux/respond/host.describe),上游基线已删这些端点,故不对新后端工作,仅作历史/教学说明;产品化前端 = 仓库顶层 webui/ 独立 React 工程(只依赖新 wire 约定,见 §3 三层边界) | | web/launcher.py | 07 | packages/host/webserver(Config:具体 host + port 0) + api/gateway heartbeat | host/port 优先级「CLI --host/--port(经 cli/main 传入)> env MINIHARNESS_WEB_HOST/PORT > 缺省 127.0.0.1/0」;通配地址(0.0.0.0/:: 及 IPv4-mapped/zone 等价)加载期拒绝(web/host.is_wildcard_host,对齐上游 index.ts),非回环具体地址无 token fail-loud;心跳与上游 gateway 约定一致:uvicorn_options 设 ws_ping_interval=2 / ws_ping_timeout=4(transport 级 Ping 2s + 连续 2 周期无 Pong 判定断开 ≈ 上游 websocketHeartbeatIntervalMs @default 2000 + MAX_MISSED_HEARTBEATS=2 terminate)。缺口:上游 tls/--public-url/--trusted-host 未见对应物(登记) | | web_tools/(runtime + network + policy + fetch_http + search_deepseek + deepseek_api + search_tool + fetch_tool + trust + types) | 06、07 | packages/web/web + web-search-deepseek + web-fetch-http + web-deepseek-api + web/tool-web | 模型可见 web 功能族(L2,默认组合 dsh-base 挂载;install_web(ctx) 经 ctx.provide("web", ...) 暴露,四个 CLI 入口同挂,cli/default_tools.py 按 ctx.get("web") 条件注册工具):WebRuntime(URL 策略 + 凭据检查、双 provider 注册表重复 id → WEB_DUPLICATE_PROVIDER、执行期选择六分支、search 按 request.maxResults 封顶置 truncated、配置 id 回落 DSH_WEB_SEARCH_PROVIDER/DSH_WEB_FETCH_PROVIDER)+ fetch_http(匿名公共抓取恒可用 + 整址公网策略防 DNS 重绑定 + 字节帽/字符帽 + 同源重定向跟随 ≤maxRedirects、跨源拒绝)+ search_deepseek(Anthropic /messages 协议 + redirect:'error' 手动 3xx 拒绝 + citation_snippets + 归一 WebSearchResult)+ 两工具 web_search/web_fetch(schema/描述/输出必需字段逐字 + 节 order 2000/2100 + format_*_output 截断规则)。载体差异(见 verified-diffs §3.35):turndown→markdownify+bs4(GFM 表头/colspan 差异如实登记)、AbortSignal→threading.Event/FusedSignal 轮询、代理面简化恒直连、无 present 卡片、WebConfig searchTimeoutMs 烘焙 base 补丁 60000。测试:tests/test_web_tools.py 75 测(本地钉桩不触公网);全量 3048 绿。详见 verified-diffs §2.58 | | protocol/acp.py | 07 | packages/acp/acp | 自动化专用 JSON-RPC 服务:initialize(sessionCapabilities:{close,list,resume})、会话生命周期 new/resume/list/close(校验序逐字、keyset 分页 page.at(-1) 游标、selectionFor 恢复已提交路由)、模型选择标准配置 set(model/reasoning_effort 逐字文案、切 model 复位 reasoning;目录经可选 adapter.models_catalog/resolve_model_info['reasoning'] 教学扩展承载;provider/model 变化时 agent/pre-step 追加 durable modelSwitchNotice user 消息——source {kind:'model-selection', form:'notice', summary≤120 字符},对齐 packages/core/agent/src/model-selection.ts)、prompt 同步完整回合(snapshot+pin、turnless/max-tokens/error 结算逐字)+ 更新流投影(agent_message_chunk 带 messageId、agent_thought_chunk、tool_call/_update completed/failed)+ 富媒体受理 + 一次性审批桥 + usage_update 发射(request/context 带 contextWindow + Session.request_context + _emit_usage_update,assistant/message 带 usage 时发射)+ session/update 并发逐块流式通知(_install_update_stream 订阅 session/event 逐事件实时投影、update_sink 即时外发;in-process 载体收敛 server.updates 批量)+ 可写入磁盘归档:AcpServer(persistence=...) 可选 JsonlPersistence 后端——new_session declare + _install_persistence_hook(session/event append / session/flush flush)、close_session flush、list_sessions 合并磁盘 headers、resume_session 非 live 经 repair_and_replay 物化;磁盘写默认关闭(宿主装配持久化);简化标注见模块 docstring(磁盘会话仅事件日志重建、不给 live turn 后台执行) | | protocol/sdk.py | 07 | packages/sdk/protocol + sdk/server | messageId 为真实消息 id(与 inbox 回执一致,官方 SDK 依赖);互操作测试 tests/test_upstream_sdk_interop.py(需 pydantic + 上游 SDK 源码,缺则 skip) | | protocol/hooks.py | 07 | packages/hooks/hook-protocol + hooks-claude-code | 默认 runner 与 runner.ts 一致:stdin JSON payload + trailing newline、cwd、CLAUDEROJECT_DIR v、缺省 600000ms 超时;保留"异步 + signal"同步近似(subprocess);sourceind:PostToolUse additionalContext 铸 hooks-claude-code source user 消息 prepend 进 additionalContexts(对齐 index.ts/258/265/269),Stop 阻塞时同 source steer(index.ts) | | seams/sandbox_local.py | 06 §6.9 | packages/sandbox/sandbox-local + sandbox-windows-acl | landlock 后端经 seams/landlock_run.py ctypes 自限制执行器真执行(CLI 约定与 native/landlock-run/docs/cli-contract.md 一致:--ro/--rw/--/--probe、exit 125、报告行逐字);Windows ACL 写限制由 seams/sandbox_windows_acl/ 物化(见下行) | | seams/sandbox_windows_acl/(12 模块) | 06 §6.9 | sandbox/windows-acl-restrict-poc(单文件 index.ts 分区) | ctypes FFI 物化 WRITEESTRTED 写入限制:win32bi / ffi(替上游 koffi)/ errs / acl / token / workspaceid /athoundy / grant / spawn / index / runner 一一对应上游分区;runner 为 python -m CLI(exit 127 失败签名);非 win32 平台 import 即抛 OSError;门控 e2e 见 tests/testindowscl2e.py | seams/landlock_run.py | 06 §6.9 | native/landlock-run(C11 launcher) | ctypes 复刻同一 CLI 约定与 Landlock UAPI 语义(ABI 协商 / PATHENEA 规则 / PRET_NNEWRIVS restrictelf execvp;full ⟺ 内核 ABI ≥ 5,否则 partial 但仍受限;非 Linux 宿主干净退出 125) | | seams/sandbox_policy.py | 06 §6.9 | packages/sandbox/sandbox-policy | ctx.sandboxPolicy:Config {mode 缺省 read-only, workspaceRoot} fail-loud 校验;resolve 显式 me > 会话日志最后一条 sandbox/mode(session-mode.ts 的 effectiveSandboxMode fold)> 部署缺省,workspace 根先 canonical 后词法规范化、会话 cwd 即边界;三档策略上下文经 systemPrompt .context('sandbox:policy', order=110) 注册,loop 侧投影在变化时把快照注入对话消息流(core/agent_loop/runtime_context.py);模式变更 klwxh:1609 + set_mode(session, mode)(唯一写路径前逐个拒绝)——上游 terminal-controller 经 internal/dispatch 拦截 sandbox/mode 的同步等价面(mini 的 session/event 监听异常被存储层 contained,无法拒绝写入) | | shell/(types/bashocabashandb/pwshocal/pwssandbox/helpers/env) | 06 §6.9 | packages/shell/{shell, bash-local, bash-sandbox, pwsh-local, pwsh-sandbox, shell-env} | ctx.shell 执行器族:execute(spec) -> ShellExecution(句柄含 status/exitCode/signal/done/observed 非消耗偏移读/read_output 消费读/kill 与 result 前台投影);resolve 补齐 workdir/timeoutMs/onExpiry(kill|none)/stdoutMaxBytes;已 aborted signal 视为已触发。本地直跑 / 经 ctx.sandbox confine 包裹并报告 {mode, denied, enforcement};三路归因与 helpers.ts 一致——runner 启动失败(ENOENT/EACCES 且 argv[0] 证据 + cwd 可用性独立校验)与 runner 失败规则命中经 result 装饰抛 SandboxUnavailableError 且优先于 denial,denial 非零退出 + stderr 大小写不敏感签danger-full-access 直通不包裹。pwsh体(M16):PwshLocalExecutor(lzzwxh:1623 + UTF-8 编码前导 + PATH/ProgramFiles 解析、Windows PowerShell 5.1 兜底)+ SandboxPwshExecutor(confine + 三路归因),install_pwsh_executor/install_bash_executor 幂等。env.py 的 ctx.shellEnv 收集内置 DSH_* 并在 profileContext 在场时填充保留键 DSH_PROFILE/DSH_PROFILE_DIR。载体差异**:ctx.subprocess 托管范围/spill 收集器,进程经 subprocess.Popen + 读/监视线程、内存增长缓冲(UTF-8 安全裁头)承载,observed 无 spillPath;SIGTERM→SIGKILL 宽限期近似。详见 verified-diffs §2.68/§3.45 | | tool_bash/(index/background/render) | 06 §6.9 | packages/shell/tool-bash/src/{index,background,render}.ts | 模型面 bash 工具(层 3 登记,消费 ctx.shell + ctx.jobs + ctx.shellEnv):Config {enableRunInBackground?, promoteOnTimeout?}(缺省皆 true);前台超时不再杀——提升为后台作业返回 {kind:'promoted', cwd, jobId, timeoutMs, output},run_in_background 返回 {kind:'background', jobId, cwd},纯前台投影 {kind:'foreground', cwd, …, stopped?}——三态均带 requiredklzzwxh:1642(= 执行器解析后的 klzxh:1643,由 workdir 参数按会话有效工作目录解析)并作为 presentationMeta;workdir 经 working-directory 服务(§3.52);process_outcome(killed/completed + detail,runner 失败/denial 追加)、process_sources(observed 非消耗流作 pull 源)、ring_delta;parse_exit_status/render_result/render_promoted/render_job_read 逐字对齐 shell+tool-bash render.ts。载体差异**:无 schemasry/沙箱升级审批面;一次装配——jobs 在注册时在场即用作业尾巴,foreground→job-backed 换装未承载;作业 owner=agent id。详见 verified-diffs §2.68/§2.134/§3.45 | | tool_pwsh/(index/render) | 06 §6.9 | packages/shell/tool-pwsh/src/{index,render}.ts | 模型面 pwsh 工具(M16,层 3 登记,消费 ctx.shell + ctx.jobs + ctx.shellEnv):与 tool-bash 同构(三态 + jobs 集成 + stopped + required cwd/presentationMeta),差异在 pwsh 方言——描述文本(pwsh -Command/原生 Windows 路径/$env:)、作业 kind 'pwsh'、前台 canonical 恒带 kind:'foreground'、render_pwsh_result/render_promoted/render_job_read | | persistent_shell/ | 06 §6.9 | packages/shell/tool-{bash,pwsh}-persistent(共享引擎) | 持久 shell 工具族共享引擎(L2):ShellDialect(bash/pwsh 方言:标记前缀 / 重置文案 / 超时码 / 描述 / quote+wrap / PSReadLine 回显剥离 / 初始化命令)+ 标记包装与抽取(captured_command_output/captured_partial_output)+ 多页回滚合并(retained_scrollback)+ 渲染(截断 / 丢头前缀 / 退出码尾标 / 退出状态)+ PersistentShells(owner 作用域池化一个 shell 会话 + bash stty -echo 初始化 + owner/服务级清理)+ run_persistent_command(发送→驱动→抽取,覆盖 stdin_read/超时/退出分支)+ 工具工厂/幂等安装。载体差异:上游 async poll(await pause 循环 + operation.done Promise)→ mini 同步 ctx.terminals.await_send(run_until_settled 驱动)+ time.sleep 轮询交界;WeakMap/AbortSignal → agent 键 dict + 鸭子类型信号(.is_set/.aborted)。详见 verified-diffs §2.100 | | tool_bash_persistent/ | 06 §6.9 | packages/shell/tool-bash-persistent/src/index.ts | 模型面持久 bash 工具(L3,opt-in):只读 bash 工具({command});owner=agent;per-owner 串行;描述逐字(持久 bash,状态含当前目录/导出环境变量跨调用保持)。与 tool_bash 同名互为替代(组合按需挂载其一,不由 default_tools 自动收编) | | tool_pwsh_persistent/ | 06 §6.9 | packages/shell/tool-pwsh-persistent/src/index.ts | 模型面持久 pwsh 工具(L3,opt-in):pwsh 方言(Invoke-Expression 包装 + PSReadLine 回显剥离);与 tool_pwsh 同名互为替代 | | terminal/(types/sanitize/bounded_buffer/operation/service/__init__) | 06、07 | packages/terminal/terminal/src/index.ts + terminal-bash/src/{session,sanitize}.ts(P1 核心契约,P2 由 terminal_bash 域承接) | 终端服务域(L1,仅依赖 core.scope):TerminalSessionService(ctx.terminals:spawn/kill/read/signal/start_send/await_send/list/get_owner_sessions/has_owner_activity/register_backend)+ TerminalError 8 码闭集(TERMINAL_ERROR_CODES)+ BoundedTextBuffer(bytes+maxLines 双限、consume={delta,truncated}、首块永不增长、代理对感知记账与拼接修正、淘汰端逐单元出队)+ TerminalSanitizer(CSI/OSC/short 转义 + 跨块 pending + 二进制拒绝)+ LocalSendOperation(单飞 + owner 栅栏)。对齐证据:service.ts 名校验(仅空串拒绝,PTY session name must be non-empty)、session.ts 缓冲语义、service.spec.ts 拒绝面(OWNER_NOT_LIVE/NO_BACKEND/DUPLICATE_NAME/SEND_ACTIVE/FOREIGN_SESSION)。详见 verified-diffs §2.52/§3.29 | | terminal_bash/(config/environment/emulator/provider/shell_activity/session/index) | 06、07 | packages/terminal/terminal-bash/src/{index,config,environment,session}.ts + packages/shell/pwsh-local/src/index.ts(P2 后端)+ packages/subprocess/subprocess-local/src/{terminal,shell-activity}.ts(subprocess PTY 面) | 真实 PTY 后端(层 3 登记,拓扑同 shell):resolve_config(rows=40/cols=160 缺省)+ child_environment(owner.id/DSH_SESSION_ID/DSH_PTY_SESSION_ID + UTF-8 preamble + NO_COLOR/TERM=dumb)+ bash CONTROLLED_PROMPT 与 pwsh 133;D 标记 prompt 复盘 + LocalPtySession(poll_readiness 五判据兜底结算 stdin_read/inferred_idle/timeout/session_exit、interrupt:posix 前台组 SIGINT / win sendintr、增量 UTF-8 解码)+ TerminalHandle 契约(SubprocessForeground/SubprocessOutcome/SubprocessTerminalActivity + inspect_foreground/inspect_activity;write/signal 前作废 shell-activity、terminate 置静默并释放)+ 平台拆三 provider(_posix.py pty;_winpty.py pywinpty PtyProcess + reader 线程 + SubprocessOutcome 退出封装)+ shell_activity.py(仅非 win32 纯 bash|zsh -i 注入私有 --rcfile/ZDOTDIR,状态文件 pid:seq:idle|busy,inspect_activity 据 prompt 证据 + 前台进程组判读)+ install_terminal_bash(幂等)/apply(依赖 terminals 先装,镜像上游 install/apply 分离)。载体差异:pyte 不含 ? 私有前缀 CSI(扫描层剥离)、pyte LF 无 CR、Windows 无前台组/无 termios(sendintr,activity 恒 unknown)、winpty write 收 str / read 回 str;inspect_activity 无进程表 inspect(descendants/完整快照/会话存活)与 managed task count,只凭 shell-activity + 前台组。详见 verified-diffs §2.53/§2.66/§3.30/§3.43 | | tool_terminal/(render/tools/__init__) | 06、07 | packages/terminal/tool-terminal/src/{index,render}.ts(P3 六工具) | 终端模型工具族(层 3 登记,消费 terminal P1 + jobs L2 + core.system_prompt):六工具 terminal_open/terminal_send/terminal_read/terminal_signal/terminal_close/terminal_list(schema/description/output/render/present_call/present_result/finalize_content 全量)+ render_spawn/send/send_read/read/list 与 bound_terminal_text 逐字对齐 render.ts(fitWithPrefix/boundBodyWithSuffix)+ resolve_config(DEFAULT_MAX_RESULT_BYTES=256*1024、MIN_MAX_RESULT_BYTES=64 fail loud)+ register_terminal_tools + install_tool_terminal(幂等,缺服务即建:systemPrompt tool:pty/order 1700 + terminals + tools 注册)/apply;后台 terminal_send 经 jobs.start(kind='pty-send', label='<id>: <text|(input)>', owner=owner.id, outputLimitBytes=maxResultBytes) 装配(惰性 pull 源 _send_source 消费 operation 增量并渲染 render_send_read,对齐 background.ts sendSource;JobDoneBox + _await_settle 轮询结算 → completed/killed/failed)。载体差异:无 presentationMeta 通道、无 tools/execute 中间件(finalize_content 施加在五类 ToolResult 路径)、同步轮询桥接替代 Promise、tool:pty order 用字面量 1700、_SignalAdapter 映射 ToolExec.signal→terminal Cancellation。详见 verified-diffs §2.54/§3.31 | | terminal_controller/(types/stream/terminal/shells/index) | 06、07 | packages/api/terminal-controller/src/{index,terminal,stream,shells,types}.ts(P4 浏览器终端域) | Session 作用域浏览器终端(层 3 登记,消费 terminal P1 + terminal_bash.provider PTY seam + core.scope):TerminalController(ctx.terminalController:environment/shells/list/create/attach/rename/close;owner 作用域 + 服务拆解 + install_terminal_controller 幂等)+ BrowserTerminal(pyte HistoryScreen 有界恢复屏、attach 独占输入并降级旧附加为只读、writable/_require_controller 精确 not-running/read-only、close 先 terminate→drain→finish)+ TerminalAttachment(submit 校验 TerminalInput 序列连续 + _apply_command 推 ack;control-unavailable 折带 refusal 的 ack,缺口即失败整条附加)+ TerminalFollower(JSON.stringify(frame) UTF-8 字节预算、超额显式失败 reconnect to recover)+ types.decode_terminal_input(TerminalInput 判别联合上行 codec)+ shells.py(terminal_environment/resolve_executable 对齐 subprocess-local resolveExecutable:空拒/相对路径拒/绝对 stat+X_OK/PATH×PATHEXT;profile cmd=[]、pwsh=-NoLogo、其余=-i)。消费面:web/args.py 八条 terminal/* 边界规格(agent wire=agentId、list/retain=sessionId)+ web/api.py 六 handler + web/streams.py terminal/retain(一帧 retained 后保持到取消/身份关闭)/terminal/attach(snapshot+writable+inputWindow 后接 output/state/ack,双工上行)+ envelope.RPC_ERROR_CODES 两码;cli/plugins/terminal_controller.py(web profile 组合条目,boot/profile 驱动装配 sandbox+sandboxPolicy+terminalController)。载体差异:同步单线程无 pending 窗口、pyte 纯文本恢复屏、沙箱模式围栏挂在 sandboxPolicy.add_mode_fence(上游 internal/dispatch 拦截的等价面)。详见 verified-diffs §2.55/§3.32 | | workspace_controller/(index) | 07、08 | packages/api/workspace-controller/src/{index,commands,feed,types}.ts | 工作区 Remote(层 3 登记,消费 ctx.workspaces):WorkspaceController(ctx.workspaceController:create/initializeDefault/rename/delete/insertBefore/insertSessionBefore/archiveSession/unarchiveSession/pinSession/unpinSession + follow 代次;命令经锁串行化 + WorkspaceFault 稳定 workspace/* 码,归档活跃折 workspace/session-active 带 activity)+ WorkspaceFollow(订阅 workspace/changed 投影 baseline/upsert/remove/order/archived/pinned)。依赖扩展:workspace 注册表新增 order/归档集/置顶集/默认登记/resolve_by_path/insert_before/delete/变更通知。载体差异:变更事件以自有 workspace/changed 承载(上游 storage-domain domain/changed);首用目录经配置 documentsDirectory(缺省 ~/Documents)而非原生命令查系统 Documents;initializeDefault 无 AbortSignal(无原生命令面);directoryPicker namespace 因无后端缺席。详见 verified-diffs §2.63/§3.40 | | workspace_files/(__init__) | 07、08 | packages/api/workspace-files/src/{index,changes,types}.ts | 工作区文件预览(层 3 登记,消费 ctx.fs):WorkspaceFiles(ctx.workspaceFiles:read 按行分页 bounded 切页、readBytes 原生字节(options.range 窗口 / 省略读整文件受 maxFileBytes cap / options.baseFile 基目录解析,rc.1 折入 readAll/readRelated)、stat、工作区限定 list + 目标级 changes 流);WorkspaceChanges(ctx.fs.watch OS 监听 + fs/observed 过滤到解析目标,命中后重 stat 产出 version/absent);FsError 折 workspace-file/* 七码(含 watch-unsupported);fs 异步面经 run_on_resident 同步驱动。详见 verified-diffs §2.56/§3.33、§2.70/§3.47 | | workspace_changes/(__init__/recorder/git/capture/compare/paths) | 07、08 | packages/deliverables/workspace-changes/src/{index,recorder,git,capture,compare,paths,numstat}.ts | 回合工作区变更(L2,web 默认组合 workspace-changes 条目):WorkspaceChanges Service(ctx.workspaceChanges:summary(session_id, seq) / diff(session_id, seq, index, signal),会话处置即停服)+ TurnRecorder(turn/start 基线经私有索引 + 临时对象库拍 git 工作树快照;fs/write-intent/fs/edit-intent prepend 捕获变更前内容;turn/end 或 turn-stopping 记录——snapshot diff-tree numstat 与未覆盖捕获并集、gitlink 排除、check-ignore 覆盖判定、临时根过滤、maxFiles/maxOutputBytes 上限;较早记录后的空摘要仍追加);成功记录追加 durable workspace/changes {turn} 事件;git 缺失或无仓库时只用整文件捕获。比较按需读取两侧内容:maxFileBytes 超限/二进制拒绝,文本走 Myers + 统一 hunk(三行上下文,diffTimeoutMs 超时退整文件替换)。载体差异:上游 diff 库 → 手写 Myers(相同 hunk 合并语义,jsdiff v9 对照);AbortSignal → 鸭子信号;os.tmpdir → 可配 tempRoot;不实现 ui-deliverables 的 comparison HTTP 路由(与 presented 读侧同口径,客户端路由未迁入 mini);子代理/委派会话不记录。详见 verified-diffs §2.148 | | deliverables/(__init__/present) | 07、08 | packages/deliverables/tool-present/src/index.ts | present 模型工具(L2):校验 1..maxFiles(缺省 8)个 {path, description?},路径经 ctx.fs.resolve 后必须是工作区内普通文件(否则 not a regular file / 带路径的 not found 文案),成功后在当前 turn 追加 deliverables/presented {turn, callId, files} durable 事件;无读侧 HTTP 路由(客户端 ui-deliverables 未迁入)。详见 verified-diffs §2.146 | | settings_controller/(__init__) | 07 | packages/api/settings-controller/src/{index,credentials,types}.ts | 设置/凭据 Remote(层 3 登记):SettingsController(ctx.settingsController:脱敏 describe + update/replace/mutate + openSettingsDocument/openAgentPresetDirectory)+ CredentialsController(ctx.credentialsController:describe ≤64 refs / set / unset);settings/conflict/settings/rejected/credential/rejected/agent-preset/read-only。依赖扩展:settings 新增 document_path/prepare_document、credentials 服务新增 describe/set/unset。载体差异:无原生打开器(canOpen 恒 False)、schema 以 {} 占位;autoGenerate 缺省 true(上游 presentations.get(fiber)?.auto ?? true,mini 无 configure 面恒缺省)。详见 verified-diffs §2.56/§3.33 | | context/(time_context/tmux_context/file_reference/file_reference_local/session_reference/agent_instructions) | 07 | packages/context/{time-context,tmux-context,file-reference,file-reference-local,session-reference,agent-instructions} | 请求上下文插件(层 2 登记,消费 ctx.sessionProjections/ctx.shell/ctx.sessionQuery/ctx.spillStore):time_context(每步时钟读数 + 浏览器时区策略 + timeContext 投影)、tmux_context(tmux 方位查询/变化抑制 + tmuxContext 投影)、file_reference+file_reference_local(@file 词法 + WorkspaceFileSearch 模糊索引 + ctx.fileReferences)、session_reference(dsh-session: URI/提及 + 跨会话有界快照 + ctx.sessionReferenceResolver candidates:title+subagent 两投影键 → label/displayTitle,mention 用 displayTitle)、agent_instructions(AGENTS.md 发现/去重/预算渲染/基线/reconcile + pre-step 注入与 tools/post-execute touch:两个 user-global 根——$DSH_HOME 与共享 $DSH_AGENTS_HOME(缺省 ~/.agents)——分属两 scope 但同属一个候选组去重,项目首段撞 scope 名经 escape_project_display_path 加 .)。载体差异:time-context zoneinfo + tzdata.zi(canonical 回读数据面,§3.50)、tmux 同步 shell、file-reference-local 同步索引、agent-instructions 无 turnBoundary 投影与无持久投影缓存(冷会话标签不回退)。详见 verified-diffs §2.57/§3.34/§2.113/§2.137/§3.50 | | seams/credentials_local.py | 06 | packages/credentials/credentials-local | 文档为 version-1 JSON 布局 {version:1, refs, records}(上游 YAML):fail-closed 解析 + 可识别 flat 文档启动自动迁移;0.2.1 层序 file > env > project .env > user .env(管理文件胜出,替代旧 env 优先)、删 assertUnshadowed(全 ref 可写)、未知顶层键只告警且原样保留在盘(_ignored 随写带回);记录服务侧五件套(read/describe/list/modify/delete_record + .records 只读视图,键语法 [a-z][a-z0-9-]*、写锁 DOCUMENT_LOCK_WAIT_SECONDS=30、modifyRecord 唯一写路径——锁内 reconcile + mutate + 写前准入 = 读路径选择);CredentialsService 桥接:CredentialsService(Service) provide="credentials" 包装 LocalCredentialProvider,modify_record/delete_record 成功后发 credentials/record-updated(key)(无 carrier ancestor 路由);install_credentials(ctx, provider) 装配;引用半边:describe(ref)/set(ref,value)/unset(ref) 委托 provider(settings-controller 的 credentials namespace,值只进不出);读侧热重载:读入口 _refresh_if_changed 先 os.stat 比对 mtime/size、变了才整表重解析(外部编辑/删除即时生效),写路径 _reconcile_from_disk 折叠不变,原子写无撕裂读侧不需锁 | | seams/authorization.py | 06 | packages/credentials/authorization(src/{index,types,invariant}.ts,全套 437 行) | AuthorizationService(Service) provide="authorization" + install_authorization(ctx)(显式 opt-in,依赖 ctx.credentials 缺失 fail-loud)。错误码闭集 DUPLICATE_FLOW/NO_FLOW/UNKNOWN_METHOD/ALREADY_IN_FLIGHT/NOT_COMMITTED/DECLINED/CANCELLED;registerFlow effect 登记(disposer 注销,二次 DUPLICATE_FLOW)+ begin 复核 ALREADY_IN_FLIGHT;list/describe;begin 校验序 NO_FLOW→UNKNOWN_METHOD→ALREADY_IN_FLIGHT→pre-aborted(返回 cancelled 不占槽不 settle)→ 占槽(同步 AbortSignal)→ _attempt(AuthorizationSession.commit 对齐上游 index.ts:signal.throwIfAborted + attempt 活跃检查 + committing 置位 + modifyRecord 写记录;cancel 在 committing 后不取消——"Once admitted, cancellation waits for completion";credentials/record-updated 记账兜底 + describe_record 二次确认、declined/pre-aborted → cancelled 不核 commit、未提交 → NOT_COMMITTED)→ _settle 发 authorization/settled(payload (key, settlement) 元组、listener 异常 contained);简化标注:async→sync(begin 同步返回)、AbortSignal 无事件机、interaction 回调参数化 | | seams/subprocess_env.py | 06 | packages/subprocess/subprocess/src/index.ts + types.ts | 环境清洗切片:SENSITIVE_ENV_PATTERN 凭据形启发式 + DSH_ENV_PREFIX 大小写不敏感剔除;显式 env 在 scrub 之后合并(providers spawn 层叠)。subprocess 的终端 process 契约(SubprocessTerminalActivity/inspect_activity/shellActivity)由载体 terminal_bash.provider 承载(seams 层不得反向 import terminal_bash,§依赖方向):inspect_activity 见 verified-diffs §2.66 | | seams/subagent/(__init__.py + descriptor.py + providers.py + worker.py + continuation.py + archive_admission.py + tool.py) | 06 | packages/subagent/subagent + subagent-fork-in-process + -acp + -dsh-sdk + subagent-spawn-in-process + subagent-in-process-driver + tool-subagent-control + tool-subagent-report | 续跑 A8 为异步事件驱动(双路径:父有 driver → 投递即返回 + watchSettlement 结算 + steer 批内合并;无 driver → 回退同步 pump)。生命周期 scoped dispatch(委托父 scope 载体过滤,无标号退化祖先链)+ provider 注册表(register_provider → 注销发布 subagent/provider-removed)+ DRAINING 拒绝面(drain/drain_descendants/drain_children + assert_admitting 准入边界)+ report 工具逐字约定(output 参数、部署级 reportDelivery 'quiet'|'next-step'、{messageId} 返回与 render)+ childId 预留 DUPLICATE_CHILD 断言已与上游一致;prompt 内容受理与上游一致:文本穿透、图片经父作用域 attachments store 受理为 durable 引用(子适配器须声明 image 输入模态,否则 reason=MODEL_DOES_NOT_SUPPORT_IMAGES;store 缺席/受理失败折 subagent/attachment-invalid,reason=底层 code),file 在宿主边界拒收(reason=SUBAGENT_FILE_UNSUPPORTED,镜像上游浏览器客户端路由前拒绝);rc.1 增量:archive_admission.py 归档准入(running 后代 workspace/session-activity 的 {kind:'subagent'} + session-stop parent 取消,runtime 构造点注册根上下文)+ ActivationPool 进程内容量(经不间断 continuable 父链共享,maxActiveSubagents 默认 8 / maxDepth 默认 1 / resolve_max_depth,满额抛 ACTIVATION_LIMIT_REACHED)+ list_agents status running|inactive + scope(children 默认 / descendants);catalog 事件/投影、sessionQuery.observeSession、Remote subagent.list、model-selection settings 链为 mini 无载体(架构不适用,见 verified-diffs §2.69/§3.46);invariant 运行时校验架构不适用;同步模式结算投递走非唤醒 next-step;0.2.1 增量:start_activation(SubagentActivation{childId,result,dispose} + delivery:'parent'\|'caller')取代 startContinuable(保留为门面,供 agent_team/测试消费)、cwd/agent_preset 写入子会话 header、SubagentResult 结果箱;tool.py 整体 0.2.1 形态(canonical {kind:'activation',subagentId} + render started subagent {id}、新 cwd 参数、config 逐字拒绝 persona/toolFilter、删 run_in_background/background_mode/{kind:'background',jobId});agentPreset 模型参数(config agent_preset/allowed_agent_presets,配置允许名单时暴露)+ 子组合挂载(独立选择经 ctx.agentPresets.resolve_composition 得 {tools,persona},子作用域装 preset 工具视图 + persona;继承选择用父组合)(P0-4a,见 verified-diffs §2.132/§3.72) | | seams/agent_team/(13 模块) | 06 | packages/experimental/agent-team + tool-agent-team(src/index.ts) | Agent Teams 实验族:implicit-root roster + durable peer mailbox + shared task DAG。types/validation/error/journal/projection(team/member(v2)/team/task/team/message/queued/team/message/delivered 四事件全 log-only、payload 逐字段 zod-strict fail-closed、task revision 从 1 连续、图成环拒、写域 advisory 重叠校验);roster(spawn/stop/interrupt/reconcile/live_children_by_root;成员以 start_continuable(agent_options={provider}) 子会话承载,descriptor agentProvider 承载请求方 provider);mailbox(Team authority queue → steer_host_subagent 冷/热三态路由);task_board(8 动作 CAS 转移矩阵);activity(with观测窗口 wait_for);lifecycle(admit/JOINED 窗);service(同步门面);tools(9 工具 + team:policy 提示节,canonical value 全 fixed record)。sync/async 双投递载体:同步 _spawn_admitted(harness/CLI 无循环态)+ 事件循环内 start_continuable_async/spawn_async/_checkpoint_initial_prompt_async(await 让出控制,驱动载体不被 time.sleep 阻塞)。简化:wire/Remote 端点不承载(错误语义走 TeamError.code 闭集)、上游 todo 事件与 client-ui-agent-team/web-profile 前端 wire 面由 webui/ 自行选择 | | seams/session_checkpoint.py | 05 | packages/session/session-checkpoint-policy/src/index.ts | 语义持久化检查点(三屏障):模型请求(agent/checkpoint boundary='request',请求信封落日志后、adapter 派发前)+ 顶层工具(tools/pre-execute,exec_.agent 有且 exec_.parent 为空;取消折叠为 canonical ABORTED_BEFORE_DISPATCH)+ 步边界(agent/pre-step);经 SessionStore.checkpoint(无持久化参与者 fail-closed)。载体差异:上游经 llm/stream 服务 waterfall 延迟适配器构造,mini 单一 adapter 直接调用故改用 agent/checkpoint waterfall。install_checkpoint_policy(ctx) opt-in | | ptc_runtime/(types + service + runtime) | 06 §6.9 | packages/ptc-runtime/ptc-runtime/src/{index,types}.ts + ptc-runtime-node + packages/experimental/ptc-runtime-python | PTC(programmatic tool calls,程序化工具调用)执行 seam:PtcRuntime Service Definition(ctx.ptcRuntime)+ 保留名常量(RESERVED_BINDING_GLOBALS/RESERVED_ERROR_MEMBERS/PORTABLE_RESERVED_WORDS/DUNDER_MEMBER)+ 绑定校验;PythonPtcRuntime 每请求在全新 CPython 子进程跑模型 Python(顶层 await/return),绑定经 stdin/stdout 行 JSON 协议桥接,墙钟预算/中止/输出上限 + 正交失败分类(exception/timeout/abort/worker-exit/invalid-output/output-limit/protocol);program_format('function-body')与 release(owner)(owner=请求 stateOwner,无状态后端为 no-op)随 Service Definition 默认;resolve 把 stateOwner 与可选 sandboxPolicy 透传到 spec;sandbox_mode 只读属性供 workflow-ptc 沙箱门查询。载体差异:上游 Node 后端 worker/subprocess + fd-3 wire,mini CPython 子进程 + 行 JSON;受限策略下 worker 经 sandbox confine(与 run_code 同族);子进程非安全边界(上游同款声明)。install_ptc_runtime(ctx) | | ptc/run_code.py | 04、06 | packages/core/tools/src/ptc.ts | PTC 模式 run_code 工具(上游 createRunCodeTool):程序经 tools.<name> 调用 agent 可见工具(嵌套子派发);每次子派发落 tool/ptc-dispatch-start / tool/ptc-dispatch(rootCallId/parentCallId/subCallId=<parent>:ptc:<n>/name/arguments/isError/content);只有外层精心挑选的结果进模型历史。describe/parameters 按 runtime 语言取 flavor(typescript/python)。owner 契约:stateOwner = 调用 Agent(无沙箱策略时),首次调用在 agent.ctx 登记 effect,owner 结束时 release(agent)(上游 ptc.ts)。载体差异:上游用 registry 分阶段调度接口(prepare/dispatch/finalize/finish)+ 并发池,mini 经 run_pipeline 顺序执行(事件序与 payload 形状对齐,并发上限简化登记) | | demo.py | 00 | packages/examples/agent-spine-demo | 教学入口,保留顶层(python -m miniharness.demo) | | example_plugins.py | 00 | examples/ | 教学示例,保留顶层 |

3. 依赖方向规则

flowchart TB
 L3["L3 应用与入口&lt;br/&gt;cli · protocol · web · seams · preset · shell …"]
 L2["L2 编排&lt;br/&gt;agent_loop · compaction · jobs · plan · skills …"]
 L1["L1 领域&lt;br/&gt;llm · tools · boot · fs · attachment …"]
 L0["L0 地基&lt;br/&gt;session · scope · loader · schema …"]

 L3 --> L2
 L2 --> L1
 L1 --> L0

L_n 只依赖更低层;显式例外见下文规则 1 与 tests/test_dependencies.py 的 ImportDirectionTest。

分层如下(Python 没有编译期模块边界,规则由 tests/test_dependencies.py 的 import 方向断言固定,违反即测试失败):

层 内容 允许依赖
L0 地基 core/session、core/scope、core/dsh_scope、core/schema、core/hmr、core/home_paths、core/tool_timeout、loader 无(互不依赖;core.scope ↔ core.dsh_scope / core.schema / core.hmr→core.scope / loader→core.scope 经 §3 例外豁免;core.tool_timeout 是超时约定常量叶,被 core.tools 与 guard 两侧共享)
L1 领域 llm/*、core/tools、core/system_prompt、core/session_store、core/agents、core/agent_default_model、attachment、ptc_runtime、identity、storage、fs/*、lsp、boot/*、guard、session_projection、terminal 仅 L0(fs 单元还注册模型侧工具进 core.tools——§3 规则 1 显式例外;terminal 仅依赖 core.scope)
L2 编排 core/agent_loop、compaction、jobs、plan、commands、goal、skills、telemetry、session_query、todo、spill、workspace、settings、context、web_tools、lsp_stdio、tool_lsp、persistent_shell、session_turn_outline、session_title、session_projection_cache、workflow L0 + L1
L3 应用与入口 cli/*、protocol/*、seams/*、preset、extensions、interaction、feedback、client、mcp、web、shell、tool_bash、tool_pwsh、tool_bash_persistent、tool_pwsh_persistent、terminal_bash、tool_terminal、terminal_controller、workspace_controller、workspace_files、settings_controller、workflow_ptc、tool_workflow、subprocess、deepseek_account L0 ~ L2(tool_bash/tool_pwsh 消费 shell seam / cli 组装 tool_bash、tool_pwsh 复用 tool_bash background 助手 / workflow_ptc 消费 seams subagent / subprocess 收编 seams+terminal_controller / cli 组装 tool_workflow+deepseek_account / web 投影复用 preset/registry 组合行工具,见 §3 依赖例外)
教学层 demo.py、example_plugins.py 任意层,但不得被业务模块依赖

三层组织边界(代码与结构上清晰分离、解耦):

flowchart LR
 Core["core 核心能力&lt;br/&gt;L0–L2 领域逻辑"]
 Web["后端 web 服务&lt;br/&gt;web/ · protocol/"]
 UI["前端 webui/&lt;br/&gt;独立工程"]

 Core -->|"Python API"| Web
 Web -->|"HTTP/WS wire"| UI
 SA["superagent/&lt;br/&gt;旁路编排对照"]

Super-agent 并列工程:顶层 superagent/ 镜像旁路 dsh-superagent-prototype 的 Engine/Store/Passes,与 source_implement、superagent-framework 配套;不 import 进 miniharness,不增本章 §2 行级映射;进入 mini 产品仅经 adopted.md。

边界 内容 耦合面
core 核心能力 miniharness/core/ 等(L0~L2 纯领域逻辑) 不感知 web/CLI 传输载体
后端 web 服务 miniharness/web/ + protocol/ 等(L3 传输层) 消费 core 能力;对外发布 HTTP/WS wire 约定(信封/帧/错误语义)
前端工程 独立工程形态:webui/(React+TS+Vite,产品化)走新 wire;web/static/ vanilla SPA 降为教学参照(旧 wire,不实跑) 只依赖后端发布的 wire 约定,禁止 import/hack Python 内部

前端唯一的耦合面是 web/ 层发布的 wire 约定,不是 Python 内部 API——这保证前端可独立选用现代化的技术组合(如 React)而无需改造内核。

webui/(仓库顶层独立工程,React+TS+Vite):产品化浏览器前端,只消费 web/ 发布的 wire 约定(两信封 RPC /api/<endpoint> + /api/remote.mux WS 帧 + $events/$events/result + session/follow/control),零 Python import。三层结构:src/wire/(约定客户端层,纯 TS 可单测)、src/app/(React 编排 hooks)、src/ui/(无状态展示组件);测试用 vitest(mock fetch/WS)。构建/运行手册见 webui/README.md:开发期 Vite dev server 把 /api 与 /api/remote.mux 代理到本地 Python 后端(vite.config.ts,目标经 MINIHARNESS_WEBUI_PROXY 覆盖);生产期 vite build 产出 webui/dist/,后端 web/frontend.py 经 MINIHARNESS_WEBUI_DIST 指向该产物即可承载(serve_static 约定不变)。当前覆盖会话列表/新建、Trajectory(虚拟化窗口 + Overview 折叠跳转 + 全文搜索)、MarkdownText(GFM/表格/代码/KaTeX/安全链接/本地图片/搜索高亮)、Composer(草稿持久化、14 行封顶、空白聚焦与选区恢复、/ 命令、@ 文件/会话引用、附件上传、忙时 queue/steer)、工具卡(Bash/PowerShell 命令/输出/退出码、grep/glob 分组匹配、todo 计数/状态、read 行窗口、write/edit diff、web 搜索/抓取、图片元数据、通用回退)、Chat/Trajectory 双 tab、工作区文件树(逐层 workspaceFiles/changes 实时刷新)与 text/markdown/code/image/PDF 预览(office 待 officeToPdf)、xterm 终端(多 tab、重命名/关闭、写与尺寸 ack、断连重连)、右侧栏 Console/Files/Terminal 三 tab 与 per-session 布局(宽度拖拽/键盘、收起、<768px 自动全屏)、审批瀑布、计划芯片与目标栏、计划审查(批准 / 讨论修改)、通用提问卡与 /goal 命令卡、队列编辑/插话/删除与作业;不整体移植上游 packages/client 40 模块。

规则:

  1. L_n 只依赖 L_{<n},禁止依赖同层或上层。显式例外(完整可执行清单见 tests/test_dependencies.py 的 ImportDirectionTest,下列为关键条目):
  2. seams/subagent/worker.py 依赖 protocol/*(同层):worker 是 ACP / SDK 线协议的服务端载体,复用协议层的帧与信封实现;
  3. core/hmr.py 依赖 core/scope(同层):HMR 是 cordis 家族的 vendored 部件(上游 vendor/hmr 直接建在 cordis 之上),复用 Service/fiber 基座,与 core.dsh_scope 同理归属 L0;
  4. loader/* 依赖 core/scope(同层):loader 是 cordis 家族的 vendored 部件(上游 vendor/loader 直接建在 cordis 之上),复用 Service/fiber/Inject 基座,与 core.hmr 同理归属 L0;
  5. fs/* 依赖 core.tools(同层,单方向):fs 单元承载模型侧文件工具(上游 tool-fs 等是 fs 域的消费面,register 进 core.tools);core.tools 不得反向 import fs;
  6. cli/main.py 依赖 web(同层,单方向):launcher 组装 web profile——cli 把 ctx/adapter/tools 交给 web 层运行时,web 层不得反向 import cli;
  7. cli/headless.py 依赖 seams 与 shell(同层,单方向):run_headless 组装沙箱后端链路与 bash 执行器装进 ctx——同上游 bundle/headless 依赖 dsh-sandbox / sandbox-policy / bash-sandbox 的包拓扑;seams/shell 层不得反向 import cli;
  8. shell/bash_sandbox.py 依赖 seams/sandbox_local(同层,单方向):bash-sandbox 是 ctx.sandbox 的消费者——上游 bash-sandbox 同样依赖 dsh-sandbox,拓扑一致而非分层倒挂;seams 层不得反向 import shell;
  9. tool_bash/* 依赖 shell(同层,单方向):tool-bash 是 ctx.shell + ctx.shellEnv 的模型面消费者——上游 tool-bash 依赖 dsh-shell / dsh-shell-env,拓扑一致;shell 层不得反向 import tool_bash;
  10. cli/default_tools.py 依赖 tool_bash(同层,单方向):default_tools 组装真实 bash 工具(上游 bundle/base compose tool-bash),同 cli→shell 先例;tool_bash 层不得反向 import cli;
  11. mcp/connection.py 依赖 seams/subprocess_env(同层,单方向):stdio 子进程 env 组装复用 seam 的净身切片(上游 mcp-client spawn 透传 env),同 cli→seams 先例;seams 层不得反向 import mcp;
  12. cli/main.py 依赖 demo(教学层):无 profile 时以 demo 兜底(教学扩展入口)。
  13. plan/* 依赖 interaction(同层,单方向):plan-mode 审查经 userQuestions 通道(interaction.ask,上游 plan-mode peerDep @deepseek-ai/dsh-user-questions),interaction 不得反向 import plan;
  14. web/questions.py 依赖 interaction(同层,单方向):user-questions 桥消费 UserQuestionsService(上游 web-app 组合 dsh-client-ui-user-questions),interaction 不得反向 import web;
  15. cli/* 依赖 interaction(同层,单方向):四个入口安装 userQuestions 服务 seam(上游 base bundle 依赖 dsh-user-questions,同 cli→web 先例),interaction 不得反向 import cli;
  16. web/* 依赖 terminal_controller(同层,单方向):terminal/attach 双工流的类型化上行 codec(TerminalInput 判别联合)由 terminal-controller 域声明,gateway 流层仅消费它(上游 codec 由 terminal-controller 类型图生成、经 descriptor.uplink.codec 注册);terminal_controller 不得反向 import web。
  17. fs/* 依赖 attachment(同层,单方向):read_image 消费 attachment 的数据契约与错误码(上游 tool-fs peerDep @deepseek-ai/dsh-attachment,read-image.ts 引 AttachmentError/SaveImageAttachment/ImageAttachmentRef/ImageMediaType);attachment 层不得反向 import fs。
  18. deepseek_account/* 依赖 seams/authorization(同层,单方向):Platform browser flow 经 AuthorizationService 的 registerFlow/begin/commit 契约落地(上游 deepseek-account-platform static inject = ['credentials', 'authorization']);authorization 不得反向 import deepseek_account。
  19. protocol/ 内三个模块互不依赖(acp、sdk、hooks 各自独立)。
  20. seams/ 内 sandbox(sandbox_local + sandbox_policy)、credentials、subagent 互不依赖;policy 与 local 同属沙箱子域——上游 dsh-sandbox-policy 同样依赖 dsh-sandbox。
  21. seams/credentials_local.py 从 boot/dotenv.py 导入 parse_dotenv(L3 → L1):凭据文档解析复用 boot 层的 .env 解析器,方向合法。

4. 公共 API 面

白名单(约定层,改它需要对照上游 + 更新差异清单):Session、Context、RegistryService、Tool、ToolRegistry、AgentLoop、StreamChunk、LlmAdapter、DeepSeekAdapter、LlmFailure、SessionPersistence/JsonlPersistence/SqlitePersistence、apply_patch、boot、run_headless、create_message 与四个 block 构造、derive_messages、turn_balance、repair_interrupted_turn、SESSION_FORMAT_VERSION、TOOL_NOT_STARTED、TOOL_OUTCOME_UNKNOWN。 黑名单(内部工具,不在顶层 __all__,只允许深路径 import):deep_freeze、thaw、is_json_safe、now_ms、_http_error_code、_map_finish_reason、load_events_checked、repair_and_replay、balanced_after_replay。

教学扩展(上游无对应,标注于此):cli/default_tools.py、cli/session_cmds.py(会话管理子命令;--config 属 cli/main.py 启动器标志,同为教学扩展)、llm/fake.py、demo.py、example_plugins.py。

顶层 __all__ 收敛至 28 项(白名单 + FakeLlmAdapter),由 tests/test_dependencies.py 断言固定;白名单每一项都能在 §2 映射表里找到上游对应。

深路径约定(不在顶层 __all__,仅经子包深路径暴露,由 tests/test_token_meter.py、tests/test_compaction.py、tests/test_jobs.py、tests/test_plan.py、tests/test_skills.py、tests/test_session_store.py 固定行为):TokenMeter、install_compaction、CompactionEngine、compact_surface_region、select_compactable_range、inspect_compaction_entry_state、frame_summary、install_jobs、register_job_tools、LocalJobRegistry、JobDoneBox、fit_with_suffix、fit_completion_notice、install_system_prompt、SystemPromptService、install_plan_mode、PlanModeController、fold_plan_mode、resolve_config、install_skills、register_skill_tools、SkillRegistry、FileSystemSkillProvider、SkillTool、SKILL_GESTURE、render_skill_content、parse_skill_file、digest_catalog_entries、install_sessions、SessionStore、SessionForkError、SESSION_NOT_FOUND、SESSION_NOT_LIVE、SESSION_ALREADY_EXISTS、INVALID_BOUNDARY、OPEN_TURN、LocalAttachmentStore、AttachmentStore、ImageAttachmentRef、SaveImageAttachment、ImageAttachmentLimits、AttachmentError、is_image_admission_error、detect_image、probe_image、supports_acp_image_prompts、admit_acp_prompt、assistant_block_to_acp。装配约定:apply_retry_planner(ctx) → install_compaction(ctx) → install_jobs(ctx) → install_system_prompt(ctx) →(可选)install_plan_mode(ctx, config) →(可选)install_skills(ctx) →(可选)install_sessions(ctx)(均幂等;CONTEXT_WINDOW_EXCEEDED 不在重试白名单,由压缩接管;作业工具注册经 register_job_tools(reg, ctx.get("jobs")),default_tools 在 ctx.jobs 存在时自动收编;skill 工具注册经 register_skill_tools(reg, ctx.get("skills")),default_tools 在 ctx.skills 存在时自动收编;plan 依赖 systemPrompt 服务,缺失 fail loud;会话经 install_sessions(ctx) 提供 ctx.sessions,headless / demo / resume 入口已接入)。