Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:17:37 +08:00
commit 53f8448ca7
10 changed files with 1345 additions and 0 deletions

97
skills/bugsnag/README.md Normal file
View File

@@ -0,0 +1,97 @@
# Bugsnag Skill
Skill для интеграции с Bugsnag API, позволяющий просматривать и управлять ошибками в проекте.
## Возможности
- 🏢 **Управление организациями** - Просмотр списка доступных организаций в Bugsnag
- 📦 **Управление проектами** - Просмотр списка доступных проектов
- 📋 **Просмотр текущих ошибок** - Получение списка активных ошибок из Bugsnag
- 🔍 **Детальный контекст ошибки** - Просмотр полной информации об ошибке включая stack trace
-**Управление статусами** - Пометка ошибок как выполненные (resolved)
- 📈 **Анализ паттернов** - Автоматический анализ повторяющихся ошибок
- 🔐 **Безопасная авторизация** - Использование API ключей из переменных окружения
## Использование
### Быстрый доступ (Slash Commands)
Рекомендуется для частых операций:
```bash
# Работа с ошибками
/bugsnag:list # Список всех ошибок
/bugsnag:list --limit 50 # С фильтрами
/bugsnag:open # Только открытые ошибки
/bugsnag:details ERROR_ID # Детали ошибки
# Комментарии
/bugsnag:comments ERROR_ID # Просмотр комментариев
/bugsnag:comment ERROR_ID "text" # Добавить комментарий
# Управление
/bugsnag:fix ERROR_ID # Отметить ошибку как исправленную
# Обзор
/bugsnag:projects # Список проектов
/bugsnag:orgs # Список организаций
```
### Естественный язык (Skill)
Альтернативный способ через естественный язык:
```
"показать bugsnag ошибки"
"bugsnag открытые ошибки"
"bugsnag детали для error_123"
"показать комментарии для bugsnag ошибки abc123"
"добавить комментарий к bugsnag ошибке abc123: investigating"
"список проектов bugsnag"
"отметить ошибку ERROR_ID как исправленную"
"проанализируй bugsnag ошибки"
```
### Прямой вызов скрипта
Для автоматизации и скриптинга:
```bash
# Обзор
./bugsnag.rb organizations # Список организаций
./bugsnag.rb projects # Список проектов
# Работа с ошибками
./bugsnag.rb list # Список всех ошибок
./bugsnag.rb open # Только открытые ошибки
./bugsnag.rb details ERROR_ID # Детали конкретной ошибки
# Комментарии
./bugsnag.rb comments ERROR_ID # Показать комментарии
./bugsnag.rb comment ERROR_ID "message" # Добавить комментарий
# Управление
./bugsnag.rb resolve ERROR_ID # Отметить как выполненную
./bugsnag.rb analyze # Анализ паттернов ошибок
```
### Настройка
#### Как получить API ключ
1. Перейдите в [Bugsnag Dashboard](https://app.bugsnag.com)
2. Настройки → Organization → API Authentication
3. Создайте Personal Access Token с правами на чтение ошибок
4. Получите ID проекта из настроек проекта
#### Переменные окружения
```bash
export BUGSNAG_DATA_API_KEY="your_api_key_here"
export BUGSNAG_PROJECT_ID="your_project_id_here"
```
## Подробная документация
Полное описание команд и примеры использования см. в [SKILL.md](SKILL.md).

158
skills/bugsnag/SKILL.md Normal file
View File

@@ -0,0 +1,158 @@
---
name: bugsnag
description: |
**UNIVERSAL TRIGGER**: Use when user wants to GET/FETCH/RETRIEVE any data FROM Bugsnag.
Common patterns:
- "get/show/list/display [something] from bugsnag"
- "получить/показать/вывести [что-то] из bugsnag"
- "bugsnag [organizations/projects/errors/details/events/comments/stats]"
- "what [data] in bugsnag", "check bugsnag [resource]"
Specific data types supported:
📊 **Organizations & Projects**:
- "list bugsnag organizations/orgs", "show organizations"
- "list bugsnag projects", "available projects", "проекты bugsnag"
🐛 **Errors (viewing)**:
- "show/list bugsnag errors", "что в bugsnag", "check bugsnag"
- "open errors", "error list", "ошибки bugsnag", "открытые ошибки"
- "errors with severity error/warning", "filter bugsnag errors"
🔍 **Error Details**:
- "bugsnag details for <id>", "error details", "детали ошибки"
- "show stack trace", "error context", "what happened in error"
- "events for error", "error timeline", "события ошибки"
💬 **Comments**:
- "show comments for error", "error comments", "комментарии ошибки"
- "bugsnag discussion", "what comments on error"
📈 **Analysis**:
- "analyze bugsnag errors", "error patterns", "анализ ошибок"
- "bugsnag statistics", "error trends", "что происходит в bugsnag"
**Management** (write operations):
- "mark as fixed/resolved", "fix error", "resolve error", "close error"
- "закрыть ошибку", "отметить как решенную", "исправить ошибку"
- "add comment to error", "comment on bugsnag error"
- NOTE: Fix/Resolve/Close are synonyms - all mark error as resolved in Bugsnag
TRIGGERS: bugsnag, получить из bugsnag, показать bugsnag, список bugsnag,
bugsnag data, bugsnag info, check bugsnag, what in bugsnag, bugsnag status,
error tracking, error monitoring, production errors, stack trace,
bugsnag organizations, bugsnag projects, bugsnag errors, bugsnag details,
bugsnag events, bugsnag comments, bugsnag analysis, ошибки в bugsnag,
что в bugsnag, проверить bugsnag, данные bugsnag, fix error, resolve error,
close error, закрыть ошибку, исправить ошибку, отметить как решенную
This skill provides complete Bugsnag API integration for viewing and managing
error tracking data via Ruby helper scripts.
allowed-tools: Bash, Read
---
Skill для интеграции с Bugsnag API, позволяющий просматривать и управлять ошибками в проекте.
**⚠️ PATH RESOLUTION**: Этот skill использует Ruby скрипты из своей директории.
НИКОГДА не вызывай `./bugsnag.rb` из текущей рабочей директории пользователя.
**ПРАВИЛЬНО**: `find ~ -name "bugsnag.rb" -type f | head -1 | xargs dirname` → получим путь к skill
**НЕПРАВИЛЬНО**: `./bugsnag.rb` из текущей директории → ошибка "no such file or directory"
**ВАЖНО:** Используй ТОЛЬКО команды, описанные в этом файле. НЕ анализируй код bugsnag.rb - следуй документации ниже.
Вызывает скрипт ./bugsnag.rb находающийся в каталого этого skill с целью выполнить пользовательский запрос.
## Path Resolution для Claude
**КРИТИЧЕСКИ ВАЖНО**: При выполнении команд НЕ ИСПОЛЬЗУЙ `./bugsnag.rb` из текущей директории пользователя.
Всегда определяй директорию где находится skill и выполняй скрипт оттуда.
### Проблема
Когда пользователь говорит "покажи ошибки из bugsnag", выполнение `./bugsnag.rb` из текущей директории не работает.
### Решение
1. Определи директорию skill
2. Перейди в неё
3. Выполни скрипт
**Команда для Claude**: Используй `bash -c "cd [path_to_skill] && ./bugsnag.rb [args]"`
Где `[path_to_skill]` - это путь к директории skill. Определи его с помощью:
1. `find ~/.claude -name "bugsnag.rb" -type f` (если установлен)
2. или используй `pwd` если ты уже в директории skill
3. или попробуй стандартные пути установки плагинов
## Возможности
- 🏢 **Управление организациями** - Просмотр списка доступных организаций в Bugsnag
- 📦 **Управление проектами** - Просмотр списка доступных проектов
- 📋 **Просмотр текущих ошибок** - Получение списка активных ошибок из Bugsnag
- 🔍 **Детальный контекст ошибки** - Просмотр полной информации об ошибке включая stack trace
-**Управление статусами** - Пометка ошибок как выполненные (resolved)
- 🔐 **Безопасная авторизация** - Использование API ключей из переменных окружения
## Команды bugsnag.rb
### Обзор
- `organizations` / `orgs` / `организации` - Список всех организаций
- `projects` / `проекты` - Список всех проектов
### Просмотр ошибок
- `list` / `show` / `показать` - Список всех ошибок
- `open` / `открыть` / `открытые` - Только открытые ошибки
- `list --limit 50` - Показать до 50 ошибок
- `list --severity error` - Только ошибки (без предупреждений)
### Детализация
- `details <error_id>` / `детали <id>` - Полная информация об ошибке
- `events <error_id> [limit]` / `события <id> [лимит]` - Показать события ошибки
### Управление
- `resolve <error_id>` / `отметить <id>` - Отметить как выполненную
### Анализ
- `analyze` / `анализ` - Анализ паттернов ошибок
### Справка
- `help` / `помощь` / `h` - Показать справку
## ПРИМЕРЫ ИСПОЛЬЗОВАНИЯ
**FOR CLAUDE**: Используй `bash -c "cd [skill_directory] && ./bugsnag.rb [command]"`
```bash
# Показать организации
bash -c "cd [skill_dir] && ./bugsnag.rb organizations"
# Показать проекты
bash -c "cd [skill_dir] && ./bugsnag.rb projects"
# Показать открытые ошибки
bash -c "cd [skill_dir] && ./bugsnag.rb open --limit 20"
# Показать все ошибки (лимит 50)
bash -c "cd [skill_dir] && ./bugsnag.rb list --limit 50"
# Детали конкретной ошибки
bash -c "cd [skill_dir] && ./bugsnag.rb details ERROR_ID"
# Показать справку
bash -c "cd [skill_dir] && ./bugsnag.rb help"
```
**Примечание**: `[skill_dir]` - это путь к директории где установлен skill bugsnag.
## ЗАПРЕЩЕННЫЕ КОМАНДЫ
`list-errors` - такой команды НЕ существует
`--help` - используется `help` без дефисов
<EFBFBD> Использовать команды не описанные выше
## Безопасность
- API ключи хранятся только в переменных окружения
- Все запросы выполняются через HTTPS
- Минимальные необходимые права доступа к API
- Логирование чувствительных данных отключено

166
skills/bugsnag/TESTING.md Normal file
View File

@@ -0,0 +1,166 @@
# Bugsnag Skill - Testing Guide
## Auto-Activation Test Scenarios
This document contains test scenarios to verify the bugsnag skill activates correctly based on user input.
### ✅ SHOULD Activate
These phrases should trigger automatic skill activation:
1. **Direct Bugsnag mentions**:
- "показать ошибки в bugsnag"
- "show bugsnag errors"
- "check bugsnag"
- "what's in bugsnag?"
2. **Error details requests**:
- "bugsnag details for ERROR_123"
- "show error stack trace for ERROR_456"
- "get bugsnag error context"
- "покажи стектрейс ошибки ERROR_789"
3. **Error management**:
- "resolve bugsnag error ERROR_123"
- "mark bugsnag error as fixed"
- "close bugsnag error ERROR_456"
- "отметить ошибку ERROR_789 как решенную"
4. **Error analysis**:
- "analyze bugsnag errors"
- "bugsnag error patterns"
- "проанализировать ошибки в bugsnag"
- "what error patterns in production?"
5. **Generic error monitoring mentions**:
- "check production errors"
- "show error tracking"
- "what's happening in error monitoring?"
### ❌ Should NOT Activate
These phrases should NOT trigger bugsnag skill:
1. **Code errors (not monitoring)**:
- "найти ошибку в коде"
- "this code has a bug"
- "review this function for errors"
2. **Application logs (not Bugsnag)**:
- "показать логи приложения"
- "show server logs"
- "check nginx logs"
3. **Generic debugging**:
- "debug this issue"
- "why is this not working?"
- "help me fix this"
4. **Other monitoring tools**:
- "check sentry errors"
- "show datadog alerts"
- "rollbar notifications"
## Testing Procedure
### 1. Install Plugin Locally
```bash
# From repository root
/plugin marketplace add /home/danil/code/claude-code-marketplace
/plugin install dev-tools@dapi
```
### 2. Verify Skill Discovery
```bash
# Check skill is registered
/skills list
# Should show: bugsnag (dev-tools)
```
### 3. Test Auto-Activation
Start new conversation and try phrases from "SHOULD Activate" section:
```
User: "show bugsnag errors"
Expected: Claude should mention using bugsnag skill or invoke ./bugsnag.rb
```
```
User: "bugsnag details for ERROR_123"
Expected: Claude should invoke ./bugsnag.rb details ERROR_123
```
### 4. Test Non-Activation
Try phrases from "Should NOT Activate" section:
```
User: "найти ошибку в коде"
Expected: Claude uses code analysis, NOT bugsnag skill
```
## Environment Setup for Testing
Before testing, ensure environment variables are set:
```bash
export BUGSNAG_DATA_API_KEY='your_actual_api_key'
export BUGSNAG_PROJECT_ID='your_actual_project_id'
```
To get these values:
1. Visit https://app.bugsnag.com
2. Settings → Organization → API Authentication
3. Create Personal Access Token
4. Get Project ID from project settings
## Expected Behavior
### Correct Activation Flow
1. User mentions "bugsnag errors"
2. Claude recognizes trigger keywords
3. Claude invokes bugsnag skill
4. Skill executes `./bugsnag.rb <command>`
5. Results displayed to user
### Correct Non-Activation Flow
1. User asks about code errors (no "bugsnag" mention)
2. Claude uses native code analysis
3. Bugsnag skill does NOT activate
4. Standard debugging workflow proceeds
## Success Criteria
- ✅ Skill activates for all "SHOULD Activate" scenarios
- ✅ Skill does NOT activate for "Should NOT Activate" scenarios
- ✅ Commands execute correctly when activated
- ✅ Environment variables validated before execution
- ✅ Error messages are clear when API keys missing
- ✅ Help command works: `./bugsnag.rb help`
## Troubleshooting
### Skill Not Activating
1. Check skill is installed: `/skills list`
2. Verify SKILL.md frontmatter has proper YAML
3. Check description contains trigger keywords
4. Restart Claude Code session
### Commands Not Working
1. Verify script is executable: `chmod +x bugsnag.rb`
2. Check environment variables are set
3. Test script directly: `./bugsnag.rb help`
4. Check Ruby dependencies installed
### Permission Errors
1. Verify API key has correct permissions in Bugsnag
2. Check project ID is correct
3. Test API access with curl first

View File

@@ -0,0 +1,175 @@
# Bugsnag Skill Trigger Examples
Примеры запросов, которые **должны активировать** bugsnag skill.
## ✅ Универсальные паттерны (ДОЛЖНЫ СРАБОТАТЬ)
### Английский
- "get data from bugsnag"
- "show me bugsnag information"
- "list bugsnag resources"
- "retrieve bugsnag data"
- "display bugsnag status"
- "what's in bugsnag"
- "check bugsnag"
- "fetch bugsnag info"
### Русский
- "получить данные из bugsnag"
- "показать информацию bugsnag"
- "вывести список bugsnag"
- "что в bugsnag"
- "проверить bugsnag"
- "данные из bugsnag"
---
## ✅ Организации и проекты (ДОЛЖНЫ СРАБОТАТЬ)
### Организации
- "list bugsnag organizations"
- "show bugsnag orgs"
- "get organizations from bugsnag"
- "список организаций bugsnag"
- "организации в bugsnag"
- "показать организации bugsnag"
### Проекты
- "list bugsnag projects"
- "show available projects in bugsnag"
- "get bugsnag projects"
- "выведи список доступных проектов в bugsnag" ← **твой исходный запрос**
- "список проектов bugsnag"
- "проекты в bugsnag"
- "показать проекты bugsnag"
---
## ✅ Ошибки - просмотр (ДОЛЖНЫ СРАБОТАТЬ)
### Общий список
- "show bugsnag errors"
- "list errors from bugsnag"
- "what errors in bugsnag"
- "показать ошибки bugsnag"
- "список ошибок bugsnag"
- "что в bugsnag"
- "ошибки в bugsnag"
### Открытые ошибки
- "show open bugsnag errors"
- "list open errors"
- "открытые ошибки bugsnag"
- "показать открытые ошибки"
### С фильтрацией
- "show errors with severity error"
- "list bugsnag warnings"
- "filter bugsnag errors by severity"
---
## ✅ Детали ошибки (ДОЛЖНЫ СРАБОТАТЬ)
### Детальная информация
- "bugsnag details for ERROR_123"
- "show error details ERROR_123"
- "get error information ERROR_123"
- "детали ошибки ERROR_123"
- "показать детали ошибки ERROR_123"
### Stack trace
- "show stack trace for error ERROR_123"
- "error context ERROR_123"
- "what happened in error ERROR_123"
- "stack trace ошибки ERROR_123"
### События
- "show events for error ERROR_123"
- "error timeline ERROR_123"
- "события ошибки ERROR_123"
- "timeline для ошибки ERROR_123"
---
## ✅ Комментарии (ДОЛЖНЫ СРАБОТАТЬ)
- "show comments for error ERROR_123"
- "list bugsnag comments ERROR_123"
- "error discussion ERROR_123"
- "комментарии ошибки ERROR_123"
- "показать комментарии ERROR_123"
- "что говорят об ошибке ERROR_123"
---
## ✅ Анализ и статистика (ДОЛЖНЫ СРАБОТАТЬ)
- "analyze bugsnag errors"
- "show error patterns in bugsnag"
- "bugsnag statistics"
- "error trends in bugsnag"
- "what's happening in bugsnag"
- "анализ ошибок bugsnag"
- "паттерны ошибок в bugsnag"
- "статистика bugsnag"
- "что происходит в bugsnag"
---
## ✅ Управление (ДОЛЖНЫ СРАБОТАТЬ)
### Пометка как исправлено (fix/resolve/close - синонимы)
- "mark bugsnag error ERROR_123 as fixed"
- "fix error ERROR_123"
- "resolve error ERROR_123"
- "close bugsnag error ERROR_123"
- "отметить ошибку ERROR_123 как решенную"
- "закрыть ошибку ERROR_123"
- "исправить ошибку ERROR_123"
- NOTE: Fix, Resolve, Close - всё это одна операция в Bugsnag
### Добавление комментария
- "add comment to bugsnag error ERROR_123"
- "comment on error ERROR_123"
- "добавить комментарий к ошибке ERROR_123"
---
## ❌ НЕ должны активировать (другие контексты)
- "create a bug tracking system" (создание системы, не использование bugsnag)
- "what is bugsnag" (общий вопрос, не запрос данных)
- "install bugsnag" (установка, не получение данных)
- "bugsnag pricing" (коммерческий вопрос)
- "compare bugsnag with sentry" (сравнение продуктов)
---
## 🎯 Ключевые триггерные слова
### Действия (verbs)
**EN**: get, show, list, display, retrieve, fetch, check, analyze, view
**RU**: получить, показать, вывести, список, проверить, анализ, посмотреть
### Типы данных (nouns)
**EN**: organizations, orgs, projects, errors, details, events, comments, analysis, patterns, trends, statistics
**RU**: организации, проекты, ошибки, детали, события, комментарии, анализ, паттерны, статистика
### Контекст
**EN**: from bugsnag, in bugsnag, bugsnag [noun]
**RU**: из bugsnag, в bugsnag, bugsnag [существительное]
---
## 🧪 Тестирование
Для проверки активации skill попробуйте:
1. **Минимальный запрос**: "check bugsnag"
2. **Специфичный**: "list bugsnag projects"
3. **Русский**: "что в bugsnag"
4. **С ID**: "details for error 12345"
5. **Аналитический**: "analyze error patterns in bugsnag"
Каждый из этих запросов **должен активировать** bugsnag skill автоматически.

250
skills/bugsnag/bugsnag.rb Executable file
View File

@@ -0,0 +1,250 @@
#!/usr/bin/env ruby
require_relative 'bugsnag_helper'
class BugsnagCLI
def initialize
@helper = BugsnagHelper.new
rescue StandardError => e
puts "❌ Ошибка инициализации: #{e.message}"
puts ""
puts "Убедитесь что установлены переменные окружения:"
puts "export BUGSNAG_DATA_API_KEY='your_api_key' # Обязательно для всех команд"
puts "export BUGSNAG_PROJECT_ID='your_project_id' # Обязательно только для команд работы с ошибками"
puts ""
puts "💡 Команды 'organizations' и 'projects' работают без BUGSNAG_PROJECT_ID"
exit 1
end
def run(args = [])
if args.empty?
puts show_help
return
end
command = args[0].downcase
case command
when 'list', 'errors', 'show', 'показать', 'список'
list_errors(args[1..-1])
when 'open', 'открыть', 'opened', 'открытые'
show_open_errors(args[1..-1])
when 'details', 'error', 'детали'
show_error_details(args[1])
when 'resolve', 'close', 'resolve-error', 'отметить', 'решить'
resolve_error(args[1])
when 'events', 'события'
show_events(args[1], args[2])
when 'analyze', 'analysis', 'анализ', 'проанализировать'
analyze_errors
when 'organizations', 'orgs', 'организации'
list_organizations
when 'projects', 'проекты'
list_projects
when 'comment', 'комментарий'
add_error_comment(args[1], args[2..-1].join(' '))
when 'comments', 'комментарии'
show_error_comments(args[1])
when 'help', 'помощь', 'h'
puts show_help
else
puts "❌ Неизвестная команда: #{command}"
puts show_help
end
rescue StandardError => e
puts "❌ Ошибка выполнения: #{e.message}"
end
private
def list_errors(options = [])
limit = extract_option('--limit', options) || 20
status = extract_option('--status', options)
severity = extract_option('--severity', options)
puts "📋 Получение списка ошибок..."
puts ""
result = @helper.list_errors(limit: limit.to_i, status: status, severity: severity)
puts result
end
def show_open_errors(options = [])
limit = extract_option('--limit', options) || 20
severity = extract_option('--severity', options)
puts "📋 Получение списка **открытых** ошибок..."
puts ""
result = @helper.list_errors(limit: limit.to_i, status: 'open', severity: severity)
puts result
end
def show_error_details(error_id)
unless error_id
puts "❌ Укажите ID ошибки"
puts "Пример: bugsnag-lookuper details 5f8a9b2c"
return
end
puts "🔍 Получение деталей ошибки #{error_id}..."
puts ""
result = @helper.get_error_details(error_id)
puts result
# Также покажем последние события
puts ""
puts "📊 **Последние события:**"
events_result = @helper.get_error_events(error_id, 3)
puts events_result
end
def resolve_error(error_id)
unless error_id
puts "❌ Укажите ID ошибки для пометки как выполненной"
puts "Пример: bugsnag-lookuper resolve 5f8a9b2c"
return
end
puts "🔄 Пометка ошибки #{error_id} как выполненной..."
result = @helper.resolve_error(error_id)
puts result
end
def show_events(error_id, limit = nil)
unless error_id
puts "❌ Укажите ID ошибки"
puts "Пример: bugsnag-lookuper events 5f8a9b2c 5"
return
end
event_limit = limit&.to_i || 10
puts "📊 Получение событий ошибки #{error_id} (лимит: #{event_limit})..."
puts ""
result = @helper.get_error_events(error_id, limit: event_limit)
puts result
end
def analyze_errors
puts "📈 Анализ ошибок в проекте..."
puts ""
result = @helper.analyze_errors
puts result
end
def list_organizations
puts "🏢 Получение списка организаций..."
puts ""
result = @helper.list_organizations
puts result
end
def list_projects
puts "📦 Получение списка проектов..."
puts ""
result = @helper.list_projects
puts result
end
def add_error_comment(error_id, message)
unless error_id && !message.empty?
puts "❌ Укажите ID ошибки и текст комментария"
puts "Пример: bugsnag.rb comment 5f8a9b2c 'Investigating this issue'"
return
end
puts "💬 Добавление комментария к ошибке #{error_id}..."
result = @helper.add_comment(error_id, message)
puts result
end
def show_error_comments(error_id)
unless error_id
puts "❌ Укажите ID ошибки"
puts "Пример: bugsnag.rb comments 5f8a9b2c"
return
end
puts "💬 Получение комментариев для ошибки #{error_id}..."
puts ""
result = @helper.list_comments(error_id)
puts result
end
def show_help
<<~HELP
🚀 **Bugsnag** - Инструмент для работы с Bugsnag API
**Использование:**
`skill: "bugsnag" "<команда> [аргументы]"`
**Команды:**
📋 **Просмотр ошибок:**
`list` / `show` / `показать` - Список всех ошибок
`open` / `открыть` / `открытые` - Только **открытые** ошибки
`list --limit 50` - Показать до 50 ошибок
`list --status open` - Только открытые ошибки
`list --severity error` - Только ошибки (не предупреждения)
🔍 **Детали ошибки:**
`details <error_id>` / `детали <id>` - Полная информация об ошибке
Пример: `details 5f8a9b2c`
**Управление статусами:**
`resolve <error_id>` / `resolve-error <id>` / `отметить <id>` - Отметить как выполненную
Пример: `resolve 5f8a9b2c`
📊 **События ошибки:**
`events <error_id> [limit]` / `события <id> [лимит]` - Показать события
Пример: `events 5f8a9b2c 5`
📈 **Анализ:**
`analyze` / `analysis` / `анализ` - Анализ паттернов ошибок
💬 **Комментарии:**
`comment <error_id> "message"` / `комментарий <id> "текст"` - Добавить комментарий
`comments <error_id>` / `комментарии <id>` - Показать все комментарии
🏢 **Организации:**
`organizations` / `orgs` / `организации` - Список всех организаций
📦 **Проекты:**
`projects` / `проекты` - Список всех проектов
**Справка:**
`help` / `помощь` / `h` - Показать эту справку
**Настройка:**
```bash
export BUGSNAG_DATA_API_KEY="your_api_key" # Обязательно для всех команд
export BUGSNAG_PROJECT_ID="your_project_id" # Обязательно для команд работы с ошибками
```
💡 **Важно:** Команды `organizations` и `projects` работают **БЕЗ** BUGSNAG_PROJECT_ID.
Используйте их для получения списка доступных проектов и их ID.
HELP
end
def extract_option(option_name, options)
index = options.find_index { |opt| opt.start_with?(option_name) }
return nil unless index
option = options[index]
value = nil
if option.include?('=')
value = option.split('=', 2)[1]
options.delete_at(index)
elsif options[index + 1] && !options[index + 1].start_with?('--')
value = options.delete_at(index + 1)
options.delete_at(index)
else
options.delete_at(index)
end
value
end
end
# Handle execution through MCP or direct CLI
cli = BugsnagCLI.new
cli.run(ARGV)

View File

@@ -0,0 +1,370 @@
#!/usr/bin/env ruby
require 'bugsnag/api'
class BugsnagApiClient
def initialize
@api_key = ENV.fetch('BUGSNAG_DATA_API_KEY')
@project_id = ENV['BUGSNAG_PROJECT_ID'] # Optional - needed only for error-specific commands
validate_api_key
configure_api
end
def list_errors(limit: 20, status: nil, severity: nil)
errors_data = fetch_errors(limit: limit, status: status, severity: severity)
format_errors_list(errors_data)
rescue Bugsnag::Api::Error => e
handle_api_error(e, "получении списка ошибок")
end
def get_error_details(error_id)
require_project_id!
response = Bugsnag::Api.client.error(@project_id, error_id)
format_error_details(response)
rescue Bugsnag::Api::Error => e
handle_api_error(e, "получении деталей ошибки")
end
def resolve_error(error_id)
require_project_id!
# Try to resolve via API first
begin
Bugsnag::Api.client.update_errors(@project_id, [error_id], "resolve")
"✅ Ошибка `#{error_id}` успешно отмечена как выполненная!"
rescue Bugsnag::Api::Error => e
# Fallback to adding a resolution comment
begin
comment_text = "🔧 **MARKED AS RESOLVED** - Эта ошибка была помечена как выполненная через Bugsnag skill."
Bugsnag::Api.client.create_comment(@project_id, error_id, comment_text)
"✅ Ошибка `#{error_id}` помечена как выполненная через комментарий. Пожалуйста, закройте ошибку вручную в Bugsnag dashboard."
rescue Bugsnag::Api::Error => comment_error
handle_api_error(comment_error, "пометки ошибки как выполненной")
end
end
end
def add_comment(error_id, message)
require_project_id!
Bugsnag::Api.client.create_comment(@project_id, error_id, message)
"✅ Комментарий успешно добавлен к ошибке `#{error_id}`"
rescue Bugsnag::Api::Error => e
handle_api_error(e, "добавлении комментария")
end
def get_error_events(error_id, limit: 10)
require_project_id!
options = {}
options[:limit] = limit if limit
response = Bugsnag::Api.client.error_events(@project_id, error_id, options)
format_events_list(response)
rescue Bugsnag::Api::Error => e
handle_api_error(e, "получении событий ошибки")
end
def analyze_errors
errors_data = fetch_errors(limit: 50)
errors = normalize_errors_array(errors_data)
analyze_error_patterns(errors)
end
def list_organizations
response = Bugsnag::Api.client.organizations
format_organizations_list(response)
rescue Bugsnag::Api::Error => e
handle_api_error(e, "получении списка организаций")
end
def list_projects
# Get all organizations first
orgs = Bugsnag::Api.client.organizations
all_projects = []
# Get projects for each organization
orgs.each do |org|
org_projects = Bugsnag::Api.client.projects(org['id'])
all_projects.concat(org_projects)
rescue Bugsnag::Api::Error
# Skip this org if error, continue with others
next
end
format_projects_list(all_projects)
rescue Bugsnag::Api::Error => e
handle_api_error(e, "получении списка проектов")
end
def list_comments(error_id)
require_project_id!
response = Bugsnag::Api.client.comments(@project_id, error_id)
format_comments_list(response)
rescue Bugsnag::Api::Error => e
handle_api_error(e, "получении комментариев")
end
private
def fetch_errors(limit: 20, status: nil, severity: nil)
require_project_id!
options = {}
options[:limit] = limit if limit
options[:status] = status if status
options[:severity] = severity if severity
Bugsnag::Api.client.errors(@project_id, nil, options)
end
def normalize_errors_array(errors_data)
errors_data.is_a?(Array) ? errors_data : errors_data['errors'] || []
end
def validate_api_key
unless @api_key
raise "Missing required environment variable: BUGSNAG_DATA_API_KEY"
end
end
def require_project_id!
unless @project_id
raise "Missing required environment variable: BUGSNAG_PROJECT_ID\n\n" \
"This command requires a project ID. Set it with:\n" \
"export BUGSNAG_PROJECT_ID='your_project_id'\n\n" \
"Use 'projects' command to list available project IDs."
end
end
def configure_api
Bugsnag::Api.configure do |config|
config.auth_token = @api_key
end
end
def handle_api_error(error, operation)
case error
when Bugsnag::Api::ClientError
"❌ Ошибка при #{operation}: ошибка клиента API - #{error.message}"
when Bugsnag::Api::ServerError
"❌ Ошибка при #{operation}: ошибка сервера Bugsnag - #{error.message}"
when Bugsnag::Api::InternalServerError
"❌ Ошибка при #{operation}: внутренняя ошибка сервера Bugsnag - #{error.message}"
else
"❌ Ошибка при #{operation}: #{error.message}"
end
end
def format_errors_list(errors_data)
errors = errors_data.is_a?(Array) ? errors_data : errors_data['errors'] || []
output = ["📋 Найдено ошибок: #{errors.length}\n"]
errors.each do |error|
status_emoji = case error['status']
when 'open' then '❌'
when 'resolved' then '✅'
when 'ignored' then '🚫'
else '❓'
end
output << "#{status_emoji} **#{error['error_class']}** (#{error['events']} событий)"
output << " ID: `#{error['id']}`"
output << " Severity: #{error['severity']}"
output << " Первое появление: #{error['first_seen']}"
output << " Последнее: #{error['last_seen']}"
output << " URL: #{error['url']}" if error['url']
output << ""
end
output.join("\n")
end
def format_error_details(error_data)
error = error_data['error'] || error_data
output = []
output << "🔍 **Детали ошибки:** #{error['error_class']}"
output << ""
output << "**Основная информация:**"
output << "• ID: `#{error['id']}`"
output << "• Статус: #{error['status']}"
output << "• Критичность: #{error['severity']}"
output << "• Событий: #{error['events']}"
output << "• Пользователи затронуто: #{error['users']}"
output << ""
if error['first_seen'] && error['last_seen']
output << "**Временные рамки:**"
output << "• Первое появление: #{error['first_seen']}"
output << "• Последнее: #{error['last_seen']}"
output << ""
end
output << "**Контекст:**"
output << "• App Version: #{error.dig('app', 'version') || 'N/A'}"
output << "• Release Stage: #{error.dig('app', 'releaseStage') || 'N/A'}"
output << "• Language: #{error['language'] || 'N/A'}"
output << "• Framework: #{error['framework'] || 'N/A'}"
output << ""
if error['url']
output << "**URL:** #{error['url']}"
output << ""
end
if error['message']
output << "**Сообщение:**"
output << "```"
output << error['message']
output << "```"
output << ""
end
output
end
def format_events_list(events_data)
events = events_data['events'] || []
output = ["📊 События ошибки (#{events.length}):\n"]
events.each_with_index do |event, index|
output << "**Событие #{index + 1}:**"
output << "• ID: `#{event['id']}`"
output << "• Время: #{event['receivedAt']}"
output << "• App Version: #{event['app']['releaseStage'] || 'N/A'}"
output << "• OS: #{event['device']['osName'] || 'N/A'} #{event['device']['osVersion'] || ''}"
if event['user']
output << "• Пользователь: #{event['user']['name'] || event['user']['id'] || 'N/A'}"
end
if event['message']
output << "• Сообщение: #{event['message']}"
end
output << ""
end
output.join("\n")
end
def analyze_error_patterns(errors)
critical_errors = errors.select { |e| e['severity'] == 'error' && e['status'] == 'open' }
warnings = errors.select { |e| e['severity'] == 'warning' && e['status'] == 'open' }
output = ["📈 **Анализ ошибок в проекте:**\n"]
output << "🔴 **Критичные ошибки (#{critical_errors.length}):**"
if critical_errors.any?
critical_errors.first(5).each do |error|
events_count = error['events'] || error['events_count'] || 0
output << "#{error['error_class']} - #{events_count} событий (ID: #{error['id']})"
end
else
output << "• Нет критичных ошибок!"
end
output << ""
output << "🟡 **Предупреждения (#{warnings.length}):**"
if warnings.any?
warnings.first(5).each do |error|
events_count = error['events'] || error['events_count'] || 0
output << "#{error['error_class']} - #{events_count} событий (ID: #{error['id']})"
end
else
output << "• Нет предупреждений!"
end
output << ""
# Частые паттерны ошибок
error_classes = errors.group_by { |e| e['error_class'] }
frequent_errors = error_classes.select { |klass, errs| errs.length > 1 }
if frequent_errors.any?
output << "🔄 **Повторяющиеся паттерны:**"
frequent_errors.each do |error_class, errors|
total_events = errors.sum { |e| e['events'] || e['events_count'] || 0 }
output << "#{error_class}: #{errors.length} экземпляров, #{total_events} событий"
end
end
output.join("\n")
end
def format_organizations_list(orgs_data)
orgs = orgs_data.is_a?(Array) ? orgs_data : orgs_data['organizations'] || []
output = ["🏢 Доступные организации: #{orgs.length}\n"]
orgs.each_with_index do |org, index|
output << "#{index + 1}. **#{org['name']}** (ID: `#{org['id']}`)"
output << " Создана: #{org['created_at']}" if org['created_at']
output << " Коллабораторов: #{org['collaborators_count']}" if org['collaborators_count']
output << " Проектов: #{org['projects_count']}" if org['projects_count']
output << " URL: #{org['url']}" if org['url']
output << ""
end
output.join("\n")
end
def format_projects_list(projects_data)
projects = projects_data.is_a?(Array) ? projects_data : projects_data['projects'] || []
output = ["📦 Доступные проекты: #{projects.length}\n"]
projects.each_with_index do |project, index|
output << "#{index + 1}. **#{project['name']}** (ID: `#{project['id']}`)"
output << " Тип: #{project['type']}" if project['type']
output << " Открытых ошибок: #{project['open_error_count']}" if project['open_error_count']
output << " Коллабораторов: #{project['collaborators_count']}" if project['collaborators_count']
if project['release_stages'] && project['release_stages'].any?
output << " Стадии: #{project['release_stages'].join(', ')}"
end
output << " URL: #{project['url']}" if project['url']
output << ""
end
output.join("\n")
end
def format_comments_list(comments_data)
comments = comments_data.is_a?(Array) ? comments_data : comments_data['comments'] || []
output = ["💬 Комментарии (#{comments.length}):\n"]
if comments.empty?
output << "Нет комментариев для этой ошибки."
return output.join("\n")
end
comments.each_with_index do |comment, index|
output << "**Комментарий #{index + 1}:**"
output << "• ID: `#{comment['id']}`"
# Author info
author = if comment['user'] && comment['user']['name']
comment['user']['name']
elsif comment['user'] && comment['user']['email']
comment['user']['email']
else
'Unknown'
end
output << "• Автор: #{author}"
output << "• Время: #{comment['created_at']}" if comment['created_at']
output << "• Текст: #{comment['message']}" if comment['message']
output << ""
end
output.join("\n")
end
end

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env ruby
require_relative 'bugsnag_api_client'
class BugsnagHelper
def initialize
@client = BugsnagApiClient.new
end
def list_errors(limit: 20, status: nil, severity: nil)
@client.list_errors(limit: limit, status: status, severity: severity)
end
def get_error_details(error_id)
@client.get_error_details(error_id)
end
def resolve_error(error_id)
@client.resolve_error(error_id)
end
def get_error_events(error_id, limit: 10)
@client.get_error_events(error_id, limit: limit)
end
def analyze_errors
@client.analyze_errors
end
def list_organizations
@client.list_organizations
end
def list_projects
@client.list_projects
end
def add_comment(error_id, message)
@client.add_comment(error_id, message)
end
def list_comments(error_id)
@client.list_comments(error_id)
end
end