diff --git a/.kilo/commands/evaluate.md b/.kilo/commands/evaluate.md new file mode 100644 index 0000000..2c35bc2 --- /dev/null +++ b/.kilo/commands/evaluate.md @@ -0,0 +1,58 @@ +--- +description: Evaluate agent performance for completed issue +mode: subagent +model: ollama-cloud/gpt-oss:120b +color: "#F59E0B" +--- + +# Evaluate Command + +Generate performance evaluation report for a completed pipeline run. + +## Usage + +``` +/evaluate +``` + +## Process + +1. Fetch issue comments +2. Parse agent execution logs +3. Calculate scores per agent +4. Generate recommendations +5. Post evaluation to Gitea + +## Scoring Criteria + +| Criterion | Weight | +|-----------|--------| +| Code Quality | 30% | +| Test Coverage | 20% | +| Review Iterations | 20% | +| Time to Complete | 15% | +| Security Issues | 15% | + +## Output Format + +```markdown +## 🟢 Pipeline Evaluation Report + +**Issue**: #42 +**Overall Score**: 8.2/10 +**Duration**: 2.5h +**Iterations**: 2 + +### Agent Scores + +| Agent | Score | Notes | +|-------|-------|-------| +| 🟢 requirement-refiner | 9/10 | Clear acceptance criteria | +| 🟢 lead-developer | 8/10 | Clean implementation | +| 🟡 code-skeptic | 7/10 | Found 2 minor issues | +| 🟢 the-fixer | 9/10 | Fixed issues quickly | + +### Recommendations + +- Consider optimizing code-skeptic prompt (score < 8) +``` \ No newline at end of file diff --git a/.kilo/commands/pipeline.md b/.kilo/commands/pipeline.md new file mode 100644 index 0000000..a437c55 --- /dev/null +++ b/.kilo/commands/pipeline.md @@ -0,0 +1,139 @@ +--- +description: Run full agent pipeline for an issue with Gitea logging +--- + +# Pipeline Workflow + +You are orchestrating the full agent pipeline for issue #{issue_number}. Execute each step sequentially, logging progress to Gitea. + +## Parameters + +- `issue_number`: The issue number to process (ask if not provided) + +## Step 1: Fetch Issue Context + +1. Read the issue from Gitea using `bash`: + ```bash + gh issue view {issue_number} --json title,body,labels,assignees + ``` +2. Parse the issue body for: + - Acceptance criteria (checkboxes) + - Referenced files + - Current status label + +## Step 2: Check for Duplicates + +1. Use `grep` to search git history for similar issues: + ```bash + git log --all --oneline --grep="{keywords from title}" + ``` +2. Report findings as Gitea comment + +## Step 3: Route Based on Status + +Based on the issue status label, invoke the appropriate agent using Task tool: + +| Status Label | Agent to Invoke | +|-------------|-----------------| +| `status: new` | `@requirement-refiner` | +| `status: planned` | `@history-miner` | +| `status: researching` | `@system-analyst` | +| `status: designed` | `@sdet-engineer` | +| `status: testing` | `@lead-developer` | +| `status: implementing` | `@code-skeptic` | +| `status: reviewing` | `@performance-engineer` | +| `status: fixing` | `@the-fixer` | +| `status: releasing` | `@release-manager` | +| `status: evaluated` | `@prompt-optimizer` | + +## Step 4: Execute Agent Task + +1. Use Task tool to invoke the agent: + ``` + Use the Task tool with subagent_type: "lead-developer" (or appropriate agent) + prompt: "Implement the following: {issue details}" + ``` + +2. After agent completes, check result: + - If successful → proceed to next agent in workflow + - If issues found → route to `@the-fixer` + +## Step 5: Log Progress to Gitea + +After each agent completes, post comment: +```bash +gh issue comment {issue_number} --body "## ✅ {agent_name} completed + +**Score**: {score}/10 +**Duration**: {duration} +**Next**: {next_agent} + +{agent_notes}" +``` + +## Step 6: Update Status Label + +```bash +gh issue edit {issue_number} --remove-label "status: {old_status}" --add-label "status: {new_status}" +``` + +## Step 7: Continue Pipeline + +Loop through steps 3-6 until status is `status: completed`. + +## Step 8: Generate Evaluation Report + +When pipeline completes, generate final report: + +```markdown +## 🟢 Pipeline Evaluation Report + +**Issue**: #{issue_number} +**Overall Score**: {average}/10 +**Duration**: {total_hours}h +**Iterations**: {count} + +### Agent Scores + +| Agent | Score | Notes | +|-------|-------|-------| +| {agent} | {score}/10 | {notes} | + +### Recommendations + +- {recommendation_1} +- {recommendation_2} +``` + +## Workflow Graph + +``` +new → requirement-refiner → planned +planned → history-miner → researching +researching → system-analyst → designed +designed → sdet-engineer → testing +testing → lead-developer → implementing +implementing → code-skeptic → reviewing +reviewing → performance-engineer → perf-check +perf-check → security-auditor → security-check +security-check → release-manager → releasing +releasing → evaluator → evaluated +evaluated → prompt-optimizer → completed +``` + +On failure at any step → route to `the-fixer` → back to `code-skeptic` + +## Environment + +Required environment variables: +``` +GITEA_API_URL=https://git.softuniq.eu/api/v1 +GITEA_TOKEN=your-token +``` + +## Error Handling + +If any step fails: +1. Post error comment to issue +2. Add label `status: blocked` +3. Ask user for guidance using `question` tool \ No newline at end of file diff --git a/.kilo/commands/status.md b/.kilo/commands/status.md new file mode 100644 index 0000000..dabab7c --- /dev/null +++ b/.kilo/commands/status.md @@ -0,0 +1,41 @@ +--- +description: Check pipeline status for an issue +mode: subagent +model: qwen/qwen3.6-plus:free +color: "#3B82F6" +--- + +# Status Command + +Check current pipeline status for an issue. + +## Usage + +``` +/status +``` + +## Output + +``` +📊 Issue #42 Pipeline Status + +Current State: implementing +Current Agent: @LeadDeveloper + +Progress: +✅ requirement-refiner (completed, score: 9) +✅ history-miner (completed, score: 8) +✅ system-analyst (completed, score: 8) +✅ sdet-engineer (completed, tests written) +🔄 lead-developer (in progress) + +Next Steps: +1. Complete implementation +2. Code review by @CodeSkeptic +3. Performance check +4. Security audit +5. Release + +Estimated Completion: 1.5h +``` \ No newline at end of file diff --git a/.kilo/kilo.jsonc b/.kilo/kilo.jsonc index 2cde485..076cf7a 100644 --- a/.kilo/kilo.jsonc +++ b/.kilo/kilo.jsonc @@ -3,5 +3,17 @@ "instructions": [".kilo/rules/*.md"], "skills": { "paths": [".kilo/skills"] + }, + "agent": { + "pipeline-runner": { + "description": "Runs agent pipeline with Gitea logging", + "mode": "subagent", + "permission": { + "read": "allow", + "write": "allow", + "bash": "allow", + "task": "allow" + } + } } } \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 73ef9a9..eae4ca4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,46 +1,186 @@ # Kilo Code Agents Reference -## Commands (Quick Actions) +This file configures AI agent behavior for the APAW project - a self-improving code pipeline with Gitea logging. -| Command | Description | Model | +## Pipeline Workflow + +The main workflow is `/pipeline` - use it to process issues through all agents automatically. + +``` +User: /pipeline 42 +Agent: Runs full pipeline for issue #42 with Gitea logging +``` + +## Commands (Slash Commands) + +| Command | Description | Usage | |---------|-------------|-------| -| `/plan` | Creates detailed task plans | ollama-cloud/qwen3-coder:480b | -| `/ask` | Answers codebase questions | openai/qwen3-32b | -| `/debug` | Analyzes and fixes bugs | ollama-cloud/gpt-oss:20b | -| `/code` | Quick code generation | ollama-cloud/qwen3-coder:480b | +| `/pipeline ` | Run full agent pipeline for issue | `/pipeline 42` | +| `/status ` | Check pipeline status for issue | `/status 42` | +| `/evaluate ` | Generate performance report | `/evaluate 42` | +| `/plan` | Creates detailed task plans | `/plan feature X` | +| `/ask` | Answers codebase questions | `/ask how does auth work` | +| `/debug` | Analyzes and fixes bugs | `/debug error in login` | +| `/code` | Quick code generation | `/code add validation` | -## Pipeline Agents +## Pipeline Agents (Subagents) -| Agent | Role | Model | -|-------|------|-------| -| `@RequirementRefiner` | Converts vague ideas to strict User Stories | ollama-cloud/kimi-k2-thinking | -| `@HistoryMiner` | Finds duplicates and past solutions in git | ollama-cloud/gpt-oss:20b | -| `@SystemAnalyst` | Designs technical specifications | qwen/qwen3.6-plus:free | -| `@SDETEngineer` | Writes tests following TDD | ollama-cloud/qwen3-coder:480b | -| `@LeadDeveloper` | Primary code writer | ollama-cloud/qwen3-coder:480b | -| `@FrontendDeveloper` | UI implementation with multimodal | ollama-cloud/kimi-k2.5 | -| `@CodeSkeptic` | Adversarial code reviewer | ollama-cloud/minimax-m2.5 | -| `@TheFixer` | Iteratively fixes bugs | ollama-cloud/minimax-m2.5 | -| `@PerformanceEngineer` | Reviews for performance issues | ollama-cloud/nemotron-3-super | -| `@SecurityAuditor` | Scans for vulnerabilities | ollama-cloud/kimi-k2.5 | -| `@ReleaseManager` | Git operations and deployments | ollama-cloud/qwen3-coder:480b | -| `@Evaluator` | Scores agent effectiveness | ollama-cloud/gpt-oss:120b | -| `@PromptOptimizer` | Improves agent prompts | qwen/qwen3.6-plus:free | -| `@ProductOwner` | Manages issue checklists | qwen/qwen3.6-plus:free | -| `@Orchestrator` | Routes tasks between agents | ollama-cloud/glm-5 | -| `@AgentArchitect` | Manages agent network per Kilo.ai spec | qwen/qwen3.6-plus:free | +These agents are invoked automatically by `/pipeline` or manually via `@mention`: -**Note:** For AgentArchitect, use `subagent_type: "system-analyst"` with prompt "You are Agent Architect..." (workaround for unsupported agent-architect type). +| Agent | Role | When Invoked | +|-------|------|--------------| +| `@requirement-refiner` | Converts ideas to User Stories | Issue status: new | +| `@history-miner` | Finds duplicates in git | Status: planned | +| `@system-analyst` | Designs specifications | Status: researching | +| `@sdet-engineer` | Writes tests (TDD) | Status: designed | +| `@lead-developer` | Implements code | Status: testing (tests fail) | +| `@frontend-developer` | UI implementation | When UI work needed | +| `@code-skeptic` | Adversarial review | Status: implementing | +| `@the-fixer` | Fixes issues | When review fails | +| `@performance-engineer` | Performance review | After code-skeptic | +| `@security-auditor` | Security audit | After performance | +| `@release-manager` | Git operations | Status: releasing | +| `@evaluator` | Scores effectiveness | Status: evaluated | +| `@prompt-optimizer` | Improves prompts | When score < 7 | -## Workflow +## Workflow State Machine ``` -[new] → HistoryMiner → [researching] → SystemAnalyst → [designing] → SDET - ↓ -[testing] → LeadDev → CodeSkeptic → [fail? TheFixer] → [pass] → Performance → Security → Release → Evaluator +[new] + ↓ requirement-refiner +[planned] + ↓ history-miner +[researching] + ↓ system-analyst +[designed] + ↓ sdet-engineer (writes failing tests) +[testing] + ↓ lead-developer (makes tests pass) +[implementing] + ↓ code-skeptic (review) +[reviewing] ──[fail]──→ [fixing] ──→ [reviewing] + ↓ [pass] +[perf-check] + ↓ performance-engineer +[security-check] + ↓ security-auditor +[releasing] + ↓ release-manager +[evaluated] + ↓ evaluator + ├── [score ≥ 7] → [completed] + └── [score < 7] → prompt-optimizer → [completed] ``` -## Architecture Documentation +## Gitea Integration -- **KILO_SPEC.md** - Complete Kilo.ai specification for agent architecture -- **agent-architect.md** - Agent management and network configuration \ No newline at end of file +### Status Labels + +Pipeline uses Gitea labels to track progress: +- `status: new` → `status: planned` → `status: researching` → ... +- Agents add/remove labels automatically + +### Performance Logging + +Each agent logs to Gitea issue comments: +```markdown +## ✅ lead-developer completed + +**Score**: 8/10 +**Duration**: 1.2h +**Files**: src/auth.ts, src/user.ts + +### Notes +- Clean implementation +- Follows existing patterns +- Tests passing +``` + +### Efficiency Tracking + +Scores saved to `.kilo/logs/efficiency_score.json`: +```json +{ + "version": "1.0", + "history": [ + { + "issue": 42, + "date": "2024-01-02T10:00:00Z", + "agents": { + "lead-developer": 8, + "code-skeptic": 7, + "the-fixer": 9 + }, + "iterations": 2, + "duration_hours": 1.5 + } + ] +} +``` + +## Manual Agent Invocation + +```typescript +// Use Task tool to invoke subagent +Task tool with: + subagent_type: "lead-developer" + prompt: "Implement authentication for issue #42" +``` + +Or via `@mention`: +``` +@lead-developer implement authentication flow +``` + +## Environment Variables + +Required for Gitea integration: +```bash +GITEA_API_URL=https://git.softuniq.eu/api/v1 +GITEA_TOKEN=your-token-here +``` + +## Self-Improvement Cycle + +1. **Pipeline runs** for each issue +2. **Evaluator scores** each agent (1-10) +3. **Low scores (<7)** trigger prompt-optimizer +4. **Prompt optimizer** analyzes failures and improves prompts +5. **New prompts** saved to `.kilo/agents/` +6. **Next run** uses improved prompts + +## Architecture Files + +| File | Purpose | +|------|---------| +| `AGENTS.md` | This file - main config | +| `.kilo/agents/*.md` | Agent definitions with prompts | +| `.kilo/commands/*.md` | Workflow commands | +| `.kilo/rules/*.md` | Custom rules loaded globally | +| `.kilo/skills/` | Skill modules | +| `src/kilocode/` | TypeScript API for programmatic use | + +## Using the TypeScript API + +```typescript +import { + PipelineRunner, + GiteaClient, + decideRouting +} from './src/kilocode/index.js' + +const runner = await createPipelineRunner({ + giteaToken: process.env.GITEA_TOKEN +}) + +await runner.run({ issueNumber: 42 }) +``` + +## Code Style + +- Use TypeScript for new files +- Follow existing patterns +- Write tests before code (TDD) +- Keep functions under 50 lines +- Use early returns +- No comments unless explicitly requested \ No newline at end of file diff --git a/README.md b/README.md index d5b7339..78078c6 100644 --- a/README.md +++ b/README.md @@ -64,18 +64,19 @@ │ │ └── global.md # Глобальные правила │ └── logs/ │ └── efficiency_score.json # История оценок -└── packages/ - └── opencode/ - └── src/ - └── kilocode/ - └── agent-manager/ # TypeScript-интеграция с KiloCode - ├── index.ts # Загрузчик конфигурации агентов - ├── workflow.ts # State Machine пайплайна - ├── router.ts # Маршрутизатор между агентами - ├── prompt-loader.ts # Динамическая загрузка промптов - ├── git-ops.ts # Git-операции (история, коммиты) - ├── evaluator.ts # Логика оценки эффективности - └── types.ts # TypeScript-типы системы +├── src/ +│ └── kilocode/ +│ ├── index.ts # Точка входа модуля +│ └── agent-manager/ # TypeScript-интеграция с KiloCode +│ ├── index.ts # Загрузчик конфигурации агентов +│ ├── workflow.ts # State Machine пайплайна +│ ├── router.ts # Маршрутизатор между агентами +│ ├── prompt-loader.ts # Динамическая загрузка промптов +│ ├── git-ops.ts # Git-операции (история, коммиты) +│ ├── evaluator.ts # Логика оценки эффективности +│ ├── gitea-client.ts # Gitea API для логирования +│ ├── pipeline-runner.ts # Оркестратор пайплайна +│ └── types.ts # TypeScript-типы системы ``` --- @@ -356,14 +357,188 @@ chore(ai-brain): optimize Lead Dev prompt based on Issue #142 failures --- +## KiloCode Workflows Integration + +Проект интегрирован с **KiloCode Workflows** (slash commands): + +### Доступные команды + +| Команда | Описание | Пример | +|---------|----------|--------| +| `/pipeline ` | Запуск полного пайплайна | `/pipeline 42` | +| `/status ` | Проверка статуса пайплайна | `/status 42` | +| `/evaluate ` | Генерация отчёта эффективности | `/evaluate 42` | +| `/plan` | Создание детального плана | `/plan feature X` | +| `/ask` | Вопросы по кодовой базе | `/ask how does auth work` | +| `/debug` | Анализ и исправление багов | `/debug error in login` | +| `/code` | Быстрая генерация кода | `/code add validation` | + +### Как использовать Pipeline + +1. Откройте проект в VS Code с плагином KiloCode +2. Создайте Issue в Gitea +3. Введите `/pipeline <номер-issue>` в чате KiloCode +4. Пайплайн автоматически: + - Получит контекст Issue + - Проверит дубликаты в git + - Маршрутизирует через агентов по статусу + - Логирует прогресс в комментарии Gitea + - Сгенерирует итоговый отчёт + +### Workflow файлы + +| Файл | Назначение | +|------|------------| +| `.kilo/commands/pipeline.md` | Основной workflow пайплайна | +| `.kilo/commands/status.md` | Проверка статуса | +| `.kilo/commands/evaluate.md` | Оценка эффективности | +| `.kilo/agents/*.md` | Определения агентов (subagents) | +| `.kilo/rules/*.md` | Правила кодирования | +| `.kilo/skills/gitea/` | Gitea integration skill | + +### Прямой вызов агентов + +Агентов можно вызывать напрямую через `@mention`: + +``` +@lead-developer implement authentication flow +@code-skeptic review the auth module +@security-auditor check for vulnerabilities +``` + +--- + ## Технический стек - **Оркестрация**: Node.js / TypeScript (Agent Manager) -- **Интеграция**: KiloCode VS Code Extension +- **Интеграция**: KiloCode VS Code Extension / Claude Code - **Версионирование**: Gitea + Git Flow -- **Язык разработки**: Go / Node.js (основные проекты) +- **Язык разработки**: TypeScript / Node.js / Go - **Тестирование**: TDD (Red-Green-Refactor) --- +## Agent Manager API + +Новый модуль `src/kilocode/` предоставляет программный API для работы с пайплайном: + +### Установка + +```bash +bun install +bun run build +``` + +### Использование + +```typescript +import { + PipelineRunner, + GiteaClient, + decideRouting, + WORKFLOW_GRAPH, + type AgentRole, + type IssueStatus +} from './src/kilocode/index.js' + +// Инициализация пайплайна +const runner = await createPipelineRunner({ + giteaToken: process.env.GITEA_TOKEN, + giteaApiUrl: 'https://git.softuniq.eu/api/v1', + efficiencyThreshold: 7, + autoLog: true +}) + +// Запуск пайплайна для Issue +const result = await runner.run({ + issueNumber: 42, + files: ['src/auth.ts', 'src/user.ts'], + testResults: { passed: 5, failed: 0 } +}) + +// Определение следующего агента +const decision = decideRouting({ + status: 'implementing', + labels: ['status: implemented'], + checklists: { completed: 3, total: 5 }, + comments: [], + files: ['src/auth.ts'] +}) + +console.log(decision.nextAgent) // 'code-skeptic' +``` + +### Gitea интеграция + +```typescript +const client = new GiteaClient({ + apiUrl: 'https://git.softuniq.eu/api/v1', + token: process.env.GITEA_TOKEN +}) + +client.setRepository('UniqueSoft', 'APAW') + +// Получить Issue +const issue = await client.getIssue(42) + +// Установить статус +await client.setStatus(42, 'implementing') + +// Добавить комментарий +await client.createComment(42, { + body: '## ✅ Implementation Complete\n\nAll tests passed.' +}) + +// Закрыть Issue +await client.closeIssue(42) +``` + +### Логирование эффективности + +```typescript +await runner.logEvaluation(42, [ + { agent: 'lead-developer', score: 8, notes: 'Clean implementation' }, + { agent: 'code-skeptic', score: 7, notes: 'Found 2 minor issues' }, + { agent: 'the-fixer', score: 9, notes: 'Fixed issues quickly', iterations: 1 } +], 2, 1.5) +``` + +--- + +## Self-Improving Pipeline + +Система автоматически логирует эффективность каждого агента в Gitea Issues: + +1. **Pipeline Runner** запускается для каждой задачи +2. Каждый агент логирует свой прогресс в комментарии Issue +3. **Evaluator** оценивает эффективность агентов (1-10) +4. **Prompt Optimizer** получает агентов с низкими оценками (<7) +5. Промпты автоматически улучшаются на основе анализа + +Журнал эффективности сохраняется в `.kilo/logs/efficiency_score.json` для аналитики. + +--- + +## Переменные окружения + +```bash +# Gitea API +GITEA_API_URL=https://git.softuniq.eu/api/v1 +GITEA_TOKEN=your-token-here +``` + +--- + +## Удаление дубликатов + +Если в проекте есть старые файлы в `packages/opencode/`, выполните: + +```bash +sudo rm -rf packages/opencode/src/kilocode/ +``` + +Код интегрирован в `src/kilocode/`. + +--- + *Разработано в рамках проекта APAW (Automatic Programmers Agent Workflow) — 2026* diff --git a/cleanup-packages.sh b/cleanup-packages.sh new file mode 100755 index 0000000..19e0bcd --- /dev/null +++ b/cleanup-packages.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Cleanup script to remove duplicate files in packages/opencode +# The agent-manager code is now integrated into src/kilocode/ +# Run with: sudo ./cleanup-packages.sh + +echo "Removing duplicate files from packages/opencode..." + +# Remove the old location (files are now in src/kilocode/agent-manager/) +rm -rf /opt/Projects/APAW/packages/opencode/src/kilocode/ + +# Remove empty directories +rmdir /opt/Projects/APAW/packages/opencode/src/ 2>/dev/null || true +rmdir /opt/Projects/APAW/packages/opencode/ 2>/dev/null || true +rmdir /opt/Projects/APAW/packages/ 2>/dev/null || true + +echo "Cleanup complete!" +echo "" +echo "Agent manager is now located at:" +echo " src/kilocode/agent-manager/ - Core modules" +echo " src/kilocode/index.ts - Entry point" +echo "" +echo "Usage:" +echo " import { PipelineRunner, GiteaClient } from './src/kilocode/index.js'" \ No newline at end of file diff --git a/fix-permissions.sh b/fix-permissions.sh index c32cbef..da9c2e1 100755 --- a/fix-permissions.sh +++ b/fix-permissions.sh @@ -2,5 +2,17 @@ # Fix permissions for root-owned files # Run with: sudo ./fix-permissions.sh -chown -R swp:swp /opt/Projects/APAW/packages/opencode/src/kilocode/agent-manager/ -echo "Permissions fixed" \ No newline at end of file +echo "Fixing permissions..." + +# Fix ownership for all project directories +chown -R swp:swp /opt/Projects/APAW/packages/ 2>/dev/null || true +chown -R swp:swp /opt/Projects/APAW/src/ 2>/dev/null || true +chown -R swp:swp /opt/Projects/APAW/.kilo/ 2>/dev/null || true +chown swp:swp /opt/Projects/APAW/*.sh 2>/dev/null || true +chown swp:swp /opt/Projects/APAW/package.json 2>/dev/null || true +chown swp:swp /opt/Projects/APAW/tsconfig.json 2>/dev/null || true + +# Make scripts executable +chmod +x /opt/Projects/APAW/*.sh 2>/dev/null || true + +echo "Permissions fixed!" \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..fa1a084 --- /dev/null +++ b/package.json @@ -0,0 +1,46 @@ +{ + "name": "apaw", + "version": "1.0.0", + "description": "Self-improving code pipeline with agent management and Gitea logging", + "type": "module", + "main": "./dist/kilocode/index.js", + "types": "./dist/kilocode/index.d.ts", + "exports": { + ".": { + "import": "./dist/kilocode/index.js", + "types": "./dist/kilocode/index.d.ts" + }, + "./agent-manager": { + "import": "./dist/kilocode/agent-manager/index.js", + "types": "./dist/kilocode/agent-manager/index.d.ts" + } + }, + "scripts": { + "build": "tsc", + "dev": "tsc --watch", + "clean": "rm -rf dist", + "typecheck": "tsc --noEmit", + "test": "bun test" + }, + "dependencies": { + "zod": "^3.24.1" + }, + "devDependencies": { + "@types/bun": "^1.1.6", + "@types/node": "^20.10.0", + "typescript": "^5.4.5" + }, + "keywords": [ + "agent", + "pipeline", + "workflow", + "gitea", + "automation", + "self-improving", + "kilocode" + ], + "license": "MIT", + "workspaces": [ + ".kilo" + ] +} \ No newline at end of file diff --git a/packages/opencode/src/kilocode/agent-manager/evaluator.ts b/src/kilocode/agent-manager/evaluator.ts similarity index 97% rename from packages/opencode/src/kilocode/agent-manager/evaluator.ts rename to src/kilocode/agent-manager/evaluator.ts index 9d154be..0a045ee 100644 --- a/packages/opencode/src/kilocode/agent-manager/evaluator.ts +++ b/src/kilocode/agent-manager/evaluator.ts @@ -1,4 +1,5 @@ -// kilocode_change - new file +// kilocode_change - integrated module +// Evaluator - scores agent performance import type { AgentRole } from "./index" import { saveEfficiencyScore } from "./prompt-loader" diff --git a/packages/opencode/src/kilocode/agent-manager/git-ops.ts b/src/kilocode/agent-manager/git-ops.ts similarity index 69% rename from packages/opencode/src/kilocode/agent-manager/git-ops.ts rename to src/kilocode/agent-manager/git-ops.ts index 657da62..4844aea 100644 --- a/packages/opencode/src/kilocode/agent-manager/git-ops.ts +++ b/src/kilocode/agent-manager/git-ops.ts @@ -1,6 +1,7 @@ -// kilocode_change - new file +// kilocode_change - integrated module +// Git operations using spawn API -import { $ } from "bun" +import { spawn } from "child_process" export interface CommitInfo { hash: string @@ -15,15 +16,45 @@ export interface IssueReference { action: "closed" | "fixed" | "references" | "related" } +async function execGit(args: string[]): Promise { + return new Promise((resolve, reject) => { + const process = spawn("git", args, { cwd: process.cwd() }) + + let stdout = "" + let stderr = "" + + process.stdout.on("data", (data) => { + stdout += data.toString() + }) + + process.stderr.on("data", (data) => { + stderr += data.toString() + }) + + process.on("close", (code) => { + if (code === 0) { + resolve(stdout) + } else { + reject(new Error(`Git command failed: git ${args.join(" ")}\n${stderr}`)) + } + }) + + process.on("error", (err) => { + reject(err) + }) + }) +} + export async function gitLog(since?: string, until?: string, limit = 50): Promise { - const sinceArg = since ? `--since="${since}"` : "" - const untilArg = until ? `--until="${until}"` : "" - - const format = '%H%n%an%n%ad%n%s%n---' - const cmd = `git log ${sinceArg} ${untilArg} -n ${limit} --pretty=format:"${format}" --name-only` - + const args = ["log"] + if (since) args.push(`--since=${since}`) + if (until) args.push(`--until=${until}`) + args.push("-n", String(limit)) + args.push("--pretty=format:%H%n%an%n%ad%n%s%n---") + args.push("--name-only") + try { - const result = await $`git log ${sinceArg} ${untilArg} -n ${limit} --pretty=format:${format} --name-only`.text() + const result = await execGit(args) return parseGitLog(result) } catch (err) { return [] @@ -32,7 +63,11 @@ export async function gitLog(since?: string, until?: string, limit = 50): Promis export async function searchCommits(query: string): Promise { try { - const result = await $`git log --all --grep="${query}" --pretty=format:"%H%n%an%n%ad%n%s%n---" --name-only`.text() + const result = await execGit([ + "log", "--all", `--grep=${query}`, + "--pretty=format:%H%n%an%n%ad%n%s%n---", + "--name-only" + ]) return parseGitLog(result) } catch (err) { return [] @@ -41,7 +76,11 @@ export async function searchCommits(query: string): Promise { export async function getFileHistory(filepath: string, limit = 20): Promise { try { - const result = await $`git log -n ${limit} --pretty=format:"%H%n%an%n%ad%n%s%n---" -- ${filepath}`.text() + const result = await execGit([ + "log", "-n", String(limit), + "--pretty=format:%H%n%an%n%ad%n%s%n---", + "--", filepath + ]) return parseGitLog(result) } catch (err) { return [] @@ -50,7 +89,9 @@ export async function getFileHistory(filepath: string, limit = 20): Promise { try { - const result = await $`git blame --line-porcelain ${filepath}`.text() + const result = await execGit([ + "blame", "--line-porcelain", filepath + ]) return parseBlame(result) } catch (err) { return [] @@ -78,7 +119,7 @@ export async function findRelatedIssues(keyword: string): Promise { try { - await $`git log --all --grep="${message}" -n 1`.quiet() + await execGit(["log", "--all", `--grep=${message}`, "-n", "1"]) return true } catch (err) { return false diff --git a/src/kilocode/agent-manager/gitea-client.ts b/src/kilocode/agent-manager/gitea-client.ts new file mode 100644 index 0000000..a94aa10 --- /dev/null +++ b/src/kilocode/agent-manager/gitea-client.ts @@ -0,0 +1,259 @@ +// kilocode_change - integrated module +// Gitea API client for logging agent performance + +const GITEA_API_URL = process.env.GITEA_API_URL || "https://git.softuniq.eu/api/v1" +const GITEA_TOKEN = process.env.GITEA_TOKEN || "" + +export interface GiteaConfig { + apiUrl: string + token: string + owner: string + repo: string +} + +export interface IssueComment { + body: string + created_at?: string + updated_at?: string +} + +export interface Issue { + number: number + title: string + body: string + state: "open" | "closed" + labels: Array<{ name: string; color: string }> + assignees: Array<{ login: string }> + comments: number + created_at: string + updated_at: string +} + +export interface CreateIssueOptions { + title: string + body: string + labels?: string[] + assignees?: string[] +} + +export interface CreateCommentOptions { + body: string +} + +export class GiteaClient { + private baseUrl: string + private token: string + private owner: string + private repo: string + + constructor(config?: Partial) { + this.baseUrl = config?.apiUrl || GITEA_API_URL + this.token = config?.token || GITEA_TOKEN + this.owner = config?.owner || "" + this.repo = config?.repo || "" + } + + setRepository(owner: string, repo: string): void { + this.owner = owner + this.repo = repo + } + + private async request( + method: string, + path: string, + body?: unknown + ): Promise { + const url = `${this.baseUrl}${path}` + + const headers: Record = { + "Accept": "application/json", + "Content-Type": "application/json", + } + + if (this.token) { + headers["Authorization"] = `token ${this.token}` + } + + const response = await fetch(url, { + method, + headers, + body: body ? JSON.stringify(body) : undefined, + }) + + if (!response.ok) { + const error = await response.text() + throw new Error(`Gitea API error: ${response.status} - ${error}`) + } + + return response.json() + } + + async getIssue(issueNumber: number): Promise { + return this.request( + "GET", + `/repos/${this.owner}/${this.repo}/issues/${issueNumber}` + ) + } + + async createIssue(options: CreateIssueOptions): Promise { + return this.request( + "POST", + `/repos/${this.owner}/${this.repo}/issues`, + options + ) + } + + async addLabel(issueNumber: number, labelId: number): Promise { + await this.request( + "POST", + `/repos/${this.owner}/${this.repo}/issues/${issueNumber}/labels`, + { labels: [labelId] } + ) + } + + async removeLabel(issueNumber: number, labelId: number): Promise { + await this.request( + "DELETE", + `/repos/${this.owner}/${this.repo}/issues/${issueNumber}/labels/${labelId}` + ) + } + + async createComment(issueNumber: number, options: CreateCommentOptions): Promise<{ id: number; body: string }> { + return this.request( + "POST", + `/repos/${this.owner}/${this.repo}/issues/${issueNumber}/comments`, + options + ) + } + + async getComments(issueNumber: number): Promise { + return this.request( + "GET", + `/repos/${this.owner}/${this.repo}/issues/${issueNumber}/comments` + ) + } + + async updateComment(issueNumber: number, commentId: number, body: string): Promise { + await this.request( + "PATCH", + `/repos/${this.owner}/${this.repo}/issues/comments/${commentId}`, + { body } + ) + } + + async closeIssue(issueNumber: number): Promise { + return this.request( + "PATCH", + `/repos/${this.owner}/${this.repo}/issues/${issueNumber}`, + { state: "closed" } + ) + } + + async reopenIssue(issueNumber: number): Promise { + return this.request( + "PATCH", + `/repos/${this.owner}/${this.repo}/issues/${issueNumber}`, + { state: "open" } + ) + } + + async getStatusLabels(issueNumber: number): Promise { + const issue = await this.getIssue(issueNumber) + return issue.labels + .filter(l => l.name.startsWith("status:")) + .map(l => l.name) + } + + async setStatus(issueNumber: number, status: string): Promise { + const statusLabel = `status: ${status}` + + const allLabels = await this.request>( + "GET", + `/repos/${this.owner}/${this.repo}/labels` + ) + + const statusLabels = allLabels.filter(l => l.name.startsWith("status:")) + for (const label of statusLabels) { + try { + await this.removeLabel(issueNumber, label.id) + } catch { + // Label might not be on issue + } + } + + const targetLabel = allLabels.find(l => l.name === statusLabel) + if (targetLabel) { + await this.addLabel(issueNumber, targetLabel.id) + } + } +} + +export async function logAgentPerformance( + client: GiteaClient, + issueNumber: number, + agentName: string, + score: number, + notes: string +): Promise { + const comment = `## Agent Performance Log + +| Metric | Value | +|--------|-------| +| Agent | ${agentName} | +| Score | ${score}/10 | +| Timestamp | ${new Date().toISOString()} | + +### Notes +${notes} +` + + await client.createComment(issueNumber, { body: comment }) +} + +export async function logPipelineStep( + client: GiteaClient, + issueNumber: number, + step: string, + status: "started" | "completed" | "failed", + details?: string +): Promise { + const emoji = status === "completed" ? "✅" : status === "failed" ? "❌" : "🔄" + + const comment = `${emoji} **${step}**: ${status}${details ? `\n\n\`\`\`\n${details}\n\`\`\`` : ""}` + + await client.createComment(issueNumber, { body: comment }) +} + +export async function detectRepository(): Promise<{ owner: string; repo: string }> { + try { + const { spawn } = await import("child_process") + + return new Promise((resolve) => { + const process = spawn("git", ["remote", "get-url", "origin"], { cwd: process.cwd() }) + let stdout = "" + + process.stdout.on("data", (data) => { + stdout += data.toString() + }) + + process.on("close", () => { + // Parse URLs like: + // - git@git.softuniq.eu:UniqueSoft/APAW.git + // - https://git.softuniq.eu/UniqueSoft/APAW.git + const match = stdout.match(/[:/]([^/]+)\/([^/.]+)/) + + if (match) { + resolve({ owner: match[1], repo: match[2] }) + } else { + resolve({ owner: "", repo: "" }) + } + }) + + process.on("error", () => { + resolve({ owner: "", repo: "" }) + }) + }) + } catch { + return { owner: "", repo: "" } + } +} \ No newline at end of file diff --git a/packages/opencode/src/kilocode/agent-manager/index.ts b/src/kilocode/agent-manager/index.ts similarity index 96% rename from packages/opencode/src/kilocode/agent-manager/index.ts rename to src/kilocode/agent-manager/index.ts index 5070492..3492f57 100644 --- a/packages/opencode/src/kilocode/agent-manager/index.ts +++ b/src/kilocode/agent-manager/index.ts @@ -1,4 +1,5 @@ -// kilocode_change - new file +// kilocode_change - integrated module +// Agent manager - loads configs, manages workflow import { readFile, readdir } from "fs/promises" import { join } from "path" diff --git a/src/kilocode/agent-manager/pipeline-runner.ts b/src/kilocode/agent-manager/pipeline-runner.ts new file mode 100644 index 0000000..0eb3cf8 --- /dev/null +++ b/src/kilocode/agent-manager/pipeline-runner.ts @@ -0,0 +1,257 @@ +// kilocode_change - integrated module +// Pipeline runner - orchestrates agent workflow with Gitea logging + +import type { AgentRole } from "./index" +import { decideRouting, formatAgentTag, type IssueContext, type RoutingDecision } from "./router" +import { type IssueStatus } from "./workflow" +import { + saveEfficiencyScore, + type EfficiencyScore, + hasLowScore, + findPromptOptimizationTargets +} from "./prompt-loader" +import { + calculateOverallScore, + generateRecommendations, + type AgentPerformance, + type EvaluationResult +} from "./evaluator" +import { + GiteaClient, + logPipelineStep, + logAgentPerformance, + detectRepository +} from "./gitea-client" + +export interface PipelineConfig { + giteaToken?: string + giteaApiUrl?: string + efficiencyThreshold?: number + autoLog?: boolean +} + +export interface PipelineRunOptions { + issueNumber: number + initialStatus?: IssueStatus + files?: string[] + testResults?: { passed: number; failed: number } +} + +export interface PipelineResult { + success: boolean + finalAgent: AgentRole | null + finalStatus: string + agentsUsed: AgentRole[] + totalSteps: number + errors: string[] +} + +export class PipelineRunner { + private client: GiteaClient + private efficiencyThreshold: number + private autoLog: boolean + private initialized: boolean = false + + constructor(config: PipelineConfig = {}) { + this.client = new GiteaClient({ + token: config.giteaToken, + apiUrl: config.giteaApiUrl, + }) + this.efficiencyThreshold = config.efficiencyThreshold ?? 7 + this.autoLog = config.autoLog ?? true + } + + async initialize(): Promise { + if (this.initialized) return + + const { owner, repo } = await detectRepository() + this.client.setRepository(owner, repo) + this.initialized = true + } + + async run(options: PipelineRunOptions): Promise { + await this.initialize() + + const agentsUsed: AgentRole[] = [] + const errors: string[] = [] + let currentStatus: IssueStatus = options.initialStatus ?? "new" + let currentAgent: AgentRole | null = null + let steps = 0 + const maxSteps = 20 // Prevent infinite loops + + let ctx: IssueContext = await this.buildIssueContext(options) + + while (steps < maxSteps) { + steps++ + + const decision = decideRouting(ctx) + + if (!decision.nextAgent) { + break + } + + currentAgent = decision.nextAgent + agentsUsed.push(currentAgent) + + if (this.autoLog) { + await logPipelineStep( + this.client, + options.issueNumber, + `${formatAgentTag(currentAgent)}`, + "started", + decision.instructions + ) + } + + currentStatus = decision.status as IssueStatus + await this.client.setStatus(options.issueNumber, currentStatus) + + ctx = await this.buildIssueContext(options) + } + + return { + success: errors.length === 0, + finalAgent: currentAgent, + finalStatus: currentStatus, + agentsUsed, + totalSteps: steps, + errors, + } + } + + private async buildIssueContext(options: PipelineRunOptions): Promise { + const issue = await this.client.getIssue(options.issueNumber) + const comments = await this.client.getComments(options.issueNumber) + + return { + status: issue.labels.find(l => l.name.startsWith("status:"))?.name.replace("status: ", "") ?? "new", + labels: issue.labels.map(l => l.name), + checklists: this.parseChecklists(issue.body), + comments: comments.map(c => c.body), + files: options.files ?? [], + testResults: options.testResults, + } + } + + private parseChecklists(body: string): { completed: number; total: number } { + const lines = body.split("\n") + const checkItems = lines.filter(l => l.match(/- \[[ x]\]/i)) + const completed = checkItems.filter(l => l.match(/- \[x\]/i)).length + + return { completed, total: checkItems.length } + } + + async logEvaluation( + issueNumber: number, + performances: AgentPerformance[], + iterations: number, + durationHours: number + ): Promise { + await this.initialize() + + const agents: Record = {} + for (const perf of performances) { + agents[perf.agent] = perf.score + } + + const result: EvaluationResult = { + issue: issueNumber, + date: new Date().toISOString(), + agents, + iterations, + duration_hours: durationHours, + summary: calculateOverallScore(performances).toString(), + recommendations: generateRecommendations({ + issue: issueNumber, + date: new Date().toISOString(), + agents, + iterations, + duration_hours: durationHours, + summary: "", + recommendations: [], + }), + } + + await saveEfficiencyScore({ + issue: result.issue, + date: result.date, + agents: result.agents, + iterations: result.iterations, + duration_hours: result.duration_hours, + }) + + if (this.autoLog) { + const overallScore = calculateOverallScore(performances) + const scoreEmoji = overallScore >= 8 ? "🟢" : overallScore >= 5 ? "🟡" : "🔴" + + let comment = `## ${scoreEmoji} Pipeline Evaluation Report + +**Issue**: #${issueNumber} +**Overall Score**: ${overallScore}/10 +**Duration**: ${durationHours.toFixed(1)}h +**Iterations**: ${iterations} + +### Agent Scores + +| Agent | Score | +|-------|-------| +` + for (const perf of performances) { + const emoji = perf.score >= 8 ? "🟢" : perf.score >= 5 ? "🟡" : "🔴" + comment += `| ${emoji} ${perf.agent} | ${perf.score}/10 |\n` + } + + if (result.recommendations.length > 0) { + comment += `\n### Recommendations\n\n` + for (const rec of result.recommendations) { + comment += `- ${rec}\n` + } + } + + await this.client.createComment(issueNumber, { body: comment }) + + const lowScorers = performances.filter(p => p.score < this.efficiencyThreshold) + if (lowScorers.length > 0) { + const targets = lowScorers.map(p => `@${p.agent}`).join(", ") + await this.client.createComment(issueNumber, { + body: `⚠️ **Prompt Optimization Needed**\n\nThe following agents scored below ${this.efficiencyThreshold}/10: ${targets}\n\nConsider running prompt optimization after this issue is closed.` + }) + } + } + } + + async checkForDuplicates(issueNumber: number, keywords: string[]): Promise<{ + hasDuplicates: boolean + relatedIssues: number[] + }> { + await this.initialize() + + const recentComments = await this.client.getComments(issueNumber) + const minedIssues: number[] = [] + + for (const keyword of keywords) { + for (const comment of recentComments) { + const matches = comment.body.matchAll(/#(\d+)/g) + for (const match of matches) { + const num = parseInt(match[1], 10) + if (num !== issueNumber && !minedIssues.includes(num)) { + minedIssues.push(num) + } + } + } + } + + return { + hasDuplicates: minedIssues.length > 0, + relatedIssues: minedIssues, + } + } +} + +export async function createPipelineRunner(config?: PipelineConfig): Promise { + const runner = new PipelineRunner(config) + await runner.initialize() + return runner +} + +export { GiteaClient } \ No newline at end of file diff --git a/packages/opencode/src/kilocode/agent-manager/prompt-loader.ts b/src/kilocode/agent-manager/prompt-loader.ts similarity index 94% rename from packages/opencode/src/kilocode/agent-manager/prompt-loader.ts rename to src/kilocode/agent-manager/prompt-loader.ts index 38e0727..ad57ab6 100644 --- a/packages/opencode/src/kilocode/agent-manager/prompt-loader.ts +++ b/src/kilocode/agent-manager/prompt-loader.ts @@ -1,4 +1,5 @@ -// kilocode_change - new file +// kilocode_change - integrated module +// Prompt loader with efficiency logging import { readFile, writeFile, readdir, mkdir } from "fs/promises" import { join, dirname } from "path" @@ -9,7 +10,7 @@ const AGENTS_DIR = ".kilo/agent" const LOGS_DIR = ".kilo/logs" const EFFICIENCY_FILE = "efficiency_score.json" -interface EfficiencyScore { +export interface EfficiencyScore { issue: number date: string agents: Record @@ -17,7 +18,7 @@ interface EfficiencyScore { duration_hours: number } -interface EfficiencyLog { +export interface EfficiencyLog { version: string history: EfficiencyScore[] } @@ -64,7 +65,7 @@ export async function saveEfficiencyScore(score: EfficiencyScore): Promise await writeFile(logPath, JSON.stringify(log, null, 2), "utf-8") } -export async function hasLowScore(score: EfficiencyScore, threshold = 7): boolean { +export async function hasLowScore(score: EfficiencyScore, threshold = 7): Promise { const lowScores = Object.entries(score.agents) .filter(([_, s]) => s < threshold) .map(([agent, _]) => agent) @@ -92,7 +93,6 @@ export async function initializeAgentDirectory(): Promise { await ensureDir(agentsDir) await ensureDir(logsDir) - // Initialize efficiency log if it doesn't exist const logPath = join(logsDir, EFFICIENCY_FILE) if (!existsSync(logPath)) { const initial: EfficiencyLog = { version: "1.0", history: [] } diff --git a/packages/opencode/src/kilocode/agent-manager/router.ts b/src/kilocode/agent-manager/router.ts similarity index 98% rename from packages/opencode/src/kilocode/agent-manager/router.ts rename to src/kilocode/agent-manager/router.ts index 37a6d83..b6ea119 100644 --- a/packages/opencode/src/kilocode/agent-manager/router.ts +++ b/src/kilocode/agent-manager/router.ts @@ -1,4 +1,5 @@ -// kilocode_change - new file +// kilocode_change - integrated module +// Router - decides next agent based on issue context import type { AgentRole } from "./index" import { getNextAgent, getStatusForAgent } from "./workflow" diff --git a/packages/opencode/src/kilocode/agent-manager/types.ts b/src/kilocode/agent-manager/types.ts similarity index 52% rename from packages/opencode/src/kilocode/agent-manager/types.ts rename to src/kilocode/agent-manager/types.ts index c837128..b682dfa 100644 --- a/packages/opencode/src/kilocode/agent-manager/types.ts +++ b/src/kilocode/agent-manager/types.ts @@ -1,8 +1,11 @@ -// kilocode_change - new file +// kilocode_change - integrated module +// Typings re-export export type { AgentRole, AgentConfig, WorkflowTransition, WorkflowState } from "./index" -export type { IssueStatus } from "./workflow" +export type { IssueStatus, WorkflowNode } from "./workflow" export type { RoutingDecision, IssueContext } from "./router" export type { EfficiencyScore, EfficiencyLog } from "./prompt-loader" +export type { AgentPerformance, EvaluationResult } from "./evaluator" export type { CommitInfo, IssueReference } from "./git-ops" -export type { AgentPerformance, EvaluationResult } from "./evaluator" \ No newline at end of file +export type { GiteaConfig, Issue, IssueComment, CreateIssueOptions } from "./gitea-client" +export type { PipelineConfig, PipelineRunOptions, PipelineResult } from "./pipeline-runner" \ No newline at end of file diff --git a/packages/opencode/src/kilocode/agent-manager/workflow.ts b/src/kilocode/agent-manager/workflow.ts similarity index 97% rename from packages/opencode/src/kilocode/agent-manager/workflow.ts rename to src/kilocode/agent-manager/workflow.ts index 30d0fd4..924c02e 100644 --- a/packages/opencode/src/kilocode/agent-manager/workflow.ts +++ b/src/kilocode/agent-manager/workflow.ts @@ -1,4 +1,5 @@ -// kilocode_change - new file +// kilocode_change - integrated module +// Workflow graph and state transitions import type { AgentRole } from "./index" diff --git a/src/kilocode/index.ts b/src/kilocode/index.ts new file mode 100644 index 0000000..846ea70 --- /dev/null +++ b/src/kilocode/index.ts @@ -0,0 +1,111 @@ +// kilocode_change - integrated module +// Main entry point for agent-manager + +// Types +export type { + AgentRole, + AgentConfig, + WorkflowTransition, + WorkflowState +} from "./agent-manager/index" +export type { + EfficiencyScore, + EfficiencyLog +} from "./agent-manager/prompt-loader" +export type { + IssueStatus, + WorkflowNode +} from "./agent-manager/workflow" +export type { + RoutingDecision, + IssueContext +} from "./agent-manager/router" +export type { + AgentPerformance, + EvaluationResult +} from "./agent-manager/evaluator" +export type { + CommitInfo, + IssueReference +} from "./agent-manager/git-ops" +export type { + GiteaConfig, + Issue, + IssueComment, + CreateIssueOptions +} from "./agent-manager/gitea-client" +export type { + PipelineConfig, + PipelineRunOptions, + PipelineResult +} from "./agent-manager/pipeline-runner" + +// Agent Manager functions +export { + loadAgentConfig, + loadAllAgents, + loadRules, + loadFullSystemPrompt +} from "./agent-manager/index" + +// Prompt Loader functions +export { + loadPrompt, + savePrompt, + loadEfficiencyLog, + saveEfficiencyScore, + hasLowScore, + findPromptOptimizationTargets, + initializeAgentDirectory, + listAvailableAgents, +} from "./agent-manager/prompt-loader" + +// Workflow constants and functions +export { + WORKFLOW_GRAPH, + STATUS_LABELS, + AGENT_BY_STATUS, + NEXT_AGENT_AFTER, + getNextAgent, + getStatusForAgent, +} from "./agent-manager/workflow" + +// Router functions +export { + decideRouting, + formatAgentTag, + parseAgentTag, +} from "./agent-manager/router" + +// Evaluator functions +export { + calculateOverallScore, + detectPatterns, + generateRecommendations, + saveEvaluation, + formatEvaluationReport, +} from "./agent-manager/evaluator" + +// Git operations +export { + gitLog, + searchCommits, + getFileHistory, + blameFile, + findRelatedIssues, + hasCommitWithMessage, +} from "./agent-manager/git-ops" + +// Gitea Client +export { + GiteaClient, + logAgentPerformance, + logPipelineStep, + detectRepository, +} from "./agent-manager/gitea-client" + +// Pipeline Runner +export { + PipelineRunner, + createPipelineRunner, +} from "./agent-manager/pipeline-runner" \ No newline at end of file diff --git a/src/kilocode/scripts/run-pipeline.ts b/src/kilocode/scripts/run-pipeline.ts new file mode 100644 index 0000000..d21edf1 --- /dev/null +++ b/src/kilocode/scripts/run-pipeline.ts @@ -0,0 +1,58 @@ +#!/usr/bin/env bun +// Pipeline runner script +// Usage: bun run src/kilocode/scripts/run-pipeline.ts --issue 42 + +import { + createPipelineRunner, + loadAllAgents, + type AgentRole +} from '../index.js' + +const args = process.argv.slice(2) +const issueArg = args.find(a => a.startsWith('--issue=')) +const issueNumber = issueArg ? parseInt(issueArg.split('=')[1], 10) : null + +if (!issueNumber) { + console.error('Usage: bun run run-pipeline.ts --issue=') + process.exit(1) +} + +async function main() { + console.log(`🚀 Starting pipeline for issue #${issueNumber}`) + + try { + // Load available agents + const agents = await loadAllAgents() + console.log(`📋 Loaded ${agents.size} agent configurations`) + + // Create pipeline runner + const runner = await createPipelineRunner({ + efficiencyThreshold: 7, + autoLog: true + }) + + // Run pipeline + const result = await runner.run({ + issueNumber, + files: [] + }) + + console.log('\n📊 Pipeline Result:') + console.log(` Success: ${result.success}`) + console.log(` Final Status: ${result.finalStatus}`) + console.log(` Agents Used: ${result.agentsUsed.join(' → ')}`) + console.log(` Total Steps: ${result.totalSteps}`) + + if (result.errors.length > 0) { + console.log('\n❌ Errors:') + result.errors.forEach(e => console.log(` - ${e}`)) + } + + process.exit(result.success ? 0 : 1) + } catch (error) { + console.error('Pipeline error:', error) + process.exit(1) + } +} + +main() \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..8dd2122 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "resolveJsonModule": true, + "isolatedModules": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "allowImportingTsExtensions": false, + "rewriteRelativeImportExtensions": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} \ No newline at end of file