llm-sentry-tools 1.0.0
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/README.md +161 -0
- package/bin/cli.js +103 -0
- package/package.json +48 -0
- package/prompts/analyze-sentry-error.md +51 -0
- package/prompts/fix-sentry-error.md +66 -0
- package/scripts/setup-commands.js +144 -0
- package/scripts/setup-sentry-mcp.js +100 -0
package/README.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# LLM Tools
|
|
2
|
+
|
|
3
|
+
基于 Sentry MCP 的智能错误分析和修复工具,让 AI 助手能够自动分析和修复 Sentry 上报的错误。
|
|
4
|
+
|
|
5
|
+
## 🌟 特性
|
|
6
|
+
|
|
7
|
+
- 🔍 **智能错误分析**:自动从 Sentry 获取错误详情并进行深度分析
|
|
8
|
+
- 🛠️ **自动错误修复**:AI 辅助修复代码,减少人工调试时间
|
|
9
|
+
- 🤖 **多 AI 工具支持**:支持 Claude Code、Cursor、Windsurf、Continue 等主流 AI 编程工具
|
|
10
|
+
- 🎯 **简单易用**:通过斜杠命令快速调用,只需粘贴 Sentry URL
|
|
11
|
+
- 🏢 **自建 Sentry 支持**:完美支持自建 Sentry 站点
|
|
12
|
+
|
|
13
|
+
## 📦 安装
|
|
14
|
+
|
|
15
|
+
**无需安装!** 直接使用 `npx` 运行:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 交互式菜单
|
|
19
|
+
npx llm-sentry-tools
|
|
20
|
+
|
|
21
|
+
# 或直接运行特定命令
|
|
22
|
+
npx llm-sentry-tools setup-sentry # 配置 Sentry MCP
|
|
23
|
+
npx llm-sentry-tools setup-commands # 配置 AI 工具
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 🚀 快速开始(仅需 2 步)
|
|
27
|
+
|
|
28
|
+
### 第一步:配置 Sentry MCP
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx llm-sentry-tools setup-sentry
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
按照提示输入:
|
|
35
|
+
- **Sentry 站点地址**(例如:`sentry.tec-do.cn` 或 `sentry.io`)
|
|
36
|
+
- **Sentry Access Token**(从 Sentry 设置中获取,见下方说明)
|
|
37
|
+
|
|
38
|
+
配置完成后,**重启你的 AI 工具**(如 Claude Code)以使 MCP 配置生效。
|
|
39
|
+
|
|
40
|
+
### 第二步:配置 AI 工具命令
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx llm-sentry-tools setup-commands
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
脚本会引导你:
|
|
47
|
+
1. **选择要配置的 AI 工具**(支持多选,空格选择,回车确认)
|
|
48
|
+
- ✅ Claude Code
|
|
49
|
+
- ✅ Cursor
|
|
50
|
+
- ✅ Windsurf
|
|
51
|
+
- ✅ Continue
|
|
52
|
+
2. **输入项目根目录路径**(默认为当前目录)
|
|
53
|
+
|
|
54
|
+
配置完成后,对应的命令文件会自动创建:
|
|
55
|
+
- Claude Code → `.claude/skills/`
|
|
56
|
+
- Cursor → `.cursor/commands/`
|
|
57
|
+
- Windsurf → `.windsurf/commands/`
|
|
58
|
+
- Continue → `.continue/commands/`
|
|
59
|
+
|
|
60
|
+
## 💡 使用方法
|
|
61
|
+
|
|
62
|
+
### 分析 Sentry 错误
|
|
63
|
+
|
|
64
|
+
在你的 AI 工具中输入:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
/analyze-sentry-error https://sentry.tec-do.cn/organizations/your-org/issues/12345/
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
或者直接输入 Issue ID:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
/analyze-sentry-error 12345
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
AI 会自动:
|
|
77
|
+
1. 从 Sentry 获取错误详情
|
|
78
|
+
2. 分析堆栈跟踪和错误上下文
|
|
79
|
+
3. 定位问题代码位置
|
|
80
|
+
4. 提供详细的分析报告,包括:
|
|
81
|
+
- 📋 错误概要
|
|
82
|
+
- 🔍 详细分析
|
|
83
|
+
- 📍 问题定位
|
|
84
|
+
- 💡 可能原因
|
|
85
|
+
- 📊 影响评估
|
|
86
|
+
- 🎯 修复建议
|
|
87
|
+
|
|
88
|
+
### 修复 Sentry 错误
|
|
89
|
+
|
|
90
|
+
在你的 AI 工具中输入:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
/fix-sentry-error https://sentry.tec-do.cn/organizations/your-org/issues/12345/
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
AI 会:
|
|
97
|
+
1. 分析错误
|
|
98
|
+
2. 定位问题代码
|
|
99
|
+
3. 提出修复方案并征求确认
|
|
100
|
+
4. 自动修改代码
|
|
101
|
+
5. 提供验证建议
|
|
102
|
+
|
|
103
|
+
## 📁 项目结构
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
llm-tools/
|
|
107
|
+
├── scripts/
|
|
108
|
+
│ ├── setup-sentry-mcp.js # Sentry MCP 配置脚本
|
|
109
|
+
│ └── setup-commands.js # AI 工具命令配置脚本
|
|
110
|
+
├── prompts/
|
|
111
|
+
│ ├── analyze-sentry-error.md # 错误分析 prompt 模板
|
|
112
|
+
│ └── fix-sentry-error.md # 错误修复 prompt 模板
|
|
113
|
+
├── package.json
|
|
114
|
+
└── README.md
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 🔧 进阶配置
|
|
118
|
+
|
|
119
|
+
### 手动配置 Sentry MCP
|
|
120
|
+
|
|
121
|
+
如果你更喜欢手动配置,可以直接编辑 Claude Code 的配置文件:
|
|
122
|
+
|
|
123
|
+
**macOS/Linux**: `~/.config/claude-code/config.json`
|
|
124
|
+
**Windows**: `%APPDATA%/Claude Code/config.json`
|
|
125
|
+
|
|
126
|
+
添加以下配置:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"mcpServers": {
|
|
131
|
+
"sentry": {
|
|
132
|
+
"command": "npx",
|
|
133
|
+
"args": [
|
|
134
|
+
"@sentry/mcp-server@latest",
|
|
135
|
+
"--access-token=YOUR_ACCESS_TOKEN",
|
|
136
|
+
"--host=YOUR_SENTRY_HOST"
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 获取 Sentry Access Token
|
|
144
|
+
|
|
145
|
+
1. 登录你的 Sentry 账号
|
|
146
|
+
2. 进入 **Settings** → **Account** → **API** → **Auth Tokens**
|
|
147
|
+
3. 点击 **Create New Token**
|
|
148
|
+
4. 选择权限:至少需要 `event:read` 和 `project:read`
|
|
149
|
+
5. 创建并复制 token
|
|
150
|
+
|
|
151
|
+
## 🤝 贡献
|
|
152
|
+
|
|
153
|
+
欢迎提交 Issue 和 Pull Request!
|
|
154
|
+
|
|
155
|
+
## 📄 许可证
|
|
156
|
+
|
|
157
|
+
MIT
|
|
158
|
+
|
|
159
|
+
## 🙏 致谢
|
|
160
|
+
|
|
161
|
+
本项目灵感来源于 [OpenSpec](https://github.com/Fission-AI/OpenSpec),感谢他们提供的优秀实践
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { dirname, join } from 'path';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
|
|
11
|
+
const runScript = (scriptPath) => {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const child = spawn('node', [scriptPath], {
|
|
14
|
+
stdio: 'inherit',
|
|
15
|
+
shell: true
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
child.on('close', (code) => {
|
|
19
|
+
if (code !== 0) {
|
|
20
|
+
reject(new Error(`脚本执行失败,退出码: ${code}`));
|
|
21
|
+
} else {
|
|
22
|
+
resolve();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
child.on('error', (err) => {
|
|
27
|
+
reject(err);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const main = async () => {
|
|
33
|
+
const args = process.argv.slice(2);
|
|
34
|
+
|
|
35
|
+
// 如果有命令行参数,直接执行对应脚本
|
|
36
|
+
if (args[0] === 'setup-sentry') {
|
|
37
|
+
const scriptPath = join(__dirname, '../scripts/setup-sentry-mcp.js');
|
|
38
|
+
await runScript(scriptPath);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (args[0] === 'setup-commands') {
|
|
43
|
+
const scriptPath = join(__dirname, '../scripts/setup-commands.js');
|
|
44
|
+
await runScript(scriptPath);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 没有参数,显示菜单
|
|
49
|
+
console.log('🛠️ LLM Tools - Sentry 错误分析修复工具\n');
|
|
50
|
+
|
|
51
|
+
const { action } = await inquirer.prompt([
|
|
52
|
+
{
|
|
53
|
+
type: 'list',
|
|
54
|
+
name: 'action',
|
|
55
|
+
message: '请选择要执行的操作:',
|
|
56
|
+
choices: [
|
|
57
|
+
{
|
|
58
|
+
name: '🔧 配置 Sentry MCP(连接到 Sentry)',
|
|
59
|
+
value: 'setup-sentry'
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: '⚙️ 配置 AI 工具命令(Claude Code, Cursor 等)',
|
|
63
|
+
value: 'setup-commands'
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: '📚 查看使用文档',
|
|
67
|
+
value: 'docs'
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: '❌ 退出',
|
|
71
|
+
value: 'exit'
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
switch (action) {
|
|
78
|
+
case 'setup-sentry':
|
|
79
|
+
await runScript(join(__dirname, '../scripts/setup-sentry-mcp.js'));
|
|
80
|
+
break;
|
|
81
|
+
case 'setup-commands':
|
|
82
|
+
await runScript(join(__dirname, '../scripts/setup-commands.js'));
|
|
83
|
+
break;
|
|
84
|
+
case 'docs':
|
|
85
|
+
console.log('\n📖 使用文档\n');
|
|
86
|
+
console.log('GitHub: https://github.com/your-org/llm-tools');
|
|
87
|
+
console.log('\n快速开始:');
|
|
88
|
+
console.log(' 1. npx llm-tools setup-sentry # 配置 Sentry MCP');
|
|
89
|
+
console.log(' 2. npx llm-tools setup-commands # 配置 AI 工具');
|
|
90
|
+
console.log(' 3. 在 AI 工具中使用:');
|
|
91
|
+
console.log(' /analyze-sentry-error <url> # 分析错误');
|
|
92
|
+
console.log(' /fix-sentry-error <url> # 修复错误\n');
|
|
93
|
+
break;
|
|
94
|
+
case 'exit':
|
|
95
|
+
console.log('👋 再见!\n');
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
main().catch((error) => {
|
|
101
|
+
console.error('❌ 执行失败:', error.message);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "llm-sentry-tools",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "基于 Sentry MCP 的错误分析和修复工具,支持 Claude Code、Cursor 等 AI 工具",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"llm-sentry-tools": "bin/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"setup:sentry": "node scripts/setup-sentry-mcp.js",
|
|
11
|
+
"setup:commands": "node scripts/setup-commands.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"bin",
|
|
15
|
+
"scripts",
|
|
16
|
+
"prompts",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"sentry",
|
|
21
|
+
"mcp",
|
|
22
|
+
"llm",
|
|
23
|
+
"error-fixing",
|
|
24
|
+
"claude",
|
|
25
|
+
"cursor",
|
|
26
|
+
"ai-tools",
|
|
27
|
+
"claude-code",
|
|
28
|
+
"windsurf",
|
|
29
|
+
"error-analysis",
|
|
30
|
+
"bug-fix"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://git.tec-do.com/lijiaqi/llm-tools.git"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://git.tec-do.com/lijiaqi/llm-tools",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://git.tec-do.com/lijiaqi/llm-tools/issues"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"inquirer": "^13.1.0"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Sentry 错误分析
|
|
2
|
+
|
|
3
|
+
你是一个专业的错误分析专家。用户会提供一个 Sentry 错误的 URL 或错误 ID,你需要:
|
|
4
|
+
|
|
5
|
+
## 分析步骤
|
|
6
|
+
|
|
7
|
+
1. **提取错误信息**
|
|
8
|
+
- 从 Sentry URL 中提取 Issue ID(例如:从 `https://sentry.tec-do.cn/organizations/your-org/issues/12345/` 提取 `12345`)
|
|
9
|
+
- 使用 Sentry MCP 工具获取错误详情
|
|
10
|
+
|
|
11
|
+
2. **错误分析**
|
|
12
|
+
- 错误类型和消息
|
|
13
|
+
- 堆栈跟踪信息
|
|
14
|
+
- 发生频率和影响范围
|
|
15
|
+
- 错误发生的环境(浏览器、操作系统、版本等)
|
|
16
|
+
- 最近一次发生时间
|
|
17
|
+
- 用户影响情况
|
|
18
|
+
|
|
19
|
+
3. **根因分析**
|
|
20
|
+
- 分析堆栈跟踪,定位问题代码位置
|
|
21
|
+
- 识别可能的触发条件
|
|
22
|
+
- 分析是否与最近的代码变更相关
|
|
23
|
+
- 识别类似的历史错误
|
|
24
|
+
|
|
25
|
+
4. **生成分析报告**
|
|
26
|
+
提供清晰的中文分析报告,包括:
|
|
27
|
+
- 📋 **错误概要**
|
|
28
|
+
- 🔍 **详细分析**
|
|
29
|
+
- 📍 **问题定位**(具体文件和行号)
|
|
30
|
+
- 💡 **可能原因**
|
|
31
|
+
- 📊 **影响评估**
|
|
32
|
+
- 🎯 **修复建议**(不实际修复代码)
|
|
33
|
+
|
|
34
|
+
## 使用方式
|
|
35
|
+
|
|
36
|
+
用户输入:
|
|
37
|
+
```
|
|
38
|
+
/analyze-sentry-error https://sentry.tec-do.cn/organizations/your-org/issues/12345/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
或者:
|
|
42
|
+
```
|
|
43
|
+
/analyze-sentry-error 12345
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 注意事项
|
|
47
|
+
|
|
48
|
+
- 仅进行分析,不修改任何代码
|
|
49
|
+
- 如果无法访问 Sentry 或获取错误信息,清晰地说明问题
|
|
50
|
+
- 分析报告应该对技术和非技术人员都易于理解
|
|
51
|
+
- 优先关注高频率、高影响的错误
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Sentry 错误修复
|
|
2
|
+
|
|
3
|
+
你是一个专业的错误修复专家。用户会提供一个 Sentry 错误的 URL 或错误 ID,你需要分析并修复问题。
|
|
4
|
+
|
|
5
|
+
## 修复流程
|
|
6
|
+
|
|
7
|
+
### 1. 错误分析
|
|
8
|
+
- 从 Sentry URL 中提取 Issue ID(例如:从 `https://sentry.tec-do.cn/organizations/your-org/issues/12345/` 提取 `12345`)
|
|
9
|
+
- 使用 Sentry MCP 工具获取错误详情
|
|
10
|
+
- 分析堆栈跟踪和错误上下文
|
|
11
|
+
|
|
12
|
+
### 2. 问题定位
|
|
13
|
+
- 根据堆栈跟踪找到具体的文件和行号
|
|
14
|
+
- 使用 Read 工具读取相关代码文件
|
|
15
|
+
- 理解代码逻辑和错误发生的上下文
|
|
16
|
+
|
|
17
|
+
### 3. 修复方案设计
|
|
18
|
+
在修复前,向用户展示:
|
|
19
|
+
- 📋 **错误概要**
|
|
20
|
+
- 🔍 **根本原因**
|
|
21
|
+
- 📍 **问题代码位置**
|
|
22
|
+
- 💡 **修复方案**
|
|
23
|
+
- ⚠️ **潜在影响**
|
|
24
|
+
|
|
25
|
+
### 4. 征求用户确认
|
|
26
|
+
在实际修改代码前,询问用户是否同意该修复方案
|
|
27
|
+
|
|
28
|
+
### 5. 执行修复
|
|
29
|
+
用户确认后:
|
|
30
|
+
- 使用 Edit 工具修改相关文件
|
|
31
|
+
- 确保修复不引入新的问题
|
|
32
|
+
- 添加必要的错误处理和边界检查
|
|
33
|
+
- 如需要,添加测试用例
|
|
34
|
+
|
|
35
|
+
### 6. 修复验证
|
|
36
|
+
- 说明如何验证修复是否有效
|
|
37
|
+
- 建议需要测试的场景
|
|
38
|
+
- 提醒用户在 Sentry 中监控错误是否消失
|
|
39
|
+
|
|
40
|
+
## 修复原则
|
|
41
|
+
|
|
42
|
+
1. **最小化变更**:只修改必要的代码,避免过度重构
|
|
43
|
+
2. **防御性编程**:添加适当的错误处理和输入验证
|
|
44
|
+
3. **兼容性**:确保修复不破坏现有功能
|
|
45
|
+
4. **可读性**:代码修改应该清晰易懂
|
|
46
|
+
5. **测试友好**:考虑测试的可行性
|
|
47
|
+
|
|
48
|
+
## 使用方式
|
|
49
|
+
|
|
50
|
+
用户输入:
|
|
51
|
+
```
|
|
52
|
+
/fix-sentry-error https://sentry.tec-do.cn/organizations/your-org/issues/12345/
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
或者:
|
|
56
|
+
```
|
|
57
|
+
/fix-sentry-error 12345
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 注意事项
|
|
61
|
+
|
|
62
|
+
- 必须先分析,后修复,不要盲目修改代码
|
|
63
|
+
- 复杂问题应该先与用户讨论修复方案
|
|
64
|
+
- 如果错误信息不足以定位问题,主动询问用户更多信息
|
|
65
|
+
- 修复后提醒用户进行充分测试
|
|
66
|
+
- 对于高风险修改(核心功能、数据处理等),额外谨慎
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
5
|
+
import { join, dirname } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
|
|
11
|
+
console.log('🚀 AI 工具命令配置\n');
|
|
12
|
+
|
|
13
|
+
// AI 工具配置
|
|
14
|
+
const AI_TOOLS = {
|
|
15
|
+
'claude-code': {
|
|
16
|
+
name: 'Claude Code',
|
|
17
|
+
configDir: '.claude/skills',
|
|
18
|
+
fileExtension: 'md',
|
|
19
|
+
createCommand: (commandName, promptContent) => {
|
|
20
|
+
// Claude Code 使用 skill 格式
|
|
21
|
+
return `---
|
|
22
|
+
description: ${commandName === 'analyze-sentry-error' ? 'Sentry 错误分析' : 'Sentry 错误修复'}
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
${promptContent}`;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
'cursor': {
|
|
29
|
+
name: 'Cursor',
|
|
30
|
+
configDir: '.cursor/commands',
|
|
31
|
+
fileExtension: 'md',
|
|
32
|
+
createCommand: (commandName, promptContent) => promptContent
|
|
33
|
+
},
|
|
34
|
+
'windsurf': {
|
|
35
|
+
name: 'Windsurf',
|
|
36
|
+
configDir: '.windsurf/commands',
|
|
37
|
+
fileExtension: 'md',
|
|
38
|
+
createCommand: (commandName, promptContent) => promptContent
|
|
39
|
+
},
|
|
40
|
+
'continue': {
|
|
41
|
+
name: 'Continue',
|
|
42
|
+
configDir: '.continue/commands',
|
|
43
|
+
fileExtension: 'md',
|
|
44
|
+
createCommand: (commandName, promptContent) => promptContent
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const setupCommands = async () => {
|
|
49
|
+
try {
|
|
50
|
+
// 让用户选择要配置的 AI 工具
|
|
51
|
+
const { selectedTools } = await inquirer.prompt([
|
|
52
|
+
{
|
|
53
|
+
type: 'checkbox',
|
|
54
|
+
name: 'selectedTools',
|
|
55
|
+
message: '请选择要配置的 AI 工具(空格选择,回车确认):',
|
|
56
|
+
choices: Object.entries(AI_TOOLS).map(([key, value]) => ({
|
|
57
|
+
name: value.name,
|
|
58
|
+
value: key,
|
|
59
|
+
checked: false
|
|
60
|
+
})),
|
|
61
|
+
validate: (answer) => {
|
|
62
|
+
if (answer.length === 0) {
|
|
63
|
+
return '请至少选择一个 AI 工具';
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
// 询问项目路径
|
|
71
|
+
const { projectPath } = await inquirer.prompt([
|
|
72
|
+
{
|
|
73
|
+
type: 'input',
|
|
74
|
+
name: 'projectPath',
|
|
75
|
+
message: '请输入项目根目录路径(留空使用当前目录):',
|
|
76
|
+
default: process.cwd()
|
|
77
|
+
}
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
console.log('\n开始配置命令...\n');
|
|
81
|
+
|
|
82
|
+
// 读取 prompt 模板
|
|
83
|
+
const promptsDir = join(__dirname, '..', 'prompts');
|
|
84
|
+
const analyzePrompt = readFileSync(
|
|
85
|
+
join(promptsDir, 'analyze-sentry-error.md'),
|
|
86
|
+
'utf-8'
|
|
87
|
+
);
|
|
88
|
+
const fixPrompt = readFileSync(
|
|
89
|
+
join(promptsDir, 'fix-sentry-error.md'),
|
|
90
|
+
'utf-8'
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const commands = [
|
|
94
|
+
{ name: 'analyze-sentry-error', content: analyzePrompt },
|
|
95
|
+
{ name: 'fix-sentry-error', content: fixPrompt }
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
// 为每个选中的工具配置命令
|
|
99
|
+
for (const toolKey of selectedTools) {
|
|
100
|
+
const tool = AI_TOOLS[toolKey];
|
|
101
|
+
const toolConfigDir = join(projectPath, tool.configDir);
|
|
102
|
+
|
|
103
|
+
// 创建配置目录
|
|
104
|
+
if (!existsSync(toolConfigDir)) {
|
|
105
|
+
mkdirSync(toolConfigDir, { recursive: true });
|
|
106
|
+
console.log(`✓ 创建目录: ${toolConfigDir}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 创建命令文件
|
|
110
|
+
for (const command of commands) {
|
|
111
|
+
const commandContent = tool.createCommand(command.name, command.content);
|
|
112
|
+
const commandFilePath = join(
|
|
113
|
+
toolConfigDir,
|
|
114
|
+
`${command.name}.${tool.fileExtension}`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
writeFileSync(commandFilePath, commandContent, 'utf-8');
|
|
118
|
+
console.log(`✓ 创建命令: ${commandFilePath}`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log(`✅ ${tool.name} 配置完成\n`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log('🎉 所有命令配置完成!\n');
|
|
125
|
+
console.log('使用方式:');
|
|
126
|
+
console.log(' - 分析错误: /analyze-sentry-error <sentry-url>');
|
|
127
|
+
console.log(' - 修复错误: /fix-sentry-error <sentry-url>\n');
|
|
128
|
+
|
|
129
|
+
// 如果配置了 Claude Code,提示需要重启
|
|
130
|
+
if (selectedTools.includes('claude-code')) {
|
|
131
|
+
console.log('💡 提示:如果正在运行 Claude Code,请重启以加载新的 skills\n');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (error.isTtyError) {
|
|
136
|
+
console.error('❌ 无法在当前环境中运行交互式命令');
|
|
137
|
+
} else {
|
|
138
|
+
console.error('❌ 配置失败:', error.message);
|
|
139
|
+
}
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
setupCommands();
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
|
|
8
|
+
console.log('🔧 Sentry MCP 配置工具\n');
|
|
9
|
+
|
|
10
|
+
// 检测操作系统,确定配置文件路径
|
|
11
|
+
const getConfigPath = () => {
|
|
12
|
+
const platform = process.platform;
|
|
13
|
+
|
|
14
|
+
if (platform === 'darwin' || platform === 'linux') {
|
|
15
|
+
// macOS 或 Linux: ~/.config/claude-code/config.json
|
|
16
|
+
return join(homedir(), '.config', 'claude-code', 'config.json');
|
|
17
|
+
} else if (platform === 'win32') {
|
|
18
|
+
// Windows: %APPDATA%/Claude Code/config.json
|
|
19
|
+
return join(process.env.APPDATA || '', 'Claude Code', 'config.json');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
throw new Error('不支持的操作系统');
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const setupSentry = async () => {
|
|
26
|
+
try {
|
|
27
|
+
// 询问用户输入
|
|
28
|
+
const answers = await inquirer.prompt([
|
|
29
|
+
{
|
|
30
|
+
type: 'input',
|
|
31
|
+
name: 'host',
|
|
32
|
+
message: 'Sentry 站点地址 (例如: sentry.tec-do.cn):',
|
|
33
|
+
validate: (input) => {
|
|
34
|
+
if (!input.trim()) {
|
|
35
|
+
return '请输入 Sentry 站点地址';
|
|
36
|
+
}
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
type: 'input',
|
|
42
|
+
name: 'accessToken',
|
|
43
|
+
message: 'Sentry Access Token:',
|
|
44
|
+
validate: (input) => {
|
|
45
|
+
if (!input.trim()) {
|
|
46
|
+
return '请输入 Access Token';
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]);
|
|
52
|
+
|
|
53
|
+
const configPath = getConfigPath();
|
|
54
|
+
|
|
55
|
+
// 读取现有配置
|
|
56
|
+
let config = {};
|
|
57
|
+
if (existsSync(configPath)) {
|
|
58
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
59
|
+
config = JSON.parse(configContent);
|
|
60
|
+
console.log(`\n✓ 找到现有配置文件: ${configPath}`);
|
|
61
|
+
} else {
|
|
62
|
+
console.log(`\n⚠ 配置文件不存在,将创建新文件: ${configPath}`);
|
|
63
|
+
config = { mcpServers: {} };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 确保 mcpServers 字段存在
|
|
67
|
+
if (!config.mcpServers) {
|
|
68
|
+
config.mcpServers = {};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// 添加 Sentry MCP 配置
|
|
72
|
+
config.mcpServers.sentry = {
|
|
73
|
+
command: 'npx',
|
|
74
|
+
args: [
|
|
75
|
+
'@sentry/mcp-server@latest',
|
|
76
|
+
`--access-token=${answers.accessToken}`,
|
|
77
|
+
`--host=${answers.host}`
|
|
78
|
+
]
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// 写回配置文件
|
|
82
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
83
|
+
|
|
84
|
+
console.log('\n✅ Sentry MCP 配置成功!');
|
|
85
|
+
console.log('\n配置信息:');
|
|
86
|
+
console.log(` - 站点: ${answers.host}`);
|
|
87
|
+
console.log(` - 配置文件: ${configPath}`);
|
|
88
|
+
console.log('\n请重启 Claude Code 以使配置生效。\n');
|
|
89
|
+
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (error.isTtyError) {
|
|
92
|
+
console.error('❌ 无法在当前环境中运行交互式命令');
|
|
93
|
+
} else {
|
|
94
|
+
console.error('❌ 配置失败:', error.message);
|
|
95
|
+
}
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
setupSentry();
|