run_repl 函数解析

run_repl 函数解析

位置: rust/crates/rusty-claude-cli/src/main.rs:4612-4678

run_repl 是 claw-code CLI 的交互式 REPL 主循环。它是用户在终端输入 claw(不带子命令)后进入的那个交互对话界面的核心入口。

函数签名

fn run_repl(
    model: String,
    allowed_tools: Option<AllowedToolSet>,
    permission_mode: PermissionMode,
    base_commit: Option<String>,
    reasoning_effort: Option<String>,
    allow_broad_cwd: bool,
) -> Result<(), Box<dyn std::error::Error>>

整体流程

run_repl()
  ├── 1. 启动前检查
  │     ├── enforce_broad_cwd_policy()   ← 安全策略
  │     └── run_stale_base_preflight()   ← 过期 base 警告
  ├── 2. 初始化
  │     ├── resolve_repl_model()         ← 解析模型名
  │     ├── LiveCli::new()               ← 创建 CLI 会话
  │     ├── LineEditor::new()            ← 创建行编辑器(Tab 补全)
  │     ├── startup_banner()             ← 打印横幅
  │     └── format_connected_line()      ← 打印模型连接信息
  └── 3. 主循环
        └── loop {
              刷新补全 → 读输入 → 匹配处理
            }

三个阶段

1. 启动前检查

enforce_broad_cwd_policy(allow_broad_cwd, CliOutputFormat::Text)?;
run_stale_base_preflight(base_commit.as_deref());
  • 安全策略检查 (enforce_broad_cwd_policy): 验证当前工作目录是否在允许范围内,防止访问敏感路径
  • stale base 警告 (run_stale_base_preflight): 如果 --base 参数引用的 commit 太旧,打印警告提示用户更新基准

2. 初始化

let resolved_model = resolve_repl_model(model);
let mut cli = LiveCli::new(resolved_model, true, allowed_tools, permission_mode)?;
let mut editor = LineEditor::new("> ", cli.repl_completion_candidates()?);
println!("{}", cli.startup_banner());
println!("{}", format_connected_line(&cli.model));
  • resolve_repl_model: 解析用户指定的模型名称(处理别名等)
  • LiveCli::new: 创建核心 CLI 会话实例,封装了整个会话状态、runtime、工具权限等
  • LineEditor::new: 创建带 Tab 补全 功能的行编辑器,提示符为 >
  • startup_banner + format_connected_line: 打印启动横幅和当前连接的模型信息

3. REPL 主循环

loop {
    editor.set_completions(cli.repl_completion_candidates()?);
    match editor.read_line()? {
        // ...
    }
}

每次迭代刷新补全候选列表,然后等待用户输入。editor.read_line() 返回三种结果:

结果 含义 行为
Submit(input) 用户按了回车 按下述优先级匹配处理
Cancel Ctrl+C 不做任何事,回到循环开头
Exit Ctrl+D 持久化会话后退出循环

Submit 的匹配优先级(由高到低)

  1. 空输入continue,跳过本轮
  2. /exit / /quit → 调用 cli.persist_session() 持久化会话后 break 退出
  3. 斜杠命令SlashCommand::parse 解析出 72 种命令,交给 cli.handle_repl_command() 处理。常用命令包括:
    • /help — 帮助
    • /model — 切换模型
    • /compact — 压缩上下文
    • /commit — 生成 commit
    • /pr — 创建 PR
    • /issue — 创建 Issue
    • /clear — 清屏
    • /cost — 查看费用
    • /resume — 恢复会话
    • /plugins — 管理插件
    • /mcp — 管理 MCP 服务器
    • /skills — 管理技能
    • ... 共 72 种
  4. 裸技能名try_resolve_bare_skill_prompt 检测首 token 是否匹配已安装的技能名:
    • 不以 / 开头
    • 纯字母数字+连字符(a-z, 0-9, -, _
    • 匹配成功则包装为 /skills <input> 调用,失败则走第 5 步
  5. 普通文本 → 直接送给 LLM:cli.run_turn(&trimmed) — 这是最主要的对话路径

每次成功提交后都会记录历史:

editor.push_history(input);      // 行编辑器历史(上下键回溯)
cli.record_prompt_history(&trimmed);  // 会话历史(/history 查看)

关键依赖

组件 位置 说明
LiveCli main.rs:4699 核心 CLI 会话,封装 runtime、工具、权限、会话管理
SlashCommand commands/src/lib.rs:1040 72 种斜杠命令的枚举定义和解析
LineEditor input 模块 带 Tab 补全和历史回溯的行编辑器
try_resolve_bare_skill_prompt main.rs:1446 裸技能名检测与调度
resolve_repl_model 同文件 模型名解析(处理别名、默认值)
enforce_broad_cwd_policy 同文件 工作目录安全策略检查
run_stale_base_preflight main.rs:4601 过期 base commit 警告

总结

run_repl 是 claw-code 交互模式的核心事件循环:初始化会话 → 打印横幅 → 不断读取用户输入,区分退出/exit/Ctrl+D)、斜杠命令(72 种 CLI 命令)、技能调度(裸技能名)、自然语言对话(送 LLM 处理)四种意图,分别路由到对应处理器。外层调用者只需关心返回的 Result<(), ...>,成功返回 Ok(()) 表示正常退出。

posted @ 2026-05-28 17:49  青山見我  阅读(45)  评论(0)    收藏  举报