From 39376fec46f665b6b9e342e9ff8524cc96d55116 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Mon, 12 Jan 2026 19:47:52 +0800 Subject: [PATCH 01/12] feat: rename illegal files --- docs/.claude/{README.md => ABCoder-README.md} | 0 docs/.claude/commands/{abcoder:recheck.md => recheck.md} | 0 docs/.claude/commands/{abcoder:schd.md => schd.md} | 0 docs/.claude/commands/{abcoder:task.md => task.md} | 0 docs/.claude/settings.json | 8 ++++---- docs/.claude/tmpls/{CODE_TASK.md => ABCODER_CODE_TASK.md} | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename docs/.claude/{README.md => ABCoder-README.md} (100%) rename docs/.claude/commands/{abcoder:recheck.md => recheck.md} (100%) rename docs/.claude/commands/{abcoder:schd.md => schd.md} (100%) rename docs/.claude/commands/{abcoder:task.md => task.md} (100%) rename docs/.claude/tmpls/{CODE_TASK.md => ABCODER_CODE_TASK.md} (100%) diff --git a/docs/.claude/README.md b/docs/.claude/ABCoder-README.md similarity index 100% rename from docs/.claude/README.md rename to docs/.claude/ABCoder-README.md diff --git a/docs/.claude/commands/abcoder:recheck.md b/docs/.claude/commands/recheck.md similarity index 100% rename from docs/.claude/commands/abcoder:recheck.md rename to docs/.claude/commands/recheck.md diff --git a/docs/.claude/commands/abcoder:schd.md b/docs/.claude/commands/schd.md similarity index 100% rename from docs/.claude/commands/abcoder:schd.md rename to docs/.claude/commands/schd.md diff --git a/docs/.claude/commands/abcoder:task.md b/docs/.claude/commands/task.md similarity index 100% rename from docs/.claude/commands/abcoder:task.md rename to docs/.claude/commands/task.md diff --git a/docs/.claude/settings.json b/docs/.claude/settings.json index d051471..b5e108a 100644 --- a/docs/.claude/settings.json +++ b/docs/.claude/settings.json @@ -2,7 +2,7 @@ "permissions": { "allow": [ "Edit(\\.md)", - "Read(~/.claude/**)", + "Read(.claude/**)", "mcp__abcoder", "mcp__sequential-thinking" ] @@ -14,7 +14,7 @@ "hooks": [ { "type": "command", - "command": "~/.claude/hooks/abcoder/parse.sh" + "command": ".claude/hooks/abcoder/parse.sh" } ] } @@ -25,7 +25,7 @@ "hooks": [ { "type": "command", - "command": "~/.claude/hooks/abcoder/prompt.sh" + "command": ".claude/hooks/abcoder/prompt.sh" } ] }, @@ -34,7 +34,7 @@ "hooks": [ { "type": "command", - "command": "~/.claude/hooks/abcoder/reminder.sh" + "command": ".claude/hooks/abcoder/reminder.sh" } ] } diff --git a/docs/.claude/tmpls/CODE_TASK.md b/docs/.claude/tmpls/ABCODER_CODE_TASK.md similarity index 100% rename from docs/.claude/tmpls/CODE_TASK.md rename to docs/.claude/tmpls/ABCODER_CODE_TASK.md From 38826956511394d551976ac674e8257b864a5489 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Mon, 12 Jan 2026 21:00:51 +0800 Subject: [PATCH 02/12] feat: support auto install cc integretion --- README.md | 44 +-- cmd_init_spec.go | 274 ++++++++++++++++++ docs/.claude/{ABCoder-README.md => README.md} | 0 docs/.claude/commands/README.md | 4 +- docs/.claude/commands/task.md | 2 +- docs/.claude/hooks/README.md | 2 +- docs/.claude/hooks/abcoder/parse.sh | 2 +- docs/.claude/hooks/abcoder/prompt.sh | 2 +- docs/.claude/settings.json | 10 +- main.go | 24 ++ 10 files changed, 325 insertions(+), 39 deletions(-) create mode 100644 cmd_init_spec.go rename docs/.claude/{ABCoder-README.md => README.md} (100%) diff --git a/README.md b/README.md index f83c8e6..cc296f1 100644 --- a/README.md +++ b/README.md @@ -91,35 +91,23 @@ ABCoder provides deep integration with [Claude Code](https://claude.ai/code) thr ### Setup -1. **Install ABCoder Claude Configuration** +Use the `init-spec` command to automatically configure Claude Code integration: - Copy [`docs/.claude/`](docs/.claude/) to your home directory or project root: - - ```bash - cp -r docs/.claude ~/ - ``` - -2. **Configure ABCoder MCP Server** - - Configure in Claude Code's `~/.claude.json` (the hook uses `abcoder parse go/ts . -o ~/.asts/repo.json` for the default AST folder): - - ```json - { - "mcpServers": { - "abcoder": { - "command": "abcoder", - "args": ["mcp", "~/.asts"] - } - } - } - ``` +```bash +# Install ABCoder +go install github.com/cloudwego/abcoder@latest -3. **Configure Hooks** +# Run init-spec in your project directory (optional: specify target path) +cd /path/to/your/project +abcoder init-spec +``` - Claude Code will automatically read hooks from [`~/.claude/settings.json`](docs/.claude/settings.json) to enable: - - Auto-detect language and generate AST before calling `mcp__abcoder` tools - - Display ABCoder workflow SOP to Claude after `list_repos` - - Remind to call `get_ast_node` recursively +The `init-spec` command will: +1. Copy `.claude` directory to your project root +2. Configure MCP servers in `~/.claude.json`: + - `abcoder`: for code analysis using AST + - `sequential-thinking`: for complex problem decomposition +3. Replace all `{{CLAUDE_HOME_PATH}}` placeholders with actual project paths ### AST-Driven Coding Workflow @@ -167,13 +155,13 @@ sub-agent ─────────→ Execute Implementation | [`settings.json`](docs/.claude/settings.json) | Hooks and permissions configuration | | [`hooks/`](docs/.claude/hooks/) | Automation scripts (parse/prompt/reminder) | | [`commands/`](docs/.claude/commands/) | Slash command definitions (abcoder:task/abcoder:schd/abcoder:recheck) | -| [`tmpls/CODE_TASK.md`](docs/.claude/tmpls/CODE_TASK.md) | Coding task template | +| [`tmpls/ABCODER_CODE_TASK.md`](docs/.claude/tmpls/ABCODER_CODE_TASK.md) | Coding task template | ### Dependencies - Claude Code CLI - abcoder MCP server (provides `mcp__abcoder` tools) -- sequential-thinking MCP server (provides `mcp__sequential_thinking` tools, optional) +- sequential-thinking MCP server (provides `mcp__sequential_thinking` tools, automatically configured by init-spec) > For detailed configuration, see [docs/.claude/README.md](docs/.claude/README.md) diff --git a/cmd_init_spec.go b/cmd_init_spec.go new file mode 100644 index 0000000..8149077 --- /dev/null +++ b/cmd_init_spec.go @@ -0,0 +1,274 @@ +/** + * Copyright 2025 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "embed" + "encoding/json" + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" + + "github.com/cloudwego/abcoder/llm/log" +) + +//go:embed docs/.claude +var claudeFS embed.FS + +// claudeConfig represents the Claude Code configuration structure +type claudeConfig struct { + MCPServers map[string]mcpServerConfig `json:"mcpServers"` +} + +type mcpServerConfig struct { + Command string `json:"command"` + Args []string `json:"args"` +} + +// runInitSpec implements the init-spec command +func runInitSpec(targetDir string) error { + if targetDir == "" { + // Default to current directory if not specified + cwd, err := os.Getwd() + if err != nil { + return fmt.Errorf("failed to get current directory: %w", err) + } + targetDir = cwd + } + + // Ensure targetDir is absolute + targetDirAbs, err := filepath.Abs(targetDir) + if err != nil { + return fmt.Errorf("failed to get absolute path: %w", err) + } + + // 1. Copy docs/.claude to targetDir/.claude + claudeDestDir := filepath.Join(targetDirAbs, ".claude") + if err := copyEmbeddedDir("docs/.claude", claudeDestDir, targetDirAbs); err != nil { + return fmt.Errorf("failed to copy .claude directory: %w", err) + } + log.Info("Copied .claude directory to %s", claudeDestDir) + + // 2. Get home directory for MCP server configuration + homeDir, err := os.UserHomeDir() + if err != nil { + return fmt.Errorf("failed to get home directory: %w", err) + } + + // 3. Configure MCP servers in ~/.claude.json + // Get asts directory path from parse.sh hook (default ~/.asts) + astsDir := filepath.Join(homeDir, ".asts") + + // Create asts directory if it doesn't exist + if err := os.MkdirAll(astsDir, 0755); err != nil { + return fmt.Errorf("failed to create asts directory: %w", err) + } + + claudeConfigPath := filepath.Join(homeDir, ".claude.json") + if err := configureMCPServers(claudeConfigPath, astsDir); err != nil { + return fmt.Errorf("failed to configure MCP servers: %w", err) + } + log.Info("Configured MCP servers in %s", claudeConfigPath) + + // 4. Print success message + printSuccessMessage(targetDirAbs, claudeConfigPath, astsDir) + + return nil +} + +// copyEmbeddedDir copies an embedded directory to a destination directory +func copyEmbeddedDir(srcPath string, destDir string, projectRootDir string) error { + // First, ensure the destination directory exists + if err := os.MkdirAll(destDir, 0755); err != nil { + return fmt.Errorf("failed to create destination directory %s: %w", destDir, err) + } + + // Track md files to process after copying + var mdFilesToReplace []string + + err := fs.WalkDir(claudeFS, srcPath, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + // Calculate relative path from srcPath + relPath, err := filepath.Rel(srcPath, path) + if err != nil { + return err + } + + // Skip the root directory itself + if relPath == "." { + return nil + } + + destPath := filepath.Join(destDir, relPath) + + if d.IsDir() { + // Create directory + return os.MkdirAll(destPath, 0755) + } + + // Ensure parent directory exists before writing file + parentDir := filepath.Dir(destPath) + if err := os.MkdirAll(parentDir, 0755); err != nil { + return fmt.Errorf("failed to create parent directory %s: %w", parentDir, err) + } + + // Rename command files with abcoder: prefix + if strings.HasPrefix(relPath, "commands/") { + baseName := filepath.Base(relPath) + switch baseName { + case "recheck.md": + destPath = filepath.Join(filepath.Dir(destPath), "abcoder:recheck.md") + case "schd.md": + destPath = filepath.Join(filepath.Dir(destPath), "abcoder:schd.md") + case "task.md": + destPath = filepath.Join(filepath.Dir(destPath), "abcoder:task.md") + } + } + + // Copy file + data, err := claudeFS.ReadFile(path) + if err != nil { + return fmt.Errorf("failed to read embedded file %s: %w", path, err) + } + + if err := os.WriteFile(destPath, data, 0644); err != nil { + return fmt.Errorf("failed to write file %s: %w", destPath, err) + } + + // Set executable permission for shell scripts + if strings.HasSuffix(relPath, ".sh") { + if err := os.Chmod(destPath, 0755); err != nil { + return fmt.Errorf("failed to set executable permission for %s: %w", destPath, err) + } + } + + // Track md and json files for placeholder replacement + if strings.HasSuffix(relPath, ".md") || strings.HasSuffix(relPath, ".json") { + mdFilesToReplace = append(mdFilesToReplace, destPath) + } + + return nil + }) + + if err != nil { + return err + } + + // Replace {{CLAUDE_HOME_PATH}} placeholder in md files with project root directory + for _, mdFile := range mdFilesToReplace { + if err := replaceClaudeHomePlaceholder(mdFile, projectRootDir); err != nil { + log.Info("Failed to replace placeholder in %s: %v", mdFile, err) + } + } + + return nil +} + +// replaceClaudeHomePlaceholder replaces {{CLAUDE_HOME_PATH}} with actual project root directory path +func replaceClaudeHomePlaceholder(filePath string, projectRootDir string) error { + data, err := os.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to read file %s: %w", filePath, err) + } + + content := string(data) + newContent := strings.ReplaceAll(content, "{{CLAUDE_HOME_PATH}}", projectRootDir) + + if err := os.WriteFile(filePath, []byte(newContent), 0644); err != nil { + return fmt.Errorf("failed to write file %s: %w", filePath, err) + } + + return nil +} + +// configureMCPServers configures MCP servers in the Claude config file +func configureMCPServers(configPath string, astsDir string) error { + var config claudeConfig + + // Read existing config if it exists + if data, err := os.ReadFile(configPath); err == nil { + if err := json.Unmarshal(data, &config); err != nil { + return fmt.Errorf("failed to parse existing config: %w", err) + } + } else if !os.IsNotExist(err) { + return fmt.Errorf("failed to read config file: %w", err) + } + + // Initialize mcpServers map if nil + if config.MCPServers == nil { + config.MCPServers = make(map[string]mcpServerConfig) + } + + // Add/Update abcoder MCP server + config.MCPServers["abcoder"] = mcpServerConfig{ + Command: "abcoder", + Args: []string{"mcp", astsDir}, + } + + // Add sequential-thinking MCP server + config.MCPServers["sequential-thinking"] = mcpServerConfig{ + Command: "npx", + Args: []string{"-y", "@modelcontextprotocol/server-sequential-thinking"}, + } + + // Write the config file + data, err := json.MarshalIndent(config, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal config: %w", err) + } + + if err := os.WriteFile(configPath, data, 0644); err != nil { + return fmt.Errorf("failed to write config file: %w", err) + } + + return nil +} + +// printSuccessMessage prints a success message with instructions +func printSuccessMessage(targetDir string, configPath string, astsDir string) { + fmt.Printf(` +✓ ABCoder Claude Code integration setup completed! + +Configuration files: + .claude directory: %s + Claude Code config: %s + AST storage directory: %s + +MCP servers configured: + - abcoder: for code analysis using AST + - sequential-thinking: for complex problem decomposition + +Next steps: + 1. Ensure abcoder is installed and in your PATH: + go install github.com/cloudwego/abcoder@latest + + 2. Restart Claude Code to apply the configuration + + 3. Use ABCoder tools in Claude Code: + - /abcoder:schd - Analyze codebase and design solution + - /abcoder:task - Create coding task + - /abcoder:recheck - Verify solution + +For more information, see: + - https://github.com/cloudwego/abcoder +`, targetDir, configPath, astsDir) +} diff --git a/docs/.claude/ABCoder-README.md b/docs/.claude/README.md similarity index 100% rename from docs/.claude/ABCoder-README.md rename to docs/.claude/README.md diff --git a/docs/.claude/commands/README.md b/docs/.claude/commands/README.md index 049276c..077656a 100644 --- a/docs/.claude/commands/README.md +++ b/docs/.claude/commands/README.md @@ -10,7 +10,7 @@ Claude Code 斜杠命令定义,用于规范化和自动化开发工作流。 **执行流程**: 1. 创建 `./task/{{MMDD}}/` 目录 -2. 读取模板 `~/.claude/tmpls/CODE_TASK.md` +2. 读取模板 `{{CLAUDE_HOME_PATH}}/.claude/tmpls/CODE_TASK.md` 3. 根据任务上下文填充模板,生成 `./task/{{MMDD}}/{{NAME}}__CODE_TASK.md` 4. 列出外部依赖包(如有) 5. 提示创建成功 @@ -104,7 +104,7 @@ coding-executor ──────→ 执行实现 ## 文件位置 ``` -~/.claude/ +{{CLAUDE_HOME_PATH}}/.claude/ ├── commands/ │ ├── abcoder:task.md │ ├── abcoder:schd.md diff --git a/docs/.claude/commands/task.md b/docs/.claude/commands/task.md index 69a0638..7e95a8b 100644 --- a/docs/.claude/commands/task.md +++ b/docs/.claude/commands/task.md @@ -3,7 +3,7 @@ 请帮我创建一个CODE_TASK。 1. `d=$(date +%m%d) && mkdir -p "./task/$d/" && echo "目录 ./task/$d/ 已创建"` 创建 `./task/{{MMDD}}/` 目录 -2. 读取模板文件 `~/.claude/tmpls/CODE_TASK.md` +2. 读取模板文件 `{{CLAUDE_HOME_PATH}}/.claude/tmpls/ABCODER_CODE_TASK.md` 3. 根据任务上下文,按照格式和要求填充模板,创建新文件 `./task/{{MMDD}}/{{NAME}}__CODE_TASK.md` 4. 告知用户这个`CODE_TASK`是否包含外部依赖;如果包含,请清晰列出完整的外部依赖包名称 5. 提示用户文件已创建成功,停止操作 diff --git a/docs/.claude/hooks/README.md b/docs/.claude/hooks/README.md index 83615cc..d131e04 100644 --- a/docs/.claude/hooks/README.md +++ b/docs/.claude/hooks/README.md @@ -67,7 +67,7 @@ Claude Code 钩子系统,用于自动化 ABCoder 代码分析工作流。 ## 安装位置 ``` -~/.claude/hooks/abcoder/ +{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/ ├── parse.sh ├── prompt.sh ├── reminder.sh diff --git a/docs/.claude/hooks/abcoder/parse.sh b/docs/.claude/hooks/abcoder/parse.sh index 18c5247..2061d81 100755 --- a/docs/.claude/hooks/abcoder/parse.sh +++ b/docs/.claude/hooks/abcoder/parse.sh @@ -72,7 +72,7 @@ abc() { mkdir -p ~/.asts/ # 执行实际命令 - abcoder parse "${lang}" "${repo_path}" -o "/Users/bytedance/.asts/${repo_name}.json" + abcoder parse "${lang}" "${repo_path}" -o "~/.asts/${repo_name}.json" else # 如果不是预期的 parse 命令格式,直接将参数传递给原始 abcoder 命令 abcoder "$@" diff --git a/docs/.claude/hooks/abcoder/prompt.sh b/docs/.claude/hooks/abcoder/prompt.sh index 454acb3..00d0d47 100755 --- a/docs/.claude/hooks/abcoder/prompt.sh +++ b/docs/.claude/hooks/abcoder/prompt.sh @@ -7,7 +7,7 @@ set -euo pipefail # 验证文件存在 -SOP_FILE="$HOME/.claude/hooks/abcoder/abcoder-workflow.md" +SOP_FILE=".claude/hooks/abcoder/abcoder-workflow.md" # echo "DEBUG: Checking file: $SOP_FILE" >&2 if [[ ! -f "$SOP_FILE" ]]; then diff --git a/docs/.claude/settings.json b/docs/.claude/settings.json index b5e108a..b68e0ac 100644 --- a/docs/.claude/settings.json +++ b/docs/.claude/settings.json @@ -2,7 +2,7 @@ "permissions": { "allow": [ "Edit(\\.md)", - "Read(.claude/**)", + "Read({{CLAUDE_HOME_PATH}}/.claude/**)", "mcp__abcoder", "mcp__sequential-thinking" ] @@ -14,7 +14,7 @@ "hooks": [ { "type": "command", - "command": ".claude/hooks/abcoder/parse.sh" + "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/parse.sh" } ] } @@ -25,7 +25,7 @@ "hooks": [ { "type": "command", - "command": ".claude/hooks/abcoder/prompt.sh" + "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/prompt.sh" } ] }, @@ -34,10 +34,10 @@ "hooks": [ { "type": "command", - "command": ".claude/hooks/abcoder/reminder.sh" + "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/reminder.sh" } ] } ] } -} +} \ No newline at end of file diff --git a/main.go b/main.go index ffab2ea..290f7ce 100644 --- a/main.go +++ b/main.go @@ -56,6 +56,7 @@ Action: write write the specific UniAST back to codes mcp run as a MCP server for all repo ASTs (*.json) in the specific directory agent run as an Agent for all repo ASTs (*.json) in the specific directory. WIP: only support code-analyzing at present. + init-spec initialize ABCoder integration for Claude Code (copies .claude directory and configures MCP servers) version print the version of abcoder Language: go for golang codes @@ -195,6 +196,29 @@ func main() { os.Exit(1) } + case "init-spec": + // Parse flags only, uri is optional and defaults to current directory + flags.Parse(os.Args[2:]) + + var uri string + if flagHelp != nil && *flagHelp { + flags.Usage() + os.Exit(0) + } + + if flagVerbose != nil && *flagVerbose { + log.SetLogLevel(log.DebugLevel) + } + + if len(os.Args) > 2 && !strings.HasPrefix(os.Args[2], "-") { + uri = os.Args[2] + } + + if err := runInitSpec(uri); err != nil { + log.Error("Failed to init-spec: %v\n", err) + os.Exit(1) + } + case "agent": _, uri := parseArgsAndFlags(flags, false, flagHelp, flagVerbose) if uri == "" { From 950a6dca8634280fbdc65fe07b7da367f8e67da7 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Tue, 13 Jan 2026 14:23:06 +0800 Subject: [PATCH 03/12] optimize: parser before list --- docs/.claude/hooks/abcoder/parse.sh | 60 ++++++++++------------------- docs/.claude/settings.json | 2 +- 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/docs/.claude/hooks/abcoder/parse.sh b/docs/.claude/hooks/abcoder/parse.sh index 2061d81..f8663da 100755 --- a/docs/.claude/hooks/abcoder/parse.sh +++ b/docs/.claude/hooks/abcoder/parse.sh @@ -92,68 +92,50 @@ cwd=$(echo "$input" | jq -r '.cwd // ""') # 复用现有的 get_basename 函数 current_base_name=$(get_basename "$cwd") -# 检测项目信息(语言和仓库标识) +# 检测项目信息(语言和仓库标识符) project_info=$(detect_project_info "$cwd") project_lang=$(echo "$project_info" | cut -d'|' -f1) project_identifier=$(echo "$project_info" | cut -d'|' -f2) -# echo "Detected project language: $project_lang" >> "$LOG_FILE" -# echo "Detected project identifier: $project_identifier" >> "$LOG_FILE" - -if [ "$repo_name" = "$cwd" ] || [ "$current_base_name" = "$repo_name" ] || [ "$project_identifier" = "$repo_name" ]; then - # echo "Path or identifier matched, executing abc parse..." >> "$LOG_FILE" - - # 检查是否检测到目标语言 - if [[ "$project_lang" == "unknown" ]]; then - jq -n '{ - "decision": "block", - "reason": "未检测到支持的语言(仅支持 Go 和 TypeScript)", - "hookSpecificOutput": { - "hookEventName": "PreToolUse", - "additionalContext": "请确保项目是 Go 或 TypeScript 类型" - } - }' - exit 0 - fi - +# 优化判断逻辑:只要检测到有效项目,就执行 parse +if [[ "$project_lang" != "unknown" ]]; then # 捕获标准输出和错误输出 output_file=$(mktemp) error_file=$(mktemp) - # 修改:使用检测到的语言执行 parse 命令(替换原有的固定 ts) - if abcoder parse "$project_lang" . >"$output_file" 2>"$error_file"; then - # echo "abc parse succeeded" >> "$LOG_FILE" - # cat "$output_file" >> "$LOG_FILE" + # 使用检测到的语言执行 parse 命令 + # 确保输出目录存在 + mkdir -p ~/.asts/ + ast_output_file=~/.asts/$(echo "$project_identifier" | sed 's|/|_|g').json - jq -n --arg lang "$project_lang" '{ - "systemMessage": "abcoder parse 已成功完成(语言:\($lang))。AST文件已生成,可以继续分析代码。" - }' + # 使用检测到的语言执行 parse 命令,并输出到 AST 目录 + if abcoder parse "$project_lang" . -o "$ast_output_file" >"$output_file" 2>"$error_file"; then + jq -n --arg lang "$project_lang" --arg repo "$project_identifier" '{ + "systemMessage": ("abcoder parse 已成功完成(语言:" + $lang + ",仓库:" + $repo + ")。AST文件已生成,可以继续分析代码。") + }' else exit_code=$? - # echo "abc parse FAILED with exit code $exit_code" >> "$LOG_FILE" - # echo "STDOUT:" >> "$LOG_FILE" - # cat "$output_file" >> "$LOG_FILE" - # echo "STDERR:" >> "$LOG_FILE" - # cat "$error_file" >> "$LOG_FILE" - # 读取错误信息 error_msg=$(cat "$error_file" | tail -20) - jq -n --arg code "$exit_code" --arg err "$error_msg" --arg lang "$project_lang" '{ + jq -n --arg code "$exit_code" --arg err "$error_msg" --arg lang "$project_lang" --arg repo "$project_identifier" '{ "decision": "block", - "reason": ("abcoder parse 失败(语言:\($lang),退出码: " + $code + ")。错误信息:\n" + $err + "\n\n可能的原因:\n1. 项目配置文件有问题(Go: go.mod;TS: tsconfig.json)\n2. 缺少依赖包\n3. 代码语法错误\n\n建议:\n- Go 项目:运行 'go mod tidy' 和 'go build' 检查\n- TS 项目:运行 'npm install' 和 'tsc --noEmit' 检查"), + "reason": ("abcoder parse 失败(语言:" + $lang + ",仓库:" + $repo + ",退出码: " + $code + ")。错误信息:\n" + $err + "\n\n可能的原因:\n1. 项目配置文件有问题(Go: go.mod;TS: tsconfig.json)\n2. 缺少依赖包\n3. 代码语法错误\n\n建议:\n- Go 项目:运行 'go mod tidy' 和 'go build' 检查\n- TS 项目:运行 'npm install' 和 'tsc --noEmit' 检查"), "hookSpecificOutput": { "hookEventName": "PreToolUse", - "additionalContext": ("解析失败,需要修复后重试") + "additionalContext": "解析失败,需要修复后重试" } }' fi # 清理临时文件 - trash "$output_file" "$error_file" + trash "$output_file" "$error_file" 2>/dev/null || rm -f "$output_file" "$error_file" else - # echo "Path did not match" >> "$LOG_FILE" - echo '{}' + # 当前目录不是支持的项目,返回空对象 + jq -n '{ + "decision": "block", + "reason": "当前目录未检测到支持的语言(仅支持 Go 和 TypeScript),请确保项目是 Go 或 TypeScript 类型" + }' fi exit 0 diff --git a/docs/.claude/settings.json b/docs/.claude/settings.json index b68e0ac..7593f90 100644 --- a/docs/.claude/settings.json +++ b/docs/.claude/settings.json @@ -10,7 +10,7 @@ "hooks": { "PreToolUse": [ { - "matcher": "mcp__abcoder__get_repo_structure|mcp__abcoder__get_file_structure|mcp__abcoder__get_package_structure|mcp__abcoder__get_ast_node", + "matcher": "mcp__abcoder__list_repos|mcp__abcoder__get_repo_structure|mcp__abcoder__get_file_structure|mcp__abcoder__get_package_structure|mcp__abcoder__get_ast_node", "hooks": [ { "type": "command", From 8bb5075b02ecc772f58d3bce623ed772155f8d7a Mon Sep 17 00:00:00 2001 From: gaowenju Date: Tue, 13 Jan 2026 14:33:14 +0800 Subject: [PATCH 04/12] optimize: add a cache time for parse.sh --- docs/.claude/hooks/abcoder/parse.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/.claude/hooks/abcoder/parse.sh b/docs/.claude/hooks/abcoder/parse.sh index f8663da..da7f0eb 100755 --- a/docs/.claude/hooks/abcoder/parse.sh +++ b/docs/.claude/hooks/abcoder/parse.sh @@ -108,6 +108,17 @@ if [[ "$project_lang" != "unknown" ]]; then mkdir -p ~/.asts/ ast_output_file=~/.asts/$(echo "$project_identifier" | sed 's|/|_|g').json + # 检查 AST 文件是否存在且更新时间小于 1 分钟(缓存优化) + if [[ -f "$ast_output_file" ]]; then + local file_age_seconds=$(($(date +%s) - $(stat -f %m "$ast_output_file" 2>/dev/null || stat -c %Y "$ast_output_file" 2>/dev/null))) + if [[ $file_age_seconds -lt 60 ]]; then + jq -n --arg lang "$project_lang" --arg repo "$project_identifier" --arg age "$file_age_seconds" '{ + "systemMessage": ("abcoder AST 缓存命中(语言:" + $lang + ",仓库:" + $repo + ")。文件更新于 " + $file_age_seconds + " 秒前,跳过 parse 操作。") + }' + exit 0 + fi + fi + # 使用检测到的语言执行 parse 命令,并输出到 AST 目录 if abcoder parse "$project_lang" . -o "$ast_output_file" >"$output_file" 2>"$error_file"; then jq -n --arg lang "$project_lang" --arg repo "$project_identifier" '{ From 9be99a618cd281a6d2a98ee11dfe1a38cdc3d9f9 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Tue, 13 Jan 2026 14:58:12 +0800 Subject: [PATCH 05/12] optimize: sop --- docs/.claude/commands/README.md | 6 +++--- docs/.claude/hooks/abcoder/abcoder-workflow.md | 5 +++-- docs/.claude/hooks/abcoder/prompt.sh | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/.claude/commands/README.md b/docs/.claude/commands/README.md index 077656a..8273374 100644 --- a/docs/.claude/commands/README.md +++ b/docs/.claude/commands/README.md @@ -10,7 +10,7 @@ Claude Code 斜杠命令定义,用于规范化和自动化开发工作流。 **执行流程**: 1. 创建 `./task/{{MMDD}}/` 目录 -2. 读取模板 `{{CLAUDE_HOME_PATH}}/.claude/tmpls/CODE_TASK.md` +2. 读取模板 `{{CLAUDE_HOME_PATH}}/.claude/tmpls/ABCODER_CODE_TASK.md` 3. 根据任务上下文填充模板,生成 `./task/{{MMDD}}/{{NAME}}__CODE_TASK.md` 4. 列出外部依赖包(如有) 5. 提示创建成功 @@ -66,7 +66,7 @@ Claude Code 斜杠命令定义,用于规范化和自动化开发工作流。 ## 模板文件 -### CODE_TASK.md +### ABCODER_CODE_TASK.md 编码任务模板,定义任务清单格式。 @@ -110,5 +110,5 @@ coding-executor ──────→ 执行实现 │ ├── abcoder:schd.md │ └── abcoder:recheck.md └── tmpls/ - └── CODE_TASK.md + └── ABCODER_CODE_TASK.md ``` diff --git a/docs/.claude/hooks/abcoder/abcoder-workflow.md b/docs/.claude/hooks/abcoder/abcoder-workflow.md index a30b8c6..1d3bf62 100644 --- a/docs/.claude/hooks/abcoder/abcoder-workflow.md +++ b/docs/.claude/hooks/abcoder/abcoder-workflow.md @@ -20,8 +20,9 @@ 2. **代码定位** (repo→package→node→ast node relationship): - 2.1 **定位package**: 基于 `get_repo_structure` 返回的package list选择目标package - - 2.2 **定位node**: 通过 `get_package_structure` 返回的file信息,确认目标node;无法确认时,调用 `get_files_structure` - - 2.3 **确认ast node relationship**: 递归调用 `get_ast_node` 获取node详细(dependencies, references, inheritance, implementation, grouping) + - 2.2 **定位文件**: 通过 `get_package_structure` 返回的file信息,确认目标文件 + - 2.3 **定位节点**: 通过 `get_files_structure` 返回的node信息,确认目标节点 + - 2.4 **确认node详情**: 递归调用 `get_ast_node` 获取node详细(dependencies, references, inheritance, implementation, grouping) 3. **自我反思**: - 理解完整的code calling-chain、contextual-relationship diff --git a/docs/.claude/hooks/abcoder/prompt.sh b/docs/.claude/hooks/abcoder/prompt.sh index 00d0d47..21bf54c 100755 --- a/docs/.claude/hooks/abcoder/prompt.sh +++ b/docs/.claude/hooks/abcoder/prompt.sh @@ -7,7 +7,7 @@ set -euo pipefail # 验证文件存在 -SOP_FILE=".claude/hooks/abcoder/abcoder-workflow.md" +SOP_FILE="{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/abcoder-workflow.md" # echo "DEBUG: Checking file: $SOP_FILE" >&2 if [[ ! -f "$SOP_FILE" ]]; then From 554487729b72c42180cceae6f2a2f207f34f20f0 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Tue, 13 Jan 2026 15:34:31 +0800 Subject: [PATCH 06/12] fix: wrong return schema in hooks --- cmd_init_spec.go | 2 +- docs/.claude/hooks/abcoder/parse.sh | 2 ++ docs/.claude/hooks/abcoder/prompt.sh | 12 ++++++------ docs/.claude/hooks/abcoder/reminder.sh | 6 +++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cmd_init_spec.go b/cmd_init_spec.go index 8149077..aadd888 100644 --- a/cmd_init_spec.go +++ b/cmd_init_spec.go @@ -162,7 +162,7 @@ func copyEmbeddedDir(srcPath string, destDir string, projectRootDir string) erro } // Track md and json files for placeholder replacement - if strings.HasSuffix(relPath, ".md") || strings.HasSuffix(relPath, ".json") { + if strings.HasSuffix(relPath, ".md") || strings.HasSuffix(relPath, ".json") || strings.HasSuffix(relPath, "prompt.sh") { mdFilesToReplace = append(mdFilesToReplace, destPath) } diff --git a/docs/.claude/hooks/abcoder/parse.sh b/docs/.claude/hooks/abcoder/parse.sh index da7f0eb..4ce488f 100755 --- a/docs/.claude/hooks/abcoder/parse.sh +++ b/docs/.claude/hooks/abcoder/parse.sh @@ -113,6 +113,7 @@ if [[ "$project_lang" != "unknown" ]]; then local file_age_seconds=$(($(date +%s) - $(stat -f %m "$ast_output_file" 2>/dev/null || stat -c %Y "$ast_output_file" 2>/dev/null))) if [[ $file_age_seconds -lt 60 ]]; then jq -n --arg lang "$project_lang" --arg repo "$project_identifier" --arg age "$file_age_seconds" '{ + "continue": true, "systemMessage": ("abcoder AST 缓存命中(语言:" + $lang + ",仓库:" + $repo + ")。文件更新于 " + $file_age_seconds + " 秒前,跳过 parse 操作。") }' exit 0 @@ -122,6 +123,7 @@ if [[ "$project_lang" != "unknown" ]]; then # 使用检测到的语言执行 parse 命令,并输出到 AST 目录 if abcoder parse "$project_lang" . -o "$ast_output_file" >"$output_file" 2>"$error_file"; then jq -n --arg lang "$project_lang" --arg repo "$project_identifier" '{ + "continue": true, "systemMessage": ("abcoder parse 已成功完成(语言:" + $lang + ",仓库:" + $repo + ")。AST文件已生成,可以继续分析代码。") }' else diff --git a/docs/.claude/hooks/abcoder/prompt.sh b/docs/.claude/hooks/abcoder/prompt.sh index 21bf54c..eb52d1c 100755 --- a/docs/.claude/hooks/abcoder/prompt.sh +++ b/docs/.claude/hooks/abcoder/prompt.sh @@ -7,12 +7,12 @@ set -euo pipefail # 验证文件存在 -SOP_FILE="{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/abcoder-workflow.md" +SOP_FILE="/Users/bytedance/github/github.com/cloudwego/abcoder2/.claude/hooks/abcoder/abcoder-workflow.md" # echo "DEBUG: Checking file: $SOP_FILE" >&2 if [[ ! -f "$SOP_FILE" ]]; then # echo "DEBUG: File not found" >&2 - echo '{"decision": "block", "reason": "SOP file not found", "hookSpecificOutput": {"hookEventName": "PostToolUse"}}' + echo '{"ok": false, "reason": "SOP file not found", "hookSpecificOutput": {"hookEventName": "PostToolUse"}}' exit 0 fi @@ -22,7 +22,7 @@ fi SOP_CONTENT=$(cat "$SOP_FILE" | jq -Rs . 2>/dev/null) if [[ $? -ne 0 ]]; then # echo "DEBUG: jq failed" >&2 - echo '{"decision": "block", "reason": "Failed to process SOP content", "hookSpecificOutput": {"hookEventName": "PostToolUse"}}' + echo '{"ok": false, "reason": "Failed to process SOP content", "hookSpecificOutput": {"hookEventName": "PostToolUse"}}' exit 0 fi @@ -31,10 +31,10 @@ fi # 输出 JSON cat <This is a reminder that when executing the ABCoder code analysis workflow, after locating the target node, you MUST use the get_ast_node tool. It is required to recursively call get_ast_node to obtain the complete AST node information, including type, code, position, and related relationships (dependency, reference, inheritance, implementation, grouping node IDs).", + "continue": true, + "systemMessage": "This is a reminder that when executing the ABCoder code analysis workflow, after locating the target node, you MUST use the get_ast_node tool. It is required to recursively call get_ast_node to obtain the complete AST node information, including type, code, position, and related relationships (dependency, reference, inheritance, implementation, grouping node IDs).", "hookSpecificOutput": { - "hookEventName": "PostToolUse", + "hookEventName": "PostToolUse" } } EOF From 76f91e46db3f702097d17f59686b27a3f6335493 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Tue, 13 Jan 2026 21:15:31 +0800 Subject: [PATCH 07/12] fix: parse cache --- docs/.claude/hooks/abcoder/parse.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/.claude/hooks/abcoder/parse.sh b/docs/.claude/hooks/abcoder/parse.sh index 4ce488f..48298dd 100755 --- a/docs/.claude/hooks/abcoder/parse.sh +++ b/docs/.claude/hooks/abcoder/parse.sh @@ -110,11 +110,11 @@ if [[ "$project_lang" != "unknown" ]]; then # 检查 AST 文件是否存在且更新时间小于 1 分钟(缓存优化) if [[ -f "$ast_output_file" ]]; then - local file_age_seconds=$(($(date +%s) - $(stat -f %m "$ast_output_file" 2>/dev/null || stat -c %Y "$ast_output_file" 2>/dev/null))) + file_age_seconds=$(($(date +%s) - $(stat -f %m "$ast_output_file" 2>/dev/null || stat -c %Y "$ast_output_file" 2>/dev/null))) if [[ $file_age_seconds -lt 60 ]]; then jq -n --arg lang "$project_lang" --arg repo "$project_identifier" --arg age "$file_age_seconds" '{ "continue": true, - "systemMessage": ("abcoder AST 缓存命中(语言:" + $lang + ",仓库:" + $repo + ")。文件更新于 " + $file_age_seconds + " 秒前,跳过 parse 操作。") + "systemMessage": ("abcoder AST 缓存命中(语言:" + $lang + ",仓库:" + $repo + ")。文件更新于 " + $age + " 秒前(小于1分钟更新阈值),跳过 parse 操作。") }' exit 0 fi From f17e1fd3748e071779a93304e5e89e9e1a500ae2 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Wed, 14 Jan 2026 11:10:43 +0800 Subject: [PATCH 08/12] optimize: add more details for slash commands --- docs/.claude/commands/recheck.md | 3 ++- docs/.claude/commands/schd.md | 2 +- docs/.claude/commands/task.md | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/.claude/commands/recheck.md b/docs/.claude/commands/recheck.md index 9476d8c..326f190 100644 --- a/docs/.claude/commands/recheck.md +++ b/docs/.claude/commands/recheck.md @@ -1,4 +1,5 @@ -# 系统指令: ReCheck +# 系统指令: 核对任务实现方案(二次对齐) + 理解任务 {1},并使用`mcp__abcoder`核对技术细节(下钻到`mcp__abcoder__get_ast_node`粒度); diff --git a/docs/.claude/commands/schd.md b/docs/.claude/commands/schd.md index 52dbfff..41d6e1d 100644 --- a/docs/.claude/commands/schd.md +++ b/docs/.claude/commands/schd.md @@ -1,4 +1,4 @@ -# 系统指令:Schedule +# 系统指令:规划一个任务(输入:任务描述) 使用`mcp__abcoder`分析相关仓库(下钻到`mcp__abcoder__get_ast_node`查看细节),帮助用户设计实现方案。 diff --git a/docs/.claude/commands/task.md b/docs/.claude/commands/task.md index 7e95a8b..d212e89 100644 --- a/docs/.claude/commands/task.md +++ b/docs/.claude/commands/task.md @@ -1,4 +1,4 @@ -# 系统指令:创建CODE_TASK +# 系统指令:基于当前上下文创建一个 SPEC 驱动的 CODE_TASK(输入:任务名称) 请帮我创建一个CODE_TASK。 From 6a5daebc48faf5895d2913510f8888077034603a Mon Sep 17 00:00:00 2001 From: gaowenju Date: Wed, 14 Jan 2026 11:21:38 +0800 Subject: [PATCH 09/12] chore: rename schd -> schedule --- README.md | 8 ++++---- cmd_init_spec.go | 6 +++--- docs/.claude/README.md | 6 +++--- docs/.claude/commands/README.md | 6 +++--- docs/.claude/commands/{schd.md => schedule.md} | 3 ++- 5 files changed, 15 insertions(+), 14 deletions(-) rename docs/.claude/commands/{schd.md => schedule.md} (90%) diff --git a/README.md b/README.md index cc296f1..2cf8ac4 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ list_repos → get_repo_structure → get_package_structure → get_file_structu | Command | Function | Description | |---------|----------|-------------| -| [`/abcoder:schd`](docs/.claude/commands/abcoder:schd.md) | Design implementation | Analyze codebase using ABCoder, design technical solution | +| [`/abcoder:schedule` ](docs/.claude/commands/abcoder:schedule.md) | Design implementation | Analyze codebase using ABCoder, design technical solution | | [`/abcoder:task `](docs/.claude/commands/abcoder:task.md) | Create coding task | Generate standardized CODE_TASK document | | [`/abcoder:recheck `](docs/.claude/commands/abcoder:recheck.md) | Verify solution | Critically check CODE_TASK feasibility, useful when a CODE_TASK contains external dependencies | @@ -135,7 +135,7 @@ list_repos → get_repo_structure → get_package_structure → get_file_structu User Request │ ▼ -/abcoder:schd ──────────→ Design Solution (ABCoder Analysis) +/abcoder:schedule ──────────→ Design Solution (ABCoder Analysis) │ │ ▼ ▼ /abcoder:task ─────────→ CODE_TASK (with Technical Specs, including accurate `get_ast_node` call args) @@ -144,7 +144,7 @@ User Request /abcoder:recheck ────→ Verify Solution (ABCoder Validation. After `/abcoder:task` Claude Code will tell you what the external dependencies CODE_TASK contains, use `/abcoder:recheck` to analyze external ast_node and technical detail with ABCoder) │ │ ▼ ▼ -sub-agent ─────────→ Execute Implementation +Start coding(sub-agent) ─────────→ Execute Implementation ``` ### Configuration Files @@ -154,7 +154,7 @@ sub-agent ─────────→ Execute Implementation | [`CLAUDE.md`](docs/.claude/CLAUDE.md) | Core AST-Driven Coder role definition | | [`settings.json`](docs/.claude/settings.json) | Hooks and permissions configuration | | [`hooks/`](docs/.claude/hooks/) | Automation scripts (parse/prompt/reminder) | -| [`commands/`](docs/.claude/commands/) | Slash command definitions (abcoder:task/abcoder:schd/abcoder:recheck) | +| [`commands/`](docs/.claude/commands/) | Slash command definitions (abcoder:task/abcoder:schedule/abcoder:recheck) | | [`tmpls/ABCODER_CODE_TASK.md`](docs/.claude/tmpls/ABCODER_CODE_TASK.md) | Coding task template | ### Dependencies diff --git a/cmd_init_spec.go b/cmd_init_spec.go index aadd888..0f7cab0 100644 --- a/cmd_init_spec.go +++ b/cmd_init_spec.go @@ -137,8 +137,8 @@ func copyEmbeddedDir(srcPath string, destDir string, projectRootDir string) erro switch baseName { case "recheck.md": destPath = filepath.Join(filepath.Dir(destPath), "abcoder:recheck.md") - case "schd.md": - destPath = filepath.Join(filepath.Dir(destPath), "abcoder:schd.md") + case "schedule.md": + destPath = filepath.Join(filepath.Dir(destPath), "abcoder:schedule.md") case "task.md": destPath = filepath.Join(filepath.Dir(destPath), "abcoder:task.md") } @@ -264,7 +264,7 @@ Next steps: 2. Restart Claude Code to apply the configuration 3. Use ABCoder tools in Claude Code: - - /abcoder:schd - Analyze codebase and design solution + - /abcoder:schedule - Analyze codebase and design solution - /abcoder:task - Create coding task - /abcoder:recheck - Verify solution diff --git a/docs/.claude/README.md b/docs/.claude/README.md index 293dc77..a189445 100644 --- a/docs/.claude/README.md +++ b/docs/.claude/README.md @@ -14,7 +14,7 @@ Claude Code 的 AST 驱动开发配置,通过 MCP 工具、钩子和斜杠命 │ └── reminder.sh # 提醒递归调用 get_ast_node ├── commands/ # 斜杠命令定义 │ ├── abcoder:task.md # /abcoder:task - 创建编码任务 -│ ├── abcoder:schd.md # /abcoder:schd - 设计实现方案 +│ ├── abcoder:schedule.md # /abcoder:schedule - 设计实现方案 │ └── abcoder:recheck.md # /abcoder:recheck - 技术方案核对 └── tmpls/ # 文档模板 └── CODE_TASK.md # 编码任务模板 @@ -73,7 +73,7 @@ list_repos → get_repo_structure → get_package_structure → get_file_structu - 涉及 curl: 提供完整命令和响应结构 - 提供具体验证方法 -### /abcoder:schd +### /abcoder:schedule 使用 mcp__abcoder 设计实现方案 @@ -97,7 +97,7 @@ list_repos → get_repo_structure → get_package_structure → get_file_structu 用户需求 │ ▼ -/abcoder:schd ──────────────→ 设计方案(abcoder分析) +/abcoder:schedule ──────────────→ 设计方案(abcoder分析) │ │ ▼ ▼ /abcoder:task ────────→ CODE_TASK(含技术规格) diff --git a/docs/.claude/commands/README.md b/docs/.claude/commands/README.md index 8273374..86fe9d9 100644 --- a/docs/.claude/commands/README.md +++ b/docs/.claude/commands/README.md @@ -30,7 +30,7 @@ Claude Code 斜杠命令定义,用于规范化和自动化开发工作流。 --- -### /abcoder:schd - 设计实现方案 +### /abcoder:schedule - 设计实现方案 使用 mcp__abcoder 分析代码库,设计技术实现方案。 @@ -89,7 +89,7 @@ Claude Code 斜杠命令定义,用于规范化和自动化开发工作流。 用户需求 │ ▼ -/abcoder:schd ──────────────→ 设计方案(abcoder分析) +/abcoder:schedule ──────────────→ 设计方案(abcoder分析) │ │ ▼ ▼ /abcoder:task ────────→ CODE_TASK(含技术规格) @@ -107,7 +107,7 @@ coding-executor ──────→ 执行实现 {{CLAUDE_HOME_PATH}}/.claude/ ├── commands/ │ ├── abcoder:task.md -│ ├── abcoder:schd.md +│ ├── abcoder:schedule.md │ └── abcoder:recheck.md └── tmpls/ └── ABCODER_CODE_TASK.md diff --git a/docs/.claude/commands/schd.md b/docs/.claude/commands/schedule.md similarity index 90% rename from docs/.claude/commands/schd.md rename to docs/.claude/commands/schedule.md index 41d6e1d..0d6bef6 100644 --- a/docs/.claude/commands/schd.md +++ b/docs/.claude/commands/schedule.md @@ -7,6 +7,7 @@ - 优先采用直接、最小改动的实现方式,只有在用户明确要求时才增加复杂度。 - 严格限制修改影响面在所请求的结果范围内。 - 找出任何模糊或含糊不清的细节,并在修改文件前提出必要的后续问题。 -- 在Schdule阶段禁止编写代码,禁止使用agent。 +- 在Schedule阶段禁止编写代码,禁止使用agent。 + IMPORTANT: 必须从`mcp__abcoder__get_repo_strucure`开始 From 46a870d42093bb96c37fafb8736735a503bea267 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Wed, 14 Jan 2026 14:05:20 +0800 Subject: [PATCH 10/12] refactor: cc intergrete --- README.md | 2 +- .../.claude/hooks/abcoder/abcoder-workflow.md | 32 ---- docs/.claude/hooks/abcoder/parse.sh | 154 ------------------ docs/.claude/hooks/abcoder/prompt.sh | 43 ----- docs/.claude/hooks/abcoder/reminder.sh | 11 -- docs/.claude/settings.json | 43 ----- .../README.md => claude-code-spec.md} | 0 .../utils/assets}/.claude/CLAUDE.md | 0 internal/utils/assets/.claude/README.md | 127 +++++++++++++++ .../utils/assets}/.claude/commands/README.md | 0 .../utils/assets}/.claude/commands/recheck.md | 0 .../assets}/.claude/commands/schedule.md | 0 .../utils/assets}/.claude/commands/task.md | 0 .../utils/assets}/.claude/hooks/README.md | 0 .../.claude/tmpls/ABCODER_CODE_TASK.md | 0 .../utils/cmd_init_spec.go | 10 +- main.go | 3 +- 17 files changed, 135 insertions(+), 290 deletions(-) delete mode 100644 docs/.claude/hooks/abcoder/abcoder-workflow.md delete mode 100755 docs/.claude/hooks/abcoder/parse.sh delete mode 100755 docs/.claude/hooks/abcoder/prompt.sh delete mode 100755 docs/.claude/hooks/abcoder/reminder.sh delete mode 100644 docs/.claude/settings.json rename docs/{.claude/README.md => claude-code-spec.md} (100%) rename {docs => internal/utils/assets}/.claude/CLAUDE.md (100%) create mode 100644 internal/utils/assets/.claude/README.md rename {docs => internal/utils/assets}/.claude/commands/README.md (100%) rename {docs => internal/utils/assets}/.claude/commands/recheck.md (100%) rename {docs => internal/utils/assets}/.claude/commands/schedule.md (100%) rename {docs => internal/utils/assets}/.claude/commands/task.md (100%) rename {docs => internal/utils/assets}/.claude/hooks/README.md (100%) rename {docs => internal/utils/assets}/.claude/tmpls/ABCODER_CODE_TASK.md (100%) rename cmd_init_spec.go => internal/utils/cmd_init_spec.go (97%) diff --git a/README.md b/README.md index 2cf8ac4..6eb9f64 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ see [UniAST Specification](docs/uniast-zh.md) ## Claude Code Integration -ABCoder provides deep integration with [Claude Code](https://claude.ai/code) through the AST-Driven Coding workflow, enabling hallucination-free code analysis and precise execution. +ABCoder provides deep integration with [Claude Code](https://claude.ai/code) through the AST-Driven Coding workflow, enabling hallucination-free code analysis and precise execution. Check [Claude Code Specification](docs/claude-code-spec.md) for more details. ### Setup diff --git a/docs/.claude/hooks/abcoder/abcoder-workflow.md b/docs/.claude/hooks/abcoder/abcoder-workflow.md deleted file mode 100644 index 1d3bf62..0000000 --- a/docs/.claude/hooks/abcoder/abcoder-workflow.md +++ /dev/null @@ -1,32 +0,0 @@ -# ABCoder代码分析工作流 - -## AST 层次结构 -- **模块(Module)**: 仓库中的编译单元,由 `mod_path` 标识;例如: "github.com/cloudwego/kitex" -- **包(Package)**: 符号的命名空间,由 `pkg_path` 标识;例如: "github.com/cloudwego/kitex/pkg/generic" -- **文件(File)**: 代码文件,由 `file_path` 标识;例如: "pkg/generic/closer.go" -- **AST节点**: 语法单元(函数、类型、变量),由 `NodeID` 标识;例如: -``` -{ - "mod_path": "github.com/cloudwego/kitex", - "pkg_path": "github.com/cloudwego/kitex/pkg/generic", - "name": "Closer" -} -``` - -## ABCoder工作SOP -1. **问题分析**: - - 基于用户问题分析相关关键词 - - 必须使用 `list_repos` 确认repo_name - -2. **代码定位** (repo→package→node→ast node relationship): - - 2.1 **定位package**: 基于 `get_repo_structure` 返回的package list选择目标package - - 2.2 **定位文件**: 通过 `get_package_structure` 返回的file信息,确认目标文件 - - 2.3 **定位节点**: 通过 `get_files_structure` 返回的node信息,确认目标节点 - - 2.4 **确认node详情**: 递归调用 `get_ast_node` 获取node详细(dependencies, references, inheritance, implementation, grouping) - -3. **自我反思**: - - 理解完整的code calling-chain、contextual-relationship - - 如果无法清楚解释机制,使用`sequential_thinking` 来帮助分解问题并记录信息,调整选择并重复步骤2 - -## 注意事项 -- 回复应列出相关代码的准确 metadata,包括 AST node(或 package)的 identity、file location 和代码。**必须提供确切的 file location(包括 line numbers)!** diff --git a/docs/.claude/hooks/abcoder/parse.sh b/docs/.claude/hooks/abcoder/parse.sh deleted file mode 100755 index 48298dd..0000000 --- a/docs/.claude/hooks/abcoder/parse.sh +++ /dev/null @@ -1,154 +0,0 @@ -#!/bin/bash - -# 修正并简化的 get_basename 函数 -get_basename() { - # 检查输入是否为 "." 或 ".." - if [[ "$1" == "." || "$1" == ".." ]]; then - # 对于当前或上级目录,使用 basename 结合 pwd - basename "$(cd "$1" && pwd)" - else - # 对于其他路径,直接使用 basename - basename "$1" - fi -} - -# 新增:检测项目语言并获取仓库标识 -detect_project_info() { - local target_dir="$1" - local project_info="" - - # 1. 优先检测 Go 项目(判断 go.mod 或 main.go) - if [[ -f "${target_dir}/go.mod" ]]; then - # 从 go.mod 中提取 module name - local module_name=$(grep "^module " "${target_dir}/go.mod" | head -1 | awk '{print $2}') - if [[ -n "$module_name" ]]; then - echo "go|${module_name}" - return 0 - fi - # 如果无法获取 module name,使用 main.go 所在目录 - if [[ -f "${target_dir}/main.go" ]]; then - echo "go|$(get_basename "$target_dir")" - return 0 - fi - fi - - # 2. 检测 TypeScript 项目(判断 package.json 或 tsconfig.json) - if [[ -f "${target_dir}/package.json" ]]; then - # 从 package.json 中提取 name - local package_name=$(jq -r '.name // empty' "${target_dir}/package.json" 2>/dev/null) - if [[ -n "$package_name" && "$package_name" != "null" ]]; then - echo "ts|${package_name}" - return 0 - fi - fi - - # 3. 检测 TypeScript 项目(判断 tsconfig.json 或 .ts/.tsx 文件) - if [[ -f "${target_dir}/tsconfig.json" ]]; then - echo "ts|$(get_basename "$target_dir")" - return 0 - fi - - # 统计 .ts 和 .tsx 文件数量(排除 node_modules 目录) - local ts_file_count=$(find "${target_dir}" -type f -not -path "*/node_modules/*" \( -name "*.ts" -o -name "*.tsx" \) | wc -l) - if [[ $ts_file_count -gt 0 ]]; then - echo "ts|$(get_basename "$target_dir")" - return 0 - fi - - # 4. 未检测到目标语言 - echo "unknown|$(get_basename "$target_dir")" - return 1 -} - -# 直接映射 abc 为别名,处理 parse <语言> <仓库路径> 形式的参数 -abc() { - # 检查命令格式是否为 "parse <语言> <仓库路径>" - if [ $# -eq 3 ] && [ "$1" = "parse" ]; then - local lang="$2" - local repo_path="$3" - local repo_name=$(get_basename "$repo_path") - - # 确保输出目录存在 - mkdir -p ~/.asts/ - - # 执行实际命令 - abcoder parse "${lang}" "${repo_path}" -o "~/.asts/${repo_name}.json" - else - # 如果不是预期的 parse 命令格式,直接将参数传递给原始 abcoder 命令 - abcoder "$@" - fi -} - -# LOG_FILE="/tmp/claude-hook-debug.log" - -input=$(cat) -repo_name=$(echo "$input" | jq -r '.tool_input.repo_name // ""') -cwd=$(echo "$input" | jq -r '.cwd // ""') - -# echo "=== $(date) ===" >> "$LOG_FILE" -# echo "repo_name: $repo_name" >> "$LOG_FILE" -# echo "cwd: $cwd" >> "$LOG_FILE" - -# 复用现有的 get_basename 函数 -current_base_name=$(get_basename "$cwd") - -# 检测项目信息(语言和仓库标识符) -project_info=$(detect_project_info "$cwd") -project_lang=$(echo "$project_info" | cut -d'|' -f1) -project_identifier=$(echo "$project_info" | cut -d'|' -f2) - -# 优化判断逻辑:只要检测到有效项目,就执行 parse -if [[ "$project_lang" != "unknown" ]]; then - # 捕获标准输出和错误输出 - output_file=$(mktemp) - error_file=$(mktemp) - - # 使用检测到的语言执行 parse 命令 - # 确保输出目录存在 - mkdir -p ~/.asts/ - ast_output_file=~/.asts/$(echo "$project_identifier" | sed 's|/|_|g').json - - # 检查 AST 文件是否存在且更新时间小于 1 分钟(缓存优化) - if [[ -f "$ast_output_file" ]]; then - file_age_seconds=$(($(date +%s) - $(stat -f %m "$ast_output_file" 2>/dev/null || stat -c %Y "$ast_output_file" 2>/dev/null))) - if [[ $file_age_seconds -lt 60 ]]; then - jq -n --arg lang "$project_lang" --arg repo "$project_identifier" --arg age "$file_age_seconds" '{ - "continue": true, - "systemMessage": ("abcoder AST 缓存命中(语言:" + $lang + ",仓库:" + $repo + ")。文件更新于 " + $age + " 秒前(小于1分钟更新阈值),跳过 parse 操作。") - }' - exit 0 - fi - fi - - # 使用检测到的语言执行 parse 命令,并输出到 AST 目录 - if abcoder parse "$project_lang" . -o "$ast_output_file" >"$output_file" 2>"$error_file"; then - jq -n --arg lang "$project_lang" --arg repo "$project_identifier" '{ - "continue": true, - "systemMessage": ("abcoder parse 已成功完成(语言:" + $lang + ",仓库:" + $repo + ")。AST文件已生成,可以继续分析代码。") - }' - else - exit_code=$? - # 读取错误信息 - error_msg=$(cat "$error_file" | tail -20) - - jq -n --arg code "$exit_code" --arg err "$error_msg" --arg lang "$project_lang" --arg repo "$project_identifier" '{ - "decision": "block", - "reason": ("abcoder parse 失败(语言:" + $lang + ",仓库:" + $repo + ",退出码: " + $code + ")。错误信息:\n" + $err + "\n\n可能的原因:\n1. 项目配置文件有问题(Go: go.mod;TS: tsconfig.json)\n2. 缺少依赖包\n3. 代码语法错误\n\n建议:\n- Go 项目:运行 'go mod tidy' 和 'go build' 检查\n- TS 项目:运行 'npm install' 和 'tsc --noEmit' 检查"), - "hookSpecificOutput": { - "hookEventName": "PreToolUse", - "additionalContext": "解析失败,需要修复后重试" - } - }' - fi - - # 清理临时文件 - trash "$output_file" "$error_file" 2>/dev/null || rm -f "$output_file" "$error_file" -else - # 当前目录不是支持的项目,返回空对象 - jq -n '{ - "decision": "block", - "reason": "当前目录未检测到支持的语言(仅支持 Go 和 TypeScript),请确保项目是 Go 或 TypeScript 类型" - }' -fi - -exit 0 diff --git a/docs/.claude/hooks/abcoder/prompt.sh b/docs/.claude/hooks/abcoder/prompt.sh deleted file mode 100755 index eb52d1c..0000000 --- a/docs/.claude/hooks/abcoder/prompt.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/zsh - -# 添加调试信息 -# LOG_FILE="/tmp/claude-hook-debug.log" - -# 错误处理 -set -euo pipefail - -# 验证文件存在 -SOP_FILE="/Users/bytedance/github/github.com/cloudwego/abcoder2/.claude/hooks/abcoder/abcoder-workflow.md" -# echo "DEBUG: Checking file: $SOP_FILE" >&2 - -if [[ ! -f "$SOP_FILE" ]]; then - # echo "DEBUG: File not found" >&2 - echo '{"ok": false, "reason": "SOP file not found", "hookSpecificOutput": {"hookEventName": "PostToolUse"}}' - exit 0 -fi - -# echo "DEBUG: File found, reading content" >&2 - -# 读取并转义内容 -SOP_CONTENT=$(cat "$SOP_FILE" | jq -Rs . 2>/dev/null) -if [[ $? -ne 0 ]]; then - # echo "DEBUG: jq failed" >&2 - echo '{"ok": false, "reason": "Failed to process SOP content", "hookSpecificOutput": {"hookEventName": "PostToolUse"}}' - exit 0 -fi - -# echo "DEBUG: Content processed successfully" >&2 - -# 输出 JSON -cat <&2 -exit 0 diff --git a/docs/.claude/hooks/abcoder/reminder.sh b/docs/.claude/hooks/abcoder/reminder.sh deleted file mode 100755 index dbb661c..0000000 --- a/docs/.claude/hooks/abcoder/reminder.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/zsh -cat <This is a reminder that when executing the ABCoder code analysis workflow, after locating the target node, you MUST use the get_ast_node tool. It is required to recursively call get_ast_node to obtain the complete AST node information, including type, code, position, and related relationships (dependency, reference, inheritance, implementation, grouping node IDs).", - "hookSpecificOutput": { - "hookEventName": "PostToolUse" - } -} -EOF -exit 0 diff --git a/docs/.claude/settings.json b/docs/.claude/settings.json deleted file mode 100644 index 7593f90..0000000 --- a/docs/.claude/settings.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "permissions": { - "allow": [ - "Edit(\\.md)", - "Read({{CLAUDE_HOME_PATH}}/.claude/**)", - "mcp__abcoder", - "mcp__sequential-thinking" - ] - }, - "hooks": { - "PreToolUse": [ - { - "matcher": "mcp__abcoder__list_repos|mcp__abcoder__get_repo_structure|mcp__abcoder__get_file_structure|mcp__abcoder__get_package_structure|mcp__abcoder__get_ast_node", - "hooks": [ - { - "type": "command", - "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/parse.sh" - } - ] - } - ], - "PostToolUse": [ - { - "matcher": "mcp__abcoder__list_repos", - "hooks": [ - { - "type": "command", - "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/prompt.sh" - } - ] - }, - { - "matcher": "mcp__abcoder__get_repo_structure|mcp__abcoder__get_package_structure|mcp__abcoder__get_file_structure", - "hooks": [ - { - "type": "command", - "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/reminder.sh" - } - ] - } - ] - } -} \ No newline at end of file diff --git a/docs/.claude/README.md b/docs/claude-code-spec.md similarity index 100% rename from docs/.claude/README.md rename to docs/claude-code-spec.md diff --git a/docs/.claude/CLAUDE.md b/internal/utils/assets/.claude/CLAUDE.md similarity index 100% rename from docs/.claude/CLAUDE.md rename to internal/utils/assets/.claude/CLAUDE.md diff --git a/internal/utils/assets/.claude/README.md b/internal/utils/assets/.claude/README.md new file mode 100644 index 0000000..a189445 --- /dev/null +++ b/internal/utils/assets/.claude/README.md @@ -0,0 +1,127 @@ +# AST-Driven Coding 配置 + +Claude Code 的 AST 驱动开发配置,通过 MCP 工具、钩子和斜杠命令实现无幻觉的代码分析和精确执行。 + +## 目录结构 + +``` +.claude/ +├── CLAUDE.md # 核心指令:AST-Driven Coder 角色定义 +├── settings.json # 钩子配置:PreToolUse/PostToolUse +├── hooks/ # 钩子脚本 +│ ├── parse.sh # 自动检测语言并生成 AST +│ ├── prompt.sh # 显示工作流程 SOP +│ └── reminder.sh # 提醒递归调用 get_ast_node +├── commands/ # 斜杠命令定义 +│ ├── abcoder:task.md # /abcoder:task - 创建编码任务 +│ ├── abcoder:schedule.md # /abcoder:schedule - 设计实现方案 +│ └── abcoder:recheck.md # /abcoder:recheck - 技术方案核对 +└── tmpls/ # 文档模板 + └── CODE_TASK.md # 编码任务模板 +``` + +## 核心理念 + +**AST-Driven Coding**: 基于 UniAST + LSP 的无幻觉代码分析 + +| 原则 | 说明 | +|------|------| +| 绝不假设 | 不确定代码 MUST 通过 `mcp__abcoder__get_ast_node` 验证 | +| 代码分析优先级 | `mcp__abcoder` > Read/Search | +| 直接使用原则 | 预先分析提供完整上下文,SubAgent 直接执行无需重分析 | +| 分阶段开发 | MVP → 完善 → 优化 | + +## MCP 工具 + +### mcp__abcoder + +本地代码深度分析工具,提供四层 AST 结构: + +``` +list_repos → get_repo_structure → get_package_structure → get_file_structure → get_ast_node + │ │ │ │ │ + └── repo_name └── mod/pkg list └── file list └── node list └── dependencies/references/inheritance +``` + +**SOP 流程**: +1. 问题分析 → `list_repos` 确认 repo_name +2. 定位 package → `get_repo_structure` 选择目标 package +3. 定位 node → `get_package_structure` 确认目标 node +4. 获取关系 → `get_ast_node` 递归获取完整信息 + +### mcp__sequential_thinking + +多步骤问题的系统化思考工具,用于复杂问题分解和模糊需求质询。 + +## 钩子系统 + +| 钩子 | 事件 | 匹配工具 | 作用 | +|------|------|----------|------| +| parse.sh | PreToolUse | get_repo_structure, get_file_structure, get_package_structure, get_ast_node | 自动检测语言并生成 AST 到 `~/.asts/` 目录 | +| prompt.sh | PostToolUse | list_repos | 显示 ABCoder 工作流程 SOP | +| reminder.sh | PostToolUse | get_repo_structure, get_package_structure, get_file_structure | 提醒递归调用 get_ast_node | + +## 斜杠命令 + +### /abcoder:task <名称> + +创建 CODE_TASK 文档,生成 `./task/{{MMDD}}/{{NAME}}__CODE_TASK.md` + +**格式要求**: +- action: create/modify/delete +- 涉及 SDK: 指定 Package/Method 名称 +- 涉及 curl: 提供完整命令和响应结构 +- 提供具体验证方法 + +### /abcoder:schedule + +使用 mcp__abcoder 设计实现方案 + +**Guardrails**: +- 最大化复用已有功能 +- 优先最小改动 +- 禁止编写代码、禁止使用 agent + +### /abcoder:recheck <任务> + +批判性检查 CODE_TASK 技术可行性 + +**检查项**: +- 方案可实现性 +- 技术风险 +- 代码复用和改动最小化 + +## 工作流 + +``` +用户需求 + │ + ▼ +/abcoder:schedule ──────────────→ 设计方案(abcoder分析) + │ │ + ▼ ▼ +/abcoder:task ────────→ CODE_TASK(含技术规格) + │ │ + ▼ ▼ +/abcoder:recheck ─────→ 方案核对(abcoder验证) + │ │ + ▼ ▼ +coding-executor ──────→ 执行实现 +``` + +## 安装 + +1. 复制 `.claude/` 目录到项目根目录或用户主目录 +2. 确保 `settings.json` 中的钩子路径正确 +3. 确保 `~/.claude/tmpls/` 目录存在且包含模板文件 + +## 依赖 + +- Claude Code CLI +- abcoder MCP 服务器(提供 mcp__abcoder 工具) +- sequential-thinking MCP 服务器(提供 mcp__sequential_thinking 工具) + +## 相关文档 + +- [hooks/README.md](hooks/README.md) - 钩子系统详解 +- [commands/README.md](commands/README.md) - 斜杠命令详解 diff --git a/docs/.claude/commands/README.md b/internal/utils/assets/.claude/commands/README.md similarity index 100% rename from docs/.claude/commands/README.md rename to internal/utils/assets/.claude/commands/README.md diff --git a/docs/.claude/commands/recheck.md b/internal/utils/assets/.claude/commands/recheck.md similarity index 100% rename from docs/.claude/commands/recheck.md rename to internal/utils/assets/.claude/commands/recheck.md diff --git a/docs/.claude/commands/schedule.md b/internal/utils/assets/.claude/commands/schedule.md similarity index 100% rename from docs/.claude/commands/schedule.md rename to internal/utils/assets/.claude/commands/schedule.md diff --git a/docs/.claude/commands/task.md b/internal/utils/assets/.claude/commands/task.md similarity index 100% rename from docs/.claude/commands/task.md rename to internal/utils/assets/.claude/commands/task.md diff --git a/docs/.claude/hooks/README.md b/internal/utils/assets/.claude/hooks/README.md similarity index 100% rename from docs/.claude/hooks/README.md rename to internal/utils/assets/.claude/hooks/README.md diff --git a/docs/.claude/tmpls/ABCODER_CODE_TASK.md b/internal/utils/assets/.claude/tmpls/ABCODER_CODE_TASK.md similarity index 100% rename from docs/.claude/tmpls/ABCODER_CODE_TASK.md rename to internal/utils/assets/.claude/tmpls/ABCODER_CODE_TASK.md diff --git a/cmd_init_spec.go b/internal/utils/cmd_init_spec.go similarity index 97% rename from cmd_init_spec.go rename to internal/utils/cmd_init_spec.go index 0f7cab0..d34b1eb 100644 --- a/cmd_init_spec.go +++ b/internal/utils/cmd_init_spec.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package main +package utils import ( "embed" @@ -28,7 +28,7 @@ import ( "github.com/cloudwego/abcoder/llm/log" ) -//go:embed docs/.claude +//go:embed assets/.claude var claudeFS embed.FS // claudeConfig represents the Claude Code configuration structure @@ -42,7 +42,7 @@ type mcpServerConfig struct { } // runInitSpec implements the init-spec command -func runInitSpec(targetDir string) error { +func RunInitSpec(targetDir string) error { if targetDir == "" { // Default to current directory if not specified cwd, err := os.Getwd() @@ -58,9 +58,9 @@ func runInitSpec(targetDir string) error { return fmt.Errorf("failed to get absolute path: %w", err) } - // 1. Copy docs/.claude to targetDir/.claude + // 1. Copy assets/.claude to targetDir/.claude claudeDestDir := filepath.Join(targetDirAbs, ".claude") - if err := copyEmbeddedDir("docs/.claude", claudeDestDir, targetDirAbs); err != nil { + if err := copyEmbeddedDir("assets/.claude", claudeDestDir, targetDirAbs); err != nil { return fmt.Errorf("failed to copy .claude directory: %w", err) } log.Info("Copied .claude directory to %s", claudeDestDir) diff --git a/main.go b/main.go index 290f7ce..9148f15 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ import ( "path/filepath" "strings" + interutils "github.com/cloudwego/abcoder/internal/utils" "github.com/cloudwego/abcoder/lang" "github.com/cloudwego/abcoder/lang/log" "github.com/cloudwego/abcoder/lang/uniast" @@ -214,7 +215,7 @@ func main() { uri = os.Args[2] } - if err := runInitSpec(uri); err != nil { + if err := interutils.RunInitSpec(uri); err != nil { log.Error("Failed to init-spec: %v\n", err) os.Exit(1) } From b67c7e24853c70c15dcca2c1631220fb2c97cee6 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Wed, 14 Jan 2026 14:14:09 +0800 Subject: [PATCH 11/12] docs: update READEME --- README.md | 136 +++++++++++++++++--------------- docs/claude-code-spec.md | 6 +- internal/utils/cmd_init_spec.go | 2 +- 3 files changed, 77 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 6eb9f64..cc6a62f 100644 --- a/README.md +++ b/README.md @@ -25,65 +25,6 @@ see [UniAST Specification](docs/uniast-zh.md) # Quick Start -## Use ABCoder as a MCP server - -1. Install ABCoder: - - ```bash - go install github.com/cloudwego/abcoder@latest - ``` - -2. Use ABCoder to parse a repository to UniAST (JSON) - - ```bash - abcoder parse {language} {repo-path} -o xxx.json - ``` - - ABCoder will try to install any dependency automatically. - In case of failure (or if you want to customize installation), refer to the [docs](./docs/lsp-installation-en.md). - - For example, to parse a Go repository: - - ```bash - git clone https://github.com/cloudwego/localsession.git localsession - abcoder parse go localsession -o /abcoder-asts/localsession.json - ``` - - -3. Integrate ABCoder's MCP tools into your AI agent. - - ```json - { - "mcpServers": { - "abcoder": { - "command": "abcoder", - "args": [ - "mcp", - "{the-AST-directory}" - ] - } - } - } - ``` - - -4. Enjoy it! - - Try to click and watch the video below: - -
- - [MCP](https://www.bilibili.com/video/BV14ggJzCEnK) - -
- - -## Tips: - -- You can add more repo ASTs into the AST directory without restarting abcoder MCP server. - -- Try to use [the recommended prompt](llm/prompt/analyzer.md) and combine planning/memory tools like [sequential-thinking](https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking) in your AI agent. - ## Claude Code Integration @@ -91,7 +32,7 @@ ABCoder provides deep integration with [Claude Code](https://claude.ai/code) thr ### Setup -Use the `init-spec` command to automatically configure Claude Code integration: +Use the `init-spec` command to automatically configure Claude Code integration for your project: ```bash # Install ABCoder @@ -109,6 +50,16 @@ The `init-spec` command will: - `sequential-thinking`: for complex problem decomposition 3. Replace all `{{CLAUDE_HOME_PATH}}` placeholders with actual project paths +### Start Coding with Claude Code + +Once setup, you can start coding with Claude Code: + +1. Start Claude Code in your project directory +2. Use slash common `/abcoder:schedule ` to address your feature/requirement/issue, and ABCoder will help you analyze the codebase and design a technical solution. +3. Once all questions are set, use slash common `/abcoder:task ` to create a coding task(specification) +4. Recheck the task using `/abcoder:recheck ` before real implementation +5. Begin coding! Claude Code will process the task step by step according to the specification, leveraging the power of AST-driven analysis. + ### AST-Driven Coding Workflow [`.claude/hooks`](docs/.claude/hooks) provide a 4-layer analysis chain from repository to node details: @@ -125,7 +76,7 @@ list_repos → get_repo_structure → get_package_structure → get_file_structu | Command | Function | Description | |---------|----------|-------------| -| [`/abcoder:schedule` ](docs/.claude/commands/abcoder:schedule.md) | Design implementation | Analyze codebase using ABCoder, design technical solution | +| [`/abcoder:schedule` ](docs/.claude/commands/abcoder:schedule.md) | Design implementation | Analyze codebase by using ABCoder, design technical solution | | [`/abcoder:task `](docs/.claude/commands/abcoder:task.md) | Create coding task | Generate standardized CODE_TASK document | | [`/abcoder:recheck `](docs/.claude/commands/abcoder:recheck.md) | Verify solution | Critically check CODE_TASK feasibility, useful when a CODE_TASK contains external dependencies | @@ -160,13 +111,72 @@ Start coding(sub-agent) ─────────→ Execute Implementation ### Dependencies - Claude Code CLI -- abcoder MCP server (provides `mcp__abcoder` tools) -- sequential-thinking MCP server (provides `mcp__sequential_thinking` tools, automatically configured by init-spec) +- ABCoder MCP server (provides `mcp__abcoder` tools) +- Sequential-thinking MCP server (provides `mcp__sequential_thinking` tools, automatically configured by init-spec) > For detailed configuration, see [docs/.claude/README.md](docs/.claude/README.md) > Watch the demo video [here](https://github.com/cloudwego/abcoder/pull/141) +## Use ABCoder as a MCP server + +1. Install ABCoder: + + ```bash + go install github.com/cloudwego/abcoder@latest + ``` + +2. Use ABCoder to parse a repository to UniAST (JSON) + + ```bash + abcoder parse {language} {repo-path} -o xxx.json + ``` + + ABCoder will try to install any dependency automatically. + In case of failure (or if you want to customize installation), refer to the [docs](./docs/lsp-installation-en.md). + + For example, to parse a Go repository: + + ```bash + git clone https://github.com/cloudwego/localsession.git localsession + abcoder parse go localsession -o /abcoder-asts/localsession.json + ``` + + +3. Integrate ABCoder's MCP tools into your AI agent. + + ```json + { + "mcpServers": { + "abcoder": { + "command": "abcoder", + "args": [ + "mcp", + "{the-AST-directory}" + ] + } + } + } + ``` + + +4. Enjoy it! + + Try to click and watch the video below: + +
+ + [MCP](https://www.bilibili.com/video/BV14ggJzCEnK) + +
+ + +## Tips: + +- You can add more repo ASTs into the AST directory without restarting abcoder MCP server. + +- Try to use [the recommended prompt](llm/prompt/analyzer.md) and combine planning/memory tools like [sequential-thinking](https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking) in your AI agent. + ## Use ABCoder as an Agent (WIP) diff --git a/docs/claude-code-spec.md b/docs/claude-code-spec.md index a189445..4f72806 100644 --- a/docs/claude-code-spec.md +++ b/docs/claude-code-spec.md @@ -63,7 +63,7 @@ list_repos → get_repo_structure → get_package_structure → get_file_structu ## 斜杠命令 -### /abcoder:task <名称> +### /abcoder:task <任务名称> 创建 CODE_TASK 文档,生成 `./task/{{MMDD}}/{{NAME}}__CODE_TASK.md` @@ -73,7 +73,7 @@ list_repos → get_repo_structure → get_package_structure → get_file_structu - 涉及 curl: 提供完整命令和响应结构 - 提供具体验证方法 -### /abcoder:schedule +### /abcoder:schedule <任务描述> 使用 mcp__abcoder 设计实现方案 @@ -82,7 +82,7 @@ list_repos → get_repo_structure → get_package_structure → get_file_structu - 优先最小改动 - 禁止编写代码、禁止使用 agent -### /abcoder:recheck <任务> +### /abcoder:recheck <任务名称> 批判性检查 CODE_TASK 技术可行性 diff --git a/internal/utils/cmd_init_spec.go b/internal/utils/cmd_init_spec.go index d34b1eb..a5fdf26 100644 --- a/internal/utils/cmd_init_spec.go +++ b/internal/utils/cmd_init_spec.go @@ -1,5 +1,5 @@ /** - * Copyright 2025 ByteDance Inc. + * Copyright 2026 ByteDance Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From bf52b07216ad1ffc955e82f93c255a24205be181 Mon Sep 17 00:00:00 2001 From: gaowenju Date: Wed, 14 Jan 2026 16:39:31 +0800 Subject: [PATCH 12/12] feat: re-parse if files changed by cc --- .gitignore | 2 - internal/utils/assets/.claude/README.md | 127 ------------- .../.claude/hooks/abcoder/abcoder-workflow.md | 32 ++++ .../.claude/hooks/abcoder/need_update.sh | 26 +++ .../assets/.claude/hooks/abcoder/parse.sh | 176 ++++++++++++++++++ .../assets/.claude/hooks/abcoder/prompt.sh | 43 +++++ .../assets/.claude/hooks/abcoder/reminder.sh | 11 ++ internal/utils/assets/.claude/settings.json | 52 ++++++ 8 files changed, 340 insertions(+), 129 deletions(-) delete mode 100644 internal/utils/assets/.claude/README.md create mode 100644 internal/utils/assets/.claude/hooks/abcoder/abcoder-workflow.md create mode 100755 internal/utils/assets/.claude/hooks/abcoder/need_update.sh create mode 100755 internal/utils/assets/.claude/hooks/abcoder/parse.sh create mode 100755 internal/utils/assets/.claude/hooks/abcoder/prompt.sh create mode 100755 internal/utils/assets/.claude/hooks/abcoder/reminder.sh create mode 100644 internal/utils/assets/.claude/settings.json diff --git a/.gitignore b/.gitignore index 89d64fa..99f6ff5 100644 --- a/.gitignore +++ b/.gitignore @@ -73,10 +73,8 @@ testdata/repos testdata/jsons src/lang/testdata -*.json !ts-parser/**/*.json tools -abcoder !testdata/asts/*.json \ No newline at end of file diff --git a/internal/utils/assets/.claude/README.md b/internal/utils/assets/.claude/README.md deleted file mode 100644 index a189445..0000000 --- a/internal/utils/assets/.claude/README.md +++ /dev/null @@ -1,127 +0,0 @@ -# AST-Driven Coding 配置 - -Claude Code 的 AST 驱动开发配置,通过 MCP 工具、钩子和斜杠命令实现无幻觉的代码分析和精确执行。 - -## 目录结构 - -``` -.claude/ -├── CLAUDE.md # 核心指令:AST-Driven Coder 角色定义 -├── settings.json # 钩子配置:PreToolUse/PostToolUse -├── hooks/ # 钩子脚本 -│ ├── parse.sh # 自动检测语言并生成 AST -│ ├── prompt.sh # 显示工作流程 SOP -│ └── reminder.sh # 提醒递归调用 get_ast_node -├── commands/ # 斜杠命令定义 -│ ├── abcoder:task.md # /abcoder:task - 创建编码任务 -│ ├── abcoder:schedule.md # /abcoder:schedule - 设计实现方案 -│ └── abcoder:recheck.md # /abcoder:recheck - 技术方案核对 -└── tmpls/ # 文档模板 - └── CODE_TASK.md # 编码任务模板 -``` - -## 核心理念 - -**AST-Driven Coding**: 基于 UniAST + LSP 的无幻觉代码分析 - -| 原则 | 说明 | -|------|------| -| 绝不假设 | 不确定代码 MUST 通过 `mcp__abcoder__get_ast_node` 验证 | -| 代码分析优先级 | `mcp__abcoder` > Read/Search | -| 直接使用原则 | 预先分析提供完整上下文,SubAgent 直接执行无需重分析 | -| 分阶段开发 | MVP → 完善 → 优化 | - -## MCP 工具 - -### mcp__abcoder - -本地代码深度分析工具,提供四层 AST 结构: - -``` -list_repos → get_repo_structure → get_package_structure → get_file_structure → get_ast_node - │ │ │ │ │ - └── repo_name └── mod/pkg list └── file list └── node list └── dependencies/references/inheritance -``` - -**SOP 流程**: -1. 问题分析 → `list_repos` 确认 repo_name -2. 定位 package → `get_repo_structure` 选择目标 package -3. 定位 node → `get_package_structure` 确认目标 node -4. 获取关系 → `get_ast_node` 递归获取完整信息 - -### mcp__sequential_thinking - -多步骤问题的系统化思考工具,用于复杂问题分解和模糊需求质询。 - -## 钩子系统 - -| 钩子 | 事件 | 匹配工具 | 作用 | -|------|------|----------|------| -| parse.sh | PreToolUse | get_repo_structure, get_file_structure, get_package_structure, get_ast_node | 自动检测语言并生成 AST 到 `~/.asts/` 目录 | -| prompt.sh | PostToolUse | list_repos | 显示 ABCoder 工作流程 SOP | -| reminder.sh | PostToolUse | get_repo_structure, get_package_structure, get_file_structure | 提醒递归调用 get_ast_node | - -## 斜杠命令 - -### /abcoder:task <名称> - -创建 CODE_TASK 文档,生成 `./task/{{MMDD}}/{{NAME}}__CODE_TASK.md` - -**格式要求**: -- action: create/modify/delete -- 涉及 SDK: 指定 Package/Method 名称 -- 涉及 curl: 提供完整命令和响应结构 -- 提供具体验证方法 - -### /abcoder:schedule - -使用 mcp__abcoder 设计实现方案 - -**Guardrails**: -- 最大化复用已有功能 -- 优先最小改动 -- 禁止编写代码、禁止使用 agent - -### /abcoder:recheck <任务> - -批判性检查 CODE_TASK 技术可行性 - -**检查项**: -- 方案可实现性 -- 技术风险 -- 代码复用和改动最小化 - -## 工作流 - -``` -用户需求 - │ - ▼ -/abcoder:schedule ──────────────→ 设计方案(abcoder分析) - │ │ - ▼ ▼ -/abcoder:task ────────→ CODE_TASK(含技术规格) - │ │ - ▼ ▼ -/abcoder:recheck ─────→ 方案核对(abcoder验证) - │ │ - ▼ ▼ -coding-executor ──────→ 执行实现 -``` - -## 安装 - -1. 复制 `.claude/` 目录到项目根目录或用户主目录 -2. 确保 `settings.json` 中的钩子路径正确 -3. 确保 `~/.claude/tmpls/` 目录存在且包含模板文件 - -## 依赖 - -- Claude Code CLI -- abcoder MCP 服务器(提供 mcp__abcoder 工具) -- sequential-thinking MCP 服务器(提供 mcp__sequential_thinking 工具) - -## 相关文档 - -- [hooks/README.md](hooks/README.md) - 钩子系统详解 -- [commands/README.md](commands/README.md) - 斜杠命令详解 diff --git a/internal/utils/assets/.claude/hooks/abcoder/abcoder-workflow.md b/internal/utils/assets/.claude/hooks/abcoder/abcoder-workflow.md new file mode 100644 index 0000000..1d3bf62 --- /dev/null +++ b/internal/utils/assets/.claude/hooks/abcoder/abcoder-workflow.md @@ -0,0 +1,32 @@ +# ABCoder代码分析工作流 + +## AST 层次结构 +- **模块(Module)**: 仓库中的编译单元,由 `mod_path` 标识;例如: "github.com/cloudwego/kitex" +- **包(Package)**: 符号的命名空间,由 `pkg_path` 标识;例如: "github.com/cloudwego/kitex/pkg/generic" +- **文件(File)**: 代码文件,由 `file_path` 标识;例如: "pkg/generic/closer.go" +- **AST节点**: 语法单元(函数、类型、变量),由 `NodeID` 标识;例如: +``` +{ + "mod_path": "github.com/cloudwego/kitex", + "pkg_path": "github.com/cloudwego/kitex/pkg/generic", + "name": "Closer" +} +``` + +## ABCoder工作SOP +1. **问题分析**: + - 基于用户问题分析相关关键词 + - 必须使用 `list_repos` 确认repo_name + +2. **代码定位** (repo→package→node→ast node relationship): + - 2.1 **定位package**: 基于 `get_repo_structure` 返回的package list选择目标package + - 2.2 **定位文件**: 通过 `get_package_structure` 返回的file信息,确认目标文件 + - 2.3 **定位节点**: 通过 `get_files_structure` 返回的node信息,确认目标节点 + - 2.4 **确认node详情**: 递归调用 `get_ast_node` 获取node详细(dependencies, references, inheritance, implementation, grouping) + +3. **自我反思**: + - 理解完整的code calling-chain、contextual-relationship + - 如果无法清楚解释机制,使用`sequential_thinking` 来帮助分解问题并记录信息,调整选择并重复步骤2 + +## 注意事项 +- 回复应列出相关代码的准确 metadata,包括 AST node(或 package)的 identity、file location 和代码。**必须提供确切的 file location(包括 line numbers)!** diff --git a/internal/utils/assets/.claude/hooks/abcoder/need_update.sh b/internal/utils/assets/.claude/hooks/abcoder/need_update.sh new file mode 100755 index 0000000..2899692 --- /dev/null +++ b/internal/utils/assets/.claude/hooks/abcoder/need_update.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# 当 Claude Code 执行 Write 操作后,更新 _need_update 文件为 1 + +# 错误处理 +set -euo pipefail + +# 获取脚本所在的绝对路径 +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# 定义 _need_update 文件路径(放在脚本所在目录) +need_update_file="${script_dir}/_need_update" + +# 写入 1 到文件 +echo "1" > "$need_update_file" + +# 输出 JSON +jq -n --arg file "$need_update_file" '{ + "continue": true, + "hookSpecificOutput": { + "hookEventName": "PostToolUse", + "additionalContext": ("Write 操作完成,已更新 " + $file + " 为 1") + } +}' + +exit 0 diff --git a/internal/utils/assets/.claude/hooks/abcoder/parse.sh b/internal/utils/assets/.claude/hooks/abcoder/parse.sh new file mode 100755 index 0000000..3661e93 --- /dev/null +++ b/internal/utils/assets/.claude/hooks/abcoder/parse.sh @@ -0,0 +1,176 @@ +#!/bin/bash + +# 修正并简化的 get_basename 函数 +get_basename() { + # 检查输入是否为 "." 或 ".." + if [[ "$1" == "." || "$1" == ".." ]]; then + # 对于当前或上级目录,使用 basename 结合 pwd + basename "$(cd "$1" && pwd)" + else + # 对于其他路径,直接使用 basename + basename "$1" + fi +} + +# 新增:检测项目语言并获取仓库标识 +detect_project_info() { + local target_dir="$1" + local project_info="" + + # 1. 优先检测 Go 项目(判断 go.mod 或 main.go) + if [[ -f "${target_dir}/go.mod" ]]; then + # 从 go.mod 中提取 module name + local module_name=$(grep "^module " "${target_dir}/go.mod" | head -1 | awk '{print $2}') + if [[ -n "$module_name" ]]; then + echo "go|${module_name}" + return 0 + fi + # 如果无法获取 module name,使用 main.go 所在目录 + if [[ -f "${target_dir}/main.go" ]]; then + echo "go|$(get_basename "$target_dir")" + return 0 + fi + fi + + # 2. 检测 TypeScript 项目(判断 package.json 或 tsconfig.json) + if [[ -f "${target_dir}/package.json" ]]; then + # 从 package.json 中提取 name + local package_name=$(jq -r '.name // empty' "${target_dir}/package.json" 2>/dev/null) + if [[ -n "$package_name" && "$package_name" != "null" ]]; then + echo "ts|${package_name}" + return 0 + fi + fi + + # 3. 检测 TypeScript 项目(判断 tsconfig.json 或 .ts/.tsx 文件) + if [[ -f "${target_dir}/tsconfig.json" ]]; then + echo "ts|$(get_basename "$target_dir")" + return 0 + fi + + # 统计 .ts 和 .tsx 文件数量(排除 node_modules 目录) + local ts_file_count=$(find "${target_dir}" -type f -not -path "*/node_modules/*" \( -name "*.ts" -o -name "*.tsx" \) | wc -l) + if [[ $ts_file_count -gt 0 ]]; then + echo "ts|$(get_basename "$target_dir")" + return 0 + fi + + # 4. 未检测到目标语言 + echo "unknown|$(get_basename "$target_dir")" + return 1 +} + +# 直接映射 abc 为别名,处理 parse <语言> <仓库路径> 形式的参数 +abc() { + # 检查命令格式是否为 "parse <语言> <仓库路径>" + if [ $# -eq 3 ] && [ "$1" = "parse" ]; then + local lang="$2" + local repo_path="$3" + local repo_name=$(get_basename "$repo_path") + + # 确保输出目录存在 + mkdir -p ~/.asts/ + + # 执行实际命令 + abcoder parse "${lang}" "${repo_path}" -o "~/.asts/${repo_name}.json" + else + # 如果不是预期的 parse 命令格式,直接将参数传递给原始 abcoder 命令 + abcoder "$@" + fi +} + +# LOG_FILE="/tmp/claude-hook-debug.log" + +# 获取脚本所在的绝对路径 +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# 定义 _need_update 文件路径 +need_update_file="${script_dir}/_need_update" + +input=$(cat) +repo_name=$(echo "$input" | jq -r '.tool_input.repo_name // ""') +cwd=$(echo "$input" | jq -r '.cwd // ""') + +# echo "=== $(date) ===" >> "$LOG_FILE" +# echo "repo_name: $repo_name" >> "$LOG_FILE" +# echo "cwd: $cwd" >> "$LOG_FILE" + +# 读取 _need_update 文件判断是否需要强制更新 +force_update=0 +if [[ -f "$need_update_file" ]]; then + need_update_value=$(cat "$need_update_file" 2>/dev/null || echo "0") + if [[ "$need_update_value" == "1" ]]; then + force_update=1 + # 强制更新后,将 _need_update 重置为 0 + echo "0" > "$need_update_file" + fi +fi + +# 复用现有的 get_basename 函数 +current_base_name=$(get_basename "$cwd") + +# 检测项目信息(语言和仓库标识符) +project_info=$(detect_project_info "$cwd") +project_lang=$(echo "$project_info" | cut -d'|' -f1) +project_identifier=$(echo "$project_info" | cut -d'|' -f2) + +# 优化判断逻辑:只要检测到有效项目,就执行 parse +if [[ "$project_lang" != "unknown" ]]; then + # 捕获标准输出和错误输出 + output_file=$(mktemp) + error_file=$(mktemp) + + # 使用检测到的语言执行 parse 命令 + # 确保输出目录存在 + mkdir -p ~/.asts/ + ast_output_file=~/.asts/$(echo "$project_identifier" | sed 's|/|_|g').json + + # 检查 AST 文件是否存在且更新时间小于 3 分钟(缓存优化) + # 如果 force_update=1,则跳过缓存检查,强制重新 parse + if [[ $force_update -eq 0 && -f "$ast_output_file" ]]; then + file_age_seconds=$(($(date +%s) - $(stat -f %m "$ast_output_file" 2>/dev/null || stat -c %Y "$ast_output_file" 2>/dev/null))) + if [[ $file_age_seconds -lt 180 ]]; then + jq -n --arg lang "$project_lang" --arg repo "$project_identifier" --arg age "$file_age_seconds" '{ + "continue": true, + "systemMessage": ("abcoder AST 缓存命中(语言:" + $lang + ",仓库:" + $repo + ")。文件更新于 " + $age + " 秒前(小于3分钟更新阈值),跳过 parse 操作。") + }' + exit 0 + fi + fi + + # 使用检测到的语言执行 parse 命令,并输出到 AST 目录 + if abcoder parse "$project_lang" . -o "$ast_output_file" >"$output_file" 2>"$error_file"; then + msg_prefix="[定时更新]" + if [[ $force_update -eq 1 ]]; then + msg_prefix="[检测到变更] " + fi + jq -n --arg lang "$project_lang" --arg repo "$project_identifier" --arg prefix "$msg_prefix" '{ + "continue": true, + "systemMessage": ($prefix + "abcoder parse 已成功完成(语言:" + $lang + ",仓库:" + $repo + ")。AST文件已生成,可以继续分析代码。") + }' + else + exit_code=$? + # 读取错误信息 + error_msg=$(cat "$error_file" | tail -20) + + jq -n --arg code "$exit_code" --arg err "$error_msg" --arg lang "$project_lang" --arg repo "$project_identifier" '{ + "decision": "block", + "reason": ("abcoder parse 失败(语言:" + $lang + ",仓库:" + $repo + ",退出码: " + $code + ")。错误信息:\n" + $err + "\n\n可能的原因:\n1. 项目配置文件有问题(Go: go.mod;TS: tsconfig.json)\n2. 缺少依赖包\n3. 代码语法错误\n\n建议:\n- Go 项目:运行 'go mod tidy' 和 'go build' 检查\n- TS 项目:运行 'npm install' 和 'tsc --noEmit' 检查"), + "hookSpecificOutput": { + "hookEventName": "PreToolUse", + "additionalContext": "解析失败,需要修复后重试" + } + }' + fi + + # 清理临时文件 + trash "$output_file" "$error_file" 2>/dev/null || rm -f "$output_file" "$error_file" +else + # 当前目录不是支持的项目,返回空对象 + jq -n '{ + "decision": "block", + "reason": "当前目录未检测到支持的语言(仅支持 Go 和 TypeScript),请确保项目是 Go 或 TypeScript 类型" + }' +fi + +exit 0 diff --git a/internal/utils/assets/.claude/hooks/abcoder/prompt.sh b/internal/utils/assets/.claude/hooks/abcoder/prompt.sh new file mode 100755 index 0000000..eb52d1c --- /dev/null +++ b/internal/utils/assets/.claude/hooks/abcoder/prompt.sh @@ -0,0 +1,43 @@ +#!/bin/zsh + +# 添加调试信息 +# LOG_FILE="/tmp/claude-hook-debug.log" + +# 错误处理 +set -euo pipefail + +# 验证文件存在 +SOP_FILE="/Users/bytedance/github/github.com/cloudwego/abcoder2/.claude/hooks/abcoder/abcoder-workflow.md" +# echo "DEBUG: Checking file: $SOP_FILE" >&2 + +if [[ ! -f "$SOP_FILE" ]]; then + # echo "DEBUG: File not found" >&2 + echo '{"ok": false, "reason": "SOP file not found", "hookSpecificOutput": {"hookEventName": "PostToolUse"}}' + exit 0 +fi + +# echo "DEBUG: File found, reading content" >&2 + +# 读取并转义内容 +SOP_CONTENT=$(cat "$SOP_FILE" | jq -Rs . 2>/dev/null) +if [[ $? -ne 0 ]]; then + # echo "DEBUG: jq failed" >&2 + echo '{"ok": false, "reason": "Failed to process SOP content", "hookSpecificOutput": {"hookEventName": "PostToolUse"}}' + exit 0 +fi + +# echo "DEBUG: Content processed successfully" >&2 + +# 输出 JSON +cat <&2 +exit 0 diff --git a/internal/utils/assets/.claude/hooks/abcoder/reminder.sh b/internal/utils/assets/.claude/hooks/abcoder/reminder.sh new file mode 100755 index 0000000..dbb661c --- /dev/null +++ b/internal/utils/assets/.claude/hooks/abcoder/reminder.sh @@ -0,0 +1,11 @@ +#!/bin/zsh +cat <This is a reminder that when executing the ABCoder code analysis workflow, after locating the target node, you MUST use the get_ast_node tool. It is required to recursively call get_ast_node to obtain the complete AST node information, including type, code, position, and related relationships (dependency, reference, inheritance, implementation, grouping node IDs).", + "hookSpecificOutput": { + "hookEventName": "PostToolUse" + } +} +EOF +exit 0 diff --git a/internal/utils/assets/.claude/settings.json b/internal/utils/assets/.claude/settings.json new file mode 100644 index 0000000..d1175b1 --- /dev/null +++ b/internal/utils/assets/.claude/settings.json @@ -0,0 +1,52 @@ +{ + "permissions": { + "allow": [ + "Edit(\\.md)", + "Read({{CLAUDE_HOME_PATH}}/.claude/**)", + "mcp__abcoder", + "mcp__sequential-thinking" + ] + }, + "hooks": { + "PreToolUse": [ + { + "matcher": "mcp__abcoder__list_repos|mcp__abcoder__get_repo_structure|mcp__abcoder__get_file_structure|mcp__abcoder__get_package_structure|mcp__abcoder__get_ast_node", + "hooks": [ + { + "type": "command", + "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/parse.sh" + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { + "type": "command", + "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/need_update.sh" + } + ] + }, + { + "matcher": "mcp__abcoder__list_repos", + "hooks": [ + { + "type": "command", + "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/prompt.sh" + } + ] + }, + { + "matcher": "mcp__abcoder__get_repo_structure|mcp__abcoder__get_package_structure|mcp__abcoder__get_file_structure", + "hooks": [ + { + "type": "command", + "command": "{{CLAUDE_HOME_PATH}}/.claude/hooks/abcoder/reminder.sh" + } + ] + } + ] + } +} \ No newline at end of file