DeepCode P4 Code Workbench 架构解析:基于 P2/P3 会话栈的桌面代码审查能力层
2026/9/14 18:22:14 网站建设 项目流程

DeepCode P4 Code Workbench 架构解析:基于 P2/P3 会话栈的桌面代码审查能力层

【免费下载链接】DeepCode"DeepCode: Open Agentic Coding (Agent Harness & Loop Engineering & Multi-Agent Orchestration)"项目地址: https://gitcode.com/GitHub_Trending/deepc/DeepCode

导读

本文以 DeepCode 仓库的 P4_CODE_WORKBENCH_ARCHITECTURE.md 为骨架,系统讲解 P4 Code Workbench 如何在 P2/P3 已有的 Thread、Turn、Item、Approval 与本地 stdio App Server 之上,新增代码审查(Code Review)能力:文件浏览与编辑、Git 状态/差异/丢弃、隔离 worktree、Thread 专属 PTY 终端与测试发现/运行。读完本文,你将掌握 P4 的服务边界划分、RPC 协议扩展、安全不变量及其源码级实现依据,并了解各服务的核心行为约束、消息大小限制与验证方式,可直接对照 core/application 与 app_server 继续深入。


一、P4 在整体架构中的定位

DeepCode 的整体架构按阶段演进:P1 搭建本地 stdio App Server 与基础协议,P2/P3 建立 Thread、Turn、Item、Approval 等会话与执行模型(参见 P1_APP_SERVER_ARCHITECTURE.md、P2_AGENT_EXECUTION_ARCHITECTURE.md、P3_DESKTOP_RUNTIME_ARCHITECTURE.md)。P4 的工作是在这条会话栈之上叠加代码审查能力,让桌面端 Inspector 可以直接查看文件树、浏览 Git 变更、运行测试并在 Thread 终端中执行命令。

P4 架构有三个贯穿始终的原则:

  1. 业务规则集中在core/application:所有路径校验、权限判断、并发保护、revision 检查都放在 Python 应用层,React 前端不直接访问文件系统、Git 或 shell。
  2. React 保持"哑客户端":前端只消费 RPC 返回的结构化数据,不复制业务规则。
  3. Rust bridge 不复制规则:Rust 侧只负责消息传输与 sidecar 生命周期,不实现文件、Git、终端等业务判断。

也就是说,P4 的所有新增能力都通过本地 App Server 暴露为协议方法,前端与 Rust 只是"通道"。


二、服务边界:五个核心服务与各自的职责

P4 把代码审查能力拆分为五个服务,全部位于 core/application,职责边界非常清晰:

2.1 WorkspaceService:一切路径操作的共同边界

WorkspaceService是所有文件系统访问的守门人,其resolve方法(见 workspace_service.py)完成四层校验:

  • Project/Thread 存在性校验:通过ThreadRepositoryProjectRepository加载 Thread 与 Project,缺失即抛ThreadNotFoundError/ProjectNotFoundError
  • trust 校验:需要 trusted 的操作(写文件、discard、worktree 变更、终端、测试运行)通过require_trusted=True强制要求project.trust_state is TrustState.TRUSTED,否则抛ProjectNotTrustedError
  • canonical root 校验:Thread 的workspace_pathPath.expanduser().resolve(strict=True)规范化,并确认是目录;若 Thread 不拥有 worktree,还必须root.is_relative_to(project_root),防止 workspace 越出项目边界(WorkspaceOutOfScopeError);
  • owned worktree 校验:若 Thread 拥有 worktree,则要求root == worktreeworktree/.git存在,即路径必须是真实注册的 Git worktree,而不是任意目录。

path方法(workspace_service.py)负责把 UI 提供的相对路径映射为物理路径:

  • 拒绝绝对路径、包含..的路径、包含 NUL 字节的路径;
  • candidate.resolve(strict=True)后再做一次is_relative_to(context.root)检查,无论是否存在 symlink 指向 workspace 之外,最终解析结果都必须留在 workspace 根之内
  • 对尚不存在的目标(如新建文件),则先解析父目录再拼接文件名,同样做边界检查。

这是安全不变量 #1 和 #2(UI 路径永远是 workspace-relative、canonicalization 只在后端执行)的落地实现。

2.2 FileService:有界目录树 + UTF-8 小文件 + SHA-256 乐观编辑

FileService(file_service.py)只做三类事:

  • 有界目录树list方法限制depth在 1~8、limit在 1~750(MAX_TREE_ENTRIES = 750),排序优先目录后文件、忽略.git目录,扫描超限即标记truncated
  • UTF-8 小文件读取read方法默认只读 128 KiB(DEFAULT_READ_LIMIT = MAX_READ_LIMIT = 128 * 1024),发现 NUL 字节或非法 UTF-8 即抛BinaryFileError,确保只返回文本文件;截断的文件不计算 SHA-256sha256=None if truncated),即"截断内容不返回可写 revision",防止前端基于不完整内容发起覆盖写;
  • 原子小范围编辑write方法要求内容不超过MAX_EDIT_BYTES = 128 * 1024,通过同目录NamedTemporaryFile写入、fsyncos.replace原子替换、再fsync目录实现崩溃安全落盘。

write的乐观并发控制值得单独强调:

  • 对已存在文件,必须提供expected_sha256,若与当前内容哈希不一致则抛FileChangedError("file changed since it was read"),实现"旧视图不能覆盖新内容"(安全不变量 #3);
  • 对不存在的文件,若带了expected_sha256则视为"目标已消失";
  • 写入前后还会二次比对哈希,防止保存期间文件被并发修改;
  • 活动 Turn 期间禁止编辑TurnRepository.active_for_thread(thread_id)非空即抛ConflictError,避免与 Agent 执行中的文件操作冲突。

2.3 GitService:只返回结构化 status/diff,discard 必须提交 revision

GitService(git_service.py)把所有 Git 交互封装成三类操作:

  • status:调用git status --porcelain=v1 -z --branch --untracked-files=all,解析出GitStatusEntry(path、original_path、index_status、worktree_status、kind),并支持_parse_branch_header处理 detached HEAD、"No commits yet" 等边界;

  • diff:支持scopeall/staged/working三种,对 untracked 文件直接读取内容构造"新文件"hunk;对 tracked 文件调用git diff --no-ext-diff --no-color --find-renames --unified=3 [--cached|HEAD]并解析成结构化的FileDiff/DiffHunk/DiffLine每个 FileDiff 通过_attach_revision附带一个基于 path、status、binary 标记与 patch 内容计算的 SHA-256 revision

  • discard:逐文件执行,前置条件非常严格:

    1. 必须require_trusted=True,且 Thread 无活动 Turn;
    2. 重新调用diff获取当前变更,要求恰好命中 1 个文件;
    3. 提交的expected_revision必须与后端重新计算的 revision 一致,否则抛FileChangedError——这是"逐文件 discard 必须提交该 revision,并在后端重新计算后才允许执行"的实现;
    4. untracked 文件直接删除;unborn 仓库(无 HEAD)用git rm --cached加删除;正常情况用git restore --source=HEAD --staged --worktree恢复。

revision 机制保证了"旧视图不能覆盖新内容"这一安全不变量在 Git 侧同样成立:UI 看到某个 diff 后,若文件在审查期间被改动,discard 会因 revision 不匹配而被拒绝。

Git 输出还有硬上限:MAX_GIT_OUTPUT = 8 MiB(含逐文件 diff 累计)、MAX_DIFF_FILES = 500MAX_DIFF_LINES = 4000MAX_DIFF_TEXT_BYTES = 256 KiB,任何一项超限都会抛出InvalidArgumentError,且通过 drain 线程在超限时直接 kill 子进程,避免 sidecar 因超长输出卡死。

2.4 WorktreeService:确定性 sibling 目录 + 专属分支 + ownership manifest

WorktreeService(worktree_service.py)为 Thread fork 出来的并行 Turn 提供隔离 workspace:

  • 确定性路径:worktree 一律创建在项目父目录下的.<projectName>.deepcode-worktrees/<threadId>,分支固定为deepcode/<threadId>
  • 要求项目即 Git rootgit rev-parse --show-toplevel必须等于 project canonical path,否则拒绝创建(保证 sibling 目录可控);
  • ownership manifest:每次创建在.<projectName>.deepcode-worktrees/.deepcode-manifests/<threadId>.json写入包含version/threadId/projectId/repositoryRoot/worktreePath/branch的清单;清理时必须校验数据库归属(Thread 记录)、managed path(必须是期望路径)、branch(git worktree list --porcelain注册分支与git branch --show-current实际分支都必须等于deepcode/<threadId>)和 manifest 四者一致,绝不根据目录名猜测所有权(安全不变量 #5);
  • 脏 worktree 必须显式 forceremovedisposition只允许keepcleanclean时若git status --porcelain非空且未传force=True,则抛ConflictError;活动 Turn(_require_idle)或 Thread 终端仍存活(_terminal_activity)都会阻止清理;
  • reclaim 逻辑:若 worktree 目录与.git存在但 Thread 记录未注册,只要 manifest 匹配、分支匹配,就回收使用;否则报 ConflictError。

2.5 TerminalService:Thread 专属 PTY,有界增量输出,不写 durable event log

TerminalService(terminal_service.py)管理 Unix PTY 终端:

  • Thread 专属:每个 terminal 绑定thread_id_owned校验 terminal 必须属于发起 Thread;create时以 workspace 为cwdstart_new_session=True建立独立进程组,shell 取$SHELL(无则/bin/sh),并注入DEEPCODE_THREAD_ID环境变量;
  • 大小与输入输出上限:窗口行列校验在 20~500 列、5~200 行;write单次输入上限 64 KiB;输出读取循环每次最多 16 KiB 并增量发布terminal.output通知;
  • 不写 durable event log:输出通过订阅-发布(subscribe/unsubscribe)直接推送给 App Server 写入 stdout 通知,不落入持久化事件仓库;
  • 退出清理:进程退出后发布terminal.exit(带 exitCode),close_all在应用退出时终止所有会话;_terminatekillpg(SIGTERM),0.75 秒后未退出再killpg(SIGKILL);清理 worktree 前若 terminal 仍活跃会被拒绝(set_terminal_activity_check注入的回调);
  • Windows 平台:PTY 路径需要 Windows ConPTY 适配器,当前实现直接抛NotSupportedApplicationError,并在文档中说明适用前提是 Unix 环境。

2.6 TestService:只暴露探测到的白名单命令,结果落为 durable TestResult Item

TestService(test_service.py)与 core/verification.py 配合:

  • 探测而非猜测discover_verification_commands只从仓库真实标记中探测——有pytest.ini/pyproject.toml/setup.cfg/tests目录则暴露pytest;根目录存在test_*.py/*_test.py且导入 unittest 则暴露unittestpackage.json有非空testscript(排除 "no test specified")则暴露npm test;存在Cargo.toml则暴露cargo test
  • 运行条件test/run要求 trusted Project、指定turn_id必须属于该 Thread 且当前无活动 Turn
  • 有界输出:stdout/stderr 各自只保留最后 64 KiB(MAX_VERIFICATION_OUTPUT),output_truncated标记截断;超时范围限制在 1~1800 秒,超时后killpg终止;
  • 持久化:运行结果写入ItemKind.TEST_RESULT,成功为ItemStatus.COMPLETED、失败为FAILED,payload 携带 command、exitCode、timedOut、durationMs、stdout、stderr,并通过item.created事件广播——测试结果成为会话历史的一部分。

三、协议与 UI:RPC 扩展与方法清单

3.1 Canonical schema 新增的 P4 方法

P4 在协议层新增四组方法(完整方法常量见 app_server/protocol/methods.py):

file/list git/status terminal/create file/read git/diff terminal/write file/write git/discard terminal/resize git/worktree/create test/discover terminal/close git/worktree/remove test/run

对应的协议 schema 定义位于 protocol/app-server.schema.json。所有方法都由 app_server/server.py 的Dispatcher分发给五个服务。

3.2 消息与数据硬上限

文档明确的大小约束在源码中可逐条验证:

约束数值源码位置
App Server 单条消息上限1 MiBcodec.pyDEFAULT_MAX_MESSAGE_BYTES = 1024 * 1024
文件读取/写入128 KiBfile_service.py
测试 stdout/stderr 各保留最后 64 KiBverification.pyMAX_VERIFICATION_OUTPUT
结构化 Diff 文件数500git_service.pyMAX_DIFF_FILES
结构化 Diff 行数4000git_service.pyMAX_DIFF_LINES
结构化 Diff 文本字节256 KiBgit_service.pyMAX_DIFF_TEXT_BYTES

超限时的降级行为:若请求或响应超过 1 MiB,App Server 返回稳定的RESPONSE_TOO_LARGE(错误码-32004,stable_codeRESPONSE_TOO_LARGE)并继续服务,不会让 sidecar 因超长行退出——对应 server.py 的_write_response逻辑;对超长请求还会_discard_remainder丢弃本行剩余内容再继续读下一行。事件回放(event/replay)则通过二分查找切出最大可装入单条消息的 cursor 页(_fit_replay_response),保证大历史也能分页送达。

3.3 UI 层消费与按需加载

Inspector 的Changes、Files、Tests、Terminal四个标签全部消费真实 RPC 数据,而非 mock:

  • Changes →git/statusgit/diffgit/discard
  • Files →file/listfile/readfile/write
  • Tests →test/discovertest/run
  • Terminal →terminal/createterminal/writeterminal/resizeterminal/close

Monaco 与 xterm 均按需加载:常规首屏 bundle 不包含编辑器和终端运行时代码,降低启动体积。Thread fork(thread/fork)随后为并行 Turn 创建 owned worktree,使各 Turn 在隔离 workspace 中执行。


四、安全不变量:七条规则的源码对应

文档列出七条安全不变量,逐条可找到实现证据:

  1. UI 提供的路径永远是 workspace-relative,canonicalization 只在后端执行→ workspace_service.pypath()拒绝绝对路径与..,所有resolve在后端完成;
  2. symlink 不能把读取、写入或 discard 导向 workspace 之外→ 同上,resolved.is_relative_to(context.root)二次校验;FileService.listfollow_symlinks=False标记 symlink 类型;
  3. 写文件和 discard 都使用 optimistic revision,旧视图不能覆盖新内容→ file_service.py 的 SHA-256 校验、git_service.py 的 revision 比对;
  4. discard 仅处理明确选择的文件,并由 UI 二次确认;worktree force clean 另有独立确认→ discard 只接受单个path且后端重新计算 diff 恰好命中一个文件;force 作为显式参数(worktree_service.py),UI 侧还需独立弹窗;
  5. worktree 清理同时校验数据库归属、managed path、branch 和 manifest,不根据目录名称猜测所有权→ worktree_service.py_require_manifest四要素比对;
  6. PTY 和 test subprocess 使用显式cwd,不调用全局os.chdir()→ terminal_service.py 与 verification.py 均以cwd=root启动子进程;
  7. Terminal input、Git output、文件内容、目录项和 test output 均有硬上限→ 64 KiB 输入、8 MiB Git 输出、128 KiB 文件、750 目录项、64 KiB 测试输出的常量定义。

此外,写文件、discard、worktree 变更、test/run、terminal/create 均要求trusted Project,把代码审查能力限制在用户显式信任的仓库内(参见 project_trust.py 的 trust 流程)。


五、验证证据:测试如何覆盖这些边界

P4 的验证证据在仓库中有大量对应测试:

5.1 应用层组合测试

tests/application/test_p4_code_workbench.py 覆盖:

  • test_file_tree_read_and_optimistic_edit_stay_inside_workspace——文件树与乐观编辑的 workspace 边界;
  • test_file_read_truncates_on_a_utf8_boundary_without_hashing_partial_content——UTF-8 截断边界与"截断内容不返回可写 revision";
  • test_git_status_and_diff_include_tracked_and_untracked_filestest_git_diff_handles_unborn_repositories_renames_and_deletions——unborn 仓库、rename、delete 等 diff 边界;
  • test_worktree_lifecycle_requires_explicit_dirty_cleanuptest_worktree_recreates_a_missing_registered_path_only_with_its_manifest——脏 worktree 显式 force 清理与 manifest reclaim;
  • test_terminal_is_thread_owned_and_emits_output_and_exit——PTY ownership 与输出/退出通知;
  • test_allowlisted_test_run_creates_durable_test_result_itemtest_test_discovery_requires_a_real_npm_script_and_bounds_failure_output——白名单测试发现与输出截断。

5.2 App Server 协议层测试

tests/app_server/test_p4_server.py 覆盖:

  • test_p4_file_git_and_terminal_protocol_round_trip——file/git/terminal 方法完整 RPC 往返;
  • test_oversized_result_returns_a_protocol_error_without_stopping_server——超限响应返回RESPONSE_TOO_LARGE且服务器继续服务;
  • test_event_replay_is_split_into_byte_bounded_cursor_pages——事件回放按字节边界分页。

5.3 前端与 Rust 侧验证

  • React TypeScript、ESLint、5 项 Vitest 与 production build 通过;慢旧 Thread 请求不能覆盖当前 Inspector 的竞态保护在桌面端测试中有对应覆盖;
  • Rust fmt、单元测试与 clippy-D warnings通过;
  • PyInstaller sidecar 与 macOS arm64DeepCode.apprelease bundle 构建通过,并从 bundle 内 sidecar 实测file/readgit/diff、PTY 与 graceful shutdown。

文档记录 P4 组合共51 项通过,这些边界场景——UTF-8 截断、symlink fence、stale SHA/Diff revision、unborn repository、rename/delete/untracked discard、manifest reclaim、脏 worktree、PTY ownership、test output truncation 与 oversized RPC response recovery——正是 P4 安全不变量能被持续验证的关键。


六、总结与延伸阅读

P4 Code Workbench 的核心贡献可以概括为:在既有会话模型之上,用五个职责单一的服务 + 一组受限 RPC 方法 + 七条可验证的安全不变量,把"代码审查"这一桌面功能完整装进了"业务规则只在 core/application、前端与 Rust 不复制规则"的架构约束中。对使用者和二次开发者而言,理解WorkspaceService的路径围栏、FileService/GitService的双重乐观 revision、WorktreeService的四要素归属校验,是安全使用该能力的前提。

继续深入可参考:

  • 架构总览:README.md、README_ZH.md
  • 分层架构:P2_AGENT_EXECUTION_ARCHITECTURE.md、P3_DESKTOP_RUNTIME_ARCHITECTURE.md、P4_CODE_WORKBENCH_ARCHITECTURE.md
  • 协议 schema:protocol/app-server.schema.json
  • 核心实现:core/application/workspace_service.py、file_service.py、git_service.py、worktree_service.py、terminal_service.py、test_service.py
  • 协议层:app_server/server.py、app_server/protocol/methods.py
  • 测试证据:tests/application/test_p4_code_workbench.py、tests/app_server/test_p4_server.py

【免费下载链接】DeepCode"DeepCode: Open Agentic Coding (Agent Harness & Loop Engineering & Multi-Agent Orchestration)"项目地址: https://gitcode.com/GitHub_Trending/deepc/DeepCode

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询