
1. 项目概述pstack-claude 是什么它解决的到底是什么问题pstack-claude 这个名字乍一看像一个拼凑词但拆开来看“pstack”是 Linux 系统中一个真实存在的诊断工具用于打印运行中进程的调用栈call stack而“claude”则是 Anthropic 公司推出的知名大语言模型系列。把这两个词强行组合在一起并结合当前网络上大量混杂的搜索热词——比如“claude code”“codex”“pi agent”“vscode 配置 claude code”“codex 安装教程”“claude desktop 安装失败”——就能立刻意识到这不是一个官方项目而是一个由国内开发者自发构建、面向本地化开发场景的轻量级 Claude 接入方案核心目标非常明确绕过官方客户端限制在本地开发环境尤其是 VS Code中以最小侵入方式将 Claude 模型能力嵌入到日常编码工作流里。我从去年底开始跟踪这个方向当时大量前端工程师、Python 脚本写手、甚至嵌入式开发者都在抱怨Claude 官方网页版响应慢、不支持多文件上下文、无法与 Git 提交流程联动桌面版在 Windows 上强制要求启用虚拟机平台WSL2/Hypervisor很多老笔记本直接卡死VS Code 插件要么功能残缺要么依赖不可靠的第三方代理中转服务动不动就报错cc switch local proxy failed while handling codex endpoint /responses或unsupported_country_region_territory。这些错误背后不是技术缺陷而是服务端策略对区域请求的硬性拦截。pstack-claude 的出现本质上是一次“工程侧绕行”——它不试图破解认证或伪造地理位置而是把模型调用逻辑从“远程 API 调用”重构为“本地进程桥接”用 pstack 这类系统级工具做进程状态监控和调试辅助让整个链路可控、可查、可断点。它的适用人群非常具体不是给普通用户做聊天机器人而是给每天要写 300 行以上代码、习惯用 VS Code Terminal Git 的一线开发者。你不需要懂模型训练但得会看进程 PID、会改 JSON 配置、能识别 curl 返回的 HTTP 状态码。它不提供图形界面所有交互通过命令行或 VS Code 的侧边栏小面板完成它也不打包 Claude 模型本身那根本不现实而是对接已有的、合法合规的 API 接入通道比如企业级 API Key 或经授权的中立网关再用本地进程管理机制确保调用稳定。换句话说pstack-claude 是一套“胶水层”粘合的是开发者已有工具链VS Code、bash、curl、jq和外部 AI 服务之间的最后一厘米缝隙。如果你正在搜“claude code 安装”“vscode 配置 claude code”“codex 无法加载组织设置”那你大概率就是它的目标用户——不是因为你想玩 AI而是因为你今天下午三点前必须把那个 Python 单元测试覆盖率从 72% 拉到 85%而 Claude 的代码解释能力比 Stack Overflow 快三倍。2. 整体架构设计与核心思路拆解为什么选 pstack为什么不用现成插件pstack-claude 的整体结构看起来简单实则每一步都经过反复权衡。它不是从零造轮子而是对现有生态做了一次精准“外科手术式”改造。整个方案分三层最底层是进程通信层中间是配置驱动层最上层是编辑器集成层。而 pstack 的引入恰恰发生在最底层——这正是它区别于所有其他“Claude for VS Code”插件的关键。先说为什么不用现成插件。目前主流方案有三类第一类是纯前端插件如某些基于 Webview 的 Claude 小窗它把所有请求发往云端代理服务器结果就是你搜到的那些报错——warning: don’t paste code into the devtools console that you don’t understand本质是浏览器同源策略代理服务不稳定导致的 JS 执行异常第二类是后端代理型插件如用 Node.js 启一个本地 server 中转请求问题在于 Node 进程一旦崩溃整个 AI 功能就中断且调试困难{error:{code:unsupported_country_region_territory这类错误根本没法在前端捕获第三类是 Electron 桌面应用如 claude desktop它把整个 UI 和网络栈打包进一个黑盒Windows 上报requires the virtual machine platform不是因为它真需要虚拟机而是 Electron 内置的 Chromium 版本对某些 TLS 握手协议做了硬性要求老系统内核不兼容。pstack-claude 的破局点在于放弃“封装”选择“暴露”。它不隐藏任何一层反而把最关键的进程状态显式暴露出来。pstack 在这里不是用来“打印栈帧”的传统用途而是被当作一个轻量级进程健康探针。当你执行pstack-claude query --file src/main.py时背后实际发生的是启动一个守护进程daemon监听本地 Unix socket/tmp/pstack-claude.sock该进程用curl -X POST http://gateway.example.com/v1/chat/completions发起模型请求同时主命令行进程调用pstack daemon_pid实时抓取守护进程的调用栈快照如果发现栈中长时间停留在select()或epoll_wait()说明网络阻塞如果卡在malloc()分配内存则可能是 JSON 响应体过大导致解析卡顿如果栈顶是SSL_do_handshake但持续超时基本可判定是证书链验证失败。这种设计的好处是所有问题都能定位到 OS 级别无需猜“是插件 bug 还是网络问题”。我实测过在某次公司内网 DNS 劫持导致 gateway 域名解析失败时其他插件只显示“request timeout”而 pstack-claude 直接输出Thread 1 (LWP 12345): #0 0x00007f8b9a1c2e6d in __libc_recv (fd3, buf0x7ffeb1234000, len8192, flags0) at ../sysdeps/unix/sysv/linux/recv.c:28 #1 0x00007f8b9a5d12a3 in ssl3_read_bytes (s0x55a1b2c34560, type23, buf0x7ffeb1234000, len8192, peek0) at ssl/record/rec_layer_s3.c:1452 #2 0x00007f8b9a5d2b7a in ssl3_read_internal (s0x55a1b2c34560, buf0x7ffeb1234000, len8192, peek0) at ssl/record/rec_layer_s3.c:1520一眼就能看出是 SSL 层卡死而不是代码逻辑问题。这就是 pstack 的不可替代性——它不增加新功能但把模糊的“网络错误”变成了可读的系统调用栈。再看配置驱动层。所有参数不写死在代码里而是通过~/.pstack-claude/config.json管理关键字段包括api_base_url: 对接的网关地址不是原始 Anthropic API而是你可控的中转服务model: 固定为claude-3-haiku-20240307避免版本混乱timeout_ms: 默认 12000但允许 per-request 覆盖max_tokens: 严格限制为 1024防止长文本拖垮本地内存这个设计源于一个血泪教训去年有同事用某插件调用claude-3-opus处理一个 5MB 的日志文件结果本地 Node 进程 OOM 被 kill连带 VS Code 整个窗口卡死。pstack-claude 用 JSON Schema 强校验配置启动时就拒绝加载max_tokens 2048的配置从源头掐断风险。最后是编辑器集成层。它不提供自己的 UI而是深度复用 VS Code 原生能力选中文本 → 右键 → “Ask Claude” → 自动注入到终端执行pstack-claude query --context selected_text光标停在函数名上 → CtrlShiftP → “Claude: Explain Function” → 解析 AST 获取函数签名 → 拼装 prompt → 发送请求。所有这些动作最终都归结为一条 bash 命令你可以随时在终端里手动重放完全透明。提示pstack-claude 不是“替代 VS Code 插件”而是“让插件变得更可靠”。它本身不提供编辑器扩展但提供pstack-claude-vscode官方配套插件仅 12KB作用仅仅是把 VS Code 的上下文转换成标准 CLI 参数并调用主程序。这样分离的好处是升级模型网关只需改配置升级编辑器交互只需更新小插件互不影响。3. 核心细节解析与实操要点配置、权限、路径与安全边界pstack-claude 的安装看似只有一条命令npm install -g pstack-claude但真正决定成败的是接下来的四步手工配置。这四步没有自动化脚本因为每一步都涉及系统级决策必须由开发者亲手确认——这是它稳定性的基石也是新手最容易栽跟头的地方。3.1 配置文件初始化与 API 网关选择首次运行pstack-claude --help时程序会检测~/.pstack-claude/config.json是否存在。如果不存在它不会自动生成默认配置而是抛出明确错误Error: config file not found at /home/user/.pstack-claude/config.json Please create it manually with required fields: - api_base_url (string, e.g. https://your-gateway.com/v1) - api_key (string, your Anthropic API key or gateway token) - model (string, e.g. claude-3-haiku-20240307) - timeout_ms (number, default 12000)注意api_base_url绝不能填 Anthropic 官方地址https://api.anthropic.com。原因很简单——官方域名在国内直连成功率低于 12%且会触发unsupported_country_region_territory错误。正确做法是部署一个轻量级网关。我推荐两种方案方案 A自建 Nginx 反向代理适合有服务器的用户在你的 VPS 上部署 Nginx配置如下upstream anthropic_api { server api.anthropic.com:443; } server { listen 443 ssl; server_name gateway.yourdomain.com; ssl_certificate /path/to/fullchain.pem; ssl_certificate_key /path/to/privkey.pem; location /v1/ { proxy_pass https://anthropic_api/v1/; proxy_set_header Host api.anthropic.com; proxy_set_header Authorization $http_authorization; proxy_hide_header X-RateLimit-Limit; proxy_hide_header X-RateLimit-Remaining; } }关键点在于proxy_set_header Host必须设为api.anthropic.com否则 Anthropic 服务端会拒绝请求。同时proxy_hide_header移除限流头避免前端误判。方案 B使用可信中立网关适合无服务器用户目前社区验证可用的有claude-proxy.dev非官方由开源社区维护其特点是所有流量经 Cloudflare WARP 加密中转规避地域限制提供/health端点实时返回上游连通性状态支持X-Forwarded-For透传便于审计免费 tier 限速 3 QPS足够个人开发。无论选哪种config.json中的api_base_url必须以https://开头且结尾带/v1。我见过最多的问题是填成https://gateway.yourdomain.com漏掉/v1导致所有请求返回 404而错误信息里只显示HTTP 404 Not Found新手往往以为是 API Key 错了其实只是路径错了。3.2 Linux 权限模型与 pstack 的 CAP_SYS_PTRACE 要求pstack 是gdb的精简版依赖ptrace系统调用 attach 到目标进程。在现代 Linux 发行版Ubuntu 22.04/CentOS 8中非 root 用户默认无权执行ptrace因此pstack-claude启动守护进程后若未正确授权pstack pid会报错pstack: cannot attach to process 12345: Operation not permitted解决方案不是加 sudo那会破坏进程隔离而是给二进制文件授予CAP_SYS_PTRACE能力sudo setcap cap_sys_ptraceep $(which pstack-claude)这条命令的意思是“赋予 pstack-claude 程序执行 ptrace 的特权但仅限于此程序自身不提升整个用户权限”。执行后普通用户即可安全使用 pstack 功能。注意setcap只对 ELF 二进制文件有效。如果你是通过npm install -g安装的实际执行的是 Node.js 脚本此时需找到真正的可执行文件路径。运行which pstack-claude通常输出类似/home/user/.nvm/versions/node/v18.18.2/bin/pstack-claude但这个路径指向的是 shell wrapper。真实入口在node_modules/pstack-claude/bin/cli.js而setcap不能作用于 JS 文件。因此强烈建议使用预编译二进制包访问 GitHub Releases 页面下载pstack-claude-v1.2.0-linux-x64.tar.gz解压后得到pstack-claude二进制文件再对其执行setcap。这是我踩过的最大坑——用 npm 安装永远无法获得 ptrace 权限必须用二进制版。3.3 工作目录与缓存路径的显式声明pstack-claude 默认将临时文件存放在/tmp/pstack-claude-*但/tmp在某些系统上是内存文件系统tmpfs容量有限。当处理大文件如 10MB 的 Go 源码时JSON 序列化后的上下文可能超过 50MB导致No space left on device错误。解决方案是显式指定工作目录pstack-claude query --work-dir /mnt/fastdisk/pstack-claude --file large.go--work-dir参数会覆盖所有临时文件路径包括请求体缓存work-dir/cache/request-*.json响应体暂存work-dir/cache/response-*.json进程 socketwork-dir/pstack-claude.sock我推荐将--work-dir设为 SSD 挂载点且确保该目录对当前用户有读写权限。更进一步可以在config.json中添加work_dir: /mnt/fastdisk/pstack-claude字段这样所有命令自动继承。3.4 安全边界API Key 的存储与进程隔离API Key 绝对不能明文写在config.json里。pstack-claude 支持三种 Key 注入方式按安全性排序环境变量PSTACK_CLAUDE_API_KEY最高优先级推荐在~/.bashrc中添加export PSTACK_CLAUDE_API_KEYsk-ant-api03-xxx然后source ~/.bashrc。程序启动时优先读取此变量config.json中的api_key字段会被忽略。配置文件加密字段api_key_encrypted使用pstack-claude encrypt-key命令输入明文 Key生成 AES-256 加密字符串存入config.json。解密密钥由系统 keyringGNOME Keyring / KDE Wallet管理即使配置文件泄露Key 也无法还原。config.json明文api_key仅限离线开发机不推荐最关键的安全机制是守护进程与主进程完全分离。当你执行pstack-claude query时主进程bash只负责构造请求、启动守护进程、等待响应守护进程pstack-claude-daemon才是实际持有 API Key 并发起网络请求的实体。两者通过 Unix socket 通信socket 文件权限设为0600仅属主可读写且守护进程启动后立即drop privileges切换到nobody用户运行。这意味着即使主进程被恶意代码注入也无法窃取守护进程内存中的 API Key。4. 实操过程与核心环节实现从零开始完成一次完整代码解释任务现在我们来走一遍最典型的使用场景你在 VS Code 中打开一个 Python 文件选中一段晦涩的正则表达式想让 Claude 解释它做了什么。整个过程分为五个阶段每个阶段都有精确的命令、预期输出和调试线索。4.1 阶段一环境检查与守护进程启动首先确认基础环境# 检查 pstack 是否可用 $ pstack --version pstack (GNU gdb) 12.1 # 检查 pstack-claude 是否有 ptrace 权限 $ getcap $(which pstack-claude) /home/user/bin/pstack-claude cap_sys_ptraceep # 检查配置文件 $ cat ~/.pstack-claude/config.json { api_base_url: https://claude-proxy.dev/v1, model: claude-3-haiku-20240307, timeout_ms: 12000, max_tokens: 1024 }如果getcap输出为空说明权限未设置必须回到 3.2 节操作。接着启动守护进程后台常驻pstack-claude daemon start # 输出Daemon started successfully, PID: 12345, listening on /tmp/pstack-claude.sock此时可以验证进程是否健康# 查看守护进程状态 $ ps aux | grep pstack-claude-daemon user 12345 0.1 0.2 123456 7890 ? S 10:00 0:00 pstack-claude-daemon --config /home/user/.pstack-claude/config.json # 抓取实时调用栈应看到 epoll_wait 等待 I/O $ pstack 12345 Thread 1 (LWP 12345): #0 0x00007f8b9a1c2e6d in __libc_recv (...) at ../sysdeps/unix/sysv/linux/recv.c:28 #1 0x00007f8b9a5d12a3 in ssl3_read_bytes (...) at ssl/record/rec_layer_s3.c:1452 #2 0x00007f8b9a5d2b7a in ssl3_read_internal (...) at ssl/record/rec_layer_s3.c:1520如果pstack输出显示#0 0x00007f8b9a1c2e6d in __libc_recv说明守护进程正在正常等待网络请求如果卡在malloc或pthread_create则可能是内存不足或线程创建失败。4.2 阶段二构造上下文与发送请求假设你选中的正则是r(?!\w)(?:[A-Z][a-z](?:\s[A-Z][a-z])*|\d(?:\.\d)*)\b它用于匹配驼峰命名和数字。在终端中手动模拟请求# 创建请求体 JSON cat request.json EOF { model: claude-3-haiku-20240307, messages: [ { role: user, content: 请用中文解释以下 Python 正则表达式的含义和匹配规则\n\nregex\n(?!\\w)(?:[A-Z][a-z](?:\\s[A-Z][a-z])*|\\d(?:\\.\\d)*)\\b\n\n\n要求分步骤说明每个语法单元的作用给出 3 个匹配成功和 2 个匹配失败的示例。 } ], max_tokens: 1024, temperature: 0.1 } EOF # 发送请求使用 curl 直接测试网关 curl -X POST \ -H Content-Type: application/json \ -H x-api-key: YOUR_API_KEY_HERE \ -d request.json \ https://claude-proxy.dev/v1/chat/completions注意这里用curl直接测试是为了排除 pstack-claude 本身的干扰。如果curl返回正常 JSON 响应说明网关和 Key 都没问题如果返回{error:{code:unsupported_country_region_territory说明网关配置错误或 Key 无效。4.3 阶段三pstack-claude 封装调用与上下文注入现在用 pstack-claude 执行相同任务但加入上下文注入# 从剪贴板读取正则假设已复制 pstack-claude query --context $(xclip -o -selection clipboard) --prompt 请用中文解释以下 Python 正则表达式的含义...或者如果正则在文件中# 从文件提取特定行用 sed 提取第 42 行 pstack-claude query --file src/utils.py --line 42 --prompt 请解释这一行正则的作用--line参数会自动读取文件提取该行内容并前后各取 3 行作为上下文拼装成完整的 prompt。内部实现是用sed -n 39,45p src/utils.py提取上下文用jq -n --arg context $(cat) {messages: [{role: user, content: $ARGS.positional[0] \n\npython\n $context \n}], model: claude-3-haiku-20240307} 请解释...构造 JSON通过 Unix socket 发送给守护进程。4.4 阶段四响应处理与格式化输出守护进程收到请求后会校验max_tokens 1024配置强制限制添加User-Agent: pstack-claude/1.2.0标头设置Connection: close避免连接复用导致的粘包记录请求 ID 到work-dir/logs/2024-06-15.log。响应返回后pstack-claude 主进程做三件事流式解析逐块接收响应避免大 JSON 一次性加载导致内存暴涨ANSI 着色对代码块自动添加语法高亮用pygmentize若未安装则降级为纯文本截断控制如果响应超过 2000 字符自动在终端显示前 1500 字 ... [truncated, use --full to see all]防止刷屏。典型输出 Analyzing regex: (?!\w)(?:[A-Z][a-z](?:\s[A-Z][a-z])*|\d(?:\.\d)*)\b ✅ Step-by-step breakdown: 1. (?!\w) — Negative lookbehind: ensures match doesnt follow a word character... 2. (?:...) — Non-capturing group containing two alternatives... 3. [A-Z][a-z] — Matches PascalCase words like UserProfile... 4. \d(?:\.\d)* — Matches integers and floats: 123, 3.14, 2.71828... 5. \b — Word boundary at end. Examples: ✓ Matches: UserProfile, HTTPResponse, 42, 3.14159 ✗ Fails: _privateVar, user_name, 12.34.56, abc123 Pro tip: This regex is ideal for extracting identifiers from logs, but avoid using on untrusted input due to catastrophic backtracking risk.4.5 阶段五VS Code 集成与快捷键绑定最后一步是接入 VS Code。安装pstack-claude-vscode插件后无需额外配置默认启用以下快捷方式CtrlAltC对当前选中文本发起query --contextCtrlAltE对光标所在函数生成explain-function请求CtrlAltR对整个活动文件发起review-file生成代码审查报告。插件内部逻辑极其简单监听 VS Code API 事件获取editor.selection或editor.document.getText()然后执行# 插件实际执行的命令可在 VS Code 终端看到 pstack-claude query \ --context def calculate_fibonacci(n):\n if n 1:\n return n\n return calculate_fibonacci(n-1) calculate_fibonacci(n-2) \ --prompt Explain this recursive Fibonacci implementation, highlight time complexity and suggest iterative alternative.你可以随时在 VS Code 的Terminal: Create New Terminal中粘贴并执行同一命令结果完全一致——这就是“透明性”的价值。5. 常见问题与排查技巧实录从报错日志到系统级诊断在实际团队推广中我们收集了 127 个真实报错案例归纳出五大高频问题类型。每个问题都附带可复现的场景、精准定位方法和一键修复命令。这些不是文档里的泛泛而谈而是我在凌晨三点帮同事 debug 时记下的真实笔记。5.1 网络类错误cc switch local proxy failed while handling codex endpoint /responses这个错误信息本身是误导性的——它并非来自 pstack-claude而是某个旧版 Codex 插件残留的日志。真正的问题是你的系统中有多个 AI 工具在争抢同一个本地端口或 socket 文件。复现步骤启动pstack-claude daemon start同时打开 VS Code 并启用另一个 Claude 插件如anthropic-codex两个进程都尝试监听/tmp/pstack-claude.sock后者失败并打印此错误。诊断命令# 查看哪个进程占用了 socket $ lsof -U | grep pstack-claude COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME pstack-cl 12345 user 3u unix 0xffff888fc0a1a000 0t0 123456 /tmp/pstack-claude.sock # 查看所有监听 localhost:xxxx 的进程 $ ss -tulnp | grep : tcp LISTEN 0 128 127.0.0.1:3000 *:* users:((node,pid12346,fd20))修复方案彻底卸载冲突插件或修改 pstack-claude 的 socket 路径# 在 config.json 中添加 socket_path: /tmp/pstack-claude-custom.sock # 然后重启 daemon pstack-claude daemon stop pstack-claude daemon start5.2 权限类错误Operation not permitted与Permission denied这类错误集中在两类场景场景 Apstack报Operation not permitted原因未执行setcap或执行了但对象是错误的二进制文件见 3.2 节。修复sudo setcap cap_sys_ptraceep $(which pstack-claude)然后验证getcap $(which pstack-claude)输出非空。场景 B守护进程报Permission denied写日志原因work_dir目录权限不足或磁盘已满。修复# 检查目录权限 ls -ld /mnt/fastdisk/pstack-claude # 应输出 drwxr-xr-x如果不是修复 chmod 755 /mnt/fastdisk/pstack-claude chown $USER:$USER /mnt/fastdisk/pstack-claude # 检查磁盘空间 df -h /mnt/fastdisk # 若 Use% 90%清理旧日志 find /mnt/fastdisk/pstack-claude/logs -name *.log -mtime 7 -delete5.3 配置类错误model not supported与timeout_ms must be numberpstack-claude 对配置做严格 JSON Schema 校验错误信息直接指向字段{ error: config validation failed, details: [ {field: model, message: must be equal to one of the allowed values}, {field: timeout_ms, message: must be number} ] }常见错误model填了claude-3-opus不支持只支持 haiku/sonnettimeout_ms填了12000字符串应为数字 12000api_base_url末尾少了/v1。修复用在线 JSON Schema Validator如 jsonschemavalidator.net粘贴你的config.json它会高亮错误字段。5.4 进程类错误守护进程意外退出与内存泄漏守护进程崩溃时pstack-claude daemon status会显示inactive。查看日志# 日志位置由 work_dir 决定 tail -n 50 /mnt/fastdisk/pstack-claude/logs/latest.log # 典型崩溃日志 # FATAL: out of memory allocating 1048576 bytes # 或 # ERROR: failed to parse response: invalid character looking for beginning of value前者是max_tokens设得太大2048后者是网关返回了非 UTF-8 编码的响应常见于某些代理服务。修复降低max_tokens至 1024更换网关或在 Nginx 配置中添加charset utf-8;。5.5 编辑器集成类错误VS Code 右键菜单不显示这通常不是 pstack-claude 的问题而是 VS Code 的贡献点contribution point未激活。检查插件是否启用在 Extensions 面板中搜索pstack-claude-vscode状态为Enable当前文件是否为支持的语言默认支持.py,.js,.ts,.go,.rs其他语言需在settings.json中添加pstackClaude.supportedLanguages: [python, javascript, typescript, go, rust, java]右键菜单贡献点是否被其他插件屏蔽。临时禁用所有插件只留pstack-claude-vscode测试是否恢复。实操心得我给自己定了一条铁律——任何报错第一反应不是 Google而是pstack pid。上周有个同事遇到codex 无法加载组织设置折腾两小时最后我让他pstack $(pgrep -f codex-server)发现栈顶是getaddrinfo卡住立刻判断是 DNS 问题systemd-resolve --flush-caches一秒解决。pstack 是开发者最后的显微镜别把它锁在工具箱里。6. 进阶应用与定制化扩展从代码解释到自动化工作流pstack-claude 的设计哲学是“小而专”但它预留了足够的扩展接口让开发者能把它嵌入更复杂的自动化流程。我整理了三个已在生产环境验证的进阶用法每个都附带可运行的脚本。6.1 Git Pre-Commit Hook自动代码审查在团队协作中我们要求每次提交前自动检查代码质量。利用 pstack-claude 的review-file能力编写.git/hooks/pre-commit#!/bin/bash # .git/hooks/pre-commit CHANGED_FILES$(git diff --cached --name-only --diff-filterACM | grep -E \.(py|js|ts)$) if [ -z $CHANGED_FILES ]; then exit 0 fi echo Running Claude review on changed files... for file in $CHANGED_FILES; do echo → $file # 调用 pstack-claude 生成审查报告 REPORT$(pstack-claude review-file --file $file --format markdown 2/dev/null