diff --git a/docs/GITEA_INTEGRATION.md b/docs/GITEA_INTEGRATION.md new file mode 100644 index 0000000..db600ec --- /dev/null +++ b/docs/GITEA_INTEGRATION.md @@ -0,0 +1,239 @@ +# Gitea API Integration + +Интеграция с Gitea API 1.21+ для автмоатического управления issues, milestones и логирования работы агентов. + +## Установка + +```bash +# Установите зависимости +bun install + +# Или с npm +npm install +``` + +## Настройка + +### Вариант 1: Токен через окружение + +```bash +# Установите переменные окружения +export GITEA_API_URL="https://git.softuniq.eu/api/v1" +export GITEA_TOKEN="ваш_токен_здесь" +``` + +### Вариант 2: Получение токена из логина/пароля + +```bash +# Запустите скрипт для создания токена +./scripts/create-gitea-token.sh your_username your_password + +# Скрипт выведет: +# export GITEA_TOKEN=abc123... +``` + +### Вариант 3: Программно через API + +```typescript +import { GiteaClient } from './src/kilocode/agent-manager/gitea-client.js' + +// Создать токен из логина/пароля +const { token } = await GiteaClient.createToken( + 'your_username', + 'your_password', + 'Pipeline Token', + ['all'] // или ['read:issue', 'write:issue', 'read:repository', 'write:repository'] +) + +// Использовать токен +const client = new GiteaClient({ token }) +``` + +## Использование + +### Создание Issues с Milestone + +```typescript +import { GiteaClient } from './src/kilocode/agent-manager/gitea-client.js' + +const client = new GiteaClient({ + apiUrl: 'https://git.softuniq.eu/api/v1', + token: process.env.GITEA_TOKEN +}) + +client.setRepository('UniqueSoft', 'APAW') + +// Создать milestone +const milestone = await client.createMilestone({ + title: 'Sprint 1', + description: 'First sprint', + due_on: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString() +}) + +// Создать issue с milestone +const issue = await client.createIssue({ + title: 'Implement authentication', + body: `## Чеклист +- [ ] Дизайн API +- [ ] Реализация +- [ ] Тесты`, + labels: ['status: new'], + milestone: milestone.id +}) + +// Добавить комментарий +await client.createComment(issue.number, { + body: `## ✅ Прогресс + +### Выполнено +- ✅ API спроектирован +- ✅ Начата реализация + +### В процессе +- 🔄 Написание тестов` +}) + +// Изменить статус +await client.setStatus(issue.number, 'implementing') +``` + +### Логирование производительности агентов + +```typescript +import { logAgentPerformance, logPipelineStep } from './src/kilocode/agent-manager/gitea-client.js' + +// Логировать шаг пайплайна +await logPipelineStep(client, issueNumber, '@lead-developer', 'started', 'Implementing authentication') + +// Логировать результат работы агента +await logAgentPerformance(client, issueNumber, 'lead-developer', 8, 'Clean implementation, good test coverage') +``` + +### Работа с Labels + +```typescript +// Получить все labels репозитория +const labels = await client.getRepoLabels() + +// Добавить labels к issue +await client.addLabels(issueNumber, [1, 2, 3]) // по ID +await client.addLabels(issueNumber, ['bug', 'priority:high']) // по имени + +// Заменить все labels +await client.replaceLabels(issueNumber, [1, 2]) + +// Удалить label +await client.removeLabel(issueNumber, 1) + +// Установить статус (удаляет старые status: labels) +await client.setStatus(issueNumber, 'implementing') +``` + +## API Scopes + +Gitea использует гранулярные scopes вместо старых `repo`, `issue`: + +| Scope | Описание | +|-------|----------| +| `all` | Полный доступ | +| `read:issue` | Чтение issues | +| `write:issue` | Создание/изменение issues | +| `read:repository` | Чтение репозитория | +| `write:repository` | Изменение репозитория | +| `read:milestone` | Чтение milestones | +| `write:milestone` | Создание/изменение milestones | + +## Скрипты тестирования + +### Создание токена + +```bash +./scripts/create-gitea-token.sh username password +``` + +### Полный тест (токен + milestone + issues + comments) + +```bash +./scripts/full-gitea-test.sh username password +``` + +### Тест с существующим токеном + +```bash +export GITEA_TOKEN=your_token +./scripts/test-gitea.sh +``` + +## Структура ответов API + +### Milestone + +```json +{ + "id": 42, + "title": "Pipeline Integration Test", + "description": "...", + "state": "open", + "open_issues": 3, + "closed_issues": 0, + "created_at": "2026-04-04T00:27:11Z", + "due_on": "2026-04-11T00:27:03Z" +} +``` + +### Issue + +```json +{ + "number": 1, + "title": "Setup Gitea Client", + "body": "## Чеклист\n- [x] Задача 1\n- [ ] Задача 2", + "state": "open", + "labels": [{ "id": 1, "name": "status: new", "color": "0052cc" }], + "milestone": { "id": 42, "title": "..." }, + "comments": 3 +} +``` + +### Label + +```json +{ + "id": 1, + "name": "status: new", + "color": "0052cc", + "description": "New issue", + "exclusive": false, + "is_archived": false +} +``` + +## Интеграция с агентами + +Агенты могут использовать GiteaClient для: + +1. **Создание tasks**: `client.createIssue()` +2. **Обновление статуса**: `client.setStatus()` +3. **Логирование прогресса**: `client.createComment()` +4. **Работа с milestone**: `client.createMilestone()` +5. **Парсинг чеклистов**: Извлечение `- [x]` из issue body + +### Pipeline Integration + +```typescript +// В .kilo/commands/pipeline.md +import { GiteaClient, PipelineRunner } from './src/kilocode/index.js' + +const runner = await createPipelineRunner({ + giteaToken: process.env.GITEA_TOKEN +}) + +// Запустить пайплайн для issue +await runner.run({ issueNumber: 42 }) + +// Оценить производительность +await runner.logEvaluation(42, [ + { agent: 'lead-developer', score: 8, notes: 'Clean code' }, + { agent: 'code-skeptic', score: 7, notes: 'Found 2 issues' } +], 2, 1.5) +``` \ No newline at end of file diff --git a/src/kilocode/agent-manager/gitea-client.ts b/src/kilocode/agent-manager/gitea-client.ts index f797943..575958f 100644 --- a/src/kilocode/agent-manager/gitea-client.ts +++ b/src/kilocode/agent-manager/gitea-client.ts @@ -11,6 +11,22 @@ export interface GiteaConfig { repo: string } +// AccessToken for authentication +export interface AccessToken { + id: number + name: string + sha1: string + token_last_eight: string + created_at: string + last_used_at?: string + scopes: string[] +} + +export interface CreateTokenOptions { + name: string + scopes?: string[] +} + // Label structure per Gitea API 1.21+ export interface Label { id: number @@ -111,6 +127,38 @@ export class GiteaClient { this.repo = config?.repo || "" } + /** + * Create a token using Basic Auth (username/password) + * Requires GITEA_USERNAME and GITEA_PASSWORD env vars + */ + static async createToken( + username: string, + password: string, + name: string, + scopes: string[] = ["all"], + apiUrl: string = GITEA_API_URL + ): Promise<{ token: string; id: number }> { + const response = await fetch(`${apiUrl}/users/${username}/tokens`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": "Basic " + Buffer.from(`${username}:${password}`).toString("base64") + }, + body: JSON.stringify({ name, scopes }) + }) + + if (!response.ok) { + const error = await response.text() + throw new Error(`Failed to create token: ${response.status} - ${error}`) + } + + const data = await response.json() + return { + token: data.sha1, + id: data.id + } + } + setRepository(owner: string, repo: string): void { this.owner = owner this.repo = repo