01.2 模式路由与入口汇合
关注源码
src/main.tsxsrc/commands.tssrc/dialogLaunchers.tsxsrc/interactiveHelpers.tsxsrc/replLauncher.tsxsrc/QueryEngine.ts
入口层要解决的问题
入口层真正处理的不是“启动一个程序”,而是“判断当前会话属于哪一种运行形态,并把它们收敛到同一套运行时”。
常见形态包括:
- 交互式 REPL
- 非交互式单次 query
- resume / restore 会话
- remote viewer / direct connect
- assistant / coordinator 等 feature-gated 模式
- SDK / structured I/O 场景
汇合点
commands.ts 是控制面注册表
commands.ts 把几类来源统一成一个命令池:
- 内建命令
- 技能目录命令
- 插件命令
- 动态技能
- MCP skill commands
它的价值不只是“列出命令”,而是统一了:
- 命令来源
- 是否允许模型调用
- remote / bridge 可用性
- 插件和动态技能的缓存失效
dialogLaunchers.tsx 处理一次性流程分支
很多启动期交互不是 REPL 常驻 UI 的一部分,例如:
- resume chooser
- teleport mismatch / resume
- invalid settings
- assistant install / session chooser
这些流程被抽到 launcher 里,避免 main.tsx 直接夹带大量 UI 逻辑。
interactiveHelpers.tsx 是交互式路径的门厅
它把交互式模式中的公共动作收束为几类 API:
showDialog()/showSetupDialog()showSetupScreens()renderAndRun()exitWithMessage()/exitWithError()
这样入口层可以只决定“是否进入交互模式”,而不用关心具体 Ink 根节点怎么管理。
replLauncher.tsx 是 UI 懒加载边界
replLauncher.tsx 明确把:
components/Appscreens/REPL
延迟到真正进入交互式模式时再加载。这个边界非常实用:
- 非交互式场景不必引入大体积 UI 模块图。
- 启动时可以在 UI 装载前先完成配置与策略判断。
模式路由的设计特点
1. 命令/工具在入口阶段就被裁剪
入口不是“什么都装上,后面再拒绝”,而是会按当前模式先做过滤,例如:
- remote 模式只保留
REMOTE_SAFE_COMMANDS - bridge 只允许
BRIDGE_SAFE_COMMANDS - simple mode / REPL mode / coordinator mode 直接影响工具池
这让后续运行时不必在每次交互里重复做高层策略判断。
2. 模式很多,但运行时心智模型尽量统一
不同入口最终还是会汇合到少数几个核心对象:
messagesToolUseContextAppStatequery()tasks
也就是说,入口层负责把“多种启动方式”翻译成“同一种运行时语义”。
3. UI 流程和业务启动被刻意拆开
main.tsx 决定是否需要:
- setup
- trust
- dialogs
- REPL
- QueryEngine
但真正的 UI 细节放在 launcher/helpers 中。这种拆分让:
- headless 路径更干净
- UI 迭代不容易污染启动编排
- 测试更容易隔离到单独流程
读代码时建议关注
commands.ts中getCommands()、getSkillToolCommands()、filterCommandsForRemoteMode()。interactiveHelpers.tsx如何处理 trust dialog 之前与之后的状态切换。replLauncher.tsx如何只做一件事:把已装配好的 props 交给 App + REPL。