尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Claudian 协作侧边栏(Collab Sidebar)架构解析:从 Panel Shell 到 My Changes / Team Changes / Tickets 三大子面板的生命周期管理

发布时间:2026/9/14 13:06:13

资讯中心
01
ARTICLE

Claudian 协作侧边栏(Collab Sidebar)架构解析:从 Panel Shell 到 My Changes / Team Changes / Tickets 三大子面板的生命周期管理

Claudian 协作侧边栏(Collab Sidebar)架构解析:从 Panel Shell 到 My Changes / Team Changes / Tickets 三大子面板的生命周期管理
Claudian 协作侧边栏Collab Sidebar架构解析从 Panel Shell 到 My Changes / Team Changes / Tickets 三大子面板的生命周期管理【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian本文基于 Claudian一个将 Claude Code/Codex 嵌入 Obsidian vault 作为 AI 协作者的插件仓库中的协作侧边栏模块文档 Collab Sidebar 规范 展开解析CollabPanel作为选中项目 Shell的职责边界、三大子面板Personal / Team / Ticket各自独立的读取与取消机制、TeamReviewLoader的原生评审序列化与缓存失效策略以及 Retired 项目的本地生命周期投影行为。读完后你能理解该侧边栏隐藏保留 DOM、激活不触发多余读取、陈旧结果静默抑制的完整设计并知道如何在源码与测试中验证这些行为。1. 模块定位Collab Sidebar 在 Claudian 中的位置Collab Sidebar 位于 src/features/collab/sidebar是 Claudian 协作功能在 Obsidian 侧边栏中的入口界面。目录结构如下src/features/collab/sidebar/ ├── AGENTS.md # 模块行为规范本文主体依据 ├── CLAUDE.md # 指向 AGENTS.md ├── CollabPanel.ts # 选中项目 Shell面板主体 ├── DeferredCollabSurfaceController.ts # 延迟构建控制器懒加载外壳 ├── GitSetupPanel.ts # Git 缺失/不兼容时的安装引导面板 ├── changes/ │ ├── PersonalChangesPanel.ts # My Changes个人未发布变更投影 │ ├── TeamChangesPanel.ts # Team Changes全部开放请求列表 │ └── TeamReviewLoader.ts # 原生评审准备的序列化加载器 └── tickets/ └── TicketListPanel.ts # Tickets工单列表该文档的核心论点是每个控制器只拥有自己的 DOM、订阅和异步展示生命周期不拥有数据投影或持久化操作。这一点在源码中体现为所有子面板都通过注入的 port 接口如PersonalChangesPanelPort、TeamChangesPanelPort、TicketListPanelOptions访问数据而非直接操作 Git 或网络。2. 所有权与生命周期Ownership and Lifetime2.1 CollabPanel只拥有项目选择不拥有数据规范第一条明确CollabPanel是selected-Project shell它拥有项目选择Project selection并向 Personal、Team、Ticket 三个面板传播 active/inactive 状态但不拥有它们的数据投影或持久化操作。在 CollabPanel.ts 中可以看到这一设计的落地构造器中CollabPanel implements CollabSidebarSurfaceController只维护active、destroyed、gitResolution等自身状态并通过options.port.subscribe订阅CollabFeatureState三个子面板以PersonalChangesPanel | null、TeamChangesPanel | null、TicketListPanel | null的形式作为可空字段持有在clearRoot()时统一销毁并置空状态订阅回调中只有一个轻量判断——只有当shellSignature(state)发生变化时才触发render()this.subscription options.port.subscribe(state { if (this.active this.shellSignature(state) ! this.shellStateSignature) { this.render(); } });shellSignature将error.code、lifecycle、projects与selectedProjectId序列化为 JSON 签名实现了对无关状态变更的去重渲染。2.2 显示/隐藏/销毁的三态语义规范对控制器生命周期给出了三态约定源码一一对应操作规范约定源码实现隐藏setActive(false)保留渲染树与订阅中止展示读取子面板setActive(false)内部取消在途任务inspectionTasks.cancel()/snapshotTasks.cancel()但不清除 DOM期间收到的失效被合并为一次refreshOnResume不变重激活setActive(true)不执行任何 Collab 读取CollabPanel.ts 的setActive中若shellSignature未变仅恢复各面板激活态PersonalChangesPanel.setActive(true)返回false表示无需刷新销毁destroy抑制陈旧完成、释放订阅destroy()将destroyed置真依次destroyPersonalPanel/Team/Ticket、subscription.dispose()、释放 vault 事件引用并移除根节点一个精巧的细节是激活时的刷新调度CollabPanel.setActive(true)会先让 Personal 面板尝试恢复刷新其返回值决定是否让 Team 面板补做刷新——this.teamPanel?.setActive(true, !personalRefreshScheduled)保证合并后的隐藏失效只触发一次恢复刷新而不是三个面板各刷一次。2.3 懒加载与预加载不是展示读取规范强调Lazy preload and foundation initialization are not presentation reads一旦进入admitted初始化会跨越可见性变化继续执行在选中提交selection commits之前保持 non-active并且除非控制器被销毁否则一直保留。对应实现有两层DeferredCollabSurfaceControllerDeferredCollabSurfaceController.tspreload()提前调用异步工厂create()构建真实控制器但只标记preloadRequested随后把this.active传给新建控制器的setActive——即加载完成但可见性未激活时不产生展示读取CollabPanel 自身preload()只触发startInitialization()解析 Git port.initialize()initialize()末尾有if (!this.destroyed this.active ...) this.render()守卫——若初始化完成时面板不可见就不渲染、不读取。2.4 三条独立的读取/取消通道规范禁止把 Personal、Team、Ticket 三个控制器合并成共享刷新任务也禁止用它们的任务作用域去做变更mutation。源码中每个面板各持有一个独立的LatestTaskScope来自 LatestTaskScopePersonalChangesPanel的inspectionTasks驱动inspectProjectTeamChangesPanel的snapshotTasks驱动readSnapshot另有TeamReviewLoader管理评审准备TicketListPanel的readTasks驱动listTickets。三者互不共享 Promise任一面板的取消不会影响其他面板在途的读取。3. 项目 ShellProject Shell行为3.1 空态与头部按钮顺序规范要求两种 Shell 形态无项目时onboarding 并排呈现 Create 与 Join 两个动作且不存在重复的 Add 按钮。CollabPanel.ts 的renderEmptyState()正是如此data-actionempty-create与data-actionjoin-project两个按钮并排没有任何 Add 菜单有选中项目时头部顺序固定为项目选择器 → Add 菜单 → 项目管理Create 与 Join 收敛进 Add 菜单showAddProjectMenu避免与空态的独立按钮语义重复。另一个硬约束是创建项目成功之前不得改变选择创建走CreateProjectModal只有onClosed回调后在this.active时才render()选择状态由底层port的状态机提交Shell 层从不提前改写selectedProjectId。3.2 项目选择回退fallback selection当state.selectedProjectId与实际有效项目 IDresolveEffectiveCollabProjectId解析出的结果不一致时renderFallbackProjectSelection进入回退态显示 loading 状态异步调用port.selectProject(projectId)修正选择失败则显示警告并提供 Retry 按钮。该过程用FallbackProjectSelectionStatepending/failed/projectId做幂等保护——相同项目的重复渲染不会重复发起选择且失败后会把shellStateSignature置空以打破签名相同就不重绘的短路。3.3 Retired 项目只用本地生命周期投影规范对 Retired已退役项目的约束很严格保持可见、不弹模态其 summary / retry / Keep / Delete 动作只使用本地生命周期投影Native Git 可用性与网络检查不得替代该投影清理失败时保持 Retired 并允许重试Keep/Delete 不等待自动确认也不宣称 Git-only 历史可恢复。renderRetiredProject()按project.cleanupStatus分支实现failed→ 显示告警文案 retry-retired-cleanup按钮调用port.retryProjectCleanup(projectId)pending/running→ 显示正在收尾清理的状态文本其他 → 渲染keep-files与delete-files两个终态按钮分别调用port.finalizeRetiredProject({ cleanupChoice, projectId })。注意入口守卫render()中若gitResolution.status ! available selectedProject?.lifecycle ! retired才渲染 Git 安装引导——即 Retired 项目在 Git 不可用时依然走本地投影展示不切换为 Git 设置面板与规范Native Git 可用性不得替代本地投影完全一致。runRetiredAction还保证了一个项目上只有一个动作处于 pendingif (this.retiredAction?.pending) return成功后清空动作态失败则标记failed并保留可重试。4. My Changes角色无关的个人变更投影PersonalChangesPanel.ts 是 role-neutral 的个人变更投影。规范的每一条约束都能在viewFromInspection()中找到对应只展示未发布或需要恢复的个人工作视图状态由inspection.personalChanges.action驱动PersonalChangesKind枚举包括awaiting-request、cancelled、clean、conflict、dirty、error、loading、offline、publishing、review标题与文件导航到精确的 working-tree reviewunpublishedReviewCollabWorkingTreeReview保留在 view state 中点击标题按钮或文件行时调用openWorkingTreeReview(path)若当前视图已过期workingTreeInspectionVersion workingTreeInvalidationVersion会先refresh()再打开确保 review 基于最新检查保留的恢复状态导航到精确详情页conflict状态携带conflictOperationIdreview状态携带publicationReview分别通过onOpenConflict/onOpenPublicationReview回调导航永不触发 Publish、不暴露 Get latest、不重构贡献安全性整个面板没有任何 publish 调用路径state.activeOperation?.kind publish仅用于把视图切换为publishing的展示状态——发布动作发生在别处Sidebar 只做投影不 stage、不 commit、不 fetch、不 reconcile、不打开凭据边界面板唯一的读取是port.inspectProject(projectId, { signal })所有 Git 事实来自注入端口返回的CollabProjectInspection个人文件列表是注入的 virtual-squash 工作结果changedFiles personal.unpublishedReview.files即使包含后续本地提交也不改写它们final-state review 基于 accepted-base 前进而非同文件重叠——这一判断发生在端口的检查逻辑中面板只是消费结果。面板还处理了一个微妙的角色区分当personal.action resolve-changes或review-and-publish时如果该请求属于当前成员自己ownRequestId存在视图退化为普通的dirty/clean自己的请求在 Team 面板里处理否则才呈现conflict或review的恢复入口。4.1 失效合并与防抖CollabPanel订阅了 vault 的modify/create/delete/rename事件CollabPanel.ts 的handleVaultPathChange当变更路径落在项目workspacePath内时调用personalPanel.invalidateWorkingTree()。后者以WORKING_TREE_REFRESH_DELAY_MS 200毫秒做防抖并在隐藏状态下不启动计时器、只置refreshOnResume——连续多次文件变更被合并为一次工作树刷新这就是规范中hidden invalidations coalesce into one resume refresh的实现。5. Team Changes单一开放请求列表TeamChangesPanel.ts 是所有角色的唯一开放请求列表包括当前 Member 自己的请求。关键约束每行就地展开expands in placetoggleRequest在行按钮下渲染claudian-collab-team-request-body负责精确的评审准备与变更文件选择selectedPath记录在ExpandedReviewState中请求检查是角色无关的只有 detail review 决定 Accept 是否可用面板渲染层不做角色判断Accept 能力由CollabRequestReview的 detail 视图决定侧边栏选中的请求文件即 detail 视图的当前文件目标或连续评审滚动目标onSelect直接把path传给onOpenFile(review, coordination, path)规范因此明确不要在 detail 里再添加一个变更文件导航器。排序与展示细节请求按updatedAt倒序当前成员显示ownMember文案coordination.stale时显示 stale 提示成员名从snapshot.members的映射中解析找不到则显示 unknown member。5.1 与 Personal 面板的快照协作CollabPanel把 Personal 面板的onInspection回调桥接到 Team 面板当个人检查成功且携带 coordination 时调用teamPanel.adoptSnapshot(coordination, ...)——复用同一次检查得到的协调快照避免 Team 面板重复发起readSnapshot若个人检查带resolve-changes冲突或review-and-publish评审且属于自己则以ownRequestActivity冲突操作 ID 或发布评审的形式传递Team 面板据此在对应请求行内联展示解决冲突按钮或发布评审文件列表。个人检查失败则退化为void this.teamPanel?.refresh()独立刷新。5.2 TeamReviewLoader原生评审准备的序列化与缓存失效TeamReviewLoader.ts 是规范单独点名的组件。它把prepareReview一次涉及 Git 的原生评审准备串行化为一条作业队列序列化pendingJobs队列 pump()保证同一时刻只有一个activeJob在执行port.prepareReviewselect(requestId)在用户切换展开行时中止非保留作业controller.abort()并让其以{ kind: stale }结束缓存标识reviewKey由collabReviewSourceKey(projectId, request, { currentMemberId, currentMemberRole, mainOid })生成——即项目/请求 OID、请求元数据、当前成员身份与角色共同构成缓存键。成员身份或角色变化含 Manager 职责转移会改变 key从而作废旧评审缓存不前进 ref 也能作废评审update()每次拿到新协调快照时重建sources凡缓存键与请求键不一致即删除缓存并cancelInvalidJobs()。注释与实现共同说明评论变更或 Manager 转移可以在mainOid不变的情况下让 key 变化触发缓存失效而无需任何 ref 前进结果完整性校验run()成功后还校验review.projectId、detail.request.id、detail.currentMainOid snapshot.project.mainOid、detail.reviewedHeadOid request.latestHeadOid任一不符返回error而非写入缓存prepared reviews 交接缓存可选注入的CollabPreparedReviewCache见 handoff 目录允许把已准备好的评审跨面板交接update()时对新键先查preparedReviews.readRequest命中缓存run()成功后回写preparedReviews.store。TeamChangesPanel侧用reviewIntentGeneration代际计数防止迟到的loadReview结果覆盖用户最新意图reconcileExpandedRequest在每次快照应用后校正展开行请求消失则折叠缓存键变化则重取缓存命中则直接恢复 ready 状态。6. Tickets最小化的工单列表面板TicketListPanel.ts 严格遵循规范的最小集合只有 Open/Closed 过滤器、Add 动作、分页行、详情导航不承载工单表单、正文、评论、关联或状态变更——这些都在别处模态/详情页完成。分页listTickets({ projectId, status, cursor? })返回page.tickets与nextCursor有游标时渲染load-more-tickets按钮加载失败可重试按钮恢复可用并显示错误行listRevision计数保证过期的分页结果不写入 DOM缓存/过期行标记只读并禁用 AddreadOnly来源有三条——列表结果stale、快照source cache || stale、或项目connectionStatus ! connected只读时显示 offline 提示并把 Add 按钮disabled失败读取可用新鲜协调快照区分已知为空与加载失败hasFreshEmptyOpenSnapshot()只在当前过滤为open、快照source online、!stale且openTicketCount 0时返回空态文案否则显示 loadFailed——这正是规范用 fresh coordination snapshot 区分已知空列表与加载失败的实现焦点同步可选的TicketFocusPortread()/subscribe让打开的工单详情反向高亮列表中的行aria-currenttruesyncFocusedTicket在渲染与打开回调后各执行一次。7. Git 前置条件GitSetupPanel侧边栏初始化先解析 Gitoptions.resolveGit(false)或注入的initialGitResolution失败则整个 Shell 停留在GitSetupPanel。GitSetupPanel.ts 定义了三种解析结果export type GitSetupResolution | { readonly status: available; readonly version: string } | { readonly status: incompatible; readonly missingCapabilities: readonly string[] } | { readonly status: missing };面板能力包括显示缺失/不兼容状态不兼容时列出missingCapabilities、重新扫描按钮onRescan、手动 Git 路径输入与保存onSaveConfiguredPath以及按平台win32/darwin/linux生成面向 AI Agent 的安装提示词要求安装 Native Git 2.38、不改动全局 Git 身份与凭据设置、用git --version验证并回报可执行文件路径提示词提供一键复制。CollabPanel侧的衔接逻辑是扫描结果变为available后才调用port.initialize()进入协作状态机初始化异常会把gitResolution降级为{ status: missing }并渲染安装引导用户修好 Git 后可随时重试。8. 行为验证测试如何覆盖规范清单规范最后的 Verification 一节列出了必须通过 fake ports 覆盖的行为清单懒构建、非激活预加载、隐藏失效合并、不变重激活、项目切换、陈旧完成抑制、按面板取消、订阅释放、Team 评审序列化、Ticket 分页/只读行为。仓库在 tests/unit/features/collab/sidebar 下提供了逐文件对应的单元测试CollabPanel.test.ts —— Shell 生命周期、项目切换、Git 解析与 Retired 动作DeferredCollabSurfaceController.test.ts —— 懒构建与非激活预加载PersonalChangesPanel.test.ts —— 隐藏失效合并、不变重激活、陈旧完成抑制、按面板取消TeamChangesPanel.test.ts 与 TeamReviewLoader.test.ts —— 快照桥接、缓存键失效、评审准备序列化TicketListPanel.test.ts —— 分页与只读/离线行为GitSetupPanel.test.ts —— 平台安装支持文案与路径保存。这些测试统一通过假端口fake ports驱动验证的是面板层的展示生命周期契约而非底层 Git 行为与面板不拥有持久化操作的所有权划分相呼应。9. 小结Collab Sidebar 的设计可以用文档的几句话概括Shell 只管选择与传播面板只管展示与生命周期数据与持久化永远来自注入端口。这套划分带来了几个可验证的工程性质——隐藏不丢 DOM、重激活零读取、失效合并为一次刷新、陈旧完成静默丢弃、评审准备严格串行且缓存键含身份语义、Retired 项目不依赖 Git/网络做投影。对于需要构建多面板共享状态源 各自异步读取的 Obsidian 插件开发者src/features/collab/sidebar 下的这套控制器所有权 LatestTaskScope 取消 代际计数防陈旧的模式以及配套规范文档 AGENTS.md 与 CLAUDE.md是一个完整可参照的实现样本。【免费下载链接】claudianAn Obsidian plugin that embeds Claude Code/Codex as an AI collaborator in your vault项目地址: https://gitcode.com/GitHub_Trending/cl/claudian创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。