算法工作台(Positron / VS Code 扩展)
在 Positron(以及 VS Code / Code OSS)侧边栏浏览题库的扩展:题库浏览与筛选、每日一题、学习计划、收藏、代码编辑与格式化、运行与提交、提交记录。
登录一次就够了。 登录态用 IDE 的系统级加密凭据区保存,重启 Positron、重开窗口、甚至重启电脑后都会自动恢复,不用再打开浏览器扫码。
界面里的动作按钮(返回、运行、提交、翻页、全屏等)统一用形状图标,中文说明放在悬停提示里;板块导航与题面正文保持中文原样。
为什么原来每次都要扫码
参考的 DBX 插件把会话放在 sidecar 进程的内存里,进程一退出 LEETCODE_SESSION 就没了,所以每次启动都要重新走一遍「开浏览器 → 扫码 → 读 Cookie」。
这个版本把登录态写进 vscode.SecretStorage:
- Windows:DPAPI / Windows 凭据管理器;
- macOS:Keychain;
- Linux:libsecret(gnome-keyring / kwallet)。
保存的是完整 Cookie 映射 + csrftoken + 用户信息,不是只有 session 一个值。每次 HTTP 响应里的 Set-Cookie 也会合并回写,能应对站点侧会话轮换。扩展激活时先恢复、再联网用 userStatus.isSignedIn 校验一次,有效就直接免登录;只有会话真的过期了才会提示重新登录一次。
Cookie 等同于账号凭证,请勿把本机凭据区的文件拷给别人,也不要在公用机器上勾选保存。
安装
方式 A:安装 .vsix(推荐,离线可用)
- 在本目录执行:
npm install
npm run build
npm run package
生成 leetcode-cn-<version>.vsix。
- 打开 Positron,命令面板(
Ctrl+Shift+P)执行 Extensions: Install from VSIX,选择该文件。
- 按提示重载窗口。
Positron 基于 Code OSS,扩展库是 Open VSX / P3M,与 VS Code Marketplace 不互通;本地 VSIX 安装不依赖任何市场。官方安装方式见 Extensions – Positron。若要把扩展发布到市场让别人直接搜到,见下文「发布」与 docs/PUBLISHING.md。
方式 B:开发模式
把本目录作为扩展项目用 Positron / VS Code 打开,按 F5 启动扩展开发宿主(需在 .vscode/launch.json 里配置 extensionHost 类型)。或:
npm install
npm run watch
首次登录(只需做一次)
打开工作台:点击活动栏的 算法 图标 → 「打开工作台」,或命令面板执行 算法: 打开工作台。
登录区提供两种方式:
| 方式 |
说明 |
| 受控浏览器自动导入(推荐) |
自动启动一个独立的 Chrome / Edge 窗口(独立临时 profile,不碰你日常浏览器的配置),打开登录页。你扫码或密码登录完成后,扩展通过 CDP Network.getAllCookies 读回浏览器已解密的 LEETCODE_SESSION,自动完成导入,并在这时才关闭该窗口;扫码或输入密码期间窗口会一直保持打开。全程不用手工复制粘贴。 |
| 手动粘贴 Cookie |
手动粘贴 LEETCODE_SESSION=xxx; csrftoken=yyy(也可以只粘 LEETCODE_SESSION 的值)。适合无法启动本机浏览器、或用远程/容器场景。 |
命令面板里也有对应的 算法: 登录(受控浏览器自动导入) 与 算法: 导入 Cookie 登录。
登录成功后头部会显示「已安全保存」及保存时间;侧边栏和底部状态栏也会显示登录状态。之后不用再做任何事。
会话过期怎么办
LEETCODE_SESSION 本身有有效期(通常数周到数月)。扩展在启动时校验,失效时只提示一次「请重新登录」,重新走一遍上面的流程即可,之后又是长期免登录。
功能
- 动作按钮图标化:工具栏、翻页、编辑栏、头部与全屏栏的按钮只显示形状图标(
▶ 运行、⤴ 提交、⟳ 刷新、← 返回等),中文说明放在 title / aria-label 悬停提示里;板块导航、题面正文、代码与登录卡片保持中文原样。
- 主题适配:工作台跟随 IDE 的浅色 / 深色 / 高对比主题自动切换配色,输入框、按钮、边框都取自 VS Code 主题变量。
- 全屏折叠:全屏做题时,题目列表侧栏与题面面板都能折叠 / 展开;侧栏可按编号或标题筛选、点击直接切题,折叠状态在同一会话内保留。
- 题库:按难度、状态、标签、题单筛选;关键词搜索;分页;随机一题。
- 每日一题:一键打开当日题目。
- 学习计划 / 题本:浏览官方计划与题本目录。
- 收藏:加入 / 移出默认收藏、查看自建收藏夹与夹内题目。
- 题目详情:中英文题面、代码模板、示例用例、提示、相似题、公司标签。
- 写代码:多语言模板、语法高亮、Prettier 格式化、全屏编辑;代码草稿按「题目 + 语言」保存在 globalState,切题或重启不丢。
- 运行 / 提交:走官方
interpret_solution / submit 接口,轮询判题结果,展示通过率、耗时、内存、编译/运行错误、对比输出。
- 提交记录:查看某题的历史提交。
命令
| 命令 |
作用 |
算法: 打开工作台 |
打开主界面 |
算法: 登录(受控浏览器自动导入) |
启动受控浏览器完成一次性登录 |
算法: 导入 Cookie 登录 |
手动粘贴 Cookie |
算法: 退出登录 |
清除本机保存的凭据 |
算法: 每日一题 |
在工作台内打开当日题目 |
算法: 随机一题 |
在工作台内随机打开一题 |
算法: 刷新登录状态 |
联网重新校验 |
算法: 查看登录状态 |
查看是否已持久化保存 |
配置项
| 设置 |
默认值 |
说明 |
leetcode-cn.autoRestore |
true |
启动时自动恢复并校验登录态 |
leetcode-cn.proxy |
空 |
代理地址,如 http://127.0.0.1:7897;留空自动读 HTTPS_PROXY / HTTP_PROXY;填 off 强制直连 |
leetcode-cn.browserPath |
空 |
手动指定 Chrome / Edge 可执行文件绝对路径 |
leetcode-cn.browserTimeoutSeconds |
300 |
受控浏览器登录最长等待秒数 |
leetcode-cn.defaultLanguage |
python3 |
新建题目时默认语言 |
受控浏览器与 CDP 调试端口永远走 127.0.0.1 直连,不经过代理。
发布
扩展默认以 publisher=local 生成供本地安装的 .vsix。要发布到市场让别人直接搜到安装,按目标用户选择市场:
| 目标用户 |
市场 |
| Positron 用户 |
Open VSX(目录会同步进 Positron 默认的 P3M) |
| VS Code 用户 |
VS Code Marketplace |
Positron 出于授权限制不能用 VS Code Marketplace,两者不互通;同一个 .vsix 可分别发布。发布流程、环境变量、Trusted Publishing(OIDC)与 GitHub Actions 配置见 docs/PUBLISHING.md。
快速开始(发布者 id 与令牌全部走环境变量,不写进仓库):
node scripts/publish.mjs check # 发布前自检,不联网、不发布
$env:LEETCODE_PUBLISHER = "<your-publisher-id>"
$env:OVSX_PAT = "<open-vsx-access-token>"
node scripts/publish.mjs ovsx # 发到 Open VSX(Positron 用户)
也可用 npm run publish:ovsx / publish:vscode / publish:all,或在 .github/workflows/publish.yml 里用 CI 发布。发布者 id、仓库地址在打包时注入 .vsix,源码 package.json 保持 local。
常见问题
Q:提示「找不到 Chrome / Edge」
自动查找 ProgramFiles、ProgramFiles(x86)、ProgramW6432、LOCALAPPDATA 下的 Google\Chrome\Application\chrome.exe 与 Microsoft\Edge\Application\msedge.exe。装在非标准位置就设 leetcode-cn.browserPath,或改用「手动粘贴 Cookie」。
Q:受控浏览器窗口一直不结束
默认等 300 秒。请确认在新弹出的那个窗口里完成登录(不是你日常的浏览器)。超时后点「取消」,再试一次或改用手动 Cookie。
Q:受控浏览器刚弹出来就自动关闭了
0.1.1 已修复。旧版把浏览器「启动器进程」的提前退出误判为窗口关闭;现在按 CDP 调试端口是否可达判断窗口存活,只有你真正关掉窗口、或登录成功完成导入后才会关闭。若调试端口被安全软件或企业策略拦截、25 秒内始终不可用,会明确提示改用「手动粘贴 Cookie」。
Q:点「微信 / QQ 扫码登录」,二维码刚出来、还没扫浏览器就关了
0.1.3 已修复。第三方 OAuth 跳转会在扫码前先写入一个匿名 LEETCODE_SESSION(用于保存 OAuth state / next),旧版把「存在会话 Cookie」误当成登录完成,校验发现未登录就报错并关窗;手机号登录不经过该跳转,所以只有扫码方式受影响。现在以 userStatus.isSignedIn === true 为唯一成功判据:扫码过程中窗口会一直保持打开,只有真正登录成功才导入 Cookie 并关闭窗口;网络抖动也不会误关窗或删除已保存的登录态。
Q:全屏做题时怎么收起题目列表 / 题面?
点顶部工具栏的 ☰(题目列表)可展开或收起左侧题目列表(点条目直接切题、输入框可按编号或标题筛选);点 ◧ / ▣ 可折叠 / 展开题面,让编辑器占满宽度。两个折叠状态会记住,下次进入全屏保持原样;退出全屏会自动还原,不影响普通布局。
Q:按钮只有图标,怎么知道是干什么的?
鼠标悬停会显示中文 title 提示,无障碍属性 aria-label 也带同样说明;导航项和内容卡片仍用中文文字,不做图标化,避免丢失语义。
Q:点侧边栏「每日一题 / 随机一题」怎么打开浏览器了?
0.1.7 已修复。旧版这两个入口(以及命令面板同名命令)会弹一个消息框,再点「打开题目」才用 openExternal 跳系统浏览器;现在与工作台内的每日一题、随机按钮一致,直接在插件里切到对应题目,不再弹框、不再跳浏览器。企业题库、学习计划等站内页面仍会在浏览器打开。
Q:代理环境下请求超时
设 leetcode-cn.proxy。若系统代理变量是无效地址(例如本机代理软件没开),把它设为 off 强制直连。
Q:断网 / 代理挂了,会不会又要重新扫码
不会。启动时校验只有拿到「明确未登录」的结果才会清理凭据;网络超时、代理异常、站点临时报错都只是本次校验失败,已保存的登录态原样保留,下次启动继续自动恢复。手动点「刷新登录状态」也不会因临时失败删凭据。
Q:为什么不能用「读取本机浏览器 Cookie」一键登录
Chrome 127+ 启用 App-Bound Encryption,Cookie 数据库里的值无法在进程外解密;而受控浏览器走 CDP 拿到的是浏览器自己解密后的值,所以可行。这也是本扩展把受控浏览器作为主推方式的原因。
Q:登录态存在哪、安全吗
存在 IDE 的 SecretStorage,由操作系统凭据系统加密,扩展自身读不到明文密钥。执行「退出登录」会立即删除。
开发
npm install
npm run check # tsc --noEmit + esbuild 打包
npm run smoke # 静态结构自检
npm run test:persistence # 持久登录流程端到端自检
npm run test:validate # 真实客户端的校验/过期/网络异常行为
npm run test:browser-login # 扫码登录:匿名 OAuth 会话不提前关窗
npm run test:contract # 前后端方法名与返回字段契约一致性
npm run test:fsui # 全屏折叠控件的真实交互自检
npm run test:brand # 界面文案品牌中性化自检
npm run test:open-in-workbench # 每日一题 / 随机一题在工作台内切题(不跳浏览器)
npm run test:publish # 发布就绪自检(元数据 / 图标 / 打包注入 / 文档)
npm run probe # 联网冒烟:匿名调用题库列表 / 每日一题
npm run package # 生成 .vsix
发布相关:node scripts/publish.mjs check(发布前自检)、npm run publish:ovsx / publish:vscode / publish:all,详见 docs/PUBLISHING.md。
目录说明:
| 路径 |
内容 |
src/extension.ts |
扩展宿主:SecretStorage 持久登录、Webview 桥、命令、状态栏 |
src/sidebar.ts |
活动栏侧边栏 TreeView |
src/leetcodeClient.ts |
全部业务方法(GraphQL / REST / 判题) |
src/http.ts |
Node HTTP 层:Cookie 合并、代理、超时、解压 |
src/browserLogin.ts |
受控 Chrome/Edge + CDP 自动导入 Cookie |
src/protocol.ts |
宿主与客户端之间的共享类型 |
media/index.html |
Webview 单文件工作台(内联样式、脚本与格式化器) |
assets/icon.png |
市场展示图标(PNG) |
scripts/package-vsix.mjs |
零依赖打包 .vsix(支持注入 publisher / repository) |
scripts/publish.mjs |
发布前自检 + 发布到 Open VSX / Marketplace |
docs/CONTRACT.md |
内部接口契约(方法名、返回结构、站点接口要点) |
docs/PUBLISHING.md |
发布指南(两市场、OIDC、CI、凭据) |
.github/workflows/publish.yml |
GitHub Actions 发布工作流 |
Webview 与宿主通过 postMessage 通信:{type:'request', id, method, params} → {type:'response', id, ok, data|error},宿主另有 {type:'event', ...} 推送登录态变化与提示消息。页面顶部注入了 window.dbxPlugin 兼容层,因此前端调用保持 call(method, params) 的形式。
与参考项目的关系
功能与站点接口取自 dbx-plugin-leetcode-cn,但架构做了调整:
- 去掉 Rust sidecar —— 扩展宿主本身就是 Node.js,直接发 HTTPS 请求,少一层进程间协议,也不需要为每个平台编译二进制;
- 去掉 DBX 工作台 iframe 的
default-src 'none' 限制带来的种种绕行;
- 保留原有 method 名,前端逻辑基本原样复用;
- 新增持久化:这是两个版本最本质的差别;
- 新增图标化动作按钮与主题适配:纯显示层调整,不动业务逻辑;
- 新增发布链路:PNG 图标、publisher 注入、Open VSX / Marketplace 双市场与 CI。
许可
MIT