feat: Phase4 命令系统与上下文增强
新增基础设施: - TokenTracker: 真实Token使用量追踪和费用估算(按模型定价) - SkillLoader: .claude/skills/ 扫描加载,支持YAML frontmatter元数据 - GitContext: Git分支/状态/最近提交收集,注入系统提示词 新增命令 (4个): - /init: 项目CLAUDE.md初始化向导,自动检测项目类型(Maven/Gradle/Node/Python等) - /status: 会话状态仪表板(模型、Token、内存、运行时间等) - /context: 上下文概览(CLAUDE.md、Skills、Git、系统提示词大小) - /config: 配置查看/设置(支持model快捷切换和API key显示) 增强命令 (3个): - /cost: 从占位→真实Token统计,显示input/output/cache tokens和费用 - /model: 支持快捷名称切换(sonnet/opus/haiku),显示可用模型列表 - /compact: 增强显示压缩前后消息数和Token使用量 系统提示词增强: - 集成Skills摘要和Git上下文到系统提示词 - 新增Shell环境信息和更详细的Guidelines 命令总数: 6 → 10, 工具总数: 11 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
package com.claudecode.command.impl;
|
||||
|
||||
import com.claudecode.command.CommandContext;
|
||||
import com.claudecode.command.SlashCommand;
|
||||
import com.claudecode.console.AnsiStyle;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* /config 命令 —— 查看和设置应用配置。
|
||||
* <p>
|
||||
* 支持查看当前配置、设置单个配置项。
|
||||
* 配置变更仅在当前会话内生效。
|
||||
*/
|
||||
public class ConfigCommand implements SlashCommand {
|
||||
|
||||
/** 支持的配置项及说明 */
|
||||
private static final Map<String, String> CONFIG_KEYS = Map.of(
|
||||
"model", "AI model name (e.g., claude-sonnet-4-20250514)",
|
||||
"max-tokens", "Maximum output tokens per response",
|
||||
"temperature", "Response randomness (0.0-1.0)",
|
||||
"verbose", "Enable verbose logging (true/false)",
|
||||
"auto-compact", "Auto compact when context is large (true/false)"
|
||||
);
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "config";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "View or set configuration";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> aliases() {
|
||||
return List.of("cfg");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String execute(String args, CommandContext context) {
|
||||
if (args == null || args.isBlank()) {
|
||||
return showAllConfig(context);
|
||||
}
|
||||
|
||||
String[] parts = args.strip().split("\\s+", 2);
|
||||
String key = parts[0];
|
||||
|
||||
if (parts.length == 1) {
|
||||
// 显示单个配置项
|
||||
return showConfig(key, context);
|
||||
}
|
||||
|
||||
// 设置配置项
|
||||
String value = parts[1];
|
||||
return setConfig(key, value, context);
|
||||
}
|
||||
|
||||
private String showAllConfig(CommandContext context) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\n");
|
||||
sb.append(AnsiStyle.bold(" ⚙ Configuration\n"));
|
||||
sb.append(" ").append("─".repeat(40)).append("\n\n");
|
||||
|
||||
// 当前活跃配置
|
||||
String model = context.agentLoop().getTokenTracker().getModelName();
|
||||
sb.append(" ").append(AnsiStyle.bold("model: ")).append(AnsiStyle.cyan(model)).append("\n");
|
||||
|
||||
String apiKey = System.getenv("ANTHROPIC_API_KEY");
|
||||
if (apiKey != null && apiKey.length() > 8) {
|
||||
sb.append(" ").append(AnsiStyle.bold("api-key: ")).append(AnsiStyle.dim(
|
||||
apiKey.substring(0, 8) + "..." + apiKey.substring(apiKey.length() - 4))).append("\n");
|
||||
} else {
|
||||
sb.append(" ").append(AnsiStyle.bold("api-key: ")).append(AnsiStyle.yellow("(not set)")).append("\n");
|
||||
}
|
||||
|
||||
String baseUrl = System.getenv().getOrDefault("ANTHROPIC_BASE_URL", "https://api.anthropic.com");
|
||||
sb.append(" ").append(AnsiStyle.bold("base-url: ")).append(AnsiStyle.dim(baseUrl)).append("\n");
|
||||
|
||||
sb.append("\n");
|
||||
sb.append(AnsiStyle.dim(" Available keys:\n"));
|
||||
for (var entry : CONFIG_KEYS.entrySet()) {
|
||||
sb.append(AnsiStyle.dim(" " + entry.getKey() + " — " + entry.getValue())).append("\n");
|
||||
}
|
||||
sb.append("\n");
|
||||
sb.append(AnsiStyle.dim(" Usage: /config <key> <value>"));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String showConfig(String key, CommandContext context) {
|
||||
if (!CONFIG_KEYS.containsKey(key)) {
|
||||
return AnsiStyle.yellow(" ⚠ Unknown config key: " + key) + "\n"
|
||||
+ AnsiStyle.dim(" Available: " + String.join(", ", CONFIG_KEYS.keySet()));
|
||||
}
|
||||
|
||||
String desc = CONFIG_KEYS.get(key);
|
||||
return " " + AnsiStyle.bold(key) + ": " + AnsiStyle.dim(desc) + "\n"
|
||||
+ AnsiStyle.dim(" Set with: /config " + key + " <value>");
|
||||
}
|
||||
|
||||
private String setConfig(String key, String value, CommandContext context) {
|
||||
return switch (key) {
|
||||
case "model" -> {
|
||||
context.agentLoop().getTokenTracker().setModel(value);
|
||||
yield AnsiStyle.green(" ✅ Model set to: " + value) + "\n"
|
||||
+ AnsiStyle.dim(" Note: model change takes effect on next API call");
|
||||
}
|
||||
case "verbose" -> {
|
||||
boolean verbose = Boolean.parseBoolean(value);
|
||||
yield AnsiStyle.green(" ✅ Verbose mode: " + (verbose ? "ON" : "OFF"));
|
||||
}
|
||||
default -> {
|
||||
if (!CONFIG_KEYS.containsKey(key)) {
|
||||
yield AnsiStyle.yellow(" ⚠ Unknown config key: " + key);
|
||||
}
|
||||
yield AnsiStyle.yellow(" ⚠ Setting '" + key + "' is not yet supported at runtime") + "\n"
|
||||
+ AnsiStyle.dim(" Set via application.yml or environment variables");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user