v5.1.2官网上线与自动发布
官网上线与自动发布。
- 官网部署到 Cloudflare Workers,支持 koitab.com 与 www.koitab.com
- GitHub main 分支更新后自动构建和部署;发布前运行扩展回归测试,同步更新日志与下载包
- 固定构建 Node.js 版本,提供统一的 Worker 构建与部署命令
v5.1.1修复标签与收藏的数据安全问题
修复标签与收藏的数据安全问题,统一浏览器兼容要求与官网资源生成。
- 去重保留完整 URL 的 hash、路径和查询参数,不同路由不再误关;归档分别保存这些地址
- 收藏搜索后按确认过的条目 ID 删除,保留未命中的收藏;删除从最新存储读取,避免过期界面覆盖新收藏
- 归档读取失败或数据格式异常时立即中止,不覆盖旧收藏、不关闭标签;写入失败同样保留页面
- 归档关闭每个标签前重新读取状态,地址、窗口、访问时间发生变化或已激活、固定、正在导航的页面保留不关
- 整理、归档和删除共用执行锁,执行期间禁用相关按钮、范围和阈值设置,刷新界面不会解除锁
- 最低 Chrome / Edge 版本统一为 121,与存储 Promise 和 lastAccessed 所需 API 一致
- Logo 生成脚本同时更新当前 Next.js 官网和旧版静态页资源
- 新增扩展数据安全与并发操作回归测试,可运行 node --test tests/*.test.cjs
v5.1.0SEO
官网迁移到 Next.js(App Router + SSG),部署到 Cloudflare Workers,SEO 基建补齐。
- 新增 nextjs/ 独立应用;页面文案、JSON-LD、RSS 共用一份数据源(app/content.ts),
- SEO:每个路由都预渲染为完整静态 HTML(○ Static);metadata 补齐
- RSS:新增 /feed.xml(RSS 2.0,构建期静态生成),内容解析自 CHANGELOG.md;
- 下载包改由 tools/build-site.py 产出到 nextjs/public/downloads/,页面直接下载;
- 部署方式改为 Cloudflare Workers(OpenNext 适配器):npm run deploy =
- 依赖锁定:Next 16.3.5 + React 19.2.8(create-next-app@16.3.5 的 recommended 组合)
- 坑位记录:外层 shell 若带 NODE_ENV=development,next build 会在预渲染
- 旧的纯静态 landing/ 内容已全量迁移,暂时保留作对照,确认后可删
v5.0.1排除开发用文件
官方下载上线:koitab.com 直接下载扩展包。
- landing 页顶部与页尾的下载按钮指向 downloads/koitab-latest.zip,点击即下载(带 download 属性,不会被当成导航)
- 新增 tools/build-site.py:一条命令产出可部署的 dist/(landing 静态站 + 扩展 zip);
- 发布包排除开发用文件(debug.html / debug.js —— 那是我们自查 lastAccessed 用的诊断页,不分发给用户)
- 「三步开始使用」文案同步:选择解压出的 koitab 文件夹(原文案写的 extension 与发布包结构不符)
- 部署流程见 README「发布与部署(Cloudflare Pages)」
v5.0.0归档改存 KoiTab 自己…
归档改存 KoiTab 自己的收藏夹,与浏览器书签彻底解耦(用户澄清:归档 ≠ 写浏览器书签)。
- 归档不再调用 chrome.bookmarks 写任何东西:收藏条目存进
- 这一刀顺带根治了整条"书签环境病":实测踩过的「search 不返回文件夹」
- 「收藏夹」页两个分区:KoiTab 收藏(实心「藏」印;打开/删单条/按站点清空,只动自己的存储)
- 同 URL 幂等:隔几天再开到同一页再归档,收藏只留一份;"存了没关掉"的残局再点只补关
- 保留 bookmarks 权限,仅用于只读展示浏览器书签分区
- 预览/汇总/tooltip 文案改口「KoiTab 收藏」;归档与收藏测试按新模型重写
v4.0.4根文件夹的父容器 id 不能…
定位并修复用户实测报错「Can't find parent bookmark for id.」:根文件夹的父容器 id 不能硬编码。
- 此前建「KoiTab 归档」根文件夹写死 parentId:'2'(标准 Chrome 的「其他书签」惯例 id)。
- 现在用 bookmarkParentCandidates() 按优先级找容器并逐个试到成功:
- 所有候选都被拒时,如实报「找不到可写书签的容器文件夹」,且出于安全一个页也不关
- 测试新增:无 '2' 节点的 Edge 式书签树可正常归档;容器全拒收时页原样保留 + toast 带真实错误
v4.0.3Chrome 的原话错误
「书签一条都没建成」时,把 Chrome 的原话错误放进提示,不再让用户猜。
- 4.0.2 的提示「多半是书签权限没生效」是我的猜测,把排查责任推回给了用户 —— 现在
- chrome.bookmarks 整体不可用时单独预判,提示指向重新加载扩展
- planArchive 不再把「空 URL(导航中)」的标签当归档候选 —— 这种页根本存不进书签,
v4.0.2归档点了没反应
修复归档点了没反应:预览明明写着 66 条,点下去页却一个不关。
- 主因:批量 chrome.tabs.remove([66 个 id]) 是整批成败 —— 只要其中一个标签
- 幂等:归档前扫描「KoiTab 归档」现有子夹与已归档 URL ——
- 去掉 window.confirm:弹窗里它可能被失焦无声吞掉(点了等于取消),而预览行
- 汇总提示改讲事实:书签已收进…,但页没关掉 —— 再点一次只补关 /
- 注:若你上次点击其实已经建出了书签(去书签管理器看「KoiTab 归档」),
v4.0.1如实告诉你是哪一种
修复"没有需要归档的标签页 🎉"把三种不同情况糊成一句庆祝的问题 —— 归档没候选时,
- 读不到使用时间(一个标签的 lastAccessed 都拿不到 → Chrome/Edge < 121,或刚重启时间被刷):
- 读得到、但都没闲够:报出"最久的一个 X 前还用过",并主动给一个刚好能命中的更短档
- 能归的都是正在看/固定的:直说"开着的页都在你眼前",这种才不标警
- 三种解释同时出现在:归档预览行(朱色提示)、按钮 tooltip、点按后的 toast;
- 另:诊断指标行、比例条、整理预览均不受影响
v4.0.0诊断页
「操作」页重构为诊断页:先看体检报告,再决定整不整理。
- 打开这一页只有一枚朱印引导卡 +「开始诊断」按钮 —— 不再一上来就摊四个功能卡
- 点「开始诊断」自动统计当前所有窗口:重复网页、跨窗口待集中的同站点标签、未分组散标签、
- 报告下方是带预览的两个行动卡:
- 「一键整理」:动手前就写明结果 —— 新合并出几个分组、关闭几个重复、
- 「归档未用标签」:写明几条书签收进「KoiTab 归档」、关闭几个页、几个站点、
- 分组折叠不再是独立卡片 —— 并入整理卡作为一行小设置(超过几个自动收起);
- 整理/归档完成后报告原地刷新(重复归零、按钮自动置灰),随时可「重新诊断」
- 数字口径与按钮状态共用同一份 computeMetrics(),报告、预览、按钮三者永远一致;
v3.5.1logo 还是那幅手绘锦鲤
回滚 3.5.0 的误改:logo 还是那幅手绘锦鲤,只是底板从白色换成宣纸色。
- 3.5.0 把图标整个重绘成了程序画的印章字 —— 那不是"换个背景色",越界了,已撤销
- apply-logo.py 新增 PAPER_PLATE 常量:圆角底板由白色改为宣纸色 #f5f0e4,与水墨界面同调;
- 弹窗题头恢复"册页装裱"样式(去掉旋转贴印效果)
v3.5.0朱砂印章
logo 重绘为朱砂印章,与水墨界面同一套语言。
- 新增 tools/apply-seal-logo.py:直接生成「印泥朱砂底 + 米白纸色『鲤』+ 内圈白文边线」
- 弹窗题头的 logo 从「白底小画 + 装裱框」改为一枚微旋(-3°)钤印,加印泥色投影;
- 旧手绘风并未丢失:assets/logo-source.jpg 与 tools/apply-logo.py 原样保留,
- landing 与 favicon 同步替换为新印面
v3.4.0虚拟大分区
收藏夹内区分「KoiTab 归档的」和「你自己书签栏里的」—— 加了两级总分区。
- 收藏夹现在是两个虚拟大分区:「KoiTab 归档」(实心朱印「归」标记)与「浏览器书签」
- 分区标题行:箭头 + 印章 + 名称 + 「N 夹 · M 条」计数,下方压一道朱线划层级;
- 归档分区内的组名剥掉「KoiTab 归档/」前缀(显示 github.com 而非
- 「全部折叠 / 全部展开」升级为分区粒度;搜索时命中所在分区强制展开
- 这是界面层的虚拟分区:不新建、不移动、不重排你真实的书签树
v3.3.0折叠 / 展开
收藏夹的文件夹现在可以折叠 / 展开了。
- 点夹子标题(完整路径那一行)收起整个文件夹,只留「路径名 + 条数」;再点恢复
- 折叠状态按路径记住(存 koiFavCollapsed,与站点分组的偏好分开、互不串台),
- 与标签页同规则的两条细节:搜索时强制展开全部(命中结果不能被折叠藏住),
- 底栏新增「全部折叠 / 全部展开」批量按钮,文案随状态切换
- 默认仍是全部展开 —— 收藏的是你自己的书签,不该像标签页那样自动收起
v3.2.1
- 去掉标题栏右上角的「鲤」朱印;版本号徽标移到它原来的位置(最右)
- 卡片上的「整/归/叠」小印不受影响
v3.2.0浏览器书签的实时全量视图
收藏夹升级为浏览器书签的实时全量视图 —— 搜索从此搜得到书签内容。
- 你问的「一键导入书签」不需要导入这一步:收藏夹和书签的数据本来就在同一个地方
- 分组规则:每条书签归到它直接的父文件夹名下,组标签显示完整路径
- 安全边界:清空整夹的 × 只给归档组 —— 用户自己的真实书签夹不会被一键清空;
- 页脚统计相应改为「共 N 条书签 · M 个文件夹」;空态文案更新
- 仍是懒加载:不进收藏 tab 完全不碰书签
v3.1.1
移除「操作」页里的「还会做什么」速览卡 —— 它只是文字复述,占掉首屏一屏半,
v3.1.0中国水墨书签风
弹窗整体重绘为中国水墨书签风。
- 宣纸底:米黄纸面 + 极淡墨晕 + 一层帘纹质感;卡片改「册页」——小方角、
- 朱砂印章点缀:标题栏一枚微旋的「鲤」压角章;四张功能卡的图标换成白文小印
- 字体换楷/宋衬线(系统自带楷体做标题与控件、宋体做正文,零网络字体、离线可用);
- 站点色点从彩虹 hsl 换成十色国画色(黛蓝/青黛/松绿/赭石/朱砂/绛紫/藤黄/花青/茶褐/月白),
- 表情符号从导航与图标位全部退场(彩色 emoji 会破坏水墨版面);toast 改墨牌样式;
- 折叠缩进、悬停显隐 ×、吸顶标题这三条行为/样式锚点原样保留,10 个套件全绿
v3.0.2根因
修复「收藏夹一直显示读取书签失败」。
- 根因:找「KoiTab 归档」根文件夹用的是 chrome.bookmarks.search({title}) ——
- 连带修复:同一坑会让每次归档都新建一个重复的「KoiTab 归档」根文件夹
- 失败提示现在会带上具体错误原因(如权限未生效、API 不可用),而不是干巴巴一句
- 收藏夹读取逻辑全程只读,不会改任何书签
v3.0.1顺序不该在用户没要求时改变
修复整理时散标签被"按打开时间"重排的问题 —— 顺序不该在用户没要求时改变。
- 把散标签收进新窗口时,此前按 tab.id(≈ 打开时间)排序,会造成两种"找不到":
- 现在按用户看到的顺序搬运:当前窗口的散标签整块在前,其余窗口按窗口编号整块跟随
- 「标签页」页里的重排步骤本来就保持散标签相对顺序,不受影响
v3.0.0弹窗重构为三个 tab
弹窗重构为三个 tab,整体观感重做。
- ⚡ 操作:所有功能与配置集中在这一个页面 ——
- 🗂 标签页:原来的主体内容(搜索 + 站点分组列表 + 全部折叠),搜索框从顶栏挪到了这一页
- ⭐ 收藏夹:归档走的页都能在这找回 —— 直接读「其他书签 / KoiTab 归档」子树,
- 三个 tab 带数量徽标(标签页常显;收藏数读过书签才显示),停留的 tab 会被记住
- 收藏夹懒加载:不进这个 tab 就完全不碰书签,其他页零开销
- 视觉翻新:卡片化布局、渐变主按钮、带指示条的 tab 导航、收藏分组用与站点分组一致的样式,
- 所有配置(范围 / 归档阈值 / 折叠阈值 / 当前 tab)都存在本地 storage,零上传
v2.2.0先收藏、再关闭
新增「归档未用标签」:先收藏、再关闭,不是直接丢掉。
- 弹窗新增一行次级操作:阈值下拉(3 / 7 / 30 天,默认 7 天,选择会记住)+「归档未用标签」按钮
- 超过阈值没用的标签页,先按站点收进书签「其他书签 / KoiTab 归档 / 站点名 /」,然后才关闭;
- 宁可漏、不可误杀:
- 每个窗口正在浏览的标签页、固定标签页永不归档(也因此任何窗口都不会被归档到关闭);
- 拿不到 lastAccessed 的一律跳过(Chrome 121 以下没有这个字段);
- 浏览器内部页(chrome:// 等)不收录 —— 存书签没有意义;
- 同一个 URL 开着多份时,书签只记一份、标签页全部关闭,书签里不会留重复噪音
- 失败保护:书签没建成的标签页绝不关闭。建根文件夹失败就一条不写、一个不关;
- 关闭前会弹一次确认框,写明要归档几个、去哪儿;归档后因此只剩 1 个成员的分组自动取消
- 归档遵循顶部的「整理范围」:「本窗口」只归档当前窗口,「所有窗口」才动全部窗口
- 权限新增 bookmarks(仅此一项;仍然免构建、无第三方依赖)
v2.1.2最后一次被访问
新增开发用诊断页 debug.html(只读,不影响任何整理行为),用来确认
- 背景:tabs.Tab.lastAccessed(Chrome 121+)能拿到标签页最后一次被访问的时间。
- 诊断页回答三件事:能不能拿到 lastAccessed、哪些标签页是 undefined、
- 结论判定抽成纯函数 verdictFor(),并有测试覆盖"保留 / 被重置 / 数据不足 / 不误判"
- 本页只读:不会关闭、移动或激活任何标签页
v2.1.1折叠后只留域名
界面优化:折叠后的分组不再显示标签页信息。
- 折叠后只留域名:此前折叠时会露出该站点第一个标签页的标题(以及「等 N 个」),
- 关闭整组的 × 改为悬停出现:折叠后的界面更干净,同时也避免误触这个不可撤销的操作
- 顺带移除预览行相关的一整套 DOM 渲染与样式(.koi-preview-row / .koi-preview-more),
v2.1.0两个明确的窗口
整理的目标终态改成两个明确的窗口,不再"分组进新窗口、散标签原地不动"。
- 当前窗口 = 分组的展示窗口:所有窗口里同一站点的标签一律收进当前窗口并成组
- 新窗口 = 散标签的收纳窗口:构不成分组的散标签(站点合计只有 1 个)统一收进新窗口。
- 其他窗口被搬空后关闭:只剩固定标签的窗口会留下来(固定标签不搬动)
- 散标签已经全在同一个窗口里时不再搬动,所以重复点「一键整理」不会有任何多余动作,
- 修复:固定标签不再被卷入分组。Chrome 不允许固定标签进入分组,
- 当前窗口里没有站点可成组、也没有固定标签时保持原样:把它腾空只会让窗口被关掉、
v2.0.1修复:各自"已经很整齐"的分…
修复 2.0.0 里"分组没有全部集中到一个窗口"的两个原因。
- 修复:各自"已经很整齐"的分组不会被合并。此前只要某个站点已经在同一个窗口、
- 调整:当前窗口全是可整理标签时,改为把"当前窗口"当作集中目标,不再新建窗口。
- 提示文案会说明分组集中到了哪个窗口(新窗口 / 当前窗口 / 就地成组),
v2.0.0整理方式改变
整理方式改变:不再只是就地归类,而是把所有窗口的同站点标签集中进一个新窗口,
- 跨窗口集中:点「一键整理」后,所有窗口里同一站点的标签会被收进一个新建的窗口
- 归并标准改为跨窗口统计:某站点在所有窗口合计 ≥2 个标签就会集中
- 固定标签留在原窗口:通常是邮箱 / 日历这类常驻页,不参与搬运
- 被搬空的窗口会关闭:原窗口的标签全被搬走时,Chrome 会关掉空窗口——
- 当前窗口不能被搬空。弹窗依附于当前窗口,窗口一旦被关掉弹窗就消失,
- 步骤顺序:去重 → 取消孤儿分组 → 集中到新窗口并成组 → 收拾原窗口 → 重排
- 取消孤儿分组放在集中之前:只剩 1 个标签的分组被取消后,它的标签就能参与集中
- 集中的搬运必须在成组之前:Chrome 的分组无法跨窗口,先集中才能成组
- 已整理好的站点不会被反复搬动:同站点标签已在同一个窗口、同一个分组、且分组里
- 新窗口以 focused: false 创建,不抢焦点,弹窗也不会因失焦被关闭
- 「本窗口」范围下不新建窗口、不做任何跨窗口搬运,仍是原地成组
v1.4.1按「可注册域名」归并
修复:同一站点的不同子域没有被合并到一起。
- 按「可注册域名」归并:此前只去掉 www. 后取完整主机名,导致
- 同理受益:m.weibo.cn、blog.csdn.net、pan.baidu.com / tieba.baidu.com、
- 不会过度归并:扩展拿不到公共后缀列表(PSL),所以用「最后两段 + 常见多段后缀兜底表」。
- 副作用(需留意):同一主域下的不同子域现在会合并成一组,
v1.4.0当前窗口只保留分组标签
新增「散标签另开新窗口」:整理后当前窗口只留分组标签。
- 当前窗口只保留分组标签,未分组的散标签自动挪到一个新建的窗口
- 只拆「当前窗口」:即使切到「所有窗口」范围,也只拆你正在用的这个窗口,
- 固定标签留在原窗口:通常是邮箱/日历这类常驻页,搬到新窗口很别扭
- 安全底线:当前窗口没有分组就不拆。否则把散标签全搬走会让原窗口一个标签都不剩,
- 不抢焦点(focused: false):一是不把你从当前窗口拽走,二是弹窗一旦失焦就会被关闭,
- 散标签在新窗口中保持原有先后顺序;作为一键整理的第 5 步,
- 已整理过的窗口不会重复新建窗口(原窗口已经没有散标签),窗口数不会越点越多
v1.3.0自动取消只剩 1 个标签的分…
新增「取消孤儿分组」,并修正整理幂等性。
- 自动取消只剩 1 个标签的分组:分组的价值在于把多个标签收在一起,只剩 1 个标签的
- 「取消孤儿分组」作为一键整理的第 4 步,排在分组之后:先让分组把标签收齐,
- 整理不再把已经正确的分组拆掉重建。此前 合并同类项 会无条件调用
- 每次整理都会把全部分组拆掉重建(分组 id 每次都变)
- 「一键整理」按钮永远不会变成"已经很整齐了",提示还一直声称"合并 N 个站点"
- 按钮的置灰判断与悬停提示同步修正,并新增"取消 N 个单标签分组"一项
v1.2.0分组靠左、未分组靠右
新增「重排」步骤:整理时把分组和未分组的标签页分开摆放。
- 分组靠左、未分组靠右:同一个窗口里,属于分组的标签页彼此挨着排在左边,
- 绝不打乱分组:只移动「未分组且未固定」的标签页,并且一律追加到窗口末尾。
- 为什么不用「把分组挪到左边」的做法:Chrome 要求同一分组的标签页在标签栏里连续。
- 固定标签页不动:Chrome 要求固定标签只能在最左侧,它们本来就在分组左边
- 重排作为「一键整理」的第 4 步,在分组之后执行(分组完成后才知道哪些标签属于分组);
- 整理提示会汇报结果,例如「已 2 个标签页归入 1 个站点分组 · 把 1 个未分组标签页排到分组右侧」
v1.1.1标签页缩进
界面细节优化。
- 标签页缩进:分组内的标签页向左缩进 12px,让标签明显从属于上方站点标题。
- 折叠时的预览行同样缩进,与普通标签行对齐
- Landing Page 的弹窗示意图同步这一缩进
v1.1.0分组折叠
新增「标签页太多」时的浏览体验优化,并统一弹窗排版。
- 分组折叠:点击站点分组标题即可折叠 / 展开,折叠后只留「站点名 + 数量」一行
- 折叠预览:折叠时额外显示该站点的第一个标签页标题(点击可直接跳转),
- 自动折叠大分组:未被用户操作过、且标签数达到 8 个的站点,打开弹窗时默认收起,
- 偏好模型:折叠状态从「折叠集合」升级为「明确偏好」(collapsed / expanded),
- 底栏「全部折叠 / 全部展开」会为所有站点写入明确偏好,一次点击即可全部展开(含大分组)
- 分组标题吸顶,长分组滚动时始终能看到当前站点
- 排版优化:分组标题原先只有 12px 而标签名 13px,层级倒挂;现统一为 12.5px,
- 折叠与预览共用一套 CSS 可见性规则:折叠时隐藏普通行、保留预览行
- 兼容 1.0.0 的 koiCollapsed 旧字段,自动迁移为偏好表,不丢用户已有设置
v1.0.0一键整理
首个版本。
- 一键整理:单个按钮依次执行「关闭重复网页 → 跨窗口聚合 → 合并同类项」,
- 关闭重复网页:按「去 hash 的完整 URL」判定重复,保留优先级为
- 合并同类项:按 (窗口, 站点) 把同类标签页合入浏览器原生分组,
- 跨窗口聚合:仅在「所有窗口」范围执行,把同类标签搬到该站点标签最多的窗口;
- 整理范围切换:「本窗口 / 所有窗口」,选择会被记住
- 标签页列表:按站点分组、搜索过滤、点击跳转、单条关闭、整站关闭
- 弹窗界面适配浏览器深色皮肤;图标为白底圆角 + 黑墨手绘 logo