跳转至

开发

首次检出

使用根 README安装 vp。它提供了 package.json 中固定的 Node 版本(Node 26),因此无需单独安装 Node。在仓库根目录执行:

vp i
vp run dev

打开开发运行器打印出的配对 URL。裸的 origin 无法对新浏览器进行身份验证。

更喜欢容器?请参阅开发容器了解 VS Code 和 Codespaces 的配置。

GitCafe 镜像(可选)

GitHub 是权威来源。git.cafe/pingdotgg/t3code 是一个双向同步镜像,API 速率限制高得多,在大量 agent 同时工作时很有帮助。你永远不需要它来参与贡献。

在 GitCafe 上进行的推送、PR、评论、评审、标签和 Issue 编辑会在约一分钟内同步到 GitHub,且 PR 和 Issue 编号一致。CI 在 GitHub 上运行,其检查结果会显示在 GitCafe 上。

git remote set-url origin https://git.cafe/pingdotgg/t3code.git
git remote add github https://github.com/pingdotgg/t3code.git
gh repo set-default pingdotgg/t3code   # `gh` 仍用于合并
bun install -g @gitcafe/cli@latest   # `cafe` 需要 Bun 1.2 或更高版本
cafe auth login && cafe auth http setup
cafe skills install --global  # 可选:供编码 agent 使用的 cafe-* skills

将 origin 设置在 git.cafe 后,请通过 GitCafe 工作,并让 GitHub 的 API 保持空闲:

  • 推送到 origin,使用 cafe pr create(从 fork 使用 --head owner/repo:branch)或 cafe stack submit 打开 PR,之后的一切都使用 cafe。在工具跟踪 PR 的地方,请链接 git.cafe 的 PR URL,而不是 github.com 的,这样轮询就保持在 GitCafe 上。
  • 使用 cafe pr status <n> 读取检查状态,使用 cafe ci logs <run> 读取 GitHub Actions 日志(运行 id 来自 cafe ci list --pr <n>)。cafe ci rerun <run> 可重新运行某一个。这些需要 cafe 0.11 或更高版本。
  • 关闭引用请写成 Fixes pingdotgg/t3code#<n>。GitCafe 会将其同步到 GitHub 的文本中的裸 #<n> 转换为 git.cafe 链接,而 GitHub 不会因此关闭 Issue。
  • 使用 gh pr merge <n> --match-head-commit <sha> 合并,因为 cafe pr merge 无法固定你已评审的提交。
  • cafe 命令与 gh 不同:是 cafe issue comments <n> 而不是 --comments,是 cafe pr status 而不是 pr checks。

选择开发流程

使用 vp run dev 启动服务器和 Web 端,或使用 vp run dev:desktop 启动 Electron 客户端。dev:server 和 dev:web 会分别启动这些进程。原生构建和 Metro 请参阅移动端 README。

标志直接放在任务名之后,例如 vp run dev --home-dir /tmp/t3code-dev。加上 --browser 可自动打开浏览器。

要在工作树的线程稳定后停止其开发栈,请从 t3.json 导入 Dev 操作(位于 Settings > Projects > Actions),然后通过操作菜单或其快捷键启动它。它的 stopOnSettle 选项让 T3 可以停止终端及其子进程。通过 agent 自己的 shell 工具运行 vp run dev 不会将其挂接到此生命周期。

状态与端口

关联的工作树默认使用各自的 .t3/userdata,即使设置了 T3CODE_HOME 也是如此。主检出目录默认为 ~/.t3/dev。两种情况下,显式指定的 --home-dir 都优先。

工作树首次启动时,如果源文件不超过 500 MiB,会从 ~/.t3/userdata/statev2.sqlite 的只读副本为空的数据库填充种子数据。更大的源文件会发出警告,并以空数据库启动开发环境。--no-seed 或 T3CODE_DEV_SEED=0 可跳过种子数据填充。

要复制更大的源文件,请在开发环境停止后运行 vp run migrate-dev-db。它可能在清理前占用大量磁盘空间。切勿针对实时的 ~/.t3/userdata 运行开发服务器。复制一致的数据库快照请参阅测试数据。

从 [dev-runner] 输出中读取端口。工作树会根据自身路径得出稳定的偏好设置,但已占用的端口可能会改变它们。需要时,T3CODE_PORT_OFFSET 或 T3CODE_DEV_INSTANCE 可以选择不同的偏好。

Replay 提供器

vp run dev 会注册 Replay (dev),这是一个本地 ACP agent,位于 dev-replay-agent.ts。它通过模拟流式传输来播放录制的 ACP 转录,因此真实的适配器、编排和 UI 可以在不使用付费模型的情况下运行。每个场景就是一个模型,每个提示会播放下一个录制的轮次。

捆绑的服务器(包括桌面开发环境)会跳过它,因为它们没有 agent 脚本。开发服务器会在启动时将其重新添加,因此请在 Settings 中关闭它,而不是删除它。

要添加场景,请将 SCENARIOS 条目指向通用的 ACP 回放夹具(registry_transcript.ndjson)或 dev-replay 中的文件。该 agent 会回放会话更新、权限请求和问题。它会丢弃会话设置和供应商帧,因此 Grok 和 fx 的录音会丢失其仅限供应商的行为。

分析开发启动性能

运行 vp run profile:startup 可捕获 .t3/startup-profiles/<timestamp> 下继承的 Node 进程的前 20 秒。执行预加载的 Worker 会获得单独的配置文件。它会启动正常的开发运行器并接受其标志。捕获完成后按 Ctrl+C 停止它。设置 T3CODE_STARTUP_PROFILE_DIR 可选择其他输出目录。

性能分析会带来额外开销,因此要与普通的 vp run dev 运行对比就绪状态。

在 Chrome DevTools 的 Performance 面板中打开 .cpuprofile,可查看采样函数堆栈和源代码行。每个 .modules.json 都是 Chrome trace,包含模块解析、加载、同步子进程调用和启动计时的计时信息。每个文件的记录包括导入器 URL、源码加载、准备、递归依赖链接和顶层求值。准备阶段使用同步加载器边界;链接阶段包含依赖项,CommonJS 求值可能包含嵌套的 require 调用。某些 ESM/CommonJS 互操作会报告组合阶段。.process.json 记录进程、Node 版本和捕获窗口。

服务器的嵌套 Effect 和 SQL spans 保留在 .t3/userdata/logs/server.trace.ndjson 中。

预加载会临时添加模块主体计时标记,并使用一次自动调试器暂停来对活动中的 Node 加载器进行插桩。启动器会将 --no-node-snapshot 添加到继承的 NODE_OPTIONS 中,因为 Node 26 的快照加载器无法接受该断点。直接使用 preload 时也要包含相同的标志。这会禁用 Node 内置的启动快照,可能改变编译缓存命中率,并增加开销。将逐文件捕获视为诊断性运行;基准启动延迟应使用未插桩的运行。第一个入口模块可能在加载器插桩安装之前就已编译。

全新进程仍会使用文件系统、Node 编译、provider 和 Vite 依赖缓存。应分别测量缺少 Vite 依赖缓存的情况与使用现有数据库重启的情况。Vite 就绪消息和 HTTP 监听器都不能证明浏览器已经渲染了应用。

共享与远程调试

vp run dev --share 会通过机器的 tailnet 发布 Web 端口,并打印该来源的配对 URL。请将完整 URL(包括其 token)交给测试人员。开发运行器会在退出时移除其映射。

保持 VITE_HTTP_URL 和 VITE_WS_URL 未设置。Vite 通过浏览器的来源代理后端,因此同一构建在 localhost 和远程连接上都能工作。

共享运行启用 bundled dev 以避免每个导入层级的一次网络往返。在调试 bundler 差异时,T3CODE_BUNDLED_DEV=0 可选择退出。更改此设置时有两个重载陷阱需要注意:

  • Web 入口必须动态导入应用,以便 React refresh 在应用 chunk 之前初始化。静态导入可能在首次加载时正常,但在路由拆分后失败。
  • Bundled dev 通过被监视的文件重建 Tailwind。其常规 Vite 热更新钩子期望一个 Rolldown 不提供的服务器/模块图。
  • 应用及其路由是懒加载 chunk,在首次请求时构建。一个插件在服务器启动时预打包启动链。重命名或移动启动路由或应用入口会静默地将其从该列表中移除。

这些解决方法位于 web entry、Tailwind plugin 和 startup warmup 中。

vp run dev --share --built 会跳过 Vite 开发服务器。它为 Web 应用运行 vp build --watch,后端在同一 tailnet URL 和配对流程上提供 apps/web/dist。当有人通过慢速链接测试或只需要使用应用时,可使用此模式:加载是生产大小,首次加载不需要等待开发打包。没有 HMR。编辑后,等待 built in 行(约 6 秒),然后重新加载。在首次构建完成之前,URL 显示一个会自动重新加载的页面。此模式不生成许可证清单。--built 需要 --share 和 dev 模式。

可复用的开发凭证

仅在您信任所有服务的主机名上使用此功能。浏览器会向该主机名上的所有端口发送 cookie。您在该主机名上访问的任何服务都可能收到可复用的管理员凭证,包括与 T3 Code 无关的服务。如果您在该主机名上运行不受信任的服务,请改用正常的按环境配对。

要在同一主机名上的多个 Web 开发 worktree 中使用同一个浏览器配置文件,请一次性生成一个固定值:

openssl rand -hex 32

将该值放入主检出目录的 gitignored .env 文件中:

T3CODE_DEV_AUTH_TOKEN=<the value generated above>

t3.json 中的 Setup Worktree 操作会将该文件链接到每个 worktree 的 .env。开发运行器在启动时读取仓库的环境变量文件。.env.local 和继承的进程环境变量值会覆盖 .env,因此设置后无需按 worktree 导出。

对于没有该链接的手动 worktree 或启动器,请改为导出相同的固定值:

export T3CODE_DEV_AUTH_TOKEN="<the value generated above>"

不要在启动时生成新值。配置完成后启动或重启 vp run dev --share,然后在该主机名上的每个浏览器配置文件中打开其打印的启动配对 URL。之后同一主机名上的 Web 开发服务器会在各端口间接受共享 cookie。该 cookie 在 30 天后过期。如果旧标签页的 URL 现在提供的是替代环境,请重新加载该标签页。

token 和启动配对 URL 是可复用的管理机密。绝不要将它们放入提交、拉取请求或公共输出中。每个服务器仍会在启动时植入自己的认证数据库记录,并保留自己的 SQLite 数据、签名密钥和撤销状态。桌面端和非开发服务器会忽略该值。安全模型请参阅 环境认证。

检查

vp run check:changed 会为您的分支更改运行 CI 的快速检查:更改文件的格式和 lint、代码或清单更改时的 knip:check、生成的 GraphQL 检查、受影响包及其依赖者的类型检查,以及更改文件旁边的测试文件。它还会运行读取其他文件的检查:服务器受影响时的 agent 上下文预算,以及仅针对更改的 Web 和移动文件的 React Compiler 覆盖。与 CI 一样,它使用 ci-changes.cjs 将文件映射到包。它与会任何远程的 main 最近的合并基础进行比较,因此 main 落后于上游的 fork 仍会与上游比较,或与您传入的 ref 比较。CI 仍会运行完整测试套件和摘要中列出的作业,因此本地通过并不能保证 CI 运行一定通过。

各步骤并行运行,机器允许的情况下尽可能多地同时进行:每两个核心一个,每 6 GiB 可用内存一个。在大型机器上,一次运行大约与其最慢的步骤耗时相当,通常是 knip 的导出检查,约 10 秒。传递 --concurrency <n> 或设置 CHECK_CHANGED_CONCURRENCY 可更改限制(1 表示逐个运行步骤)。运行超过 --timeout <seconds> 或 CHECK_CHANGED_TIMEOUT(默认 900)的步骤会连同它启动的每个进程一起被终止,并报告为 TIMEOUT,而不是失败检查。当文件与上次通过的运行完全相同时,它会打印该运行的摘要而不是重新运行。对文件、安装或生成文件的任何更改都会重新运行检查。

在迭代过程中,请运行单项检查:

vp test run <files>
vp lint <files>
vp run --filter <package> typecheck

在 apps/web 中,凡是渲染 React 或触碰 DOM 的测试都命名为 *.browser.test.{ts,tsx},并像应用本身一样在启用了 React Compiler 的无头 Chromium 中运行。没有 jsdom;其他 *.test.ts 文件在 Node 中运行。

TypeScript 工作区通过 @effect/tsgo 的 effect-tsgo tsrs --noEmit 进行类型检查:即内置 Effect 诊断、快速修复和重构的 tsrs 检查器。只有 apps/marketing 为 Astro 安装了 typescript。VS Code 的 TypeScript 7 扩展通过 .vscode/tsdk/tsgo(js/ts.tsdk.path)启动同一个检查器,它是一个 POSIX 脚本,因此在 Windows 上请通过 WSL 打开工作区。

原生移动端改动请使用 vp run lint:mobile。完整测试套件由 CI 负责;当前任务见 ci.yml。该套件并非必需门禁,但手动 Windows 通道可用于针对性的 Windows 调查。

未使用的代码

vp run knip:check 检查整个仓库中未使用的文件和依赖项,同时检查 apps/server、apps/desktop、apps/web 以及 packages/ 下每个内部包中未使用的运行时导出。CI 强制执行这两项检查。 允许导出类型和 Effect schema 而没有使用者。schema 预处理器能识别 schema 类型,包括别名和 schema 类;创建或解码 schema 的函数仍会被检查。规范的 Effect 服务构造 API 通过显式 @public 注解保持导出,Knip 会识别该注解。完全未使用的文件也仍会被检查。 Web UI 组件模块中的命名导出作为完整组件集保留。Knip 会忽略 apps/web/src/components/ui/*.tsx 中未使用的导出,但仍会报告整个文件未使用的情况。 使用 vp run knip --workspace apps/web 审计单个工作区(包括导出),或使用 vp run knip:production --workspace apps/web 查找仅由测试维持存活的代码。完整的导出审计仍有发现项,且不是仓库级 CI 门禁。随着更多工作区变得干净,请扩展导出检查的工作区选择器。删除代码前先审查调用方;生产模式也可能会报告开发脚本和测试夹具。运行时发现的入口点和依赖例外应放在 knip.jsonc 中。

桌面构建产物

本地构建产物默认不签名,并写入 release/:

vp run dist:desktop:dmg
vp run dist:desktop:linux
vp run dist:desktop:win

dist:desktop:linux 以 x64 为目标。要构建原生 Linux ARM64 版本,请运行:

vp run dist:desktop:artifact --platform linux --target AppImage --arch arm64

DMG 默认采用主机架构。使用 --arch 选择其他目标,使用 --keep-stage 保留打包文件以供检查。运行 vp run dist:desktop:artifact --help 查看其他选项。

预生成的服务器字节码

原生的 macOS 和 Windows 桌面构建产物,以及原生的 Linux x64 和 ARM64 构建,会在 ASAR 创建之后、签名之前,使用打包好的 Electron 可执行文件生成服务器字节码。生成过程会导入 CLI 和服务器模块声明,但不会启动服务器服务;仅用于 worker 的模块正常编译。AppImage 后端会为每个挂载使用临时链接,并在正常退出时移除这些链接。后续启动会回收链接指向已消失挂载的废弃缓存目录;AppImage 主进程缓存保持禁用。在 ARM64 主机上进行 macOS x64 构建时,会在 Rosetta 下运行打包好的 x64 Electron 以生成缓存。其他跨平台和跨架构构建会显式跳过生成。CLI、SEA 和 WSL 运行时保持其现有行为。

Electron 的 Node 24 缓存没有只读选项,并且目录名中包含生产者 UID。后端会将各个预生成文件以已安装模块路径为键,链接到其可写缓存中。Node 会原子地替换文件,因此重新生成无法通过这些链接写入已签名的资源。Windows 使用硬链接,当卷不同或资源权限阻止链接时,会回退到普通缓存。因此,受保护的安装可能无法复用预生成的字节码。启动期间不会复制任何缓存字节。

键的计算遵循 Node 内部的可移植 ESM 格式。生成过程会检查打包引擎是否产生了预期的 CLI 和服务器条目,如果该格式发生变化,则构建失败。清单还会检查 Electron、Node、操作系统、架构以及 V8 的 flags 敏感版本标签。缺失或被拒绝的条目会从随附的 JavaScript 编译。预生成后端会跳过启动时的显式刷新;Node 可以在正常退出时持久化缺失条目。可写回退保留了 Windows 强制杀死后端时所需的显式刷新。

Linux AppImage 先决条件

在 Linux 上构建,因为 browser-secret 辅助程序会链接宿主机的 libsecret。请安装 C/C++ 构建工具、libsecret 开发头文件、pkg-config 和 ImageMagick。字节码准备还会运行打包好的 Electron,并且需要 GTK、NSS、ALSA 和 GBM 运行时库。通过 rustup 安装 Rust 1.95 或更高版本,并使用与发布 CI 相同的 stable 工具链。

Ubuntu 24.04 和 Debian 13:

sudo apt-get update
sudo apt-get install build-essential libsecret-1-dev pkg-config imagemagick libgtk-3-0t64 libnss3 libasound2t64 libgbm1

在 Ubuntu 22.04 和 Debian 12 上,使用 libgtk-3-0 和 libasound2 代替 t64 包。

Fedora:

sudo dnf install gcc gcc-c++ make libsecret-devel pkgconf-pkg-config ImageMagick gtk3 nss alsa-lib mesa-libgbm

Arch Linux:

sudo pacman -S base-devel libsecret pkgconf imagemagick gtk3 nss alsa-lib mesa

C 工具链、pkg-config 和 libsecret 头文件也是 Linux 桌面开发所必需的。

macOS DMG 前提条件

使用 xcode-select --install 安装 Xcode Command Line Tools,并安装 Rust。 如需跨架构或通用构建,请添加所需的 Rust targets:

rustup target add aarch64-apple-darwin x86_64-apple-darwin

Windows 安装程序前提条件

安装 Rust、Python 3,以及包含 Desktop development with C++ 的 Visual Studio Build Tools。 为目标架构包含 Windows SDK、MSVC build tools 和 Spectre-mitigated libraries。 添加其 Rust target:

rustup target add x86_64-pc-windows-msvc
# 如需 ARM64 安装程序:
rustup target add aarch64-pc-windows-msvc

NSIS 由 electron-builder 下载。WSL 支持还需要将 Linux CLI 归档作为 --wsl-runtime 传入;请参阅 发布手册。

签名与通行密钥

在发布手册中配置好平台凭据后,添加 --signed。 macOS 通行密钥需要已签名并配置描述文件的应用;本地签名和 renderer HMR 请遵循 Connect 设置。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 t3/t3code