Initial commit
This commit is contained in:
12
.claude-plugin/plugin.json
Normal file
12
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "dev-tools",
|
||||||
|
"description": "Development tools: agents for coding, refactoring, and architecture",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Danil Pismenny",
|
||||||
|
"email": "danilpismenny@gmail.com"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# dev-tools
|
||||||
|
|
||||||
|
Development tools: agents for coding, refactoring, and architecture
|
||||||
69
plugin.lock.json
Normal file
69
plugin.lock.json
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:dapi/claude-code-marketplace:dev-tools",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "dfaee878adc4dd11d42fa70e6210d2fc70f61e06",
|
||||||
|
"treeHash": "3fc97ae028e5ec54bcc32647a973b966d83ad2c4acc9f20a1eeac20ae3827d2a",
|
||||||
|
"generatedAt": "2025-11-28T10:16:01.997856Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "dev-tools",
|
||||||
|
"description": "Development tools: agents for coding, refactoring, and architecture",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "59427e1d410bb8f3a76f36b89f5352e6ba743eb5302648235b5ff3e4863d4f38"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "614079dd673f259b91af147fa7fd0efb35a5657d649207a9d40d3e2bee23cb7b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/bugsnag/bugsnag_helper.rb",
|
||||||
|
"sha256": "ba6241914c3b207b49c82bf79e87643b05fa27799c972b092cca3bfde74cffb5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/bugsnag/TESTING.md",
|
||||||
|
"sha256": "06064b4f7bb41ce13a4dbfa3a658eb4ce8db4edb23b9fdf7985ea734cb371f01"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/bugsnag/README.md",
|
||||||
|
"sha256": "9d88ea1d0effc7ccf0ffdfccbe7cd06465947b701d1025a8ff78b300534397f2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/bugsnag/bugsnag.rb",
|
||||||
|
"sha256": "3aacfe410a619d0bd1fe3d3f582d70cff9da9168a3a516593807b3ca39e65483"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/bugsnag/TRIGGER_EXAMPLES.md",
|
||||||
|
"sha256": "8a90fdfcf4d273e1891aa3c878e624815be00dae95b4eb8184fadeba6bf7304d"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/bugsnag/SKILL.md",
|
||||||
|
"sha256": "b8c077b62b5e00d980b618b5c88173ebe601bbdf2a667f7951e9bf2bef3df692"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/bugsnag/bugsnag_api_client.rb",
|
||||||
|
"sha256": "8cf5544d18897b0383843ec86adcabf29bd828807aee8e01c6b5b740f475f115"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "3fc97ae028e5ec54bcc32647a973b966d83ad2c4acc9f20a1eeac20ae3827d2a"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
97
skills/bugsnag/README.md
Normal file
97
skills/bugsnag/README.md
Normal 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
158
skills/bugsnag/SKILL.md
Normal 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
166
skills/bugsnag/TESTING.md
Normal 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
|
||||||
175
skills/bugsnag/TRIGGER_EXAMPLES.md
Normal file
175
skills/bugsnag/TRIGGER_EXAMPLES.md
Normal 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
250
skills/bugsnag/bugsnag.rb
Executable 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)
|
||||||
370
skills/bugsnag/bugsnag_api_client.rb
Normal file
370
skills/bugsnag/bugsnag_api_client.rb
Normal 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
|
||||||
45
skills/bugsnag/bugsnag_helper.rb
Executable file
45
skills/bugsnag/bugsnag_helper.rb
Executable 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
|
||||||
Reference in New Issue
Block a user