@dahawa/hawa-cli-analysis 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.tools.json +7 -0
- package/.vscode/launch.json +27 -0
- package/LICENSE +21 -0
- package/README.md +196 -0
- package/_uclaude.js +165 -0
- package/anthropic-transformer.js +986 -0
- package/api-anthropic.js +279 -0
- package/api-openai.js +539 -0
- package/claude/claude-openai-proxy.js +305 -0
- package/claude/claude-proxy.js +341 -0
- package/clogger-openai.js +190 -0
- package/clogger.js +318 -0
- package/codex/mcp-client.js +556 -0
- package/codex/mcpclient.js +118 -0
- package/codex/mcpserver.js +374 -0
- package/codex/mcpserverproxy.js +144 -0
- package/codex/test.js +30 -0
- package/config.js +105 -0
- package/index.js +0 -0
- package/logger-manager.js +85 -0
- package/logger.js +112 -0
- package/mcp/claude-mcpproxy-launcher.js +5 -0
- package/mcp_oauth_tokens.js +40 -0
- package/package.json +36 -0
- package/port-manager.js +80 -0
- package/simple-transform-example.js +213 -0
- package/tests/test-lazy-load.js +36 -0
- package/tests/test.js +30 -0
- package/tests/test_mcp_proxy.js +51 -0
- package/tests/test_supabase_mcp.js +42 -0
- package/uclaude.js +221 -0
- package/ucodex-proxy.js +173 -0
- package/ucodex.js +129 -0
- package/untils.js +261 -0
package/.tools.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Use IntelliSense to learn about possible attributes.
|
|
3
|
+
// Hover to view descriptions of existing attributes.
|
|
4
|
+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Launch Program2",
|
|
9
|
+
"program": "${workspaceFolder}/codex/mcpserver.js",
|
|
10
|
+
"request": "launch",
|
|
11
|
+
"skipFiles": [
|
|
12
|
+
"<node_internals>/**"
|
|
13
|
+
],
|
|
14
|
+
"type": "node"
|
|
15
|
+
},
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
"type": "node",
|
|
19
|
+
"request": "launch",
|
|
20
|
+
"name": "Launch Program",
|
|
21
|
+
"skipFiles": [
|
|
22
|
+
"<node_internals>/**"
|
|
23
|
+
],
|
|
24
|
+
"program": "${workspaceFolder}\\tests\\test.js"
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Hawa CLI 分析工具
|
|
2
|
+
|
|
3
|
+
这是一个用于增强 Claude CLI、Codex CLI 的上下文日志分析工具。通过代理模式拦截和分析 API 调用,提供详细的日志记录和分析功能。
|
|
4
|
+
|
|
5
|
+
## 🌟 功能特性
|
|
6
|
+
|
|
7
|
+
- **多 CLI 支持**: 支持 Claude CLI、Codex CLI
|
|
8
|
+
- **代理模式**: 通过本地代理服务器拦截和分析 API 调用
|
|
9
|
+
- **详细日志记录**: 记录所有 API 请求和响应,支持完整和简化日志模式
|
|
10
|
+
- **多模型支持**: 支持 Kimi、DeepSeek、OpenRouter 等多种 AI 模型
|
|
11
|
+
- **MCP 服务器代理**: 支持 MCP (Model Context Protocol) 服务器代理
|
|
12
|
+
- **端口管理**: 自动分配可用端口,避免端口冲突
|
|
13
|
+
- **配置管理**: 灵活的配置文件管理,支持多环境配置
|
|
14
|
+
- **多进程支持**: 支持多进程多个端口同时运行
|
|
15
|
+
|
|
16
|
+
## 📋 支持的 CLI 工具
|
|
17
|
+
|
|
18
|
+
### 1. Claude CLI (`uclaude`)
|
|
19
|
+
- 支持 Claude Code 命令行工具
|
|
20
|
+
- 支持多种 AI 模型 (Kimi, DeepSeek, OpenRouter)
|
|
21
|
+
- 自动代理配置和端口管理
|
|
22
|
+
|
|
23
|
+
### 2. Codex CLI (`ucodex`)
|
|
24
|
+
- 支持 OpenAI Codex 命令行工具
|
|
25
|
+
- 使用代理模式进行日志获取
|
|
26
|
+
- 支持多种 AI 模型配置
|
|
27
|
+
|
|
28
|
+
## 🚀 安装方式
|
|
29
|
+
|
|
30
|
+
### 前置要求
|
|
31
|
+
- Node.js >= 16.0.0
|
|
32
|
+
- npm 或 yarn
|
|
33
|
+
|
|
34
|
+
### 安装步骤
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install -g @dahawa/hawa-cli-analysis
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
1. **克隆项目**
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/jiweigang1/hawa-cli-analysis.git
|
|
43
|
+
cd hawa-cli-analysis
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
2. **安装依赖**
|
|
47
|
+
```bash
|
|
48
|
+
npm install
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
3. **链接到全局**
|
|
52
|
+
```bash
|
|
53
|
+
npm link
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
4. **初始化配置** (首次使用)
|
|
57
|
+
```bash
|
|
58
|
+
# 运行任意命令会自动创建配置文件
|
|
59
|
+
uclaude
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## ⚙️ 配置说明
|
|
63
|
+
|
|
64
|
+
### 配置文件位置
|
|
65
|
+
配置文件位于用户主目录下的 `.hawa-cli-analysis/config.json`:
|
|
66
|
+
- **Windows**: `C:\Users\用户名\.hawa-cli-analysis\config.json`
|
|
67
|
+
- **macOS/Linux**: `~/.hawa-cli-analysis/config.json`
|
|
68
|
+
|
|
69
|
+
### 默认配置
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"kimi-k2": {
|
|
73
|
+
"enable": false,
|
|
74
|
+
"env": {
|
|
75
|
+
"BASE_URL": "https://api.moonshot.cn/anthropic",
|
|
76
|
+
"AUTH_TOKEN": "sk-{使用自己的token}",
|
|
77
|
+
"MODEL": "kimi-k2-0905-preview",
|
|
78
|
+
"SMALL_FAST_MODEL": "kimi-k2-0905-preview"
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"deepseek": {
|
|
82
|
+
"enable": false,
|
|
83
|
+
"env": {
|
|
84
|
+
"BASE_URL": "https://api.deepseek.com/anthropic",
|
|
85
|
+
"AUTH_TOKEN": "sk-{使用自己的token}",
|
|
86
|
+
"API_TIMEOUT_MS": "600000",
|
|
87
|
+
"MODEL": "deepseek-chat",
|
|
88
|
+
"SMALL_FAST_MODEL": "deepseek-chat",
|
|
89
|
+
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"openrouter": {
|
|
93
|
+
"enable": false,
|
|
94
|
+
"env": {
|
|
95
|
+
"BASE_URL": "http://127.0.0.1:3000",
|
|
96
|
+
"AUTH_TOKEN": "sk-or-v1-{使用自己的token}",
|
|
97
|
+
"MODEL": "anthropic/claude-sonnet-4",
|
|
98
|
+
"SMALL_FAST_MODEL": "anthropic/claude-sonnet-4"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 启用模型
|
|
105
|
+
将对应模型的 `enable` 设置为 `true`,并填入您的 API Token。
|
|
106
|
+
|
|
107
|
+
## 📖 使用方法
|
|
108
|
+
|
|
109
|
+
### Claude CLI 使用
|
|
110
|
+
```bash
|
|
111
|
+
# 启动 Claude CLI
|
|
112
|
+
uclaude
|
|
113
|
+
|
|
114
|
+
# 选择启用的模型,程序会自动启动代理服务器和 Claude Code
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Codex CLI 使用
|
|
118
|
+
```bash
|
|
119
|
+
# 启动 Codex CLI
|
|
120
|
+
ucodex
|
|
121
|
+
|
|
122
|
+
# 程序会自动启动代理服务器和 Codex CLI
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 🔧 高级配置
|
|
126
|
+
|
|
127
|
+
### MCP 服务器配置
|
|
128
|
+
支持配置 MCP (Model Context Protocol) 服务器:
|
|
129
|
+
|
|
130
|
+
配置文件位置:`~/.hawa-cli-analysis/mcp.json`
|
|
131
|
+
|
|
132
|
+
```json
|
|
133
|
+
{
|
|
134
|
+
"mcpServers": {
|
|
135
|
+
"supabase": {
|
|
136
|
+
"url": "https://mcp.supabase.com/mcp",
|
|
137
|
+
"bearer_token": "sbp_xxxxx",
|
|
138
|
+
"tools": {
|
|
139
|
+
"blacklist": ["tool_name_to_exclude"],
|
|
140
|
+
"descriptions": {
|
|
141
|
+
"tool_name": "Custom description for this tool"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 环境变量
|
|
150
|
+
- `LOG_LEVEL`: 日志级别 (debug, info, warn, error)
|
|
151
|
+
- `PIPE_PATH_PRE`: 管道路径前缀
|
|
152
|
+
- `BASE_URL`: API 基础地址
|
|
153
|
+
- `AUTH_TOKEN`: API 认证令牌
|
|
154
|
+
|
|
155
|
+
## 📁 项目结构
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
hawa-cli-analysis/
|
|
159
|
+
├── api-anthropic.js # Anthropic API 处理
|
|
160
|
+
├── api-openai.js # OpenAI API 处理
|
|
161
|
+
├── anthropic-transformer.js # Anthropic 数据转换
|
|
162
|
+
├── clogger.js # 主日志模块
|
|
163
|
+
├── clogger-openai.js # OpenAI 日志模块
|
|
164
|
+
├── config.js # 配置管理
|
|
165
|
+
├── logger-manager.js # 日志管理器
|
|
166
|
+
├── logger.js # 日志模块
|
|
167
|
+
├── mcp_oauth_tokens.js # MCP OAuth 令牌
|
|
168
|
+
├── port-manager.js # 端口管理
|
|
169
|
+
├── simple-transform-example.js # 简单转换示例
|
|
170
|
+
├── ucodex-proxy.js # Codex 代理
|
|
171
|
+
├── uclaude.js # Claude CLI 启动器
|
|
172
|
+
├── ucodex.js # Codex CLI 启动器
|
|
173
|
+
├── untils.js # 工具函数
|
|
174
|
+
├── _uclaude.js # Claude CLI 备用启动器
|
|
175
|
+
├── index.js # 主入口文件
|
|
176
|
+
├── claude/ # Claude 相关配置
|
|
177
|
+
├── codex/ # Codex 相关配置
|
|
178
|
+
├── mcp/ # MCP 服务器配置
|
|
179
|
+
├── tests/ # 测试文件
|
|
180
|
+
└── package.json
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## 🔍 日志文件
|
|
184
|
+
|
|
185
|
+
日志文件保存在用户主目录下的 `.hawa-cli-analysis/logs/` 目录中:
|
|
186
|
+
- **系统日志**: `system/api-simple-{timestamp}.log`
|
|
187
|
+
- **完整日志**: `{cli-type}/api-full-{timestamp}.log`
|
|
188
|
+
- **简化日志**: `{cli-type}/api-simple-{timestamp}.log`
|
|
189
|
+
|
|
190
|
+
## 🤝 贡献指南
|
|
191
|
+
|
|
192
|
+
欢迎提交 Issue 和 Pull Request!
|
|
193
|
+
|
|
194
|
+
## 📄 许可证
|
|
195
|
+
|
|
196
|
+
ISC License
|
package/_uclaude.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
global.CLI_TYPE = "claude"
|
|
4
|
+
import {initConfig,loadConfig} from "./config.js"
|
|
5
|
+
import readline from 'readline';
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
import {getClaudePath} from './untils.js';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
11
|
+
import LogManager from './logger-manager.js';
|
|
12
|
+
|
|
13
|
+
const logger = LogManager.getSystemLogger();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 启动 calude code
|
|
17
|
+
*/
|
|
18
|
+
function start(){
|
|
19
|
+
initConfig();
|
|
20
|
+
let allConfig = loadConfig();
|
|
21
|
+
let choices = [];
|
|
22
|
+
Object.entries(allConfig).forEach(([key, value], index) => {
|
|
23
|
+
if (value.enable === true) {
|
|
24
|
+
choices.push({ name: `${index}. ${key}`, value: key });
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// 检查是否有启用的模型
|
|
29
|
+
if (choices.length === 0) {
|
|
30
|
+
console.error("错误:没有启用的模型配置!");
|
|
31
|
+
console.log("请检查配置文件,确保至少有一个模型的 enable 设置为 true。");
|
|
32
|
+
logger.error("没有启用的模型配置,程序退出");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
(async () => {
|
|
37
|
+
const answers = await inquirer.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: "list", // 单选模式
|
|
40
|
+
name: "choice", // 返回结果的 key
|
|
41
|
+
message: "请选择一个模型:",
|
|
42
|
+
choices: choices
|
|
43
|
+
}
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
var config = allConfig[answers.choice];
|
|
47
|
+
let env = config.env;
|
|
48
|
+
// 添加 ANTHROPIC_ 前缀到环境变量
|
|
49
|
+
let anthropicEnv = {};
|
|
50
|
+
Object.keys(env).forEach(key => {
|
|
51
|
+
if (['BASE_URL', 'AUTH_TOKEN', 'MODEL', 'SMALL_FAST_MODEL'].includes(key)) {
|
|
52
|
+
anthropicEnv[`ANTHROPIC_${key}`] = env[key];
|
|
53
|
+
} else {
|
|
54
|
+
anthropicEnv[key] = env[key];
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// claudecode 环境变量是可以通过 env 传递到 mcpserver
|
|
58
|
+
let claudePath = config?.CLAUDE_PATH || process.env.CLAUDE_PATH || getClaudePath();
|
|
59
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
60
|
+
if(answers.choice=="openrouter"){
|
|
61
|
+
claudePath = "node --import " + pathToFileURL(path.join(dir, 'clogger-openai.js')) + " " + claudePath;
|
|
62
|
+
}else{
|
|
63
|
+
claudePath = "node --import "+ pathToFileURL(path.join(dir, 'clogger.js')) + " " + claudePath;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
logger.debug(`启动 Claude 进程: ${claudePath}`);
|
|
67
|
+
|
|
68
|
+
const child = spawn(claudePath,[],{
|
|
69
|
+
env:{
|
|
70
|
+
...anthropicEnv,
|
|
71
|
+
PIPE_PATH_PRE: process.pid
|
|
72
|
+
},
|
|
73
|
+
stdio: 'inherit', // 继承父进程 stdio,方便交互,
|
|
74
|
+
shell: true
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
child.on("error", (error) => {
|
|
79
|
+
console.error("Failed to start claude command:", error.message);
|
|
80
|
+
logger.debug(
|
|
81
|
+
"Make sure Claude Code is installed: npm install -g @anthropic-ai/claude-code"
|
|
82
|
+
);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
child.on("close", (code) => {
|
|
87
|
+
process.exit(code || 0);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
})();
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
}
|
|
96
|
+
// 这里需要判断是否启动完成,不然后面 mcp 会连接失败
|
|
97
|
+
/**
|
|
98
|
+
function startMCPServerProxy(){
|
|
99
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
100
|
+
// 启动 MCP 代理服务
|
|
101
|
+
const child = spawn("node " + (path.join(dir, "mcp" ,'claude-mcpproxy-launcher.js')), [], {
|
|
102
|
+
stdio: "pipe" ,
|
|
103
|
+
shell: true,
|
|
104
|
+
env: {
|
|
105
|
+
PIPE_PATH_PRE: process.pid
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
child.stdout.on("data", (data) => {
|
|
110
|
+
console.log("子进程输出:", data.toString());
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
child.on("error", (error) => {
|
|
114
|
+
console.error("Failed to start MCP server proxy:", error.message);
|
|
115
|
+
process.exit(1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
child.on("close", (code) => {
|
|
119
|
+
process.exit(code || 0);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
*/
|
|
123
|
+
|
|
124
|
+
async function startMCPServerProxy() {
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
const dir = path.dirname(fileURLToPath(import.meta.url));
|
|
127
|
+
const child = spawn("node " + path.join(dir, "mcp", "claude-mcpproxy-launcher.js"), [], {
|
|
128
|
+
stdio: "pipe",
|
|
129
|
+
shell: true,
|
|
130
|
+
env: {
|
|
131
|
+
PIPE_PATH_PRE: process.pid
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
child.stdout.on("data", (data) => {
|
|
136
|
+
const msg = data.toString().trim();
|
|
137
|
+
//console.log("子进程输出:", msg);
|
|
138
|
+
if (msg.includes("ok_ok")) {
|
|
139
|
+
resolve("MCP server proxy started successfully");
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
child.stderr.on("data", (data) => {
|
|
144
|
+
console.error("子进程错误输出:", data.toString());
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
child.on("error", (error) => {
|
|
148
|
+
reject(new Error("Failed to start MCP server proxy: " + error.message));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
child.on("close", (code) => {
|
|
152
|
+
if (code !== 0) {
|
|
153
|
+
reject(new Error("MCP server proxy exited with code " + code));
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function main(){
|
|
160
|
+
console.log("Starting MCP server proxy...");
|
|
161
|
+
await startMCPServerProxy();
|
|
162
|
+
console.log("MCP server proxy started successfully.");
|
|
163
|
+
start();
|
|
164
|
+
}
|
|
165
|
+
await main();
|