
Claudian Collab 前端协作层架构依赖方向约束、跨表面不变量与元数据交接缓存设计【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian本篇技术指南以 Claudian 插件的src/features/collab/协作呈现层架构文档为核心系统讲解该模块的所有权边界、依赖方向 DAG、一次性读取与持久操作的生命周期分治、跨表面交互不变量以及CollabPreparedReviewCache元数据交接缓存的实现原理。读完之后你将掌握如何在 Obsidian 插件的多表面侧边栏 / 详情 / 模态框UI 架构中划分关注点、用 latest-task scope 管理可取消的呈现读取、以及如何在表面切换时安全传递有界缓存而不泄露文件内容与凭据。1. 模块定位只持有呈现状态与用户意图架构文档首先声明了src/features/collab/的所有权范围该目录负责协作Collab呈现状态与用户意图构建在 provider 无关provider-neutral的契约之上。同时它被明确禁止导入以下四类实现应用层仓库application repositories原生 Git 适配器Native Git adapters权限存储authority storage局域网LAN实现与 provider 实现。这一边界意味着面板、详情会话、模态框只通过CollabFeaturePort或更窄的注入契约发出操作自身从不执行 Git 命令也从不直接修改 Project 记录。CollabFeaturePort定义在 CollabFeaturePort.ts 中它暴露的不仅是操作方法还有一套结构化的结果类型。例如CollabResultT将结果区分为success、cancelled、recovery-required、stale、conflict、failure六种状态见 CollabFeaturePort.ts其中stale携带具体的CollabStaleKind如project-selection、main、request-head、working-copy等使呈现层可以针对不同的过期原因做出不同 UI 反馈而不是笼统地显示错误。这种“结果即契约”的设计是呈现层能够与底层 Git/SQL/网络基础解耦的关键UI 代码只需要消费快照投影CollabCoordinationSnapshot带source: online | cache与stale标志见 CollabFeaturePort.ts无需感知底层实现细节。2. 特征内依赖方向 DAG文档给出了一张特征内部依赖方向的拓扑图各呈现表面之间不允许随意互相引用composition - sidebar detail modals handoff navigation sidebar - sidebar children modals shared handoff core detail - detail children shared handoff core modals - modal children shared core navigation - injected feature/workspace contracts shared - Obsidian core shared UI/i18n handoff - core这条规则有几条明确的负向约束shared与handoff不得导入任何呈现表面sidebar / detail / modalsmodals不得导入sidebar或detail。结合仓库中的实际目录结构可以验证这一拓扑sidebar/含 CollabPanel.ts、changes/、tickets/子目录、detail/含 CollabDetailView.ts、sessions/、review/、conflict/、modals/含project/下的项目创建、加入、重连、管理等模态框、navigation/、shared/、handoff/一一对应。每个表面子目录内部还嵌套了自己的AGENTS.md补充约束例如 sidebar/AGENTS.md 规定了CollabPanel只拥有项目选择壳与激活状态传播不拥有数据投影detail/AGENTS.md 规定了详情会话的状态所有权与 diff 渲染器生命周期。3. 一次性呈现读取与持久操作的生命周期分治文档中最具操作性的一条规则区分了两类异步工作可丢弃的呈现读取disposable presentation reads统一使用“每个逻辑车道一个 latest-task scope”。当同一车道出现新的读取请求时只有旧读取被失效invalidated而Publish、Accept、Ticket/评论变更、冲突解决等持久操作保留应用侧拥有的准入admission与幂等意图idempotency intent绝不允许放到呈现层的 latest-task scope 之后——否则用户快速点击时旧任务被取消会把已经提交的持久操作“取消掉”。仓库中的实现印证了这一设计。LatestTaskScope.ts 中的LatestTaskScope类注释即“Owns cancellation and stale-completion fencing for one disposable task lane”为一个可丢弃任务车道提供取消与过期完成围栏start()会先cancel()当前任务再用递增 token AbortController建立新任务返回携带signal、complete()、isCurrent()的句柄complete()只有当任务仍是当前且未被中止时才允许清理从而防止旧读取的晚到完成覆盖新结果stale-completion fencingclose()用于控制器销毁时统一中止。侧边栏文档进一步细化了车道隔离要求Personal、Team、Ticket 三个面板控制器保持相互独立的读取/取消车道不得合并成共享刷新任务更不得用它们的任务 scope 来执行变更操作见 sidebar/AGENTS.md。与之配合的还有 MutationIntentStore.ts它按 key 为每个变更意图分配mutation{时间戳}_{自增序号}形式的意图 ID并以JSON.stringify(input)作为身份标识——相同 payload 复用同一意图 ID幂等payload 变化则轮换意图 ID只有被当前 UI 消费的结果才能清除它。这正是“持久操作保留应用拥有的幂等意图”在呈现层的落地面板替换不能轮换丢失响应的重试编辑 payload 则必须轮换意图。4. 交接缓存CollabPreparedReviewCache 的有界元数据桥文档指出handoff/CollabPreparedReviewCache.ts是从侧边栏 review 准备到详情呈现之间的“有界、插件生命周期、仅元数据”桥它以持久化身份与精确的 review OID 为键可以保留协调元数据但永远不保留文件 blob 或凭据缺失或不匹配时必须通过注入的 port 重新推导。CollabPreparedReviewCache.ts 的源码完整印证了这些约束const DEFAULT_MAX_ENTRIES 8; // 有界最多 8 条 const DEFAULT_TTL_MS 5 * 60_000; // TTL5 分钟 export interface CollabPreparedReviewIdentity { readonly comparisonBaseOid: string; readonly comparisonTargetOid: string; readonly projectId: string; readonly requestId: string; readonly reviewedHeadOid: string; readonly reviewedMainOid: string; }几个值得注意的实现细节键的构成identityKey由projectId:requestId:reviewedMainOid:reviewedHeadOid:comparisonBaseOid:comparisonTargetOid拼接而成CollabPreparedReviewCache.ts即“持久化身份 精确 OID”双重精确匹配任何一侧 OID 前进都会导致缓存未命中并触发重新推导拒绝不一致输入store()首先校验coordination.snapshot.project.id与mainOid是否与 review 声明一致不一致直接丢弃CollabPreparedReviewCache.ts防止跨项目或陈旧 main 的元数据污染评论的单调合并同一键的重复写入不会丢弃已有评论mergeReviewComments会按评论 ID 去重合并并取commentCount的最大值保证评论数只增不减见 CollabPreparedReviewCache.ts有界驱逐与 TTL写入后按 Map 插入顺序驱逐最旧条目直到不超过maxEntries读取时若expiresAt now()则删除并返回 nullCollabPreparedReviewCache.ts来源身份索引除精确键外还维护requestEntriessourceKey → key映射readRequest()允许以“项目 请求 当前成员身份/角色”为来源视角查缓存并在读取时丢弃同请求但来源不同的陈旧条目discardStaleRequestEntries这与侧边栏文档中“TeamReviewLoader 缓存身份包含 Project/request OIDs、请求元数据与当前成员身份和角色评论与 Manager 转移可在 ref 未前进时使 review 失效”sidebar/AGENTS.md的规则一一对应。缓存还有一组面向 publication review 的独立接口storePublication/readPublication/discardPublication以projectId operationId 各精确 OID为键CollabPreparedReviewCache.ts服务于文档中“stale-base 与 conflict-resolved 候选进入独立精确 publication review”的流转见下文第 5 节。5. 跨表面不变量Cross-Surface Invariants文档列出的跨表面不变量是整个协作交互模型的正确性边界逐条解析如下5.1 冲突入口的唯一所有权在当前成员没有 open request 之前个人冲突personal conflict从 “My changes”我的工作区变更发起一旦存在 open request该 request 就是唯一的冲突入口——包括其 base 前进后才检测到的冲突此时由详情表面识别冲突归属位置。冲突呈现严格只读成员或 Agent 通过编辑真实 Project 文件并再次 Publish来解决这次 Publish 准备一次正常发布审查并更新同一个 request。已解决的 publication review 仍附着于同一 request且不得重新出现为 “My changes” 的发布动作。详情表面文档进一步落实了这一点conflict/CollabConflictResolutionPanel.ts把 provider 无关的冲突会话呈现为不可变证据不暴露任何“侧边选择、草稿编辑器、定稿操作、Git index stage/ref/marker 或 Agent 调用”detail/AGENTS.md。冲突读取始终绑定原始的 base / personal / accepted OID即使工作文件已经变化下一次 Publish 捕获精确的本地结果用私有 scratch 暂存准备一次正常 publication review并保持既有 Request 身份。5.2 stale-base 与 publication review 的隔离Stale-base 候选与冲突解决后的候选在确认前会转移到独立的精确 publication reviewpublication-review 的文件永不进入 My changes 投影。反过来只有 “My changes” 的工作树审查working-tree review可以打开可编辑的 Project 文件request、publication 与 conflict 审查只展示精确审查内容不得暴露该动作。从工作树审查发起 Publish 时会为侧边栏保留任何已准备好的精确 publication review 并关闭工作树叶节点向保留 review 的导航是显式的。这些约束在CollabFeaturePort的类型层面也有呼应CollabPersonalChangesInspection区分publish、review-and-publish、resolve-changes等个人动作CollabFeaturePort.tsCollabPublicationState区分committed-locally、pushed、request-synchronized、review-required四个状态CollabFeaturePort.ts。5.3 Ticket 表面的生命周期切分Ticket 表面按生命周期切分侧边栏负责过滤、分页与导航详情负责创建/读取/编辑、评论、已接受的关系accepted relations以及关闭/重开。所有基于权限的变更保持 online-only。侧边栏的tickets/TicketListPanel.ts因此被约束为只包含 Open/Closed 过滤、Add 动作、分页行与详情导航不得承载表单、正文、评论或状态变更sidebar/AGENTS.md缓存或过期stale的 Ticket 行必须标注只读并禁用 Add。5.4 项目管理入口唯一性项目管理只能从侧边栏项目头部动作打开。成员管理、邀请、Leave、Retire 与 LAN Host 控制保留在项目管理模态框中不得在侧边栏重复出现。modals/project/目录下的ProjectManagementModal.ts、ProjectInvitationModal.ts、LanHostSection.ts等文件即该入口的实现载体见 modals/project 目录。5.5 响应式路由不触碰应用状态navigation/ResponsiveCollabRouter.ts负责选择并显示一个兼容的 Claudian 表面失败时回退到准备好的主标签视图且不得变更聊天或 Collab 应用状态。其实现非常克制ResponsiveCollabRouter.ts先遍历已存在的候选目标做selectreveal全部不兼容时回退创建主标签目标失败被捕获为 null任何目标抛错都返回 false 由上层处理——路由层自身不做状态副作用。5.6 用户可见文案与可修复性两条面向运维稳健性的不变量文案分层用户可见文案只描述 Projects、changes、Publish、review 与 recoveryGit refs、staging、branches、receive-pack 与数据库阶段仅作为高级诊断出现。这与CollabResult中recovery-required携带durablePhaseCollabFeaturePort.ts的分工一致——应用状态可保留完整阶段信息但呈现层默认不向用户倾倒 Git 术语。缺席不等于删除许可工作副本缺失或设置被中断时Project 必须保持可见且可修复呈现代码永远不得把“本地记录缺失”解释为删除本地记录或 Host 权限的许可。侧边栏文档补充了 Retired Project 的处理它仍在侧边栏可见其摘要、重试、Keep 与 Delete 动作只使用本地生命周期投影清理失败保持 Retired 并允许重试sidebar/AGENTS.md。6. 验证要求用测试固化上述边界文档的 Verification 一节给出了两类必须覆盖的测试断言它们本质上是把架构不变量“编译”成可执行的回归防线跨表面测试必须覆盖精确 prepared-review 的转移、个人冲突到 request 的冲突所有权移交、publication-review 的保留retention、以及 Ticket 导航——且不得把持久操作意图移入呈现状态组合composition测试必须证明插件onload不 awaitCollab 工作布局就绪后的 Host 恢复保持后台执行未保存 auto-start 意图的 Project 必须让 Git、SQL 与网络基础保持未触碰。这些约束对应仓库中的测试面tests/unit/features/collab/下的 27 个单元测试文件、tests/integration/app/collab/下的 50 个集成测试文件以及测试辅助设施 CollabFeatureTestHarness.ts用 fake port 驱动呈现表面。子表面文档的 Verification 小节还列出了更细的断言清单如“prepared-handoff 再验证、草稿/幂等保留、Accept 前置权限检查preflight、Pierre 复用/清理、有界连续渲染”detail/AGENTS.md与“隐藏失效合并、Project 切换、过期完成抑制、每面板取消”sidebar/AGENTS.md。7. 小结这套架构给多表面 UI 的启示回到 src/features/collab/AGENTS.md 这条核心骨架Claudian 的 Collab 呈现层用四条纪律支撑了复杂的多表面协作交互依赖方向是单向 DAGshared/handoff 不反向依赖呈现表面保证共享层可被任意表面安全复用可丢弃读取与持久操作严格分治——latest-task scope 只管可重放的呈现读取持久操作交给应用层 admission 幂等意图MutationIntentStore表面切换只传有界元数据——CollabPreparedReviewCache以 8 条上限、5 分钟 TTL、精确 OID 键控永不缓存 blob 与凭据不变量即测试——冲突入口唯一性、publication review 隔离、入口唯一性、缺席可修复等交互规则全部落到可回归的断言上。对阅读源码的开发者而言建议的深入路径是先读 AGENTS.md 建立边界认知再沿 CollabFeaturePort.ts 看契约如何结构化然后分别进入 sidebar、detail、handoff 三个目录对照各表面的实现与子文档约束最后在tests/unit/features/collab/中验证这些约束如何被测试固化。【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考