Last updated: 2026-05-24
这份文档描述当前仓库已经落地并仍然有效的运行时边界、数据模型,以及支撑重构的工程验证边界。TypeScript、构建链和 React 迁移属于规划草案,见 TS + React 迁移评估与执行计划。
当前主链路如下:
popup.html / popup.js负责设置页 UI、标签切换、自动保存、连接测试和入口状态检查。content.js在网页中抽取正文和元信息,并在 Bilibili 视频页使用shared/bilibili-source.js抽取视频元信息、官方 AI 总结或字幕来源,然后注入侧栏容器。shared/article-utils.js把抽取结果标准化为文章快照,并根据长度决定是否分段。shared/page-strategy.js基于页面类型给出页面策略和推荐摘要模式。sidebar/state.js负责侧栏初始状态、导航策略常量和 DOM 元素绑定;sidebar.js负责侧栏编排和收藏;侧栏摘要渲染、来源/信任卡、状态提示和诊断展示由sidebar/render.js管理;历史面板由sidebar/history.js管理,Markdown 导出和分享卡由sidebar/export.js管理,阅读页快照和打开由sidebar/reader-session.js管理,主摘要、二次生成、取消和流式连接由sidebar/generation.js管理,摘要模式控件由sidebar/mode-control.js管理,按钮、键盘和入口消息事件由sidebar/events.js管理。background.js通过adapters/执行请求,统一处理连接测试、模型列表刷新、自动 endpoint 试探、流式、取消、重试和错误;右键菜单、快捷键和入口状态由background/entrypoints.js管理,运行状态表和 port-run 映射由background/run-state.js管理,阅读页临时会话由background/reader-sessions.js管理。db.js把结构化结果保存到 IndexedDB,并提供搜索、收藏、删除和站点聚合能力。reader.html / reader.js从临时阅读会话中恢复当前摘要,在新标签页提供专注阅读体验。
这三张图按阅读目的拆开:第一张看整体,第二张看代码依赖边界,第三张看启动和一次摘要的顺序。
flowchart LR
U((用户))
Entry["入口层<br/>popup / 右键 / 快捷键"]
BG["后台调度<br/>background.js<br/>入口状态 / 流式 / 取消 / reader session"]
Page["网页注入层<br/>content.js<br/>抽正文 / Bilibili 视频来源 / 创建 iframe"]
Side["侧栏工作台<br/>sidebar.html + sidebar.js<br/>生成 / 历史 / 导出 / 阅读"]
AI["模型接口<br/>adapters -> provider"]
Store[("本地状态<br/>storage.sync / storage.local / IndexedDB")]
Reader["专注阅读页<br/>reader.html"]
U --> Entry --> BG
BG -- 动态注入 --> Page --> Side
Side -- startStream / cancelRun --> BG --> AI
Side <--> Store
BG <--> Store
Side -- openReaderTab --> BG --> Reader
Reader <--> Store
核心心智模型:入口只负责触发,content.js 只负责拿网页内容和挂侧栏,侧栏负责用户可见工作流,后台负责模型请求、取消和跨页面状态,存储负责设置、历史和阅读会话。
flowchart TB
Shared["shared/*<br/>公共算法、Bilibili 来源、文案、视图模型、错误、运行工具"]
Libs["libs/*<br/>Readability / Markdown 渲染 / 截图"]
DB["db.js<br/>IndexedDB 封装"]
Adapters["adapters/*<br/>OpenAI / Anthropic 兼容协议"]
BG["background.js<br/>后台主流程"]
BGParts["background/*<br/>entrypoints / run-state / reader-sessions"]
Content["content.js<br/>网页抽取和侧栏注入"]
Popup["popup.js<br/>设置和入口状态"]
Sidebar["sidebar.js + sidebar/*<br/>侧栏 UI 和工作流"]
Reader["reader.js<br/>阅读页恢复和渲染"]
BG --> Shared
BG --> Adapters
BG --> BGParts
Content --> Shared
Content --> Libs
Popup --> Shared
Sidebar --> Shared
Sidebar --> Libs
Sidebar --> DB
Reader --> Shared
Reader --> Libs
Reader --> DB
依赖约束:provider 逻辑只进 adapters/;右键、快捷键和入口状态只进 background/entrypoints.js;运行取消和 port-run 映射只进 background/run-state.js;历史记录读写统一走 db.js。
flowchart TB
A["1. manifest.json 唤起 background.js"]
B["2. background.js importScripts 两批依赖"]
C["3. Entrypoints.bindEntrypoints()<br/>注册右键菜单、快捷键、入口状态"]
D{"4. 用户从哪里进入?"}
E["popup<br/>读写设置 / 测试连接 / 检查入口 / 打开历史"]
F["右键或快捷键<br/>触发 extractAndSummarize"]
G["5. 后台 ping 当前 tab<br/>必要时动态注入 CONTENT_SCRIPT_FILES"]
H["6. content.js 抽取文章或 Bilibili 视频来源<br/>创建 sidebar.html iframe"]
I{"7. 侧栏是否命中当前页历史?"}
J["直接展示历史摘要"]
K["8. 侧栏通过 ai-stream 请求后台"]
L["9. adapters 调用模型接口<br/>token 流式返回侧栏"]
M["10. 完成后写 IndexedDB<br/>可创建 readerSession 打开阅读页"]
A --> B --> C --> D
D --> E
D --> F --> G --> H --> I
E -- triggerHistory 时也会注入 content --> G
I -->|命中| J
I -->|未命中或重新生成| K --> L --> M
运行时代码之外,当前仓库已经有两层验证护栏:
职责:
- 覆盖纯逻辑和工具函数。
- 覆盖记录存储、搜索、收藏、删除、复用等存储行为。
- 覆盖 Manifest、HTML DOM、脚本顺序、消息 action 等静态契约。
- 用
tests/feature-matrix.js维护既有功能覆盖清单。
关键文件:
tests/harness.jstests/feature-matrix.jstests/unit-core.test.jstests/unit-adapters-transport.test.jstests/unit-record-store.test.jstests/static-contracts.test.jstests/fake-indexeddb.js
职责:
- 在真实 Chromium 中加载当前扩展目录。
- 验证 popup、content script、background service worker、sidebar iframe、reader 页面之间的真实协作。
- 通过本地 fixture 页面和 mock AI 接口回归高价值主链路。
关键文件:
playwright.config.jse2e/test-server.jse2e/extension-harness.jse2e/extension.spec.js
职责分工:
- Node 层跑得快,适合纯逻辑、存储和静态契约。
- Playwright 层更接近真实用户路径,但不追求 provider 全排列和全部视觉细节。
职责:
- 通过
npm run typecheck执行tsc --noEmit,只做类型和契约检查,不生成运行产物。 - 用
types/messages.ts、types/history.ts、types/settings.ts、types/diagnostics.ts锁定消息协议、记录结构、设置项和运行诊断字段。 - 当前仍保持无构建、纯脚本结构,类型文件不进入 Manifest 或 HTML 脚本加载列表。
定义扩展形态和权限边界:
manifest_version: 3- service worker:
background.js,保持 classic service worker,并通过importScripts显式加载依赖 - popup:
popup.html - content script: 当前不在 Manifest 中声明
content_scripts;右键菜单、快捷键或 popup 历史入口触发时,background.js通过chrome.scripting.executeScript动态注入CONTENT_SCRIPT_FILES - 权限:
contextMenus、storage、activeTab、scripting、clipboardWrite host_permissions: <all_urls>web_accessible_resources暴露侧栏运行所需的 HTML、样式、共享脚本和第三方库
当前 Manifest 仍直接引用根目录 service worker、popup HTML 和 web accessible resources;动态 content 注入列表维护在 background.js 的 CONTENT_SCRIPT_FILES。未来如果引入 dist/ 构建产物,需要同步更新 Playwright 加载目录、静态契约测试和文档入口。
职责:
- 渲染设置页三个标签:
连接、偏好、入口 - 管理“配置方案”(多套连接配置的保存与切换)
- 自动保存设置
- 测试连接
- 刷新模型列表(用于输入提示),并按 Provider + Base URL 做本地缓存
- 打开当前页历史
- 配置侧栏默认标准 / 精简布局
- 配置入口是否优先复用本页历史摘要
- 检查右键菜单 / 快捷键状态
- 打开浏览器快捷键设置页
自动保存策略:
- 文本输入走 debounce +
blur立即保存 - 复选框和下拉框走 immediate save
visibilitychange和pagehide时 flush 未完成改动- 若当前绑定了配置方案(active profile),保存时会同时写入对应的 profile key,并更新 profile 索引元数据
职责:
- 从当前网页读取 DOM、meta 信息和 Readability 结果
- 在 Bilibili 视频页调用
shared/bilibili-source.js,按“官方 AI 总结 -> 字幕 -> 视频信息 fallback”的顺序构建来源文本 - 构建文章快照输入
- 注入侧栏容器和资源
- 在入口触发时把数据发给侧栏
- 跟踪 same-document navigation,并在已有侧栏打开时刷新页面上下文
说明:
content.js使用libs/readability.js这个 vendored 的外部库做正文抽取。readability.js属于第三方依赖,不是项目自研模块。- 动态注入列表由
background.js中的CONTENT_SCRIPT_FILES维护,当前包括shared/domain.js、shared/strings.js、shared/page-strategy.js、shared/article-utils.js、shared/bilibili-source.js、shared/constants.js、libs/readability.js和content.js。 - 右键、快捷键和 popup 等显式入口仍通过
injectSidebar()打开或重建侧栏。 - SPA / 同文档路由切换不会重建 iframe;
content.js会向现有 iframepostMessage发送articleData,并带上source: 'navigation'与内部navigationPolicy。
职责:
- 渲染主要工作台
- 展示来源信息和可信与控制状态
- 处理主摘要和二次生成
- 当 Bilibili 官方 AI 总结可用时,主摘要可以直接落盘并展示,不再发起模型流式请求;否则继续走常规模型生成链路
- 在入口触发时优先复用当前页面的历史摘要,并保留当前页上下文用于重新生成
- 根据
sidebarCompactMode设置在standard/compact侧栏布局之间切换;精简布局只改变信息密度和空间分配,不改变生成、历史、导出或诊断行为 - 维护历史 / 收藏面板
- 导出 Markdown
- 生成长截图分享卡
- 打开新标签页阅读器
- 展示运行诊断
SPA 路由切换的当前默认策略:
navigationPolicy.autoStartOnNavigation默认为false,所以导航刷新只更新上下文,不自动发起模型请求。navigationPolicy.duringGeneration默认为defer,所以生成中收到导航刷新时,只保存最新 pending payload,不取消旧 run,也不断开 stream port。- 旧 run 进入
finally后,侧栏会应用最新 pending navigation:更新 meta,优先复用新页面历史;未命中历史时显示等待手动“重新生成”的占位态。 - 内部预留
defer、replace、ignore三种运行中导航策略。当前没有暴露用户设置,也没有改变chrome.storageschema 或 Manifest 权限。
sidebar/state.js 负责侧栏状态和 DOM 绑定边界:
SETTINGS_KEYS、NAVIGATION_DURING_GENERATION和DEFAULT_NAVIGATION_POLICY集中在该模块,避免sidebar.js顶部继续膨胀。createInitialState({ trust })每次创建新的状态对象、Set、设置快照和 trust policy。resolveElements(documentRef)维护侧栏 DOM id 到元素键名的映射,sidebar.js只持有返回后的elements。
sidebar/render.js 负责侧栏渲染边界:
- Markdown 渲染、DOMPurify 净化、流式渲染节流、代码高亮和自动滚动。
- 占位态、内联提示、错误态、取消态、分段进度、状态栏和统计栏。
- 来源信息、trust card 和运行诊断的 DOM 写入;展示数据仍来自
shared/sidebar-meta-view.js和shared/diagnostics-view.js。
sidebar/export.js 负责侧栏导出边界:
- Markdown 文件导出和安全文件名清理。
- 分享卡摘录、分享卡 DOM 构建和
html2canvas长图生成。 - 通过
createExportController(deps)接收sidebar.js注入的状态、元素、格式化、Markdown 净化和状态提示能力。
sidebar/reader-session.js 负责侧栏阅读页会话边界:
- 基于当前文章、可见记录、摘要、模式和诊断构建 reader snapshot。
- 通过既有
openReaderTabruntime message 打开独立阅读页。 - 通过
createReaderSessionController(deps)接收sidebar.js注入的状态、元素、snapshot builder、runtime message 和状态提示能力。
sidebar/generation.js 负责侧栏生成运行边界:
- 主摘要、长文分段汇总、二次生成、stream port 和取消控制。
- active runId、当前 port 和
AbortController仍由sidebar.js的状态对象承载,但只能通过createGenerationController(deps)注入访问。 - 保持
startStream/cancelRunruntime message 和 provider prompt 行为不变。
sidebar/mode-control.js 负责侧栏摘要模式控件边界:
- 摘要模式选项初始化、合法值兜底、菜单开关、active 状态同步和控件内事件绑定。
- 保持原生
<select>与自定义菜单同步,sidebar.js只读取当前summaryModeSelect.value并通过 controller 设置值或关闭菜单。
sidebar/events.js 负责侧栏事件绑定边界:
- 绑定主要按钮、二次生成按钮、summary 滚动、
window.message入口和全局Escape关闭顺序。 - 通过
createEventsController(deps)接收sidebar.js注入的业务动作,事件模块不直接拥有生成、历史、导出、阅读或设置逻辑。
职责:
- 从
chrome.storage.local读取阅读会话快照 - 必要时回查 IndexedDB 记录
- 展示独立阅读布局
- 提供“打开原文”和“复制 Markdown”操作
阅读页不是默认主工作区,而是侧栏之外的补充阅读路径。
职责:
- provider 适配器解析与请求执行
- 流式输出和取消控制编排
- 统一错误归一化
- 连接测试
- 模型列表刷新:当前只对 OpenAI 兼容接口调用
/models,结果按 Provider + Base URL 缓存在chrome.storage.local - OpenAI 兼容接口的
endpointMode=auto试探与成功模式缓存 - 明确网关错误下的
/v1自动补齐或去除,并把修正后的 Base URL 同步回设置页 - 委托入口模块维护右键菜单和快捷键状态
- 委托入口模块打开快捷键设置页
- 委托阅读会话模块创建独立阅读页会话并打开
reader.html
background/entrypoints.js 负责扩展入口边界:
- 注册右键菜单并记录 context menu 状态。
- 检查
trigger-summary快捷键状态并记录冲突提示。 - 绑定 context menu / command 事件到后台传入的页面触发函数。
- 打开浏览器快捷键设置页。
background/run-state.js 负责后台运行状态边界:
- 维护 active runs 和 stream port 到 run 的映射
- 绑定当前请求的
AbortController - 处理单个 run 取消、port 断开批量取消和 run 结束清理
background/reader-sessions.js 负责独立阅读页临时会话:
- 清理过期的
readerSession:storage.local 记录。 - 为
openReaderTab创建 24 小时有效的 reader session snapshot。 - 保持 reader 会话与后台运行状态解耦。
主要消息入口:
testConnectionrunPromptcancelRuntriggerHistorygetEntrypointStatusopenShortcutSettingsopenReaderTablistModels
职责:
- 打开 IndexedDB
- 维护
summaryRecordsstore - 兼容旧
historystore 迁移 - 记录标准化
- 按 articleId / URL 匹配当前页面可复用的历史记录
- 搜索、收藏、删除、站点聚合
当前关键状态:
DB_VERSION = 2- 主 store:
summaryRecords - 旧 store:
history
按“工具边界清晰、复用逻辑集中”的方式组织:
domain.js:URL 归一化、ID / hash、站点识别strings.js:摘要模式、页面类型标签、状态文案page-strategy.js:页面类型到策略和推荐模式的映射article-utils.js:文章快照构建、分段、prompt 生成trust-policy.js:无痕和默认策略归一化provider-catalog.generated.js:构建期生成的 provider catalog,包含服务商 route、Base URL、默认模型、key rule 和来源信息provider-presets.js:provider catalog 的兼容适配层,继续暴露 preset / Provider / Endpoint Mode gettertheme.js:popup、侧栏、阅读页的主题同步ui-format.js:popup、侧栏、阅读页共用的 HTML 转义和时间显示工具ui-labels.js:popup、侧栏、阅读页共用的 provider、摘要模式、记录状态、策略和 warning 显示文案summary-text.js:存储层、侧栏、阅读页共用的 Markdown 转纯文本、摘要预览截断和 bullet 提取工具diagnostics-view.js:侧栏共用的运行诊断与取消态视图推导工具,负责 partial summary、toggle 文案和取消态 facts 组装reader-view.js:侧栏与阅读页共用的阅读快照投影工具,负责会话快照构建、记录合并和外链规范化history-view.js:侧栏历史面板共用的展示数据组装工具,负责历史项与站点分组的纯视图模型sidebar-meta-view.js:侧栏文章信息与 trust card 共用的展示数据组装工具,负责 meta 文案、warnings 和 trust badge/tone 推导errors.js:统一错误模型abort-utils.js:取消控制工具run-utils.js:运行终态、取消说明、诊断摘要transport-utils.js:SSE / raw body 解析与传输层辅助工具
provider-specific 逻辑集中在这里,而不是散落在 background.js:
openai-adapter.jsanthropic-adapter.jsregistry.js
当前支持的接口族:
- OpenAI Compatible
autoresolution(最终落到下列 OpenAI 兼容 endpoint 之一) - OpenAI Compatible
responses - OpenAI Compatible
chat_completions - OpenAI Compatible
legacy_completions - Anthropic
messages
内置 provider catalog 与运行时 Provider 是分开的:catalog route 用于提供推荐 Base URL、默认模型、key rule 和可选 Endpoint Mode;最终请求仍由 aiProvider 选择 openai 或 anthropic adapter。providerPreset、aiProvider、endpointMode、aiBaseURL、modelName 的存储结构保持兼容,非默认 route 通过 aiBaseURL 和 aiProvider 反推。当前 preset 包括 custom、openai_official、anthropic_official、deepseek、gemini、qwen、glm、mimo、xai、minimax、doubao、hunyuan。
文章快照是一次页面抽取后的标准化结果,主要包含:
- 来源:
sourceUrl、normalizedUrl、sourceHost、siteName - 元信息:
title、author、publishedAt、language - 内容:
rawText、cleanText、content、contentLength - 页面理解:
sourceType、sourceStrategy、preferredSummaryMode - 长文信息:
chunkingStrategy、chunkCount、chunks - 可信边界:
allowHistory、allowShare - 质量信号:
warnings、qualityScore、diagnostics
每次请求都会快照当前适配器配置,至少包括:
provideradapterIdendpointModemodelbaseUrl
这些字段会进入结果记录,避免历史因后续设置变化而失真。
历史记录是结构化对象,而不是简单字符串列表。当前记录至少包含:
- 身份:
recordId、articleId、runId - 来源快照:URL、标题、站点、文章快照
- 请求快照:摘要模式、目标语言、prompt 配置
- 模型快照:provider、adapter、endpoint、model
- 状态:
status、retryCount、durationMs、错误信息、诊断 - 输出:
summaryMarkdown、summaryPlainText - 组织信息:
favorite、dedupeKey - 可信边界:
privacyMode、allowHistory、allowShare
独立阅读页使用临时阅读会话,而不是直接依赖侧栏状态:
- 存在
chrome.storage.local - key 前缀:
readerSession: - 默认保留 24 小时
- 优先读取侧栏传入的快照
- 如果记录允许落库,再尝试回查 IndexedDB 获得最新内容
这样即使当前结果未写入历史,也能打开独立阅读页。
保存用户设置,例如:
- API Key
- 厂商预设、Provider、Endpoint Mode
- Base URL、模型名称、额外系统要求
- 配置方案索引与当前激活配置方案(以及每个配置方案的快照数据)
- 自动翻译、默认输出语言
- 明暗模式与色彩方案
- 无痕模式、默认写入历史、默认允许分享
- 侧栏默认精简模式
- 入口自动生成、入口默认简短总结、入口优先显示本页历史摘要
配置方案相关 key 约定(当前实现):
yilanProfilesIndexV1yilanActiveProfileIdV1yilanProfileV1:<profileId>
保存本地运行时状态:
- 右键菜单 / 快捷键状态
- 最近触发信息
- 入口状态缓存:
entrypointStatus - 模型列表缓存(按 Provider + Base URL 维度缓存,用于输入提示)
- 自动 Endpoint Mode 缓存:
yilanAutoEndpointModeCacheV1 - 阅读页临时会话
模型列表缓存 key(当前实现):yilanModelsCacheV1
保存历史记录:
- 数据库名:
aiSummaryDB - 版本:
2 - store:
summaryRecords - 保留旧
historystore 用于迁移兼容
当前有几个边界不应再被打散:
- provider 逻辑继续收敛在
adapters/,不要回到background.js里堆分支。 - 右键菜单、快捷键和入口状态继续收敛在
background/entrypoints.js。 - 可信策略继续收敛在
shared/trust-policy.js,不要在 UI 层各自拼判断。 - 历史记录始终以结构化对象保存,不退回到简单字符串列表。
- 阅读页继续作为侧栏之外的补充阅读能力,而不是替代侧栏主工作流。
- 后台 reader session 创建和过期清理继续收敛在
background/reader-sessions.js。 - 验证体系保持
Node 契约与Playwright 主链路分层,不拿其中一层去替代另一层。 - 当前运行产物仍是无构建、纯脚本结构;如引入 TypeScript、构建链或 React,必须按专项迁移设计分阶段验证。