JCode Onboarding 沙箱完全指南:用 JCODE_HOME 与 JCODE_RUNTIME_DIR 隔离首次引导状态,安全反复迭代
【免费下载链接】jcodeThe most RAM efficient harness项目地址: https://gitcode.com/GitHub_Trending/jcod/jcode
本文围绕 JCode 仓库中的 onboarding 沙箱方案 展开,讲解如何在不触碰真实认证状态的前提下,反复演练、测试与回归「首次使用引导(onboarding)」流程。读完本文,你将掌握scripts/onboarding_sandbox.sh的全部命令用法、JCODE_HOME/JCODE_RUNTIME_DIR两个环境变量的重定向原理、用真实登录数据做导入演练的技巧,以及可复用本地认证 fixture 与无头截图生成的完整工作流。
为什么需要 onboarding 沙箱
JCode 的 onboarding 流程是一套「有状态」的首次引导:它要完成 provider 登录、检测并导入已有的外部登录(Codex / Claude / Gemini / Copilot / Cursor / OpenCode / pi 等)、续接历史会话、展示新会话建议卡片等步骤。这些状态默认落在真实用户目录~/.jcode、真实运行时 socket 目录和真实的应用配置中。如果直接在本机反复跑 onboarding,会产生两个问题:
- 污染真实状态:每次试跑都会读写真实的登录凭据、信任决策与配置文件,一旦引导逻辑有 bug,可能破坏开发者的正常使用环境;
- 无法复现「全新机器」场景:真实环境里早已存在的登录状态和已信任的外部认证源,会让「首次运行」分支(如外部登录导入提示)根本无法被触达,也就无法测试与验证。
为此,仓库提供了scripts/onboarding_sandbox.sh:用独立沙箱目录承载 jcode 的全部状态,使每次迭代都从「干净的首次运行」开始,随时可一键重建。
核心原理:两个环境变量的状态重定向
沙箱的隔离能力完全建立在两个环境变量之上,onboarding_sandbox.sh 中对它们进行了明确布局:
| 环境变量 | 默认指向 | 作用 |
|---|---|---|
JCODE_HOME | ~/.jcode | 重定向 jcode 自有状态(如~/.jcode)、应用配置(JCODE_HOME/config/jcode)以及外部认证/会话查找根目录 |
JCODE_RUNTIME_DIR | 系统临时目录 | 重定向 socket 等一次性运行时文件 |
沙箱脚本会为每个沙箱构建如下目录结构:
<scratch_root>/onboarding/<sandbox_name>/ ├── home/ # 作为 JCODE_HOME 使用 └── runtime/ # 作为 JCODE_RUNTIME_DIR 使用其中<scratch_root>默认是$HOME/.jcode/scratch,可用JCODE_SCRATCH_DIR覆盖(见 onboarding_sandbox.sh)。
外部认证与转录的查找重定向
当设置了JCODE_HOME时,jcode 会把每一个外部凭据与转录的查找路径解析到$JCODE_HOME/external/<与 $HOME 相同的相对路径>。这一点在 crates/jcode-base/src/storage/tests.rs 中有直接的单测证据:user_home_path(".codex/auth.json")在设置了JCODE_HOME后解析为$JCODE_HOME/external/.codex/auth.json;同一个测试文件还验证了应用配置目录在设置了JCODE_HOME时解析为$JCODE_HOME/config/jcode(crates/jcode-base/src/storage/tests.rs)。
这样设计的好处是:onboarding 的「导入外部登录」逻辑本身无需任何改动——它只是按照既有的user_home_path规则去external/目录下找文件。沙箱只需要往这个目录里"种"入文件副本,检测与导入行为就和一台装有这些工具的全新机器完全一致。
外部认证信任决策存进沙箱配置
外部认证的信任决策(例如是否信任某个路径上的 Claude / Codex / Copilot 凭据)同样被写入沙箱配置(JCODE_HOME/config/jcode之下),而非真实配置。因此一个全新沙箱默认没有任何已信任的外部认证导入,正好对应真实用户的首次运行状态。相关信任判定逻辑可参见 crates/jcode-base/src/auth/claude.rs 与 crates/jcode-base/src/auth/codex.rs 中的has_unconsented_external_auth/trust_external_auth_source实现。
快速开始:一行命令进入干净沙箱
scripts/onboarding_sandbox.sh freshfresh等价于先reset(删除整个沙箱),再在沙箱内启动 jcode(见 onboarding_sandbox.sh)。它给你的是一次干净、完全隔离的 jcode 启动,适合立刻走一遍 onboarding 主流程。
脚本内部在启动 jcode 时还会做两件关键的事:
- 清除从父进程继承的
JCODE_CLIENT_SELFDEV_MODE、JCODE_SELFDEV、JCODE_CANARY,让沙箱行为与真实独立安装一致(onboarding_sandbox.sh); - 默认追加
--no-selfdev,避免因为在仓库内启动而自动加入共享 self-dev 服务器、跳过本地首次运行行为;如需共享服务器可设JCODE_SANDBOX_SELFDEV=1(onboarding_sandbox.sh)。
用你的真实登录做导入演练
干净的沙箱是完全隔离的,所以 onboarding 的「导入既有登录」步骤一开始没有东西可导入。为了演练「导入」与「续接历史会话」这两个步骤,可以把真实凭据和转录文件的副本种进沙箱:
# 复制真实外部登录(Codex/Claude/Gemini/Copilot/Cursor/OpenCode/pi) scripts/onboarding_sandbox.sh seed-real-logins # 同时复制真实的 Codex/Claude 转录,让"续接会话"步骤有真实历史可恢复 scripts/onboarding_sandbox.sh seed-real-logins --with-transcripts # 或者一步到位:重置沙箱 → 种入真实登录 → 启动 jcode scripts/onboarding_sandbox.sh fresh-real --with-transcriptsseed 了哪些文件
从 onboarding_sandbox.sh 的实现可以看到,脚本会按$HOME相对路径逐项复制以下认证/凭据文件到$JCODE_HOME/external/下:
.codex/auth.json(Codex).claude/.credentials.json、.claude.json(Claude).local/share/opencode/auth.json(OpenCode).pi/agent/auth.json(pi).gemini/oauth_creds.json(Gemini).config/github-copilot/hosts.json、.config/github-copilot/apps.json(Copilot).cursor/auth.json、.config/cursor/auth.json、.config/Cursor/User/globalStorage/state.vscdb(Cursor,多个候选路径)
以及两个转录目录(--with-transcripts时):
.codex/sessions(Codex 会话).claude/projects(Claude 项目/会话)
安全模型:复制而非移动
seed-real-logins使用的是副本(cp -a),不是符号链接——这是有意的设计:jcode 会拒绝符号链接形式的外部认证文件,对应的单测见 crates/jcode-base/src/storage/tests.rs 的validate_external_auth_file_rejects_symlink。复制完成后脚本会立即chmod -R go-rwx收紧external/目录权限。你的原始$HOME文件永远不会被移动、重写或删除,沙箱保持纯本地。
种入完成后启动沙箱走 onboarding:
scripts/onboarding_sandbox.sh jcode它会像一台装有这些工具的全新机器一样,检测并逐一提供真实登录的导入选项。
注意:这些副本包含真实的 token,会一直存留到
reset或purge-external。status命令会在检测到external/存在时给出醒目警告。fresh-real在退出时会自动清除这些副本,除非设置JCODE_ONBOARDING_KEEP_EXTERNAL=1(onboarding_sandbox.sh)。
常用命令总览
| 命令 | 作用 |
|---|---|
env | 打印沙箱的环境变量导出(JCODE_HOME/JCODE_RUNTIME_DIR) |
status | 显示沙箱路径与当前内容,并在含真实凭据副本时告警 |
reset | 彻底删除沙箱 |
fresh | 重置后启动干净的 jcode |
shell | 打开带沙箱环境变量的干净 shell |
jcode [args...] | 在沙箱内运行任意 jcode 命令 |
auth-status | 在沙箱内运行jcode auth status |
login <provider> | 在沙箱内运行jcode --provider <provider> login ...,不影响正常 jcode 配置 |
seed-real-logins [--with-transcripts\|--transcripts-only] | 种入真实外部登录(及转录)副本 |
fresh-real [--with-transcripts] | 重置 → 种入真实登录 → 启动 jcode |
purge-external | 仅删除已复制的真实凭据/转录 |
fixture-list / fixture-save / fixture-load / fixture-run | 本地认证 fixture 的列表、保存、加载、加载后执行 |
典型用法示例:
# 查看确切的环境变量与沙箱路径 scripts/onboarding_sandbox.sh env scripts/onboarding_sandbox.sh status # 从空白 onboarding 状态重新开始 scripts/onboarding_sandbox.sh reset scripts/onboarding_sandbox.sh fresh # 在不触碰正常 jcode 配置的情况下登录某个 provider scripts/onboarding_sandbox.sh login openai scripts/onboarding_sandbox.sh login claude scripts/onboarding_sandbox.sh auth-status # 在沙箱内运行任意 jcode 命令 scripts/onboarding_sandbox.sh jcode auth status scripts/onboarding_sandbox.sh jcode pair脚本还支持用JCODE_ONBOARDING_SANDBOX命名多套互不干扰的沙箱(默认名为default),名称必须匹配^[A-Za-z0-9][A-Za-z0-9._-]*$且不能是./..(onboarding_sandbox.sh)。
可复用的本地认证 fixture
对于反复进行的登录测试,不要每次重新走一遍浏览器登录——把沙箱在某个「有趣状态」(典型的已登录 OpenAI 用户、token 过期状态、外部认证导入待批准状态等)下的JCODE_HOME存成本地 fixture。
fixture 存储默认位于.tmp/auth-fixtures,这是刻意的本地开发状态目录。fixture 可能包含真实的 OAuth token 或 API key 引用,切勿提交或分享。
推荐工作流(一次性建立真实登录态,之后快速复用):
# 一次性设置一个真实的已登录状态 scripts/onboarding_sandbox.sh reset scripts/onboarding_sandbox.sh login openai scripts/onboarding_sandbox.sh auth-status scripts/onboarding_sandbox.sh fixture-save normal-openai # 之后的快速循环 scripts/onboarding_sandbox.sh fixture-load normal-openai scripts/onboarding_sandbox.sh auth-status scripts/onboarding_sandbox.sh jcode auth-test --provider openai也可以加载 fixture 后直接执行一条命令:
scripts/onboarding_sandbox.sh fixture-run normal-openai -- auth-test --provider openai --no-smoke底层 fixture 助手
fixture 机制由 scripts/auth_fixture.sh 独立实现,onboarding_sandbox.sh通过run_auth_fixture转发(onboarding_sandbox.sh)。其命令包括:
scripts/auth_fixture.sh list # 列出已保存的 fixture scripts/auth_fixture.sh save normal-openai # 把当前沙箱 JCODE_HOME 存为 fixture scripts/auth_fixture.sh load normal-openai # 用 fixture 替换沙箱 JCODE_HOME scripts/auth_fixture.sh run normal-openai -- auth status # 加载后执行命令 scripts/auth_fixture.sh path [name] # 打印 fixture 根目录或某个 fixture 路径 scripts/auth_fixture.sh delete <name> # 删除一个 fixture scripts/auth_fixture.sh reset-sandbox # 仅清空当前沙箱 JCODE_HOME保存时会在 fixture 下写入metadata.txt,记录name、saved_at、sandbox_name、source_jcode_home,并明确标注「May contain real local auth tokens. Do not commit or share.」(scripts/auth_fixture.sh)。
有用的环境覆盖
| 环境变量 | 作用 |
|---|---|
JCODE_ONBOARDING_SANDBOX | 选择接收 fixture 的沙箱名(默认default) |
JCODE_ONBOARDING_DIR | 指定显式的沙箱目录 |
JCODE_AUTH_FIXTURE_DIR | 把 fixture 存储放到仓库之外,例如~/.local/share/jcode-auth-fixtures |
JCODE_SCRATCH_DIR | 覆盖沙箱父目录(默认$HOME/.jcode/scratch) |
建议的 fixture 命名约定:normal-openai、normal-claude、expired-openai、api-key-openrouter、external-opencode-approved。
移动端 onboarding 模拟器
仓库还提供了一个可重置的无头移动端模拟器,内置预定义 onboarding 场景,用于迭代移动端引导 UX(由 iOS 侧的JCodeMobile相关实现支撑):
# 后台启动模拟器(默认场景 onboarding) scripts/onboarding_sandbox.sh mobile-start onboarding # 检查状态 scripts/onboarding_sandbox.sh mobile-status scripts/onboarding_sandbox.sh mobile-state scripts/onboarding_sandbox.sh mobile-log # 重置回场景起点 scripts/onboarding_sandbox.sh mobile-reset当前支持的场景:
onboarding:首次引导pairing_ready:配对就绪connected_chat:已连接会话
无头截图:生成导入登录的成功引导序列
scripts/capture_onboarding.sh可以不启动终端、不读取真实凭据地生成「成功导入登录」的 onboarding 截图序列:
scripts/capture_onboarding.sh # 或指定输出目录: scripts/capture_onboarding.sh ~/onboarding-screenshots其工作原理(见 capture_onboarding.sh):设置JCODE_ONBOARDING_SCREENSHOT_DIR后,运行cargo test -p jcode-tui --lib onboarding_import_happy_path_images -- --ignored --nocapture。该测试把线上应用使用的同一套OnboardingFlow阶段与 ratatui widget 树渲染到离屏的TestBackend(对应测试位于 crates/jcode-tui/src/tui/app/tests/onboarding_golden.rs)。输出为 SVG;若安装了rsvg-convert,会同时生成 PNG。
onboarding_graph.rs中的每个静止状态(resting state)都会得到渲染:OpenAI 登录提示、已检测登录汇总(含选择模式与遥测子页)、导入进度卡片、恢复与失败界面、legacy 续接提示,以及完整应用帧(起始选择器、新会话建议、已接受的建议评审轮次)。状态机本身定义在 crates/jcode-tui/src/tui/app/onboarding_graph.rs,其中 12 个NodeId节点、显式声明的EdgeId转移以及结构不变量检查(如every_failure_node_reaches_a_settled_state_quickly、the_happy_path_stays_short)保证了引导图的可验证性。
为什么这样更安全
一个全新的沙箱意味着:
- 不复用任何真实 jcode 配置文件
- 不复用任何真实运行时 socket
- 不复用任何此前已信任的外部认证来源
- 一次
reset即可整体销毁
使用 fixture 时,沙箱与正常 jcode 状态依然是隔离的,只是加载的 fixture 可能刻意包含来自更早沙箱登录复制的认证状态。此外脚本的reset自带双重保护:拒绝删除/、$HOME、仓库根目录等危险路径;对自定义沙箱目录要求存在.jcode-onboarding-sandbox标记文件,否则拒绝删除(onboarding_sandbox.sh)。所有沙箱目录、JCODE_HOME、运行时目录均以700权限创建,外部凭据副本以go-rwx收紧,marker 文件为600(onboarding_sandbox.sh)。
推荐的迭代工作流
紧耦合的 onboarding 迭代循环:
scripts/onboarding_sandbox.sh resetscripts/onboarding_sandbox.sh fresh- 走一遍 onboarding 流程
- 调整代码
- 重复
如果专门在迭代移动端 onboarding UX,保持模拟器运行,在每轮之间使用mobile-reset。
注意事项
沙箱的设计目标是隔离jcode 自有状态与受信任的外部导入状态。如果你后续想要显式测试来自外部工具的「导入/复用」流程,请有意为之,并将其视为与首次运行 onboarding 相互独立的测试用例——不要混在同一轮迭代里。
延伸阅读
- 沙箱主脚本:scripts/onboarding_sandbox.sh
- fixture 底层助手:scripts/auth_fixture.sh
- 无头截图脚本:scripts/capture_onboarding.sh
- 状态重定向与外部文件校验的单测:crates/jcode-base/src/storage/tests.rs
- onboarding 状态机定义:crates/jcode-tui/src/tui/app/onboarding_graph.rs
- 外部认证信任判定:crates/jcode-base/src/auth/claude.rs、crates/jcode-base/src/auth/codex.rs
【免费下载链接】jcodeThe most RAM efficient harness项目地址: https://gitcode.com/GitHub_Trending/jcod/jcode
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考