Solon v4.0.3

harness - 自定义命令

</> markdown
2026年7月4日 下午1:09:28

自定义命令是一种把"常用提示词模板"固化为可复用指令的能力(兼容 Claude Code 的 Custom Commands 规范)。命令本质是带参数占位的 Markdown 模板,执行时替换参数后作为 Agent 任务运行。

1、命令定义文件

命令以 Markdown 文件定义,放在 {harnessHome}/commands/ 目录下:YAML Front Matter 描述元数据,正文即提示词模板。

---
description: 生成一条 git 提交信息
argument-hint: [message]
model: deepseek-v4-flash
---
请根据当前暂存区的变更,生成一条简洁的提交信息。
补充说明:$ARGUMENTS

元数据字段:

字段描述
description命令描述
argument-hint参数提示(用于补全提示)
model指定执行该命令的模型(可选)

2、参数占位符

模板正文支持两种占位符(兼容 Claude Code):

  • $1$2$3 …:按位置取单个参数。
  • $ARGUMENTS:把所有参数拼接为一个字符串。

替换顺序为"先位置参数、后 $ARGUMENTS"。例如模板 部署 $1 到 $2 环境($ARGUMENTS),传入 ["web", "prod"] 后得到 部署 web 到 prod 环境(web prod)

3、命名空间(子目录)

commands/ 支持子目录递归扫描,子目录会成为命令的命名空间(用冒号分隔)。例如:

  • commands/deploy/staging.md → 命令名 deploy:staging
  • commands/git/commit.md → 命令名 git:commit

4、命令接口(Command)

命令系统由 Command 接口、CommandRegistry 注册中心和 CommandContext 执行上下文共同构成。Command 接口定义:

public interface Command {
    String name();           // 命令名(不含 / 前缀)
    String description();    // 命令描述
    String[] examples();     // 示例
    default String model() { return null; }  // 使用模型(可选)
    default boolean cliOnly() { return false; }  // 是否仅 CLI 可用
    void execute(CommandContext ctx) throws Exception;  // 执行命令
}

CommandContext 提供命令执行所需的环境信息:

方法描述
getSession()获取当前会话
getEngine()获取 Agent 运行时
getRawInput()获取用户原始输入
getCommandName()获取命令名(不含 / 前缀)
getArgs()获取命令参数列表
argAt(index)按索引获取参数,越界返回 null
argCount()参数数量
getArgsJoined()全部参数拼接为单个字符串
println(text)输出一行文本(不同端有不同实现)
supportsAnsi()是否支持 ANSI 颜色(CLI=true,Web=false)
color(text)ANSI 友好的颜色输出
runAgentTask(prompt, model)运行 Agent 任务(CLI 阻塞,Web 返回 Flux 流)

5、注册与查找

命令由 CommandRegistry 管理,可从目录加载,也可用代码注册:

CommandRegistry registry = engine.getCommandRegistry();

// 从目录加载(递归扫描 .md)
registry.load(Paths.get(engine.getWorkspace(), engine.getHarnessCommands()));

// 注册 Java 命令(实现 Command 接口)
registry.register(new MyCommand());

// 查找与列举
Command cmd = registry.find("git:commit");
List<Command> all = registry.all();        // 排序后的全部命令
List<String> names = registry.names();     // 命令名列表(用于 Tab 补全)

同名命令只会注册一次,重复注册会被忽略并打印告警。

6、MarkdownCommand 执行流程

MarkdownCommand 是基于 Markdown 模板的命令实现,执行流程如下:

  1. 解析 Markdown 文件,提取 Front Matter 元数据和正文模板。
  2. 调用 getResolvedPrompt(args) 将参数占位符替换为实际值。
  3. 调用 ctx.runAgentTask(prompt, model) 将替换后的文本作为 Agent 任务执行。

7、多端支持

命令系统设计为 CLI 和 Web 共用:

  • CLI 端runAgentTask 阻塞等待返回;supportsAnsi 返回 true,支持彩色输出。
  • Web 端runAgentTask 返回 Flux 流;supportsAnsi 返回 false,自动去除 ANSI 转义序列。
  • 标记为 cliOnly()=true 的命令在 Web 端不展示也不执行。