llm-sentry-tools 1.1.4 → 1.3.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/package.json +1 -1
- package/scripts/setup-commands.js +23 -39
- package/scripts/setup-sentry-mcp.js +58 -25
package/package.json
CHANGED
|
@@ -14,20 +14,24 @@ console.log('🚀 AI 工具命令配置\n');
|
|
|
14
14
|
const AI_TOOLS = {
|
|
15
15
|
'claude-code': {
|
|
16
16
|
name: 'Claude Code',
|
|
17
|
-
configDir: '.claude/
|
|
17
|
+
configDir: '.claude/commands/sentry-tools',
|
|
18
18
|
fileExtension: 'md',
|
|
19
|
-
useSkillDirectory:
|
|
19
|
+
useSkillDirectory: false, // commands 是单个文件
|
|
20
20
|
createCommand: (commandName, promptContent) => {
|
|
21
21
|
const descriptions = {
|
|
22
22
|
'analyze-sentry-error': '从 Sentry 获取错误详情并进行深度分析,定位问题代码,提供详细分析报告',
|
|
23
23
|
'fix-sentry-error': '分析 Sentry 错误并自动修复代码,提供验证建议'
|
|
24
24
|
};
|
|
25
|
+
const argumentHints = {
|
|
26
|
+
'analyze-sentry-error': '<sentry-url> | <issue-id>',
|
|
27
|
+
'fix-sentry-error': '<sentry-url> | <issue-id>'
|
|
28
|
+
};
|
|
25
29
|
return `---
|
|
26
|
-
name: ${commandName}
|
|
27
30
|
description: ${descriptions[commandName] || commandName}
|
|
31
|
+
argument-hint: ${argumentHints[commandName] || '[参数]'}
|
|
28
32
|
---
|
|
29
33
|
|
|
30
|
-
${promptContent}`;
|
|
34
|
+
${promptContent.replace(/用户输入:\n```\n\/\S+/g, '用户输入:$ARGUMENTS')}`;
|
|
31
35
|
}
|
|
32
36
|
},
|
|
33
37
|
'cursor': {
|
|
@@ -107,26 +111,18 @@ const detectConfiguredTools = (projectPath) => {
|
|
|
107
111
|
for (const [key, tool] of Object.entries(AI_TOOLS)) {
|
|
108
112
|
const configPath = join(projectPath, tool.configDir);
|
|
109
113
|
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const skillPath = join(itemPath, 'SKILL.md');
|
|
119
|
-
return statSync(itemPath).isDirectory() && existsSync(skillPath);
|
|
120
|
-
});
|
|
121
|
-
} catch {
|
|
122
|
-
configured[key] = false;
|
|
123
|
-
}
|
|
124
|
-
} else {
|
|
114
|
+
if (existsSync(configPath)) {
|
|
115
|
+
try {
|
|
116
|
+
const items = readdirSync(configPath);
|
|
117
|
+
// 检查是否存在我们的命令文件
|
|
118
|
+
const hasAnalyze = items.includes(`analyze-sentry-error.${tool.fileExtension}`);
|
|
119
|
+
const hasFix = items.includes(`fix-sentry-error.${tool.fileExtension}`);
|
|
120
|
+
configured[key] = hasAnalyze || hasFix;
|
|
121
|
+
} catch {
|
|
125
122
|
configured[key] = false;
|
|
126
123
|
}
|
|
127
124
|
} else {
|
|
128
|
-
|
|
129
|
-
configured[key] = existsSync(configPath);
|
|
125
|
+
configured[key] = false;
|
|
130
126
|
}
|
|
131
127
|
}
|
|
132
128
|
|
|
@@ -200,22 +196,10 @@ const setupCommands = async () => {
|
|
|
200
196
|
// 创建命令文件
|
|
201
197
|
for (const command of commands) {
|
|
202
198
|
const commandContent = tool.createCommand(command.name, command.content);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const skillDir = join(toolConfigDir, command.name);
|
|
208
|
-
if (!existsSync(skillDir)) {
|
|
209
|
-
mkdirSync(skillDir, { recursive: true });
|
|
210
|
-
}
|
|
211
|
-
commandFilePath = join(skillDir, `SKILL.${tool.fileExtension}`);
|
|
212
|
-
} else {
|
|
213
|
-
// 其他工具: 创建单个文件 skill-name.md
|
|
214
|
-
commandFilePath = join(
|
|
215
|
-
toolConfigDir,
|
|
216
|
-
`${command.name}.${tool.fileExtension}`
|
|
217
|
-
);
|
|
218
|
-
}
|
|
199
|
+
const commandFilePath = join(
|
|
200
|
+
toolConfigDir,
|
|
201
|
+
`${command.name}.${tool.fileExtension}`
|
|
202
|
+
);
|
|
219
203
|
|
|
220
204
|
writeFileSync(commandFilePath, commandContent, 'utf-8');
|
|
221
205
|
console.log(`✓ 创建命令: ${commandFilePath}`);
|
|
@@ -229,9 +213,9 @@ const setupCommands = async () => {
|
|
|
229
213
|
console.log(' - 分析错误: /analyze-sentry-error <sentry-url>');
|
|
230
214
|
console.log(' - 修复错误: /fix-sentry-error <sentry-url>\n');
|
|
231
215
|
|
|
232
|
-
// 如果配置了 Claude Code
|
|
216
|
+
// 如果配置了 Claude Code,提示命令已就绪
|
|
233
217
|
if (selectedTools.includes('claude-code')) {
|
|
234
|
-
console.log('💡
|
|
218
|
+
console.log('💡 提示:在 Claude Code 中输入 / 可以看到可用的命令\n');
|
|
235
219
|
}
|
|
236
220
|
|
|
237
221
|
} catch (error) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import inquirer from 'inquirer';
|
|
4
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
5
5
|
import { homedir } from 'os';
|
|
6
|
-
import { join } from 'path';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
7
|
|
|
8
8
|
console.log('🔧 Sentry MCP 配置工具\n');
|
|
9
9
|
|
|
@@ -12,11 +12,11 @@ const getConfigPath = () => {
|
|
|
12
12
|
const platform = process.platform;
|
|
13
13
|
|
|
14
14
|
if (platform === 'darwin' || platform === 'linux') {
|
|
15
|
-
// macOS 或 Linux: ~/.
|
|
16
|
-
return join(homedir(), '.
|
|
15
|
+
// macOS 或 Linux: ~/.claude.json
|
|
16
|
+
return join(homedir(), '.claude.json');
|
|
17
17
|
} else if (platform === 'win32') {
|
|
18
|
-
// Windows: %
|
|
19
|
-
return join(
|
|
18
|
+
// Windows: %USERPROFILE%/.claude.json
|
|
19
|
+
return join(homedir(), '.claude.json');
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
throw new Error('不支持的操作系统');
|
|
@@ -24,6 +24,48 @@ const getConfigPath = () => {
|
|
|
24
24
|
|
|
25
25
|
const setupSentry = async () => {
|
|
26
26
|
try {
|
|
27
|
+
const configPath = getConfigPath();
|
|
28
|
+
|
|
29
|
+
// 读取现有配置
|
|
30
|
+
let config = {};
|
|
31
|
+
|
|
32
|
+
if (existsSync(configPath)) {
|
|
33
|
+
const configContent = readFileSync(configPath, 'utf-8');
|
|
34
|
+
config = JSON.parse(configContent);
|
|
35
|
+
console.log(`✓ 找到现有配置文件: ${configPath}\n`);
|
|
36
|
+
} else {
|
|
37
|
+
console.log(`配置文件不存在,将创建新文件: ${configPath}\n`);
|
|
38
|
+
config = {};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 确保 mcpServers 字段存在
|
|
42
|
+
if (!config.mcpServers) {
|
|
43
|
+
config.mcpServers = {};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 检查 Sentry MCP 是否已存在
|
|
47
|
+
if (config.mcpServers.sentry) {
|
|
48
|
+
const existingHost = config.mcpServers.sentry.args?.find(arg => arg.startsWith('--host='))?.replace('--host=', '') || '未知';
|
|
49
|
+
console.log('⚠️ 检测到 Sentry MCP 已配置(全局):');
|
|
50
|
+
console.log(` - 站点: ${existingHost}`);
|
|
51
|
+
console.log('');
|
|
52
|
+
|
|
53
|
+
const { shouldOverride } = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'confirm',
|
|
56
|
+
name: 'shouldOverride',
|
|
57
|
+
message: '是否要覆盖现有配置?',
|
|
58
|
+
default: false
|
|
59
|
+
}
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
if (!shouldOverride) {
|
|
63
|
+
console.log('\n✓ 保持现有配置不变\n');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
console.log('');
|
|
67
|
+
}
|
|
68
|
+
|
|
27
69
|
// 询问用户输入
|
|
28
70
|
const answers = await inquirer.prompt([
|
|
29
71
|
{
|
|
@@ -50,34 +92,24 @@ const setupSentry = async () => {
|
|
|
50
92
|
}
|
|
51
93
|
]);
|
|
52
94
|
|
|
53
|
-
|
|
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 配置
|
|
95
|
+
// 添加 Sentry MCP 配置(全局)
|
|
72
96
|
config.mcpServers.sentry = {
|
|
73
97
|
command: 'npx',
|
|
74
98
|
args: [
|
|
99
|
+
'-y',
|
|
75
100
|
'@sentry/mcp-server@latest',
|
|
76
101
|
`--access-token=${answers.accessToken}`,
|
|
77
102
|
`--host=${answers.host}`
|
|
78
103
|
]
|
|
79
104
|
};
|
|
80
105
|
|
|
106
|
+
// 确保配置目录存在
|
|
107
|
+
const configDir = dirname(configPath);
|
|
108
|
+
if (!existsSync(configDir)) {
|
|
109
|
+
mkdirSync(configDir, { recursive: true });
|
|
110
|
+
console.log(`\n✓ 创建配置目录: ${configDir}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
81
113
|
// 写回配置文件
|
|
82
114
|
writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
|
|
83
115
|
|
|
@@ -85,6 +117,7 @@ const setupSentry = async () => {
|
|
|
85
117
|
console.log('\n配置信息:');
|
|
86
118
|
console.log(` - 站点: ${answers.host}`);
|
|
87
119
|
console.log(` - 配置文件: ${configPath}`);
|
|
120
|
+
console.log(` - 配置类型: 全局`);
|
|
88
121
|
console.log('\n请重启 Claude Code 以使配置生效。\n');
|
|
89
122
|
|
|
90
123
|
} catch (error) {
|