主题
工作区与会话管理
本文引用的源码文件
本文引用的文件
- src/side_panel/workspace-manager.js
- src/side_panel/workspace-panel.js
- src/side_panel/session-manager.js
- src/side_panel/session-manager-ui.js
- src/storage/session-store.js
- src/side_panel/state.js
- agent/src/directory-picker.js
- agent/src/server.js
- agent/test/unit/directory-picker.unit.test.js
- docs/en/DOCUMENTATION.md
更新摘要
变更内容
- 新增“浏览…”按钮,用于本地代理集成下的原生目录选择框功能
- 实现跨平台系统原生目录选择器(macOS osascript、Windows PowerShell FolderBrowserDialog、Linux zenity/kdialog)
- 添加安全验证机制:仅允许本机回环地址访问目录选择 API,远端请求返回 available:false
- 完善国际化支持:新增 workspace.browseBtn、browseUnavailable、browseFailedWithError、picking 等翻译键
- 增强工作区切换对话框的用户体验,支持从允许目录列表中选择或手动输入路径
目录
引言
本文面向"工作区与会话管理"这一主题,围绕以下目标展开:
- 解释工作区概念:项目隔离、配置共享、资源管理与 Agent 连接。
- 说明会话管理器:会话创建、状态持久化、并发控制与 UI 交互。
- 描述工作区面板的界面行为:树形浏览、文件操作、预览与反馈。
- 描述会话管理界面:会话列表、状态监控、批量操作。
- 给出代码级示例路径,展示如何创建工作区、管理多会话生命周期。
- 说明数据同步机制:本地 IndexedDB、chrome.storage 兜底、归档与备份导入导出。
- 说明权限与安全边界:Agent 配对、允许目录、删除回收站语义。
- 总结性能策略:流式下载、虚拟滚动、增量保存、并发切换等。
本项目为双进程架构:Chrome 扩展端(Manifest V3,版本 2.3.1)+ 独立本地代理端 Agent(Node.js,版本 2.3.1)。扩展端通过 HTTP/WebSocket 调用 Agent 的文件系统、命令执行、长期记忆与 RAG 能力;Agent 源码修改后需重启进程接口才生效。
章节来源
项目结构
与工作区和会话相关的主要代码位于 side panel 层和 storage 层:
src/side_panel/workspace-manager.js:工作区 API 封装,负责与 Agent 通信、路径缓存、文件读写与下载。src/side_panel/workspace-panel.js:工作区面板 UI,包含目录导航、多选、上传/下载、预览、重命名、移动、删除等。src/side_panel/session-manager.js:会话管理对外 API,转发到存储层并维护"完成待查看"标记。src/side_panel/session-manager-ui.js:会话标签栏 UI,渲染会话列表、搜索、拖拽排序、批量关闭、分叉复制等。src/storage/session-store.js:IndexedDB 会话存储适配器,提供会话 CRUD、归档、恢复、复制、定时任务宿主会话等。src/side_panel/state.js:全局状态,包括活跃会话、消息历史、生成状态、Agent 信息等。agent/src/directory-picker.js:系统原生目录选择器实现,支持跨平台目录选择。agent/src/server.js:Agent 服务器,提供目录选择 API 和安全门控。
graph TB subgraph "Side Panel" WP["workspace-panel.js<br/>工作区面板 UI"] WM["workspace-manager.js<br/>工作区 API"] SMUI["session-manager-ui.js<br/>会话标签栏 UI"] SM["session-manager.js<br/>会话管理 API"] ST["state.js<br/>全局状态"] end subgraph "Storage" SS["session-store.js<br/>IndexedDB 会话存储"] end subgraph "Agent 本地代理" AG["Agent HTTP API<br/>/api/fs/* /api/config/* /api/status/*"] DP["directory-picker.js<br/>原生目录选择器"] SV["server.js<br/>API 路由与安全门控"] end WP --> WM WM --> AG SMUI --> SM SM --> SS SMUI --> ST SM --> ST SS --> ST AG --> DP AG --> SV
图表来源
- src/side_panel/workspace-panel.js#L1-L27
- src/side_panel/workspace-manager.js#L1-L24
- src/side_panel/session-manager-ui.js#L1-L23
- src/side_panel/session-manager.js#L1-L10
- src/storage/session-store.js#L1-L10
- src/side_panel/state.js#L1-L10
- agent/src/directory-picker.js#L1-L135
- agent/src/server.js#L987-L1010
章节来源
- src/side_panel/workspace-panel.js#L1-L27
- src/side_panel/workspace-manager.js#L1-L24
- src/side_panel/session-manager-ui.js#L1-L23
- src/side_panel/session-manager.js#L1-L10
- src/storage/session-store.js#L1-L10
- src/side_panel/state.js#L1-L10
- agent/src/directory-picker.js#L1-L135
- agent/src/server.js#L987-L1010
核心组件
本节从职责边界角度梳理关键模块:
工作区管理器(workspace-manager.js)
- 负责获取 Agent 配置、工作目录根路径、家目录、状态详情。
- 封装文件系统操作:列出目录、读取/写入内容、删除、重命名、创建目录、移动、统计信息。
- 封装下载能力:单文件/批量下载、带进度流式下载、取消支持。
- 新增:pickDirectory() 函数,调用 Agent 的 /api/config/pick-directory 接口进行原生目录选择。
- 提供远程搜索、MIME 类型判断、预览类型分类、文件大小/时间格式化等工具函数。
- 对 Agent 不可达进行降级日志处理,避免控制台噪音。
工作区面板(workspace-panel.js)
- 初始化浮窗/嵌入双模式面板,绑定事件、渲染面包屑、工具栏、文件列表、预览遮罩层。
- 实现目录导航、排序、全选/多选、批量下载 ZIP、批量删除、重命名、新建文件夹、移动。
- 集成文件预览:文本、Markdown、PDF、Excel、PPTX、图片、视频、音频等。
- 支持上传、拖拽移动、键盘导航、上下文问答附件。
- 已更新:增强了文件列表点击交互逻辑,改进了虚拟滚动支持和焦点管理机制。
- 新增:工作区切换对话框中的"浏览…"按钮,仅在本地代理时显示,调用原生目录选择器。
会话管理器(session-manager.js)
- 暴露会话创建、加载、保存、切换、删除、重命名、排序、归档、恢复、导入、追加消息、复制会话等 API。
- 维护"完成待查看"会话集合,持久化到 chrome.storage.local,并在 UI 上显示提示。
会话管理 UI(session-manager-ui.js)
- 渲染会话标签栏、下拉列表、分组标题(今天/昨天/近 7 天/更早)、搜索过滤。
- 支持拖拽排序、右键菜单、中键关闭、批量关闭、按组关闭、会话分叉复制。
- 与 session-manager.js 解耦,通过 DOM 事件通知上层。
会话存储(session-store.js)
- 基于 IndexedDB 的会话持久化,兼容旧 chrome.storage 迁移。
- 提供会话列表加载、当前会话保存、切换、删除、归档、恢复、复制、定时任务宿主会话等。
- 清理 ReAct checkpoint、书签、scrollPosition 等关联数据。
全局状态(state.js)
- 集中管理活跃会话 ID、消息历史、模型参数、工具开关、Agent 信息等。
- 通过 getter/setter 代理默认导出对象,保证多种 import 方式共享同一份数据。
原生目录选择器(directory-picker.js)
- 新增:跨平台系统原生目录选择器实现。
- 支持 macOS (osascript)、Windows (PowerShell FolderBrowserDialog)、Linux (zenity/kdialog)。
- 提供 buildPickCommand() 和 pickDirectoryNative() 两个主要函数。
- 包含超时保护、错误处理、路径规范化等功能。
Agent 服务器(server.js)
- 新增:/api/config/pick-directory 路由,提供目录选择 API。
- 实现安全门控:仅允许本机回环地址访问,远端请求返回 available:false。
- 集成 directory-picker.js 实现原生目录选择功能。
章节来源
- src/side_panel/workspace-manager.js#L1-L617
- src/side_panel/workspace-panel.js#L1-L800
- src/side_panel/session-manager.js#L1-L178
- src/side_panel/session-manager-ui.js#L1-L800
- src/storage/session-store.js#L1-L662
- src/side_panel/state.js#L1-L348
- agent/src/directory-picker.js#L1-L135
- agent/src/server.js#L987-L1010
架构总览
工作区与会话管理的整体流程如下:
sequenceDiagram
participant User as "用户"
participant WP as "工作区面板<br/>workspace-panel.js"
participant WM as "工作区管理器<br/>workspace-manager.js"
participant AG as "Agent 本地代理"
participant DP as "目录选择器<br/>directory-picker.js"
participant SV as "服务器<br/>server.js"
participant SMUI as "会话标签栏 UI<br/>session-manager-ui.js"
participant SM as "会话管理器<br/>session-manager.js"
participant SS as "会话存储<br/>session-store.js"
participant ST as "全局状态<br/>state.js"
User->>WP : 打开工作区面板
WP->>WM : getWorkspaceRoot()
WM->>AG : GET /api/status/detail
AG-->>WM : {workdir, homeDir}
WM-->>WP : workdir
User->>WP : 点击切换工作目录
WP->>WM : pickDirectory()
WM->>AG : POST /api/config/pick-directory
AG->>SV : 安全检查 (localhost only)
SV->>DP : pickDirectoryNative()
DP-->>SV : {success, path, available}
SV-->>WM : 目录选择结果
WM-->>WP : 填充路径输入框
User->>WP : 确认切换
WP->>WM : switchWorkspace(newPath)
WM->>AG : POST /api/config/workdir
AG-->>WM : 切换结果
WM-->>WP : 刷新工作区
User->>SMUI : 点击新建会话
SMUI->>SM : createSession()
SM->>SS : createSession()
SS->>SS : IndexedDB putSession + setActiveSessionId
SS-->>SM : newSession
SM-->>SMUI : newSession
SMUI->>ST : state.activeSessionId = newSession.id
SMUI->>SMUI : renderSessionTabs()
图表来源
- src/side_panel/workspace-panel.js#L6064-L6250
- src/side_panel/workspace-manager.js#L322-L324
- agent/src/server.js#L987-L1010
- agent/src/directory-picker.js#L104-L135
- src/side_panel/session-manager-ui.js#L304-L317
- src/side_panel/session-manager.js#L99-L102
- src/storage/session-store.js#L184-L208
- src/side_panel/state.js#L161-L176
详细组件分析
工作区管理器(workspace-manager.js)
工作区管理器是扩展端与 Agent 之间的桥梁,承担以下职责:
- 获取 Agent 配置:从 chrome.storage.local 读取 pairedAgents 与 activeAgentId,构造 URL 与 token。
- 探测工作目录与家目录:调用 /api/status/detail,缓存 workdir 与 homeDir。
- 切换工作目录:调用 /api/config/workdir,成功后重置本地缓存。
- 文件系统操作:listDirectory、readFileContent、writeFileContent、deleteFs、renameFs、createDir、moveFs、getFileInfo。
- 下载能力:downloadFileStream、downloadFilesStream、downloadFileStreamWithProgress、downloadFilesStreamWithProgress,支持 AbortSignal 取消。
- 新增:pickDirectory() 函数,调用 /api/config/pick-directory 接口进行原生目录选择。
- 远程搜索:searchFilesRemote,后端递归搜索,前端统一归一化路径。
- 错误处理:isAgentUnreachableError 与 logProbeFailure 将网络失败降为 debug,避免控制台噪音。
flowchart TD
Start(["调用 agentRequest"]) --> GetConfig["读取 Agent 配置<br/>pairedAgents + activeAgentId"]
GetConfig --> HasConfig{"是否已配对?"}
HasConfig --> |否| ReturnNotPaired["返回未配对错误"]
HasConfig --> |是| Fetch["POST /api/... with Authorization Bearer"]
Fetch --> RespOk{"响应成功?"}
RespOk --> |否| ParseErr["解析 JSON 或返回错误"]
RespOk --> |是| ReturnData["返回业务数据"]
ParseErr --> ReturnData
ReturnNotPaired --> End(["结束"])
ReturnData --> End
图表来源
章节来源
- src/side_panel/workspace-manager.js#L194-L209
- src/side_panel/workspace-manager.js#L214-L258
- src/side_panel/workspace-manager.js#L298-L305
- src/side_panel/workspace-manager.js#L341-L357
- src/side_panel/workspace-manager.js#L424-L498
- src/side_panel/workspace-manager.js#L581-L616
- src/side_panel/workspace-manager.js#L322-L324
工作区面板(workspace-panel.js)
工作区面板负责呈现目录树、文件列表、预览与操作反馈:
- 初始化面板容器、按钮、面包屑、工具栏、文件头、内容区域、预览遮罩层。
- 绑定事件:切换面板、切换工作目录、返回上级、刷新、上传、新建文件夹、问答附件、批量下载、批量删除、搜索、排序、全选、键盘导航、拖拽移动。
- 文件预览:根据扩展名判断预览类型,支持 Markdown、PDF、Excel、PPTX、图片、视频、音频、HTML 源码与渲染预览。
- 大文件处理:超过阈值时提示直接下载或在浏览器中打开。
- 下载进度:使用 ReadableStream 读取 chunk,计算 loaded/total/percent,支持取消。
- 上传与移动:支持拖拽移动至目标目录,移动前校验不能移动到子目录。
- 删除确认:区分文件与目录,提示可恢复至回收站(7 天后自动清理)。
已更新:增强了文件列表点击交互逻辑,改进了虚拟滚动支持和焦点管理机制。现在 handleFileListClick 函数能够正确处理虚拟滚动和非虚拟滚动两种场景,使用条件逻辑计算正确的全局索引以确保焦点管理的准确性。
新增:工作区切换对话框中的"浏览…"按钮功能。当检测到本地代理(localhost/127.0.0.1/[::1])时,显示浏览按钮,点击后调用原生目录选择器,将选中的路径填入输入框。
sequenceDiagram
participant User as "用户"
participant WP as "workspace-panel.js"
participant WM as "workspace-manager.js"
participant AG as "Agent"
User->>WP : 双击文件
WP->>WM : supportsPreview/getPreviewType
alt 文本/代码/HTML
WP->>WM : readFileContent(filePath)
WM->>AG : POST /api/fs/read
AG-->>WM : content
WM-->>WP : text/html
WP->>WP : 渲染源码/渲染预览
else PDF/Excel/PPTX/图片/音视频
WP->>WM : downloadFileStreamWithProgress(filePath, onProgress)
WM->>AG : POST /api/fs/download-stream
AG-->>WM : Blob + headers
WM-->>WP : blob/name/mimeType
WP->>WP : 渲染媒体/表格/文档
end
User->>WP : 点击切换工作目录
WP->>WP : 检测本地代理
alt 本地代理
WP->>WM : pickDirectory()
WM->>AG : POST /api/config/pick-directory
AG-->>WM : {success, path, available}
WM-->>WP : 填充路径输入框
else 非本地代理
WP->>WP : 隐藏浏览按钮
end
图表来源
- src/side_panel/workspace-panel.js#L539-L756
- src/side_panel/workspace-panel.js#L6064-L6250
- src/side_panel/workspace-manager.js#L87-L127
- src/side_panel/workspace-manager.js#L424-L498
- src/side_panel/workspace-manager.js#L322-L324
章节来源
- src/side_panel/workspace-panel.js#L539-L756
- src/side_panel/workspace-panel.js#L902-L930
- src/side_panel/workspace-panel.js#L481-L523
- src/side_panel/workspace-panel.js#L6064-L6250
原生目录选择器(directory-picker.js)
新增组件:系统原生目录选择器,提供跨平台的目录选择功能。
主要功能
- buildPickCommand(title, platform):根据操作系统构造相应的目录选择命令
- macOS:使用 osascript 调用 choose folder
- Windows:使用 PowerShell FolderBrowserDialog
- Linux:优先使用 zenity,回退到 kdialog
- pickDirectoryNative(title, options):执行目录选择,返回标准化结果
- 支持超时保护(120秒默认超时)
- 处理用户取消、无 GUI 环境、命令不可用等情况
- 返回统一的结果格式:
安全特性
- 标题参数经过安全清理,防止脚本注入
- 所有命令以参数数组形式传入,避免 shell 注入
- Windows 使用 base64 编码的 UTF-16LE 脚本,避免命令行转义问题
flowchart TD
Start(["pickDirectoryNative()"]) --> CheckDisplay{"检查图形界面环境"}
CheckDisplay --> |Linux无DISPLAY| ReturnNoGUI["返回 available:false"]
CheckDisplay --> |有GUI| BuildCmd["buildPickCommand()"]
BuildCmd --> RunCmd["spawn 子进程执行命令"]
RunCmd --> Timeout{"超时保护(120s)"}
Timeout --> |超时| KillProcess["kill 子进程"]
KillProcess --> ReturnTimeout["返回 timeout 错误"]
Timeout --> |正常| CollectOutput["收集 stdout 输出"]
CollectOutput --> Normalize["normalizePickedPath()"]
Normalize --> Validate{"路径有效?"}
Validate --> |是| ReturnSuccess["返回 {success:true, path}"]
Validate --> |否| ReturnCancel["返回 {success:true, path:null}"]
ReturnNoGUI --> End(["结束"])
ReturnTimeout --> End
ReturnSuccess --> End
ReturnCancel --> End
图表来源
- agent/src/directory-picker.js#L104-L135
- agent/src/directory-picker.js#L15-L52
- agent/src/directory-picker.js#L54-L92
章节来源
Agent 服务器目录选择 API(server.js)
新增功能:/api/config/pick-directory 路由,提供安全的目录选择 API。
安全门控
- 仅允许本机回环地址访问:127.0.0.1、::1、::ffff:127.0.0.1、localhost
- 远端请求返回 available:false,扩展端据此隐藏浏览按钮
- 记录安全日志:logSecurity('pick_directory_remote_blocked', ...)
错误处理
- 捕获目录选择过程中的异常,返回结构化错误信息
- 记录系统日志:logSystem('directory_picked', ...)
- 超时保护:子进程悬挂时自动终止
flowchart TD
Request["POST /api/config/pick-directory"] --> CheckIP["检查来源 IP"]
CheckIP --> IsLocal{"是否本机地址?"}
IsLocal --> |否| Block["返回 available:false"]
IsLocal --> |是| Execute["执行 pickDirectoryNative()"]
Execute --> Success{"选择成功?"}
Success --> |是| LogSuccess["记录日志"]
LogSuccess --> ReturnSuccess["返回 {success:true, path}"]
Success --> |否| HandleError["处理错误"]
HandleError --> ReturnError["返回 {success:false, error}"]
Block --> End(["结束"])
ReturnSuccess --> End
ReturnError --> End
图表来源
章节来源
虚拟滚动与焦点管理增强
新增功能:工作区面板现在具备增强的虚拟滚动支持和改进的焦点管理机制。
虚拟滚动实现
- 当文件项超过阈值(VIRTUAL_SCROLL_THRESHOLD)时自动启用虚拟滚动
- 仅渲染可视区域 + 缓冲区的文件项,大幅提升大数据集性能
- 动态测量实际行高,修正估算值以提高渲染精度
- 智能滚动位置计算,避免不必要的 DOM 重建
焦点管理改进
- 在 handleFileListClick 函数中添加了条件逻辑来处理虚拟滚动和非虚拟滚动场景
- 虚拟滚动模式下:通过 virtualScrollState.sorted.findIndex 查找全局索引
- 非虚拟滚动模式下:直接使用 items.indexOf 获取相对索引
- 确保 focusedIndex 始终为全局绝对下标,避免 updateFocusVisual 计算错误
flowchart TD
Click["文件列表点击"] --> CheckVirtual{"是否虚拟滚动模式?"}
CheckVirtual --> |是| FindGlobalIdx["virtualScrollState.sorted.findIndex<br/>查找全局索引"]
CheckVirtual --> |否| FindRelIdx["items.indexOf<br/>获取相对索引"]
FindGlobalIdx --> UpdateFocus["更新 focusedIndex<br/>调用 updateFocusVisual"]
FindRelIdx --> UpdateFocus
UpdateFocus --> ApplyVisual["应用视觉焦点样式"]
ApplyVisual --> ScrollIfNeeded{"需要滚动到可视区域?"}
ScrollIfNeeded --> |是| AutoScroll["自动滚动到目标位置"]
ScrollIfNeeded --> |否| Complete["完成"]
AutoScroll --> Complete
图表来源
章节来源
会话管理器(session-manager.js)
会话管理器作为对外 API,屏蔽底层存储细节:
- 恢复 completedSessionIds:从 chrome.storage.local 读取,用于刷新后仍显示"完成待查看"。
- 标记完成/清除完成:仅对非活跃会话标记,避免重复写入,触发 UI 更新事件。
- 会话 CRUD:loadSessions、saveSessions、saveCurrentSession、createSession、switchToSession、deleteSession、renameSession、reorderSessions、archiveCurrentSession、restoreArchivedSession、importSessions、appendMessageToSession、duplicateSession。
- 与 session-store.js 完全解耦,保持 API 兼容。
classDiagram
class SessionManager {
+restoreCompletedSessions()
+markSessionCompleted(sessionId)
+clearSessionCompleted(sessionId)
+generateSessionId()
+loadSessions()
+saveSessions(sessionsData)
+saveCurrentSession()
+createSession()
+switchToSession(sessionId)
+deleteSession(sessionId)
+renameSession(sessionId, newTitle)
+reorderSessions(orderedIds)
+archiveCurrentSession()
+restoreArchivedSession(archivedId)
+importSessions(sessionsData)
+appendMessageToSession(sessionId, message)
+duplicateSession(sourceSessionId, upToMessageId)
}
class SessionStore {
+init()
+loadSessions()
+saveSessions(sessionsData)
+saveCurrentSession()
+createSession()
+switchToSession(sessionId)
+deleteStoreSession(sessionId)
+renameSession(sessionId, newTitle)
+reorderSessions(orderedIds)
+archiveCurrentSession()
+restoreArchivedSession(archivedId)
+importSessions(sessionsData)
+appendMessageToSession(sessionId, message)
+duplicateSession(sourceSessionId, upToMessageId)
}
SessionManager --> SessionStore : "委托"
图表来源
章节来源
会话管理 UI(session-manager-ui.js)
会话标签栏 UI 负责会话列表的可视化与交互:
- 渲染会话标签:标题、关闭按钮、生成中指示器、完成待查看指示器。
- 会话切换:乐观高亮,防连点,异常时回滚高亮。
- 更多按钮与下拉面板:分组标题(今天/昨天/近 7 天/更早),搜索过滤,键盘导航。
- 批量操作:关闭全部、按组关闭、删除单个会话。
- 拖拽排序:dragstart/dragover/dragleave/drop/dragend,持久化 order。
- 会话分叉:复制源会话的消息历史与配置,自动生成新会话并激活。
sequenceDiagram participant User as "用户" participant SMUI as "session-manager-ui.js" participant SM as "session-manager.js" participant SS as "session-store.js" participant ST as "state.js" User->>SMUI : 点击新建会话 SMUI->>SM : saveCurrentSession() SM->>SS : saveCurrentSession() SMUI->>SM : createSession() SM->>SS : createSession() SS-->>SM : newSession SM-->>SMUI : newSession SMUI->>ST : state.activeSessionId = newSession.id SMUI->>SMUI : renderSessionTabs()
图表来源
- src/side_panel/session-manager-ui.js#L304-L317
- src/side_panel/session-manager.js#L99-L102
- src/storage/session-store.js#L184-L208
- src/side_panel/state.js#L161-L176
章节来源
- src/side_panel/session-manager-ui.js#L162-L286
- src/side_panel/session-manager-ui.js#L304-L317
- src/side_panel/session-manager-ui.js#L390-L409
- src/side_panel/session-manager-ui.js#L525-L693
会话存储(session-store.js)
会话存储是持久化核心,基于 IndexedDB:
- 初始化与迁移:ensureMigration,清理孤儿 scrollPosition key。
- 会话列表加载:getAllSessions + getActiveSessionId,按 order 排序。
- 当前会话保存:合并 state 中的模型、工具、Agent、温度、topP、上下文压缩记录、消息历史。
- 切换会话:并发保存当前会话与读取目标会话,恢复 state 与 Agent 配置。
- 删除会话:清理 ReAct checkpoint、书签、scrollPosition,就近激活下一个会话。
- 归档与恢复:最多保留 20 个归档,恢复时创建新活跃会话。
- 复制会话:完整复制或消息级截断,重新生成 messageId,记录 forkMetadata。
- 定时任务宿主会话:为 scheduledTaskId 创建专属宿主会话。
flowchart TD Switch["switchToSession(sessionId)"] --> SaveCurrent["saveCurrentSession()"] Switch --> LoadTarget["idb.getSession(sessionId)"] SaveCurrent --> SetActive["idb.setActiveSessionId(sessionId)"] LoadTarget --> SetState["state.activeSessionId/messageHistory/compaction/model/temperature/topP/tools/agentId"] SetActive --> ApplyAgent["加载 Agent 配置并触发 agent-model-changed"] ApplyAgent --> CleanupGen["清理过期 isGenerating 标记"] CleanupGen --> Return["返回 targetSession"]
图表来源
章节来源
- src/storage/session-store.js#L47-L54
- src/storage/session-store.js#L85-L113
- src/storage/session-store.js#L129-L178
- src/storage/session-store.js#L302-L389
- src/storage/session-store.js#L394-L442
- src/storage/session-store.js#L480-L564
- src/storage/session-store.js#L574-L627
依赖关系分析
工作区与会话管理的依赖关系如下:
graph LR WP["workspace-panel.js"] --> WM["workspace-manager.js"] WM --> CHROME["chrome.storage.local"] WM --> AGENT["Agent HTTP API"] AGENT --> DIRPICKER["directory-picker.js"] AGENT --> SERVER["server.js"] SMUI["session-manager-ui.js"] --> SM["session-manager.js"] SM --> SS["session-store.js"] SS --> IDB["IndexedDB"] SMUI --> ST["state.js"] SM --> ST
- workspace-panel.js 依赖 workspace-manager.js 提供的文件系统与下载 API。
- workspace-manager.js 依赖 chrome.storage.local 获取 Agent 配置,依赖 Agent HTTP API 执行文件操作。
- 新增:workspace-manager.js 新增 pickDirectory() 方法,调用 Agent 的 /api/config/pick-directory 接口。
- 新增:Agent server.js 依赖 directory-picker.js 实现原生目录选择功能。
- session-manager-ui.js 依赖 session-manager.js 的会话 API,并通过 state.js 更新 UI 状态。
- session-manager.js 依赖 session-store.js 的持久化 API。
- session-store.js 依赖 IndexedDB 与 chrome.storage.local(兜底与迁移)。
图表来源
- src/side_panel/workspace-panel.js#L1-L27
- src/side_panel/workspace-manager.js#L194-L209
- src/side_panel/workspace-manager.js#L322-L324
- agent/src/server.js#L57
- agent/src/server.js#L987-L1010
- agent/src/directory-picker.js#L1-135
- src/side_panel/session-manager-ui.js#L1-L23
- src/side_panel/session-manager.js#L1-L10
- src/storage/session-store.js#L1-L10
章节来源
- src/side_panel/workspace-panel.js#L1-L27
- src/side_panel/workspace-manager.js#L194-L209
- src/side_panel/workspace-manager.js#L322-L324
- agent/src/server.js#L57
- agent/src/server.js#L987-L1010
- agent/src/directory-picker.js#L1-135
- src/side_panel/session-manager-ui.js#L1-L23
- src/side_panel/session-manager.js#L1-L10
- src/storage/session-store.js#L1-L10
性能与优化
- 流式下载:workspace-manager.js 使用 ReadableStream 读取 chunk,计算进度,支持 AbortController 取消,避免 base64 膨胀。
- 虚拟滚动:当文件项超过阈值时自动启用虚拟滚动,仅渲染可见区域,大幅优化大目录性能。虚拟滚动状态管理包括 sorted 数组、itemHeight 测量、滚动位置跟踪等。
- 增强的焦点管理:handleFileListClick 函数现在正确处理虚拟滚动和非虚拟滚动场景,确保键盘导航和焦点状态的准确性。
- 原生目录选择优化:directory-picker.js 实现跨平台目录选择,支持超时保护(120秒)、命令回退机制(Linux zenity→kdialog)、路径规范化处理。
- 目录缓存:文档提到 LRU 缓存最近 20 个目录(30s TTL),避免重复请求;同时 Agent 切换时自动重置缓存。
- 并发切换:session-store.js 在 switchToSession 中并发保存当前会话与读取目标会话,减少切换延迟。
- 按需加载:workspace-panel.js 对 pdfjs-dist、mammoth、pptx-to-html 等重型库采用动态加载,避免首屏阻塞。
- 预览优化:workspace-panel.js 对 HTML 预览使用 iframe sandbox,避免双层滚动条;对大文件限制内置预览,引导下载。
章节来源
- src/side_panel/workspace-manager.js#L424-L498
- docs/en/DOCUMENTATION.md#L587-L600
- src/storage/session-store.js#L302-L389
- src/side_panel/workspace-panel.js#L21-L23
- src/side_panel/workspace-panel.js#L1430-L1650
- src/side_panel/workspace-panel.js#L1757-L1784
- agent/src/directory-picker.js#L104-L135
故障排查
- Agent 未配对:workspace-manager.js 在 getAgentConfig 失败时返回 null,UI 应提示"Agent 未配对",引导用户在设置中完成配对。
- Agent 不可达:workspace-manager.js 将网络错误降为 debug 日志,避免控制台噪音;UI 应显示"Agent 未连接"提示。
- 工作目录获取失败:getWorkspaceRoot 失败时返回 null,UI 应提示"无法获取工作目录,请确认 Agent 已连接"。
- 下载失败:downloadFileStreamWithProgress 返回 error 字段,UI 应显示"下载失败"或具体错误信息。
- 会话切换失败:session-manager-ui.js 在切换异常时回滚高亮,并重新渲染会话标签栏。
- 会话存储异常:session-store.js 在 deleteStoreSession 中清理 ReAct checkpoint、书签、scrollPosition,避免脏数据残留。
- 虚拟滚动焦点问题:如果虚拟滚动模式下焦点管理出现异常,检查 handleFileListClick 中的索引计算逻辑是否正确处理了 virtualScrollState 条件分支。
- 目录选择失败:
- 检查 Agent 是否为本地代理(localhost/127.0.0.1/[::1]),非本地代理会返回 available:false
- 检查系统是否安装了必要的目录选择工具(macOS osascript、Windows PowerShell、Linux zenity/kdialog)
- 检查是否有图形界面环境(Linux DISPLAY/WAYLAND_DISPLAY 环境变量)
- 检查超时设置(默认120秒),长时间不选择会自动终止
- 安全门控问题:远端请求被拒绝时,检查 server.js 中的 IP 白名单逻辑是否正确配置。
章节来源
- src/side_panel/workspace-manager.js#L194-L209
- src/side_panel/workspace-manager.js#L214-L258
- src/side_panel/workspace-manager.js#L424-L498
- src/side_panel/session-manager-ui.js#L227-L245
- src/storage/session-store.js#L394-L442
- src/side_panel/workspace-panel.js#L1757-L1784
- agent/src/server.js#L987-L1010
- agent/src/directory-picker.js#L104-L135
结论
工作区与会话管理在本项目中形成了清晰的职责分层:
- 工作区管理器负责与 Agent 通信,封装文件系统与下载能力。最新增强:新增原生目录选择功能,支持跨平台系统目录选择器。
- 工作区面板负责用户交互,提供目录浏览、文件操作、预览与反馈。最新增强:改进了虚拟滚动支持和焦点管理机制,新增了"浏览…"按钮和本地代理集成。
- 会话管理器提供统一的会话 API,屏蔽存储细节。
- 会话管理 UI 负责会话列表的可视化与批量操作。
- 会话存储基于 IndexedDB,提供持久化、归档、恢复、复制等能力。
- 全局状态集中管理活跃会话、消息历史、Agent 信息等。
- 新增:原生目录选择器提供跨平台系统级目录选择功能,支持 macOS、Windows、Linux 三大平台。
- 新增:Agent 服务器提供安全的目录选择 API,包含 IP 白名单安全门控。
通过流式下载、虚拟滚动、并发切换、按需加载等优化策略,系统在大数据集与多会话场景下保持了较好的性能与用户体验。最新的虚拟滚动和焦点管理增强进一步提升了文件列表的交互体验,特别是在处理大量文件时的性能和可用性方面有了显著改善。新增的原生目录选择功能为用户提供了更直观的目录选择方式,特别是在本地代理环境下,可以直接调用系统原生目录选择器,提升用户体验。权限方面,通过 Agent 配对、允许目录、删除回收站语义等机制,确保了安全边界。新增的安全门控机制确保只有本机代理可以访问目录选择功能,防止远程攻击。未来可进一步探索云端备份与冲突解决机制,以增强数据同步能力。