尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Claudian Collab 表现层架构:Provider 无关契约、跨表面不变量与读写边界

Claudian Collab 表现层架构:Provider 无关契约、跨表面不变量与读写边界 Claudian Collab 表现层架构Provider 无关契约、跨表面不变量与读写边界【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudianClaudian 是一个把 Claude Code/Codex 嵌入 Obsidian 库的插件其 Collab协作功能负责多成员围绕同一个 Vault 项目进行变更请求Request、发布审阅Publication Review、冲突处理与 Ticket 管理。本篇技术指南以src/features/collab/AGENTS.md这份架构约束文档为主体系统讲解 Collab 表现层如何通过CollabFeaturePort等 Provider 无关契约隔离 UI 与底层 Git/权威存储实现并深入源码验证其中的 handoff 缓存、响应式路由与跨表面不变量的具体落地方式。读完本文你将掌握这套表现层零副作用架构的设计原则、关键默认参数缓存上限 8 条、TTL 5 分钟以及用于守护这些不变量的测试边界。一、模块职责与硬性导入边界src/features/collab/目录拥有 Collab 的全部表现状态presentation state与用户意图user intent且只能通过 Provider 无关的契约与下层通信。模块文档开头即声明了这条硬性边界本模块不得 import 应用层仓库application repositories、Native Git 适配器、权威存储authority storage、LAN 实现或任何 Provider 实现。这条规则把整个功能树约束为单向数据流面板panels、详情会话detail sessions和模态框modals只负责把用户操作转换为契约方法调用从不直接执行 Git 命令也从不直接修改 Project 记录。对应的目录划分如下可通过 目录结构 验证子目录职责关键文件sidebar/侧栏面板Project 选择、Personal/Team 变更列表、Ticket 列表CollabPanel.ts、PersonalChangesPanel.ts、TicketListPanel.tsdetail/Obsidian 叶子视图路由与各类会话Request/Publication/Ticket/ConflictCollabDetailView.ts、CollabDetailContracts.tsmodals/Create/Join/Reconnect/项目管理等瞬态表面CollabTransientSurfaceRegistry.ts、ProjectManagementModal.tshandoff/侧栏到详情的有界元数据桥CollabPreparedReviewCache.tsnavigation/Claudian 表面选择与回退ResponsiveCollabRouter.tsshared/跨表面共享的 UI 与变更意图存储MutationIntentStore.ts二、单向依赖图与不可逆规则架构文档以一段文本图规定了功能内依赖只能沿指定方向流动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其中两条是不可逆规则inverted rulesshared与handoff不得 import 任何表现表面sidebar/detail/modalsmodals不得 importsidebar或detail。从源码结构看这套方向性在实现上得到遵守例如 CollabPreparedReviewCache.ts 的 import 只有claudian-collab/protocol类型、/core/collab类型以及同目录的 CollabReviewSourceKey.ts不引用任何面板文件。反向来看侧栏通过组合composition注入的方式获取该缓存实例而非直接持有对 detail 的引用。三、CollabFeaturePort用户意图的唯一入口CollabFeaturePort 是表现层与应用层之间的核心契约定义了约 50 个方法可按领域归为六组Project 生命周期initialize、listProjects、selectProject、inspectProject、createProject、joinProject、reconnectProject、resumeSetup发布与审阅publish、confirmPublish、prepareWorkingTreeReview、preparePublicationReview、prepareReview、readReviewFile、readConflict、readConflictFile评论与 TicketaddComment、listTickets、readTicket、createTicket、updateTicketContent、addTicketComment、closeTicket、reopenTicketRequest 元数据与接受updateRequestMetadata、acceptRequest成员与 Manager 职责createInvitation、revokeInvitation、removeMember、leaveProject、promoteManager、demoteManager、createManagerResponsibilityOffer、cancelManagerResponsibilityOfferHost 与退役startHost、stopHost、createHostTransfer、acceptHostTransfer、declineHostTransfer、cancelHostTransfer、retireProject、finalizeRetiredProject、retryProjectCleanup。该接口还有一个订阅式状态通道subscribe(listener): CollabFeatureSubscription配合 CollabFeatureState 的生命周期uninitialized / initializing / ready / failed让表现层可以响应式刷新。3.1 CollabResult区分成功、取消、恢复、陈旧、冲突与失败该契约最有辨识度的设计是六元结果类型 CollabResultexport type CollabResultT | { status: success; value: T } | { status: cancelled; operationId?: CollabOperationId; durableProgress: false } | { status: recovery-required; operationId: CollabOperationId; durableProgress: true; durablePhase: CollabOperationPhase; error: CollabError } | { status: stale; staleKind: CollabStaleKind; error: CollabError } | { status: conflict; conflict: CollabConflictDescriptor; error: CollabError } | { status: failure; error: CollabError };其中stale状态携带CollabStaleKindproject-selection / main / request-head / request-metadata / ticket / authority-sync / working-copy / operation共八类见 定义让 UI 能精确判断哪一层指针已漂移而不是笼统地报已过期。recovery-required与durableProgress: true的组合则表示操作已经产生持久化进度、可以恢复这是模态层Resume setup操作的契约基础。3.2 幂等意图intentId几乎所有变更类请求CollabCreateTicketRequest、CollabAddCommentRequest、CollabAcceptRequest等都携带可选的intentId?: string。从契约结构可以推断它的用途是让表现层在丢失响应重试场景下携带同一个幂等键使得权威端可以精确重放而不是重复提交——这与 modals 文档中lost-response retry 不得轮换 mutation intent的规则互相印证。四、Handoff 桥CollabPreparedReviewCache 的有界元数据缓存架构文档特别点名了handoff/CollabPreparedReviewCache.ts它是侧栏审阅准备到详情表现的有界、插件生命周期、仅元数据metadata-only桥按持久化身份与精确的 review OID 建立键可保留协调元数据但永不保留文件 blob 或凭据缺失或不匹配的条目必须通过注入的端口重新推导。源码完整落实了这一规格关键实现细节默认参数DEFAULT_MAX_ENTRIES 8、DEFAULT_TTL_MS 5 * 60_0005 分钟均可通过构造函数注入时间源now默认Date.now但可替换以便测试构造器。双键结构entries以六段拼接的身份键存储projectId:requestId:reviewedMainOid:reviewedHeadOid:comparisonBaseOid:comparisonTargetOid见 identityKey另有一个requestEntries副索引把请求源键含当前 Member 身份与角色、main OID见 requestSourceKey映射到该身份键使readRequest能在 Member 身份/角色变化时正确失效。存储前的身份校验store会拒绝 coordination 快照的 project id 或 mainOid 与 review 不一致的条目store 入口防止跨项目污染。有界淘汰每次store后循环淘汰最旧条目直至不超过maxEntriesL158-L162利用Map的插入序保证 LRU 语义。读取时过期清理read/readRequest/readPublication在返回前检查expiresAt过期即删除并返回nullread 实现。评论单调合并mergeReviewComments实现在新条目进入时把旧条目中尚未出现的评论并入commentCount取双方与合并结果的三者最大值保证同一 review 的评论只增不减。陈旧请求条目清除discardStaleRequestEntries会删除同 projectrequest 但源键不同的旧缓存L246-L260即 Member 换人或角色变化后旧身份下的审阅准备立即失效——这与 sidebar 文档中TeamReviewLoader 缓存身份包含 Project/request OID、请求元数据、当前 Member 身份与角色评论与 Manager 转移可以在不推进 ref 的情况下使 review 失效的规则一致。该缓存同时维护两套存储request 审阅entries与 publication 审阅publicationEntries键含operationId、candidateOid、currentMainOid与比较基线/目标 OID后者服务于跨表面的精确 publication review 保留见下文第五节。clear()在插件卸载时清空全部三张表。五、跨表面不变量Cross-Surface Invariants文档第五节是整篇架构约束的核心共七条不变量逐条拆解如下。5.1 冲突所有权My changes 与 Request 二选一在某个 Member 还没有 open request 时持久化的个人冲突从My changes入口打开一旦存在 open request该 request 就成为唯一的冲突入口——包括 base 推进之后才被检测到的冲突此时详情表面负责标识哪个位置location拥有该冲突。冲突表现是只读的Member 或 Agent 通过编辑真实的 Project 文件并重新 Publish 来解决冲突这次 Publish 准备一次常规 publication review 并更新同一个 request。已解决的 publication review 仍附着在同一个 request 上不得再作为 My changes 的发布动作重新出现。5.2 Publication review 与 My changes 投影严格分离Stale-base基线过期与 conflict-resolved冲突已解决的候选在进入确认前会转入一个独立的精确 publication reviewpublication-review 文件永不进入 My changes 投影。反向地可编辑的 Project 文件动作只属于 My changes 工作树working-tree审阅Request、publication 与冲突审阅显示的是被审阅的精确内容不得暴露打开文件编辑动作。从工作树审阅发布时会保留侧栏中已有的精确 prepared publication review 并关闭工作树叶子导航到保留的 review 必须是显式的。5.3 Ticket 表面按生命周期拆分侧栏拥有过滤、分页与导航详情拥有创建/读取/编辑、评论、已接受的关联accepted relations与关闭/重开。权威背书的变更authority-backed mutations保持 online-only——离线只能读缓存且必须呈现为只读。这一拆分在代码上对应 TicketListPanel.ts仅含 Open/Closed 过滤、Add 动作、分页行与详情导航与 TicketDetailSession.ts。5.4 项目管理的唯一入口项目仅从侧栏 Project 头部动作打开项目管理Membership、邀请、Leave、Retire 与 LAN Host 控制全部留在 ProjectManagementModal.ts 内不得在侧栏中重复出现。这避免了同一持久化操作有两个 UI 所有者。5.5 用户可见措辞与 Git 术语隔离面向用户的文案只描述 Projects、changes、Publish、review 与 recovery 这些业务概念Git refs、staging、branches、receive-pack 与数据库阶段仅作高级诊断出现。这意味着表现层错误提示必须经过语义翻译而不是把底层CollabError的技术上下文直接透出。5.6 缺失工作副本不等于删除授权工作副本缺失或 setup 中断时Project 必须保持可见且可修复表现层代码永不把缺席当作删除本地记录或 Host 授权的许可。从契约结构看retryProjectCleanup与finalizeRetiredProjectCollabFeaturePort把退役清理显式建模为带cleanupChoiceCollabLocalCleanupChoice的独立操作正体现了删除永远要用户显式选择的立场。5.7 路由不改变状态navigation/ResponsiveCollabRouter.ts选择并显示一个兼容的 Claudian 表面失败时回退到准备好的主标签页main-tab视图它不得修改聊天或 Collab 应用状态。源码印证了这一点open()先遍历listExistingTargets()逐个尝试selectAndReveal(target, false)全部失败才调用createMainTabTarget()以prepare - select - reveal三步完成且任一步抛错只被吞掉并返回 false。整个类没有任何应用状态写入ResponsiveCollabTarget接口也只暴露prepare?/reveal/select三个只读性质的动作接口定义。六、表现层状态生命周期latest-task scope 的适用边界架构文档给出了一条极易混淆的分工规则可销毁的表现读取disposable presentation reads在每条逻辑通道lane上使用一个 latest-task scope替换请求只使该通道内更旧的读取失效。而 Publish、Accept、Ticket/评论变更、冲突解决等其他持久化操作必须保留其应用层拥有的准入admission与幂等意图——绝不把它们放到表现层 latest-task scope 后面。换句话说latest-task scope 只能用于读最新即可、旧的丢弃无副作用的场景列表刷新、快照读取任何一旦提交就产生持久化后果的操作其取消与重试语义归应用层operationId 幂等intentId表现层快速切换视图不能悄悄杀掉它们。这条规则在子表面文档中被反复强调sidebar 文档要求 Personal、Team、Ticket 三个控制器保持相互独立的读/取消通道不要把它们的 task scope 用于 mutationsdetail 文档则规定替换面板不得轮换丢失响应的重试只有被当前 UI 消费掉的结果才能清除 mutation intent。七、子表面的会话与渲染约束三个子表面各有自己的 AGENTS.md构成主文档约束的具体展开值得与主文档对照阅读sidebarCollabPanel 是选中 Project 的外壳拥有 Project 选择并把激活/非激活状态传播给 Personal/Team/Ticket 面板但不拥有它们的数据投影与持久化操作。侧栏控制器的隐藏hide会保留渲染树与订阅但中止表现读取隐藏期间的失效invalidation合并为一次恢复刷新。My changes 只展示未发布或需要恢复的个人工作且永不调用 Publish、暴露 Get latest 或自行重建贡献安全性判断。detailCollabDetailView.ts 是唯一的状态路由器只持久化经过校验的 Project/request、publication 操作、个人审阅、Ticket 与冲突标识符含选中路径与精确 OID凭据与 blob 内容永不进入视图状态同一时刻恰有一个可独立销毁的详情会话。Review 叶子是会话级资源启动时移除恢复出来的 review 叶子卸载时先于布局持久化将其脱离。Accept 只在当前 Member 为 Manager 且 Project 指针一致时可见提交前还要做新鲜的权威预检authority preflightUI 状态与 WebSocket 事件不是正确性边界。modalsCollabTransientSurfaceRegistry 是组合层拥有的插件生命周期注册表Live disable 或卸载时关闭并中止所有已注册模态。异步模态启动在每次await之后都要重新校验 Collab 生命周期模态保留自己的操作准入、AbortController 与陈旧完成栅栏stale-completion fence关闭后的操作不得更新或重开已关闭的表面。八、验证标准文档定义的测试边界验证章节规定了守护上述不变量的测试必须覆盖的场景这部分对理解哪些行为是受契约保护的很有参考价值跨表面测试必须覆盖精确 prepared-review 的转移handoff、个人冲突到 request 冲突的所有权切换、publication-review 的保留、不移动持久化操作意图的 Ticket 导航。组合测试必须证明插件onload不 await 任何 Collab 工作布局就绪layout-ready的 Host 恢复始终是后台的background-only没有保存 auto-start 意图的 Project 必须让 Git、SQL 与网络基础设施保持不被触碰untouched。这些验证点与仓库的测试布局一致单元测试位于 tests/unit/features/collab/27 个测试文件跨表面集成测试位于 tests/integration/app/collab/50 个测试文件测试用 fake port 注入以隔离应用层实现。九、小结这套架构的可复制要点以 Collab Feature 架构文档 为主体梳理下来Claudian Collab 表现层的设计可以归纳为五条可迁移的工程约束单向依赖图 不可逆规则shared/handoff 不 import 表现表面、modals 不 import sidebar/detail保证共享层可以被任意表面复用而不形成环。六元结果类型 幂等 intentId用CollabResult精确表达 success/cancelled/recovery-required/stale/conflict/failure配合intentId实现丢失响应下的精确重放。有界元数据 handoff8 条上限、5 分钟 TTL、双键失效OID 身份键 Member 源键、永不缓存 blob/凭据——跨表面传数据传身份内容一律经端口重新推导。读写分离的取消语义latest-task scope 只服务于可丢弃的读取持久化操作的准入、幂等与恢复归应用层。不变量 验证清单成对出现每条跨表面规则都有对应的测试覆盖要求使架构约束可回归验证而不只是文档约定。如果你要在自己的 Obsidian 插件或多表面应用中组织类似的UI 与领域持久化边界以上五条尤其第 2、3 条在 CollabFeaturePort.ts 与 CollabPreparedReviewCache.ts 中的具体写法都是可直接参照实现的。【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表