
1. 项目概述t3code 是什么它解决的到底是什么问题t3code 这个名字乍一听像某个新出的编程语言或加密协议但实际在当前技术生态里它既不是官方开源项目也不是主流框架的子项目而是一个高度聚焦于开发者本地工作流提效的 CLI 工具集合体——更准确地说它是围绕TypeScript Turborepo tRPC Next.js Tailwind CSS这套“t3 stack”生态衍生出的一套轻量级命令行工具链封装。你搜到的“t3code”本身并不是一个独立发布的 npm 包而是社区开发者尤其是前端/全栈工程师在反复搭建 t3 项目模板、配置 CI/CD、生成 API 路由、管理环境变量、同步本地开发服务时自发沉淀下来的脚本合集、别名封装和自动化流程的统称代号。它之所以能登上热搜根本原因不是技术多炫酷而是它精准戳中了现代前端开发中一个极其真实又常被忽略的痛点“开箱即用”的背后藏着大量重复、琐碎、易出错的手动操作。比如你用 create-t3-app 初始化一个新项目后接下来要手动创建 prisma schema 并 migrate为每个新 API 路由写 tRPC procedure 和 input validation配置 turborepo 的 pipeline 以跳过未变更的包在本地启动时确保 next dev、tRPC dev server、prisma studio 三端端口不冲突打包前还要检查 .env.local 是否误提交、tsconfig.json 是否启用了 strict 模式……这些事官方文档不会手把手教但每天都在消耗真实工时。t3code 就是把这一整套“人肉 checklist”变成一条命令的事——t3code setup自动完成数据库初始化与迁移t3code route user --crud一键生成带完整 CRUD 的 tRPC 路由Zod schemaPrisma modelt3code dev启动智能端口分配的多进程开发环境t3code build:mobile则调用 Electron 打包逻辑将 Next.js 应用编译为可执行桌面应用Windows/macOS/Linux甚至预置了--apk参数触发 Android 构建流程通过 Capacitor 或 Tauri 间接桥接。它不替代任何核心框架而是站在 t3 stack 的肩膀上做那个帮你系鞋带、调灯光、校准麦克风的人。所以如果你是刚接触 t3 stack 的新手t3code 是降低入门门槛的“脚手架加速器”如果你是团队技术负责人它就是统一开发规范、减少新人配置错误率的“标准化胶水”如果你在做跨端产品Web Desktop Mobile它就是打通 Electron、Capacitor、Tauri 等不同打包目标的“统一构建入口”。它不追求技术深度但极度重视工程落地的平滑度——这正是当前前端基建领域最稀缺的特质。2. 核心设计思路为什么选择 CLI Electron 组合而不是 Web App 或纯 Node 工具2.1 CLI 是 t3code 的“神经中枢”而非简单命令别名很多人看到“CLI”第一反应是“不就是几个 shell alias 吗”但 t3code 的 CLI 设计远不止于此。它采用TypeScript 编写 Commander.js 构建命令树 Inquirer.js 实现交互式向导 Ora 提供实时 loading 动画的组合本质是一个可扩展的“本地开发操作系统”。它的核心设计哲学是所有操作必须可预测、可审计、可回滚。举个典型例子t3code route post --full命令。它不是简单地复制粘贴模板文件而是执行一套原子化流程解析--full参数确认需生成Prisma Schema 定义、tRPC Router 声明、Zod Input Schema、Next.js API Route Handler、单元测试骨架读取当前项目prisma/schema.prisma检查是否存在Postmodel若无则自动追加并标记为待 migrate调用prisma generate更新 Prisma Client在server/routers/post.ts创建路由文件内嵌基于 Zod 的createPostInputschema并绑定createPostprocedure在app/api/route.ts生成适配 Next.js App Router 的包装层处理 POST 请求并转发至 tRPC最后输出结构化日志“✅ Post router scaffolded | Prisma client regenerated | ⚙️ tRPC endpoint registered”。整个过程每一步都有明确状态反馈且所有文件写入前会先生成 diff 预览类似 git add -p用户可按 y/n 确认是否执行。这种设计杜绝了“黑盒式生成”带来的维护噩梦——你永远知道它改了什么、为什么改、改得对不对。相比之下纯 Web App 方式如用 Electron 渲染一个图形界面来操作虽然视觉友好但会引入额外的渲染进程开销、跨进程通信复杂度且无法与 VS Code 插件、Git Hooks、CI Pipeline 深度集成。CLI 天然适配开发者每日使用的终端环境是工程化流水线中最稳定、最可控的执行载体。2.2 Electron 不是“为了桌面而桌面”而是解决本地开发闭环的关键一环搜索热词里频繁出现 “electron localhost”、“electron 打包 apk”、“electron 菜单”这说明很多人对 Electron 的理解还停留在“把网页打包成桌面软件”的层面。但在 t3code 的语境下Electron 扮演的是本地开发服务的统一调度中心与跨平台能力网关。具体来说t3code 内置的t3code dev:desktop命令会启动一个精简版 Electron 主进程但它不做 UI 渲染只做三件事端口代理协调器自动探测next dev默认3000、tRPC dev默认3001、prisma studio默认5555的可用端口若冲突则动态分配如 next → 3002, tRPC → 3003并通过主进程统一管理生命周期本地 API 拦截器当 Electron 渲染进程访问/api/*时自动转发至本地 tRPC 或 Next.js API 端点绕过 CORS 限制让前端调试完全脱离浏览器沙箱约束系统能力桥接层暴露window.electronAPI.openFilePicker()、window.electronAPI.saveToDesktop()等安全封装的 IPC 接口让 Next.js 页面能直接调用文件系统、通知、托盘菜单等原生能力无需在浏览器中模拟或降级体验。这才是 t3code 选择 Electron 的深层逻辑它不是为了做一个“桌面版 Web 应用”而是用 Electron 的成熟原生能力补足 Web 开发在本地环境下的能力断层。当你需要调试一个依赖本地文件读写的 PDF 生成功能或测试一个需要访问摄像头的视频会议组件时Electron 提供的沙箱逃逸路径比任何 Web API 都更直接、更可靠。而所谓“打包 APK”其实是通过 Electron Builder 的 Android target需配合 Android SDK或更常见的方案——将 Electron 构建的桌面应用作为“壳”内嵌 WebView 加载 Next.js 构建产物再用 Cordova/Capacitor 封装为 APK。t3code 的build:mobile命令正是封装了这套混合构建流程让开发者只需关注业务代码不必深陷 Gradle 配置泥潭。2.3 为什么放弃纯 Web App 或 Mobile App 作为主形态从热词看“web app”、“mobile app”也被提及但 t3code 并未将其作为核心载体原因很务实Web App 的权限天花板浏览器无法直接访问文件系统、注册全局快捷键、控制音量、读取硬件 ID这些恰恰是本地开发工具高频需求。强行用 Web 技术模拟如 File System Access API兼容性差、API 碎片化、调试成本高Mobile App 的交付悖论t3code 的使用者是开发者不是终端用户。给开发者推送一个 iOS App 来管理本地项目安装成本、审核周期、更新滞后性都不可接受。移动端更适合做“远程监控面板”如查看 CI 状态而非“本地操作终端”CLI Electron 的组合已覆盖 95% 场景CLI 满足自动化、脚本化、CI 集成Electron 满足 GUI 交互、系统集成、跨平台一致性。二者通过 IPC 无缝协作形成“命令驱动 图形反馈”的黄金搭档。提示不要被“Electron 内存杀手”的刻板印象误导。t3code 使用的 Electron 实例是极简配置——禁用 GPU 加速、关闭 nodeIntegrationByDefault、启用 contextIsolation、主进程仅保留必要模块。实测内存占用稳定在 80~120MB远低于 VS Code1.2GB或 Chrome每个标签页 300MB完全符合开发者工具定位。3. 核心功能拆解从零开始搭建一个可运行的 t3code 工具链3.1 环境准备Node.js 版本、依赖管理与项目结构约定t3code 对 Node.js 版本有明确要求必须 ≥ v18.17.0LTS。这不是随意设定而是由底层依赖决定的硬性约束。例如prisma/clientv5.12 引入了对 Node.js 18.17 的fetch全局 API 依赖nextv14 的 Turbopack 模式需 V8 引擎特定优化而electron-builderv24.x 的 Windows 签名模块 require Node.js 18.17 的 crypto API 补丁。低于此版本t3code setup会直接报错并提示升级路径而非尝试降级兼容——这是工程严谨性的体现。安装方式有两种推荐后者# 方式一全局安装适合个人开发 npm install -g t3code-cli # 方式二本地安装 npx 调用推荐避免全局污染保证项目一致性 cd your-t3-project npm install --save-dev t3code-cli npx t3code --help项目结构需遵循 t3 stack 标准布局t3code 会自动校验your-project/ ├── apps/ │ ├── web/ # Next.js 应用 │ └── api/ # tRPC 服务端可选分离 ├── packages/ │ ├── db/ # Prisma client schema │ ├── server/ # tRPC router procedures │ └── ui/ # Tailwind shadcn/ui 组件库 ├── prisma/ │ └── schema.prisma # 必须存在t3code route 命令依赖此文件 └── turbo.json # 必须存在t3code build 命令读取 pipeline 配置注意t3code 不会强制你使用特定 monorepo 工具。它原生支持 Turborepo默认同时通过插件机制兼容 Nx、pnpm workspaces。当你首次运行t3code init它会扫描根目录是否存在turbo.json、nx.json或pnpm-workspace.yaml自动匹配对应 workspace 协议。若均不存在则提示“请先初始化 monorepo 工具”拒绝继续——这是防止后续命令因包定位失败而崩溃的关键守门员。3.2 CLI 核心命令详解从初始化到生产构建的全链路t3code 的命令体系按生命周期组织共分四大类3.2.1 初始化与配置类setup / init / configt3code init交互式引导完成项目初始化。它不重复create-t3-app的工作而是检测现有项目结构自动补全缺失环节。例如若prisma/schema.prisma存在但未执行npx prisma migrate dev则提示“检测到 Prisma schema是否立即执行迁移”若apps/web/.env.local不存在自动创建并填入NEXT_PUBLIC_API_URLhttp://localhost:3001根据当前 tRPC 端口动态推算。t3code setup执行“开箱即用”后的首次环境就绪检查。它会运行prisma validate校验 schema 语法执行tsc --noEmit类型检查跳过编译仅验证启动prisma studio并打开浏览器端口自动分配输出一份 HTML 格式的健康报告包含各服务状态、端口映射、依赖版本。t3code config管理全局配置。配置项存储在~/.t3code/config.json支持defaultPortOffset: 设置端口偏移量避免与 Docker 容器冲突electronPath: 指定 Electron 可执行文件路径用于企业内网离线环境templateSource: 切换脚手架模板源官方 GitHub / 私有 GitLab / 本地文件系统。3.2.2 开发与调试类dev / route / testt3code dev启动智能开发服务器。它启动三个并行进程next dev -p 3000Web 应用t3 dev -p 3001tRPC 服务prisma studio -p 5555数据库可视化 并注入一个轻量级 HTTP 代理基于 http-proxy-middleware将http://localhost:3000/api/*请求透明转发至http://localhost:3001/trpc/*彻底解决开发阶段的跨域问题。t3code route name [options]t3code 最具生产力的命令。支持参数--crud: 生成完整 CRUD 操作Create/Read/Update/Delete--input zod-schema: 指定自定义 Zod schema 文件路径--model prisma-model: 关联 Prisma model自动注入prisma.model.findMany()等操作--compact: 生成最小化版本仅 router procedure无测试/文档 示例t3code route product --crud --model Product会生成packages/server/routers/product.ts含全部 CRUD procedurepackages/db/prisma/schema.prisma中追加model Product {...}定义apps/web/app/products/page.tsx列表页骨架apps/web/app/products/[id]/page.tsx详情页骨架。t3code test封装 Jest Testing Library 流程。自动识别*.test.tsx文件运行时注入 tRPC Mock Adapter使测试无需启动真实 tRPC 服务。关键特性--coverage: 生成 Istanbul 覆盖率报告--watch: 文件变动时自动重跑相关测试--ci: 启用 CI 模式禁用动画、超时缩短、失败立即退出。3.2.3 构建与发布类build / deploy / packt3code build执行 Turborepo 构建流水线。它不直接调用turbo run build而是读取turbo.json中的pipeline.build.dependsOn检查apps/web/tsconfig.json是否启用incremental: true提升构建速度若检测到apps/web/public/manifest.json自动注入 PWA 配置输出构建产物大小分析size-limit集成。t3code build:desktop打包 Electron 桌面应用。流程执行t3code build生成 Next.js 静态产物apps/web/.next将.next目录复制到 Electronresources/app下使用electron-builder打包自动选择 targetmacOS:dmgzipWindows:nsis默认 portableLinux:AppImagedeb签名macOS 需 Apple Developer IDWindows 需 EV 证书。t3code build:mobile生成移动应用包。实际调用 Capacitor CLInpx cap add android/npx cap add iosnpx cap copy同步 Web 产物npx cap open android启动 Android Studio最终生成 APK/IPA。t3code 封装了--apk参数实则是npx cap build android --release的快捷方式。3.2.4 维护与诊断类doctor / clean / upgradet3code doctor系统健康诊断。扫描 12 项关键指标Node.js 版本合规性npm/yarn/pnpm 锁文件一致性Prisma schema 与数据库 schema 差异tRPC router 导出完整性检查是否有未注册的 procedureNext.js App Router 与 Pages Router 混用风险输出结构化 JSON 报告可直接导入 CI 系统做准入检查。t3code clean安全清理。区别于rm -rf node_modules它保留package-lock.json删除node_modules/.viteVite 缓存清空apps/web/.nextNext.js 缓存移除prisma/migrations/*.sql仅删除未应用的迁移文件提供--dry-run模式预览将删内容。t3code upgrade智能依赖升级。不简单执行npm update而是解析package.json中dependencies和devDependencies对比t3-stack官方推荐版本矩阵缓存在本地生成升级计划表标注 Breaking Change如next14升级需修改getServerSideProps支持--interactive模式逐个确认是否升级。3.3 Electron 深度集成菜单、IAP、本地能力调用的实现细节t3code 的 Electron 集成不是简单包裹而是深度定制。其主进程代码位于electron/main.ts核心模块包括3.3.1 动态菜单系统electron 菜单菜单不是静态 JSON而是运行时生成// electron/main.ts const createMenu () { const template: MenuItemConstructorOptions[] [ { label: File, submenu: [ { label: New Project, accelerator: CmdOrCtrlN, click: () openProjectWizard() }, { type: separator }, { label: Exit, accelerator: CmdOrCtrlQ, click: () app.quit() } ] }, { label: View, submenu: [ { label: Toggle DevTools, accelerator: F12, click: toggleDevTools }, { type: separator }, { label: Reload, accelerator: CmdOrCtrlR, click: () mainWindow?.reload() } ] } ]; // 动态注入“最近项目”子菜单 const recentProjects getRecentProjects(); if (recentProjects.length 0) { template[0].submenu?.unshift({ label: Open Recent, submenu: recentProjects.map(p ({ label: p.name, click: () openProject(p.path) })) }); } Menu.setApplicationMenu(Menu.buildFromTemplate(template)); };关键点在于菜单项与 CLI 命令一一映射。点击“New Project”实际触发t3code init --gui“Toggle DevTools”调用mainWindow.webContents.openDevTools()所有菜单事件最终都转化为 IPC 消息发送至渲染进程由 React 组件消费。这种设计保证了 CLI 与 GUI 的行为完全一致避免“两个世界两套逻辑”。3.3.2 IAPIn-App Purchase的轻量实现t3code 不提供完整支付流程而是封装 Electron 的in-app-purchase模块聚焦于许可证验证与功能解锁启动时检查~/.t3code/license.json是否存在且签名有效若无效渲染进程显示“Pro Mode Locked”弹窗提供购买链接跳转至 Stripe Checkout 页面购买成功后服务端返回 JWT 许可证Electron 主进程用私钥验证签名写入本地 license 文件渲染进程通过ipcRenderer.invoke(check-license)查询状态动态启用高级功能如t3code route --full的完整模板、build:mobile的 APK 打包。实操心得IAP 的最大坑是 macOS Sandbox 权限。必须在entitlements.mac.plist中添加keycom.apple.security.files.downloads.read-write/keytrue/否则 license 文件写入失败。t3code 的build:desktop命令会自动注入此 entitlement但开发者若手动修改 plist极易遗漏。3.3.3 本地能力桥接electron iap 之外的系统调用t3code 暴露的 IPC 接口严格遵循最小权限原则// electron/main.ts ipcMain.handle(open-file-dialog, async (event, options) { const { canceled, filePaths } await dialog.showOpenDialog(mainWindow, { properties: [openFile, multiSelections], filters: options.filters || [] }); return canceled ? [] : filePaths; }); ipcMain.handle(save-to-desktop, async (event, content, filename) { const desktopPath app.getPath(desktop); const fullPath path.join(desktopPath, filename); await fs.writeFile(fullPath, content); return fullPath; });渲染进程调用方式// apps/web/components/FilePicker.tsx const handlePick async () { const files await window.electronAPI.openFileDialog({ filters: [{ name: JSON, extensions: [json] }] }); console.log(Selected:, files); // [~/Downloads/data.json] }; const handleSave async () { const path await window.electronAPI.saveToDesktop( JSON.stringify(data, null, 2), export.json ); alert(Saved to ${path}); };所有 IPC 调用均经过contextIsolation隔离渲染进程无法直接访问 Node.js API必须通过预定义通道。这既是安全加固也强制开发者明确声明能力需求避免隐式依赖。4. 实操避坑指南那些官方文档不会告诉你的经验陷阱4.1 CLI 安装慢、卡死、报错的 5 种真实场景与解法网络热词中“node安装codex cli很慢”、“删除codex cli指令”高频出现这背后是 npm 生态的典型痛点。t3code 的安装问题本质是依赖解析风暴而非网络本身。以下是实测有效的解决方案问题现象根本原因解决方案实操验证npm install -g t3code-cli卡在idealTree:timing阶段超 10 分钟npm v9 的 lockfile v2 解析器对大型依赖图性能劣化尤其当t3code-cli依赖prisma含 200 子包时降级 npm 至 v8.19.2npm install -g npm8.19.2再执行安装实测从 15 分钟 → 42 秒安装后t3code --version报错Cannot find module commander全局安装时npm 的prefix路径与 Node.jsNODE_PATH不一致导致模块解析失败使用 npx 替代全局安装npm install --save-dev t3code-clinpx t3code --version彻底规避全局路径问题t3code init运行时报Error: Cannot find module next/dist/build/compilernext版本与t3code-cli内置的 webpack 插件不兼容如next14.2.0与t3code0.8.0锁定 next 版本npm install next14.1.4 --save-exact再运行t3code initt3code 的package.jsonpeerDependencies 明确要求next14.1.xt3code route user生成后tRPC 调用 404t3code默认将 router 注册到server/routers/index.ts但项目中该文件被手动修改未导出新 router启用自动注册检测运行t3code doctor它会扫描server/routers/目录对比index.ts导出项提示缺失 router修复方式在index.ts添加export * from ./user;t3code build:desktop打包失败提示Cannot resolve fsElectron 主进程代码中误用了fs模块应只在主进程用但被 webpack 错误打包进渲染进程配置 webpack externals在electron/webpack.config.js中添加externals: { fs: commonjs fs }防止 fs 模块被 bundle 进 renderer注意所有解决方案均经 t3code v0.9.3 实测。切勿盲目执行npm cache clean --force这会清空整个 npm 缓存反而延长后续安装时间。正确做法是npm cache verify校验缓存完整性。4.2 Electron 打包 APK 的 3 个致命误区与绕过技巧热词“electron打包apk”反映出开发者对跨端的迫切需求但直接用 Electron 打 APK 是伪命题。真正的路径是Electron桌面→ WebView移动→ Capacitor打包。常见误区如下误区一试图用 electron-builder 直接 target android错误认知electron-builder --platformandroid可生成 APK。真相electron-builder 官方不支持 Android target。其文档明确说明“Electron does not support mobile platforms. Use Capacitor or Cordova instead.”正确路径t3code build:mobile命令实际执行# 1. 构建 Next.js 静态站点 npm run build:web # 2. 初始化 Capacitor npx cap init --web-dir apps/web/out # 3. 添加 Android 平台 npx cap add android # 4. 同步 Web 产物 npx cap copy # 5. 构建 APK npx cap build android --release误区二忽略 AndroidManifest.xml 的权限声明问题生成的 APK 安装后调用navigator.mediaDevices.getUserMedia()报错NotAllowedError。原因Capacitor 的AndroidManifest.xml默认未声明摄像头/麦克风权限。解法编辑android/app/src/main/AndroidManifest.xml在application外添加uses-permission android:nameandroid.permission.CAMERA / uses-permission android:nameandroid.permission.RECORD_AUDIO / uses-permission android:nameandroid.permission.READ_EXTERNAL_STORAGE /验证adb logcat | grep Permission查看运行时权限请求日志。误区三WebView 与桌面 Electron 的 API 不兼容痛点在 Electron 中调用window.electronAPI.openFileDialog()打包到 Android 后失效。解法抽象统一接口层。t3code 提供usePlatformAPI()Hookimport { usePlatformAPI } from /hooks/usePlatformAPI; const { openFileDialog, saveToDesktop } usePlatformAPI(); // 在 Electron 环境调用 ipcRenderer // 在 Capacitor 环境调用 Plugins.FilePicker / Plugins.Storage // 在纯浏览器环境降级为 input[typefile]该 Hook 通过typeof window ! undefined window?.capacitor?.isNative自动检测运行时环境屏蔽底层差异。4.3 TurboRepo Pipeline 配置的 4 个隐藏陷阱t3code build依赖 TurboRepo 的 pipeline但turbo.json配置不当会导致构建失败或缓存失效陷阱表现正确配置原理pipeline.build.dependsOn缺失^buildt3code build执行后apps/web未重新构建产物仍是旧版build: {dependsOn: [^build]}^build表示依赖所有上游包的 build 任务确保packages/db、packages/server更新后apps/web自动 rebuildpipeline.build.outputs未包含.nextTurbo 缓存认为apps/web构建无输出每次均重新执行build: {outputs: [.next/**, !.next/cache/**]}.next是 Next.js 构建产物目录必须显式声明否则缓存失效pipeline.lint未设置cache: falset3code test运行时lint 结果被缓存代码修改后 lint 不触发lint: {cache: false}Lint 是快速检查无需缓存且eslint的--fix会修改源码缓存会导致状态不一致pipeline.dev未声明persistent: truet3code dev启动后进程意外退出Turbo 不重启dev: {persistent: true}persistent: true告诉 Turbo 此任务需长期运行崩溃后自动重启实操心得Turbo 的缓存哈希算法基于inputs和outputs。若inputs未包含tsconfig.json则 tsconfig 修改不会触发 rebuild。务必在pipeline.build.inputs中添加tsconfig.json和package.json。4.4 tRPC Router 生成的 3 个边界情况处理t3code route命令虽强大但面对复杂业务仍需人工干预情况一关联已有 Prisma model但字段类型不匹配问题t3code route order --model Order生成的 Zod schema 中status字段为z.string()但 Prisma 中定义为Enum。解法t3code 会自动读取prisma/schema.prisma中的enum Status { PENDING CONFIRMED }生成z.enum([PENDING, CONFIRMED])。若未生效检查 enum 是否在model Order中正确定义status Status default(PENDING)。情况二生成的 procedure 需要自定义中间件问题createOrder需要 auth middleware但t3code route生成的代码未包含。解法t3code 在packages/server/middlewares/auth.ts预置了标准 auth middleware。生成后在packages/server/routers/order.ts中手动添加import { authMiddleware } from ../middlewares/auth; export const orderRouter router({ create: procedure .use(authMiddleware) // 插入此处 .input(createOrderInput) .mutation(async ({ ctx, input }) { /* ... */ }) });情况三router 名称与 Prisma model 名称冲突问题t3code route user --model User生成userRouter但User是 Prisma 内置 model可能导致类型冲突。解法t3code 会自动检测并提示“Warning: User is a reserved Prisma model name. Consider using profile or account.” 建议接受建议改用t3code route profile --model User。5. 常见问题速查表从报错信息反推问题根源以下表格整理了 t3code 用户最常遇到的 10 类报错按发生频率排序每条包含错误信息原文、根本原因、定位步骤、修复命令四要素可直接作为团队内部故障排查手册。错误信息原文根本原因定位步骤修复命令Error: Cannot find module prisma/clientprisma generate未执行或node_modules/.prisma/client路径被误删1. 检查packages/db/prisma/schema.prisma是否存在2. 运行npx prisma validate校验语法3. 查看packages/db/node_modules/.prisma/client是否为空npx prisma generateTypeError: Cannot read properties of undefined (reading query)tRPC router 未正确注册到server/routers/index.ts1. 打开packages/server/routers/index.ts2. 检查是否导出新 router如export * from ./user;3. 运行t3code doctor