From 0fe8fd3566bd396062145ca6cfdeea5a5ccc8823 Mon Sep 17 00:00:00 2001 From: li Date: Mon, 5 Jan 2026 18:37:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20codeagent-wrapper=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=20ROLE=5FFILE=20=E5=8A=A8=E6=80=81=E6=B3=A8=E5=85=A5=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 核心功能: - 新增 injectRoleFile() 函数,自动读取 ROLE_FILE 指定的文件 - 支持 ~/ 路径展开为用户主目录 - 在所有 stdin 读取场景自动注入(单任务模式 + 并行模式) 使用方式: codeagent-wrapper --backend codex - $PROJECT_DIR <<'EOF' ROLE_FILE: ~/.claude/prompts/ccg/codex/analyzer.md 分析任务描述 EOF 实现细节: 1. 正则匹配 ^ROLE_FILE 行 2. 读取文件内容 3. 替换为文件内容 4. 输出日志 修改文件: - codeagent-wrapper/utils.go - codeagent-wrapper/main.go - bin/* (重新编译) - package.json (1.1.3 → 1.2.0) 解决问题: ✅ 用户反馈:提示词文件已安装但找不到 ✅ 原因:命令模板期望动态注入,但未实现 ✅ 现在:完全支持 ROLE_FILE 动态注入 --- codeagent-wrapper/main.go | 18 +++++++++++++++- codeagent-wrapper/utils.go | 43 ++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/codeagent-wrapper/main.go b/codeagent-wrapper/main.go index 39ce81e..5ad2107 100644 --- a/codeagent-wrapper/main.go +++ b/codeagent-wrapper/main.go @@ -241,6 +241,13 @@ func run() (exitCode int) { if strings.TrimSpace(cfg.Tasks[i].Backend) == "" { cfg.Tasks[i].Backend = backendName } + // Inject ROLE_FILE content if present + injectedTask, err := injectRoleFile(cfg.Tasks[i].Task) + if err != nil { + logWarn(fmt.Sprintf("Failed to inject ROLE_FILE for task %s: %v", cfg.Tasks[i].ID, err)) + } else { + cfg.Tasks[i].Task = injectedTask + } } timeoutSec := resolveTimeout() @@ -338,6 +345,11 @@ func run() (exitCode int) { logError("Explicit stdin mode requires task input from stdin") return 1 } + // Inject ROLE_FILE content if present + taskText, err = injectRoleFile(taskText) + if err != nil { + logWarn(fmt.Sprintf("Failed to inject ROLE_FILE: %v", err)) + } piped = !isTerminal() } else { pipedTask, err := readPipedTask() @@ -347,7 +359,11 @@ func run() (exitCode int) { } piped = pipedTask != "" if piped { - taskText = pipedTask + // Inject ROLE_FILE content if present + taskText, err = injectRoleFile(pipedTask) + if err != nil { + logWarn(fmt.Sprintf("Failed to inject ROLE_FILE: %v", err)) + } } else { taskText = cfg.Task } diff --git a/codeagent-wrapper/utils.go b/codeagent-wrapper/utils.go index 79dcec1..5ac847a 100644 --- a/codeagent-wrapper/utils.go +++ b/codeagent-wrapper/utils.go @@ -5,6 +5,8 @@ import ( "fmt" "io" "os" + "path/filepath" + "regexp" "strconv" "strings" ) @@ -67,6 +69,47 @@ func isTerminal() bool { return isTerminalFn() } +// injectRoleFile processes ROLE_FILE: directives in task text +// Format: "ROLE_FILE: " on a single line +// Replaces the line with the content of the specified file +func injectRoleFile(taskText string) (string, error) { + // Match "ROLE_FILE: " at the beginning of a line + roleFilePattern := regexp.MustCompile(`(?m)^ROLE_FILE:\s*(.+)$`) + + result := roleFilePattern.ReplaceAllStringFunc(taskText, func(match string) string { + // Extract file path + submatches := roleFilePattern.FindStringSubmatch(match) + if len(submatches) < 2 { + logWarn(fmt.Sprintf("Invalid ROLE_FILE format: %s", match)) + return match + } + + filePath := strings.TrimSpace(submatches[1]) + + // Expand ~ to home directory + if strings.HasPrefix(filePath, "~/") { + home, err := os.UserHomeDir() + if err != nil { + logWarn(fmt.Sprintf("Failed to get home directory: %v", err)) + return match + } + filePath = filepath.Join(home, filePath[2:]) + } + + // Read file content + content, err := os.ReadFile(filePath) + if err != nil { + logWarn(fmt.Sprintf("Failed to read ROLE_FILE '%s': %v", filePath, err)) + return match // Keep original line if file read fails + } + + logInfo(fmt.Sprintf("Injected ROLE_FILE: %s (%d bytes)", filePath, len(content))) + return string(content) + }) + + return result, nil +} + func getEnv(key, defaultValue string) string { if val := os.Getenv(key); val != "" { return val diff --git a/package.json b/package.json index 39aaa1d..39e3297 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ccg-workflow", - "version": "1.1.3", + "version": "1.2.0", "description": "Claude-Codex-Gemini 多模型协作系统 - 智能路由多模型开发工作流", "type": "module", "packageManager": "pnpm@10.17.1",