mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-12 03:27:47 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
238c7b9a13 | ||
|
|
0986fa82ee | ||
|
|
a989ce343c | ||
|
|
abe0839249 | ||
|
|
d75c973f32 | ||
|
|
e7f329940b | ||
|
|
0fc5eaaa2d | ||
|
|
420eb857ff | ||
|
|
661656c587 | ||
|
|
ed4b088631 | ||
|
|
55a574280a | ||
|
|
8f05626075 | ||
|
|
4395c5785d | ||
|
|
b0d7a09ff2 |
@@ -1,209 +1,47 @@
|
|||||||
{
|
{
|
||||||
"name": "claude-code-dev-workflows",
|
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
||||||
|
"name": "myclaude",
|
||||||
|
"version": "5.6.1",
|
||||||
|
"description": "Professional multi-agent development workflows with OmO orchestration, Requirements-Driven and BMAD methodologies",
|
||||||
"owner": {
|
"owner": {
|
||||||
"name": "Claude Code Dev Workflows",
|
"name": "cexll",
|
||||||
"email": "contact@example.com",
|
"email": "evanxian9@gmail.com"
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"metadata": {
|
|
||||||
"description": "Professional multi-agent development workflows with Requirements-Driven and BMAD methodologies, featuring 16+ specialized agents and 12+ commands",
|
|
||||||
"version": "1.0.0"
|
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
"name": "requirements-driven-development",
|
"name": "omo",
|
||||||
"source": "./requirements-driven-workflow/",
|
"description": "Multi-agent orchestration for code analysis, bug investigation, fix planning, and implementation with intelligent routing to specialized agents",
|
||||||
"description": "Streamlined requirements-driven development workflow with 90% quality gates for practical feature implementation",
|
"version": "5.6.1",
|
||||||
"version": "1.0.0",
|
"source": "./skills/omo",
|
||||||
"author": {
|
"category": "development"
|
||||||
"name": "Claude Code Dev Workflows",
|
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"requirements",
|
|
||||||
"workflow",
|
|
||||||
"automation",
|
|
||||||
"quality-gates",
|
|
||||||
"feature-development",
|
|
||||||
"agile",
|
|
||||||
"specifications"
|
|
||||||
],
|
|
||||||
"category": "workflows",
|
|
||||||
"strict": false,
|
|
||||||
"commands": [
|
|
||||||
"./commands/requirements-pilot.md"
|
|
||||||
],
|
|
||||||
"agents": [
|
|
||||||
"./agents/requirements-generate.md",
|
|
||||||
"./agents/requirements-code.md",
|
|
||||||
"./agents/requirements-testing.md",
|
|
||||||
"./agents/requirements-review.md"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bmad-agile-workflow",
|
"name": "dev",
|
||||||
"source": "./bmad-agile-workflow/",
|
"description": "Lightweight development workflow with requirements clarification, parallel codex execution, and mandatory 90% test coverage",
|
||||||
|
"version": "5.6.1",
|
||||||
|
"source": "./dev-workflow",
|
||||||
|
"category": "development"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "requirements",
|
||||||
|
"description": "Requirements-driven development workflow with quality gates for practical feature implementation",
|
||||||
|
"version": "5.6.1",
|
||||||
|
"source": "./requirements-driven-workflow",
|
||||||
|
"category": "development"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "bmad",
|
||||||
"description": "Full BMAD agile workflow with role-based agents (PO, Architect, SM, Dev, QA) and interactive approval gates",
|
"description": "Full BMAD agile workflow with role-based agents (PO, Architect, SM, Dev, QA) and interactive approval gates",
|
||||||
"version": "1.0.0",
|
"version": "5.6.1",
|
||||||
"author": {
|
"source": "./bmad-agile-workflow",
|
||||||
"name": "Claude Code Dev Workflows",
|
"category": "development"
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"bmad",
|
|
||||||
"agile",
|
|
||||||
"scrum",
|
|
||||||
"product-owner",
|
|
||||||
"architect",
|
|
||||||
"developer",
|
|
||||||
"qa",
|
|
||||||
"workflow-orchestration"
|
|
||||||
],
|
|
||||||
"category": "workflows",
|
|
||||||
"strict": false,
|
|
||||||
"commands": [
|
|
||||||
"./commands/bmad-pilot.md"
|
|
||||||
],
|
|
||||||
"agents": [
|
|
||||||
"./agents/bmad-po.md",
|
|
||||||
"./agents/bmad-architect.md",
|
|
||||||
"./agents/bmad-sm.md",
|
|
||||||
"./agents/bmad-dev.md",
|
|
||||||
"./agents/bmad-qa.md",
|
|
||||||
"./agents/bmad-orchestrator.md",
|
|
||||||
"./agents/bmad-review.md"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "development-essentials",
|
"name": "dev-kit",
|
||||||
"source": "./development-essentials/",
|
|
||||||
"description": "Essential development commands for coding, debugging, testing, optimization, and documentation",
|
"description": "Essential development commands for coding, debugging, testing, optimization, and documentation",
|
||||||
"version": "1.0.0",
|
"version": "5.6.1",
|
||||||
"author": {
|
"source": "./development-essentials",
|
||||||
"name": "Claude Code Dev Workflows",
|
"category": "productivity"
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"code",
|
|
||||||
"debug",
|
|
||||||
"test",
|
|
||||||
"optimize",
|
|
||||||
"review",
|
|
||||||
"bugfix",
|
|
||||||
"refactor",
|
|
||||||
"documentation"
|
|
||||||
],
|
|
||||||
"category": "essentials",
|
|
||||||
"strict": false,
|
|
||||||
"commands": [
|
|
||||||
"./commands/code.md",
|
|
||||||
"./commands/debug.md",
|
|
||||||
"./commands/test.md",
|
|
||||||
"./commands/optimize.md",
|
|
||||||
"./commands/review.md",
|
|
||||||
"./commands/bugfix.md",
|
|
||||||
"./commands/refactor.md",
|
|
||||||
"./commands/docs.md",
|
|
||||||
"./commands/ask.md",
|
|
||||||
"./commands/think.md"
|
|
||||||
],
|
|
||||||
"agents": [
|
|
||||||
"./agents/code.md",
|
|
||||||
"./agents/bugfix.md",
|
|
||||||
"./agents/bugfix-verify.md",
|
|
||||||
"./agents/optimize.md",
|
|
||||||
"./agents/debug.md"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "codex-cli",
|
|
||||||
"source": "./skills/codex/",
|
|
||||||
"description": "Execute Codex CLI for code analysis, refactoring, and automated code changes with file references (@syntax) and structured output",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": {
|
|
||||||
"name": "Claude Code Dev Workflows",
|
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"codex",
|
|
||||||
"code-analysis",
|
|
||||||
"refactoring",
|
|
||||||
"automation",
|
|
||||||
"gpt-5",
|
|
||||||
"ai-coding"
|
|
||||||
],
|
|
||||||
"category": "essentials",
|
|
||||||
"strict": false,
|
|
||||||
"skills": [
|
|
||||||
"./SKILL.md"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "gemini-cli",
|
|
||||||
"source": "./skills/gemini/",
|
|
||||||
"description": "Execute Gemini CLI for AI-powered code analysis and generation with Google's latest Gemini models",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": {
|
|
||||||
"name": "Claude Code Dev Workflows",
|
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"gemini",
|
|
||||||
"google-ai",
|
|
||||||
"code-analysis",
|
|
||||||
"code-generation",
|
|
||||||
"ai-reasoning"
|
|
||||||
],
|
|
||||||
"category": "essentials",
|
|
||||||
"strict": false,
|
|
||||||
"skills": [
|
|
||||||
"./SKILL.md"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "dev-workflow",
|
|
||||||
"source": "./dev-workflow/",
|
|
||||||
"description": "Minimal lightweight development workflow with requirements clarification, parallel codex execution, and mandatory 90% test coverage",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": {
|
|
||||||
"name": "Claude Code Dev Workflows",
|
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"dev",
|
|
||||||
"workflow",
|
|
||||||
"codex",
|
|
||||||
"testing",
|
|
||||||
"coverage",
|
|
||||||
"concurrent",
|
|
||||||
"lightweight"
|
|
||||||
],
|
|
||||||
"category": "workflows",
|
|
||||||
"strict": false,
|
|
||||||
"commands": [
|
|
||||||
"./commands/dev.md"
|
|
||||||
],
|
|
||||||
"agents": [
|
|
||||||
"./agents/dev-plan-generator.md"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
60
CHANGELOG.md
60
CHANGELOG.md
@@ -2,6 +2,66 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [5.6.4] - 2026-01-15
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- add reasoning effort config for codex backend
|
||||||
|
- default to skip-permissions and bypass-sandbox
|
||||||
|
- add multi-agent support with yolo mode
|
||||||
|
- add omo module for multi-agent orchestration
|
||||||
|
- add intelligent backend selection based on task complexity (#61)
|
||||||
|
- v5.4.0 structured execution report (#94)
|
||||||
|
- add millisecond-precision timestamps to all log entries (#91)
|
||||||
|
- skill-install install script and security scan
|
||||||
|
- add uninstall scripts with selective module removal
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- filter codex stderr noise logs
|
||||||
|
- use config override for codex reasoning effort
|
||||||
|
- propagate SkipPermissions to parallel tasks (#113)
|
||||||
|
- add timeout for Windows process termination
|
||||||
|
- reject dash as workdir parameter (#118)
|
||||||
|
- add sleep in fake script to prevent CI race condition
|
||||||
|
- fix gemini env load
|
||||||
|
- fix omo
|
||||||
|
- fix codeagent skill TaskOutput
|
||||||
|
- 修复 Gemini init 事件 session_id 未提取的问题 (#111)
|
||||||
|
- Windows 后端退出:taskkill 结束进程树 + turn.completed 支持 (#108)
|
||||||
|
- support model parameter for all backends, auto-inject from settings (#105)
|
||||||
|
- replace setx with reg add to avoid 1024-char PATH truncation (#101)
|
||||||
|
- 移除未知事件格式的日志噪声 (#96)
|
||||||
|
- prevent duplicate PATH entries on reinstall (#95)
|
||||||
|
- Minor issues #12 and #13 - ASCII mode and performance optimization
|
||||||
|
- correct settings.json filename and bump version to v5.2.8
|
||||||
|
- allow claude backend to read env from setting.json while preventing recursion (#92)
|
||||||
|
- comprehensive security and quality improvements for PR #85 & #87 (#90)
|
||||||
|
- Improve backend termination after message and extend timeout (#86)
|
||||||
|
- Parser重复解析优化 + 严重bug修复 + PR #86兼容性 (#88)
|
||||||
|
- filter noisy stderr output from gemini backend (#83)
|
||||||
|
- 修復 wsl install.sh 格式問題 (#78)
|
||||||
|
- 修复多 backend 并行日志 PID 混乱并移除包装格式 (#74) (#76)
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- remove sisyphus agent and unused code
|
||||||
|
- streamline agent documentation and remove sisyphus
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- add OmO workflow to README and fix plugin marketplace structure
|
||||||
|
- update FAQ for default bypass/skip-permissions behavior
|
||||||
|
- 添加 FAQ 常见问题章节
|
||||||
|
- update troubleshooting with idempotent PATH commands (#95)
|
||||||
|
|
||||||
|
### 💼 Other
|
||||||
|
|
||||||
|
- add test-cases skill
|
||||||
|
- add browser skill
|
||||||
|
- BMADh和Requirements-Driven支持根据语义生成对应的文档 (#82)
|
||||||
|
- update all readme
|
||||||
|
|
||||||
## [5.2.4] - 2025-12-16
|
## [5.2.4] - 2025-12-16
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
37
README.md
37
README.md
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
[](https://www.gnu.org/licenses/agpl-3.0)
|
[](https://www.gnu.org/licenses/agpl-3.0)
|
||||||
[](https://claude.ai/code)
|
[](https://claude.ai/code)
|
||||||
[](https://github.com/cexll/myclaude)
|
[](https://github.com/cexll/myclaude)
|
||||||
|
|
||||||
> AI-powered development automation with multi-backend execution (Codex/Claude/Gemini)
|
> AI-powered development automation with multi-backend execution (Codex/Claude/Gemini)
|
||||||
|
|
||||||
@@ -35,6 +35,41 @@ python3 install.py --install-dir ~/.claude
|
|||||||
|
|
||||||
## Workflows Overview
|
## Workflows Overview
|
||||||
|
|
||||||
|
### 0. OmO Multi-Agent Orchestrator (Recommended for Complex Tasks)
|
||||||
|
|
||||||
|
**Intelligent multi-agent orchestration that routes tasks to specialized agents based on risk signals.**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/omo "analyze and fix this authentication bug"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Agent Hierarchy:**
|
||||||
|
| Agent | Role | Backend | Model |
|
||||||
|
|-------|------|---------|-------|
|
||||||
|
| `oracle` | Technical advisor | Claude | claude-opus-4-5 |
|
||||||
|
| `librarian` | External research | Claude | claude-sonnet-4-5 |
|
||||||
|
| `explore` | Codebase search | OpenCode | grok-code |
|
||||||
|
| `develop` | Code implementation | Codex | gpt-5.2 |
|
||||||
|
| `frontend-ui-ux-engineer` | UI/UX specialist | Gemini | gemini-3-pro |
|
||||||
|
| `document-writer` | Documentation | Gemini | gemini-3-flash |
|
||||||
|
|
||||||
|
**Routing Signals (Not Fixed Pipeline):**
|
||||||
|
- Code location unclear → `explore`
|
||||||
|
- External library/API → `librarian`
|
||||||
|
- Risky/multi-file change → `oracle`
|
||||||
|
- Implementation needed → `develop` / `frontend-ui-ux-engineer`
|
||||||
|
|
||||||
|
**Common Recipes:**
|
||||||
|
- Explain code: `explore`
|
||||||
|
- Small fix with known location: `develop` directly
|
||||||
|
- Bug fix, location unknown: `explore → develop`
|
||||||
|
- Cross-cutting refactor: `explore → oracle → develop`
|
||||||
|
- External API integration: `explore + librarian → oracle → develop`
|
||||||
|
|
||||||
|
**Best For:** Complex bug investigation, multi-file refactoring, architecture decisions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 1. Dev Workflow (Recommended)
|
### 1. Dev Workflow (Recommended)
|
||||||
|
|
||||||
**The primary workflow for most development tasks.**
|
**The primary workflow for most development tasks.**
|
||||||
|
|||||||
37
README_CN.md
37
README_CN.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[](https://www.gnu.org/licenses/agpl-3.0)
|
[](https://www.gnu.org/licenses/agpl-3.0)
|
||||||
[](https://claude.ai/code)
|
[](https://claude.ai/code)
|
||||||
[](https://github.com/cexll/myclaude)
|
[](https://github.com/cexll/myclaude)
|
||||||
|
|
||||||
> AI 驱动的开发自动化 - 多后端执行架构 (Codex/Claude/Gemini)
|
> AI 驱动的开发自动化 - 多后端执行架构 (Codex/Claude/Gemini)
|
||||||
|
|
||||||
@@ -30,6 +30,41 @@ python3 install.py --install-dir ~/.claude
|
|||||||
|
|
||||||
## 工作流概览
|
## 工作流概览
|
||||||
|
|
||||||
|
### 0. OmO 多智能体编排器(复杂任务推荐)
|
||||||
|
|
||||||
|
**基于风险信号智能路由任务到专业智能体的多智能体编排系统。**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/omo "分析并修复这个认证 bug"
|
||||||
|
```
|
||||||
|
|
||||||
|
**智能体层级:**
|
||||||
|
| 智能体 | 角色 | 后端 | 模型 |
|
||||||
|
|-------|------|------|------|
|
||||||
|
| `oracle` | 技术顾问 | Claude | claude-opus-4-5 |
|
||||||
|
| `librarian` | 外部研究 | Claude | claude-sonnet-4-5 |
|
||||||
|
| `explore` | 代码库搜索 | OpenCode | grok-code |
|
||||||
|
| `develop` | 代码实现 | Codex | gpt-5.2 |
|
||||||
|
| `frontend-ui-ux-engineer` | UI/UX 专家 | Gemini | gemini-3-pro |
|
||||||
|
| `document-writer` | 文档撰写 | Gemini | gemini-3-flash |
|
||||||
|
|
||||||
|
**路由信号(非固定流水线):**
|
||||||
|
- 代码位置不明确 → `explore`
|
||||||
|
- 外部库/API → `librarian`
|
||||||
|
- 高风险/多文件变更 → `oracle`
|
||||||
|
- 需要实现 → `develop` / `frontend-ui-ux-engineer`
|
||||||
|
|
||||||
|
**常用配方:**
|
||||||
|
- 解释代码:`explore`
|
||||||
|
- 位置已知的小修复:直接 `develop`
|
||||||
|
- Bug 修复,位置未知:`explore → develop`
|
||||||
|
- 跨模块重构:`explore → oracle → develop`
|
||||||
|
- 外部 API 集成:`explore + librarian → oracle → develop`
|
||||||
|
|
||||||
|
**适用场景:** 复杂 bug 调查、多文件重构、架构决策
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### 1. Dev 工作流(推荐)
|
### 1. Dev 工作流(推荐)
|
||||||
|
|
||||||
**大多数开发任务的首选工作流。**
|
**大多数开发任务的首选工作流。**
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "bmad-agile-workflow",
|
|
||||||
"source": "./",
|
|
||||||
"description": "Full BMAD agile workflow with role-based agents (PO, Architect, SM, Dev, QA) and interactive approval gates",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": {
|
|
||||||
"name": "Claude Code Dev Workflows",
|
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"bmad",
|
|
||||||
"agile",
|
|
||||||
"scrum",
|
|
||||||
"product-owner",
|
|
||||||
"architect",
|
|
||||||
"developer",
|
|
||||||
"qa",
|
|
||||||
"workflow-orchestration"
|
|
||||||
],
|
|
||||||
"category": "workflows",
|
|
||||||
"strict": false,
|
|
||||||
"commands": [
|
|
||||||
"./commands/bmad-pilot.md"
|
|
||||||
],
|
|
||||||
"agents": [
|
|
||||||
"./agents/bmad-po.md",
|
|
||||||
"./agents/bmad-architect.md",
|
|
||||||
"./agents/bmad-sm.md",
|
|
||||||
"./agents/bmad-dev.md",
|
|
||||||
"./agents/bmad-qa.md",
|
|
||||||
"./agents/bmad-orchestrator.md",
|
|
||||||
"./agents/bmad-review.md"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
9
bmad-agile-workflow/.claude-plugin/plugin.json
Normal file
9
bmad-agile-workflow/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "bmad",
|
||||||
|
"description": "Full BMAD agile workflow with role-based agents (PO, Architect, SM, Dev, QA) and interactive approval gates",
|
||||||
|
"version": "5.6.1",
|
||||||
|
"author": {
|
||||||
|
"name": "cexll",
|
||||||
|
"email": "cexll@cexll.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,9 +26,8 @@ var defaultModelsConfig = ModelsConfig{
|
|||||||
DefaultBackend: "opencode",
|
DefaultBackend: "opencode",
|
||||||
DefaultModel: "opencode/grok-code",
|
DefaultModel: "opencode/grok-code",
|
||||||
Agents: map[string]AgentModelConfig{
|
Agents: map[string]AgentModelConfig{
|
||||||
"sisyphus": {Backend: "claude", Model: "claude-sonnet-4-20250514", PromptFile: "~/.claude/skills/omo/references/sisyphus.md", Description: "Primary orchestrator"},
|
"oracle": {Backend: "claude", Model: "claude-opus-4-5-20251101", PromptFile: "~/.claude/skills/omo/references/oracle.md", Description: "Technical advisor"},
|
||||||
"oracle": {Backend: "claude", Model: "claude-sonnet-4-20250514", PromptFile: "~/.claude/skills/omo/references/oracle.md", Description: "Technical advisor"},
|
"librarian": {Backend: "claude", Model: "claude-sonnet-4-5-20250929", PromptFile: "~/.claude/skills/omo/references/librarian.md", Description: "Researcher"},
|
||||||
"librarian": {Backend: "claude", Model: "claude-sonnet-4-5-20250514", PromptFile: "~/.claude/skills/omo/references/librarian.md", Description: "Researcher"},
|
|
||||||
"explore": {Backend: "opencode", Model: "opencode/grok-code", PromptFile: "~/.claude/skills/omo/references/explore.md", Description: "Code search"},
|
"explore": {Backend: "opencode", Model: "opencode/grok-code", PromptFile: "~/.claude/skills/omo/references/explore.md", Description: "Code search"},
|
||||||
"develop": {Backend: "codex", Model: "", PromptFile: "~/.claude/skills/omo/references/develop.md", Description: "Code development"},
|
"develop": {Backend: "codex", Model: "", PromptFile: "~/.claude/skills/omo/references/develop.md", Description: "Code development"},
|
||||||
"frontend-ui-ux-engineer": {Backend: "gemini", Model: "", PromptFile: "~/.claude/skills/omo/references/frontend-ui-ux-engineer.md", Description: "Frontend engineer"},
|
"frontend-ui-ux-engineer": {Backend: "gemini", Model: "", PromptFile: "~/.claude/skills/omo/references/frontend-ui-ux-engineer.md", Description: "Frontend engineer"},
|
||||||
|
|||||||
@@ -19,9 +19,8 @@ func TestResolveAgentConfig_Defaults(t *testing.T) {
|
|||||||
wantModel string
|
wantModel string
|
||||||
wantPromptFile string
|
wantPromptFile string
|
||||||
}{
|
}{
|
||||||
{"sisyphus", "claude", "claude-sonnet-4-20250514", "~/.claude/skills/omo/references/sisyphus.md"},
|
{"oracle", "claude", "claude-opus-4-5-20251101", "~/.claude/skills/omo/references/oracle.md"},
|
||||||
{"oracle", "claude", "claude-sonnet-4-20250514", "~/.claude/skills/omo/references/oracle.md"},
|
{"librarian", "claude", "claude-sonnet-4-5-20250929", "~/.claude/skills/omo/references/librarian.md"},
|
||||||
{"librarian", "claude", "claude-sonnet-4-5-20250514", "~/.claude/skills/omo/references/librarian.md"},
|
|
||||||
{"explore", "opencode", "opencode/grok-code", "~/.claude/skills/omo/references/explore.md"},
|
{"explore", "opencode", "opencode/grok-code", "~/.claude/skills/omo/references/explore.md"},
|
||||||
{"frontend-ui-ux-engineer", "gemini", "", "~/.claude/skills/omo/references/frontend-ui-ux-engineer.md"},
|
{"frontend-ui-ux-engineer", "gemini", "", "~/.claude/skills/omo/references/frontend-ui-ux-engineer.md"},
|
||||||
{"document-writer", "gemini", "", "~/.claude/skills/omo/references/document-writer.md"},
|
{"document-writer", "gemini", "", "~/.claude/skills/omo/references/document-writer.md"},
|
||||||
@@ -69,8 +68,8 @@ func TestLoadModelsConfig_NoFile(t *testing.T) {
|
|||||||
if cfg.DefaultBackend != "opencode" {
|
if cfg.DefaultBackend != "opencode" {
|
||||||
t.Errorf("DefaultBackend = %q, want %q", cfg.DefaultBackend, "opencode")
|
t.Errorf("DefaultBackend = %q, want %q", cfg.DefaultBackend, "opencode")
|
||||||
}
|
}
|
||||||
if len(cfg.Agents) != 7 {
|
if len(cfg.Agents) != 6 {
|
||||||
t.Errorf("len(Agents) = %d, want 7", len(cfg.Agents))
|
t.Errorf("len(Agents) = %d, want 6", len(cfg.Agents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +122,8 @@ func TestLoadModelsConfig_WithFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that defaults are merged
|
// Check that defaults are merged
|
||||||
if _, ok := cfg.Agents["sisyphus"]; !ok {
|
if _, ok := cfg.Agents["oracle"]; !ok {
|
||||||
t.Error("default agent sisyphus should be merged")
|
t.Error("default agent oracle should be merged")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +188,15 @@ func TestOpencodeBackend_BuildArgs(t *testing.T) {
|
|||||||
t.Errorf("got %v, want %v", got, want)
|
t.Errorf("got %v, want %v", got, want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("stdin mode omits dash", func(t *testing.T) {
|
||||||
|
cfg := &Config{Mode: "new"}
|
||||||
|
got := backend.BuildArgs(cfg, "-")
|
||||||
|
want := []string{"run", "--format", "json"}
|
||||||
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
t.Errorf("got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpencodeBackend_Interface(t *testing.T) {
|
func TestOpencodeBackend_Interface(t *testing.T) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ func TestValidateAgentName(t *testing.T) {
|
|||||||
input string
|
input string
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{name: "simple", input: "sisyphus", wantErr: false},
|
{name: "simple", input: "develop", wantErr: false},
|
||||||
{name: "upper", input: "ABC", wantErr: false},
|
{name: "upper", input: "ABC", wantErr: false},
|
||||||
{name: "digits", input: "a1", wantErr: false},
|
{name: "digits", input: "a1", wantErr: false},
|
||||||
{name: "dash underscore", input: "a-b_c", wantErr: false},
|
{name: "dash underscore", input: "a-b_c", wantErr: false},
|
||||||
|
|||||||
@@ -204,7 +204,10 @@ func (OpencodeBackend) BuildArgs(cfg *Config, targetArg string) []string {
|
|||||||
if cfg.Mode == "resume" && cfg.SessionID != "" {
|
if cfg.Mode == "resume" && cfg.SessionID != "" {
|
||||||
args = append(args, "-s", cfg.SessionID)
|
args = append(args, "-s", cfg.SessionID)
|
||||||
}
|
}
|
||||||
args = append(args, "--format", "json", targetArg)
|
args = append(args, "--format", "json")
|
||||||
|
if targetArg != "-" {
|
||||||
|
args = append(args, targetArg)
|
||||||
|
}
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ type TaskSpec struct {
|
|||||||
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
ReasoningEffort string `json:"reasoning_effort,omitempty"`
|
||||||
Agent string `json:"agent,omitempty"`
|
Agent string `json:"agent,omitempty"`
|
||||||
PromptFile string `json:"prompt_file,omitempty"`
|
PromptFile string `json:"prompt_file,omitempty"`
|
||||||
|
SkipPermissions bool `json:"skip_permissions,omitempty"`
|
||||||
Mode string `json:"-"`
|
Mode string `json:"-"`
|
||||||
UseStdin bool `json:"-"`
|
UseStdin bool `json:"-"`
|
||||||
Context context.Context `json:"-"`
|
Context context.Context `json:"-"`
|
||||||
@@ -184,6 +185,10 @@ func parseParallelConfig(data []byte) (*ParallelConfig, error) {
|
|||||||
case "id":
|
case "id":
|
||||||
task.ID = value
|
task.ID = value
|
||||||
case "workdir":
|
case "workdir":
|
||||||
|
// Validate workdir: "-" is not a valid directory
|
||||||
|
if value == "-" {
|
||||||
|
return nil, fmt.Errorf("task block #%d has invalid workdir: '-' is not a valid directory path", taskIndex)
|
||||||
|
}
|
||||||
task.WorkDir = value
|
task.WorkDir = value
|
||||||
case "session_id":
|
case "session_id":
|
||||||
task.SessionID = value
|
task.SessionID = value
|
||||||
@@ -197,6 +202,12 @@ func parseParallelConfig(data []byte) (*ParallelConfig, error) {
|
|||||||
case "agent":
|
case "agent":
|
||||||
agentSpecified = true
|
agentSpecified = true
|
||||||
task.Agent = value
|
task.Agent = value
|
||||||
|
case "skip_permissions", "skip-permissions":
|
||||||
|
if value == "" {
|
||||||
|
task.SkipPermissions = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
task.SkipPermissions = parseBoolFlag(value, false)
|
||||||
case "dependencies":
|
case "dependencies":
|
||||||
for _, dep := range strings.Split(value, ",") {
|
for _, dep := range strings.Split(value, ",") {
|
||||||
dep = strings.TrimSpace(dep)
|
dep = strings.TrimSpace(dep)
|
||||||
@@ -417,6 +428,10 @@ func parseArgs() (*Config, error) {
|
|||||||
cfg.Task = args[2]
|
cfg.Task = args[2]
|
||||||
cfg.ExplicitStdin = (args[2] == "-")
|
cfg.ExplicitStdin = (args[2] == "-")
|
||||||
if len(args) > 3 {
|
if len(args) > 3 {
|
||||||
|
// Validate workdir: "-" is not a valid directory
|
||||||
|
if args[3] == "-" {
|
||||||
|
return nil, fmt.Errorf("invalid workdir: '-' is not a valid directory path")
|
||||||
|
}
|
||||||
cfg.WorkDir = args[3]
|
cfg.WorkDir = args[3]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -424,6 +439,10 @@ func parseArgs() (*Config, error) {
|
|||||||
cfg.Task = args[0]
|
cfg.Task = args[0]
|
||||||
cfg.ExplicitStdin = (args[0] == "-")
|
cfg.ExplicitStdin = (args[0] == "-")
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
|
// Validate workdir: "-" is not a valid directory
|
||||||
|
if args[1] == "-" {
|
||||||
|
return nil, fmt.Errorf("invalid workdir: '-' is not a valid directory path")
|
||||||
|
}
|
||||||
cfg.WorkDir = args[1]
|
cfg.WorkDir = args[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const postMessageTerminateDelay = 1 * time.Second
|
const postMessageTerminateDelay = 1 * time.Second
|
||||||
|
const forceKillWaitTimeout = 5 * time.Second
|
||||||
|
|
||||||
// commandRunner abstracts exec.Cmd for testability
|
// commandRunner abstracts exec.Cmd for testability
|
||||||
type commandRunner interface {
|
type commandRunner interface {
|
||||||
@@ -765,7 +766,7 @@ func buildCodexArgs(cfg *Config, targetArg string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if reasoningEffort := strings.TrimSpace(cfg.ReasoningEffort); reasoningEffort != "" {
|
if reasoningEffort := strings.TrimSpace(cfg.ReasoningEffort); reasoningEffort != "" {
|
||||||
args = append(args, "--reasoning-effort", reasoningEffort)
|
args = append(args, "-c", "model_reasoning_effort="+reasoningEffort)
|
||||||
}
|
}
|
||||||
|
|
||||||
args = append(args, "--skip-git-repo-check")
|
args = append(args, "--skip-git-repo-check")
|
||||||
@@ -814,6 +815,7 @@ func runCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
|
|||||||
WorkDir: taskSpec.WorkDir,
|
WorkDir: taskSpec.WorkDir,
|
||||||
Model: taskSpec.Model,
|
Model: taskSpec.Model,
|
||||||
ReasoningEffort: taskSpec.ReasoningEffort,
|
ReasoningEffort: taskSpec.ReasoningEffort,
|
||||||
|
SkipPermissions: taskSpec.SkipPermissions,
|
||||||
Backend: defaultBackendName,
|
Backend: defaultBackendName,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,6 +983,9 @@ func runCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
|
|||||||
if cfg.Backend == "gemini" {
|
if cfg.Backend == "gemini" {
|
||||||
stderrFilter = newFilteringWriter(os.Stderr, geminiNoisePatterns)
|
stderrFilter = newFilteringWriter(os.Stderr, geminiNoisePatterns)
|
||||||
stderrOut = stderrFilter
|
stderrOut = stderrFilter
|
||||||
|
} else if cfg.Backend == "codex" {
|
||||||
|
stderrFilter = newFilteringWriter(os.Stderr, codexNoisePatterns)
|
||||||
|
stderrOut = stderrFilter
|
||||||
}
|
}
|
||||||
stderrWriters = append([]io.Writer{stderrOut}, stderrWriters...)
|
stderrWriters = append([]io.Writer{stderrOut}, stderrWriters...)
|
||||||
}
|
}
|
||||||
@@ -1109,7 +1114,8 @@ func runCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
|
|||||||
waitLoop:
|
waitLoop:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case waitErr = <-waitCh:
|
case err := <-waitCh:
|
||||||
|
waitErr = err
|
||||||
break waitLoop
|
break waitLoop
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
ctxCancelled = true
|
ctxCancelled = true
|
||||||
@@ -1120,8 +1126,17 @@ waitLoop:
|
|||||||
terminated = true
|
terminated = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
waitErr = <-waitCh
|
for {
|
||||||
break waitLoop
|
select {
|
||||||
|
case err := <-waitCh:
|
||||||
|
waitErr = err
|
||||||
|
break waitLoop
|
||||||
|
case <-time.After(forceKillWaitTimeout):
|
||||||
|
if proc := cmd.Process(); proc != nil {
|
||||||
|
_ = proc.Kill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case <-messageTimerCh:
|
case <-messageTimerCh:
|
||||||
forcedAfterComplete = true
|
forcedAfterComplete = true
|
||||||
messageTimerCh = nil
|
messageTimerCh = nil
|
||||||
@@ -1135,8 +1150,17 @@ waitLoop:
|
|||||||
// Close pipes to unblock stream readers, then wait for process exit.
|
// Close pipes to unblock stream readers, then wait for process exit.
|
||||||
closeWithReason(stdout, "terminate")
|
closeWithReason(stdout, "terminate")
|
||||||
closeWithReason(stderr, "terminate")
|
closeWithReason(stderr, "terminate")
|
||||||
waitErr = <-waitCh
|
for {
|
||||||
break waitLoop
|
select {
|
||||||
|
case err := <-waitCh:
|
||||||
|
waitErr = err
|
||||||
|
break waitLoop
|
||||||
|
case <-time.After(forceKillWaitTimeout):
|
||||||
|
if proc := cmd.Process(); proc != nil {
|
||||||
|
_ = proc.Kill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case <-completeSeen:
|
case <-completeSeen:
|
||||||
completeSeenObserved = true
|
completeSeenObserved = true
|
||||||
if messageTimer != nil {
|
if messageTimer != nil {
|
||||||
|
|||||||
@@ -625,6 +625,27 @@ func TestExecutorRunCodexTaskWithContext(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("claudeSkipPermissionsPropagatesFromTaskSpec", func(t *testing.T) {
|
||||||
|
t.Setenv("CODEAGENT_SKIP_PERMISSIONS", "false")
|
||||||
|
var gotArgs []string
|
||||||
|
newCommandRunner = func(ctx context.Context, name string, args ...string) commandRunner {
|
||||||
|
gotArgs = append([]string(nil), args...)
|
||||||
|
return &execFakeRunner{
|
||||||
|
stdout: newReasonReadCloser(`{"type":"item.completed","item":{"type":"agent_message","text":"ok"}}`),
|
||||||
|
process: &execFakeProcess{pid: 15},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = closeLogger()
|
||||||
|
res := runCodexTaskWithContext(context.Background(), TaskSpec{ID: "task-skip", Task: "payload", WorkDir: ".", SkipPermissions: true}, ClaudeBackend{}, nil, false, false, 1)
|
||||||
|
if res.ExitCode != 0 || res.Error != "" {
|
||||||
|
t.Fatalf("unexpected result: %+v", res)
|
||||||
|
}
|
||||||
|
if !slices.Contains(gotArgs, "--dangerously-skip-permissions") {
|
||||||
|
t.Fatalf("expected --dangerously-skip-permissions in args, got %v", gotArgs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("missingMessage", func(t *testing.T) {
|
t.Run("missingMessage", func(t *testing.T) {
|
||||||
newCommandRunner = func(ctx context.Context, name string, args ...string) commandRunner {
|
newCommandRunner = func(ctx context.Context, name string, args ...string) commandRunner {
|
||||||
return &execFakeRunner{
|
return &execFakeRunner{
|
||||||
|
|||||||
@@ -18,6 +18,12 @@ var geminiNoisePatterns = []string{
|
|||||||
"YOLO mode is enabled",
|
"YOLO mode is enabled",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// codexNoisePatterns contains stderr patterns to filter for codex backend
|
||||||
|
var codexNoisePatterns = []string{
|
||||||
|
"ERROR codex_core::codex: needs_follow_up:",
|
||||||
|
"ERROR codex_core::skills::loader:",
|
||||||
|
}
|
||||||
|
|
||||||
// filteringWriter wraps an io.Writer and filters out lines matching patterns
|
// filteringWriter wraps an io.Writer and filters out lines matching patterns
|
||||||
type filteringWriter struct {
|
type filteringWriter struct {
|
||||||
w io.Writer
|
w io.Writer
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@@ -15,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version = "5.5.0"
|
version = "5.6.4"
|
||||||
defaultWorkdir = "."
|
defaultWorkdir = "."
|
||||||
defaultTimeout = 7200 // seconds (2 hours)
|
defaultTimeout = 7200 // seconds (2 hours)
|
||||||
defaultCoverageTarget = 90.0
|
defaultCoverageTarget = 90.0
|
||||||
@@ -32,8 +31,6 @@ const (
|
|||||||
stdoutDrainTimeout = 100 * time.Millisecond
|
stdoutDrainTimeout = 100 * time.Millisecond
|
||||||
)
|
)
|
||||||
|
|
||||||
var useASCIIMode = os.Getenv("CODEAGENT_ASCII_MODE") == "true"
|
|
||||||
|
|
||||||
// Test hooks for dependency injection
|
// Test hooks for dependency injection
|
||||||
var (
|
var (
|
||||||
stdinReader io.Reader = os.Stdin
|
stdinReader io.Reader = os.Stdin
|
||||||
@@ -45,7 +42,6 @@ var (
|
|||||||
buildCodexArgsFn = buildCodexArgs
|
buildCodexArgsFn = buildCodexArgs
|
||||||
selectBackendFn = selectBackend
|
selectBackendFn = selectBackend
|
||||||
commandContext = exec.CommandContext
|
commandContext = exec.CommandContext
|
||||||
jsonMarshal = json.Marshal
|
|
||||||
cleanupLogsFn = cleanupOldLogs
|
cleanupLogsFn = cleanupOldLogs
|
||||||
signalNotifyFn = signal.Notify
|
signalNotifyFn = signal.Notify
|
||||||
signalStopFn = signal.Stop
|
signalStopFn = signal.Stop
|
||||||
@@ -181,6 +177,7 @@ func run() (exitCode int) {
|
|||||||
backendName := defaultBackendName
|
backendName := defaultBackendName
|
||||||
model := ""
|
model := ""
|
||||||
fullOutput := false
|
fullOutput := false
|
||||||
|
skipPermissions := envFlagEnabled("CODEAGENT_SKIP_PERMISSIONS")
|
||||||
var extras []string
|
var extras []string
|
||||||
|
|
||||||
for i := 0; i < len(args); i++ {
|
for i := 0; i < len(args); i++ {
|
||||||
@@ -218,13 +215,19 @@ func run() (exitCode int) {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
model = value
|
model = value
|
||||||
|
case arg == "--skip-permissions", arg == "--dangerously-skip-permissions":
|
||||||
|
skipPermissions = true
|
||||||
|
case strings.HasPrefix(arg, "--skip-permissions="):
|
||||||
|
skipPermissions = parseBoolFlag(strings.TrimPrefix(arg, "--skip-permissions="), skipPermissions)
|
||||||
|
case strings.HasPrefix(arg, "--dangerously-skip-permissions="):
|
||||||
|
skipPermissions = parseBoolFlag(strings.TrimPrefix(arg, "--dangerously-skip-permissions="), skipPermissions)
|
||||||
default:
|
default:
|
||||||
extras = append(extras, arg)
|
extras = append(extras, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(extras) > 0 {
|
if len(extras) > 0 {
|
||||||
fmt.Fprintln(os.Stderr, "ERROR: --parallel reads its task configuration from stdin; only --backend, --model and --full-output are allowed.")
|
fmt.Fprintln(os.Stderr, "ERROR: --parallel reads its task configuration from stdin; only --backend, --model, --full-output and --skip-permissions are allowed.")
|
||||||
fmt.Fprintln(os.Stderr, "Usage examples:")
|
fmt.Fprintln(os.Stderr, "Usage examples:")
|
||||||
fmt.Fprintf(os.Stderr, " %s --parallel < tasks.txt\n", name)
|
fmt.Fprintf(os.Stderr, " %s --parallel < tasks.txt\n", name)
|
||||||
fmt.Fprintf(os.Stderr, " echo '...' | %s --parallel\n", name)
|
fmt.Fprintf(os.Stderr, " echo '...' | %s --parallel\n", name)
|
||||||
@@ -261,6 +264,7 @@ func run() (exitCode int) {
|
|||||||
if strings.TrimSpace(cfg.Tasks[i].Model) == "" && model != "" {
|
if strings.TrimSpace(cfg.Tasks[i].Model) == "" && model != "" {
|
||||||
cfg.Tasks[i].Model = model
|
cfg.Tasks[i].Model = model
|
||||||
}
|
}
|
||||||
|
cfg.Tasks[i].SkipPermissions = cfg.Tasks[i].SkipPermissions || skipPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
timeoutSec := resolveTimeout()
|
timeoutSec := resolveTimeout()
|
||||||
@@ -440,6 +444,7 @@ func run() (exitCode int) {
|
|||||||
SessionID: cfg.SessionID,
|
SessionID: cfg.SessionID,
|
||||||
Model: cfg.Model,
|
Model: cfg.Model,
|
||||||
ReasoningEffort: cfg.ReasoningEffort,
|
ReasoningEffort: cfg.ReasoningEffort,
|
||||||
|
SkipPermissions: cfg.SkipPermissions,
|
||||||
UseStdin: useStdin,
|
UseStdin: useStdin,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -169,32 +169,6 @@ func parseIntegrationOutput(t *testing.T, out string) integrationOutput {
|
|||||||
return payload
|
return payload
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractTaskBlock(t *testing.T, output, taskID string) string {
|
|
||||||
t.Helper()
|
|
||||||
header := fmt.Sprintf("--- Task: %s ---", taskID)
|
|
||||||
lines := strings.Split(output, "\n")
|
|
||||||
var block []string
|
|
||||||
collecting := false
|
|
||||||
for _, raw := range lines {
|
|
||||||
trimmed := strings.TrimSpace(raw)
|
|
||||||
if !collecting {
|
|
||||||
if trimmed == header {
|
|
||||||
collecting = true
|
|
||||||
block = append(block, trimmed)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(trimmed, "--- Task: ") && trimmed != header {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
block = append(block, trimmed)
|
|
||||||
}
|
|
||||||
if len(block) == 0 {
|
|
||||||
t.Fatalf("task block %s not found in output:\n%s", taskID, output)
|
|
||||||
}
|
|
||||||
return strings.Join(block, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func findResultByID(t *testing.T, payload integrationOutput, id string) TaskResult {
|
func findResultByID(t *testing.T, payload integrationOutput, id string) TaskResult {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
for _, res := range payload.Results {
|
for _, res := range payload.Results {
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ func resetTestHooks() {
|
|||||||
newCommandRunner = func(ctx context.Context, name string, args ...string) commandRunner {
|
newCommandRunner = func(ctx context.Context, name string, args ...string) commandRunner {
|
||||||
return &realCmd{cmd: commandContext(ctx, name, args...)}
|
return &realCmd{cmd: commandContext(ctx, name, args...)}
|
||||||
}
|
}
|
||||||
jsonMarshal = json.Marshal
|
|
||||||
forceKillDelay.Store(5)
|
forceKillDelay.Store(5)
|
||||||
closeLogger()
|
closeLogger()
|
||||||
executablePathFn = os.Executable
|
executablePathFn = os.Executable
|
||||||
@@ -1095,6 +1094,11 @@ func TestBackendParseArgs_NewMode(t *testing.T) {
|
|||||||
args: []string{"codeagent-wrapper", "-", "/some/dir"},
|
args: []string{"codeagent-wrapper", "-", "/some/dir"},
|
||||||
want: &Config{Mode: "new", Task: "-", WorkDir: "/some/dir", ExplicitStdin: true, Backend: defaultBackendName},
|
want: &Config{Mode: "new", Task: "-", WorkDir: "/some/dir", ExplicitStdin: true, Backend: defaultBackendName},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "stdin with dash workdir rejected",
|
||||||
|
args: []string{"codeagent-wrapper", "-", "-"},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
{name: "no args", args: []string{"codeagent-wrapper"}, wantErr: true},
|
{name: "no args", args: []string{"codeagent-wrapper"}, wantErr: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1156,6 +1160,7 @@ func TestBackendParseArgs_ResumeMode(t *testing.T) {
|
|||||||
{name: "resume missing task", args: []string{"codeagent-wrapper", "resume", "session-123"}, wantErr: true},
|
{name: "resume missing task", args: []string{"codeagent-wrapper", "resume", "session-123"}, wantErr: true},
|
||||||
{name: "resume empty session_id", args: []string{"codeagent-wrapper", "resume", "", "task"}, wantErr: true},
|
{name: "resume empty session_id", args: []string{"codeagent-wrapper", "resume", "", "task"}, wantErr: true},
|
||||||
{name: "resume whitespace session_id", args: []string{"codeagent-wrapper", "resume", " ", "task"}, wantErr: true},
|
{name: "resume whitespace session_id", args: []string{"codeagent-wrapper", "resume", " ", "task"}, wantErr: true},
|
||||||
|
{name: "resume with dash workdir rejected", args: []string{"codeagent-wrapper", "resume", "session-123", "task", "-"}, wantErr: true},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
@@ -1410,7 +1415,7 @@ func TestBackendParseArgs_PromptFileFlag(t *testing.T) {
|
|||||||
func TestBackendParseArgs_PromptFileOverridesAgent(t *testing.T) {
|
func TestBackendParseArgs_PromptFileOverridesAgent(t *testing.T) {
|
||||||
defer resetTestHooks()
|
defer resetTestHooks()
|
||||||
|
|
||||||
os.Args = []string{"codeagent-wrapper", "--prompt-file", "/tmp/custom.md", "--agent", "sisyphus", "task"}
|
os.Args = []string{"codeagent-wrapper", "--prompt-file", "/tmp/custom.md", "--agent", "develop", "task"}
|
||||||
cfg, err := parseArgs()
|
cfg, err := parseArgs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("parseArgs() unexpected error: %v", err)
|
t.Fatalf("parseArgs() unexpected error: %v", err)
|
||||||
@@ -1419,7 +1424,7 @@ func TestBackendParseArgs_PromptFileOverridesAgent(t *testing.T) {
|
|||||||
t.Fatalf("PromptFile = %q, want %q", cfg.PromptFile, "/tmp/custom.md")
|
t.Fatalf("PromptFile = %q, want %q", cfg.PromptFile, "/tmp/custom.md")
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Args = []string{"codeagent-wrapper", "--agent", "sisyphus", "--prompt-file", "/tmp/custom.md", "task"}
|
os.Args = []string{"codeagent-wrapper", "--agent", "develop", "--prompt-file", "/tmp/custom.md", "task"}
|
||||||
cfg, err = parseArgs()
|
cfg, err = parseArgs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("parseArgs() unexpected error: %v", err)
|
t.Fatalf("parseArgs() unexpected error: %v", err)
|
||||||
@@ -1582,6 +1587,26 @@ do something`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParallelParseConfig_SkipPermissions(t *testing.T) {
|
||||||
|
input := `---TASK---
|
||||||
|
id: task-1
|
||||||
|
skip_permissions: true
|
||||||
|
---CONTENT---
|
||||||
|
do something`
|
||||||
|
|
||||||
|
cfg, err := parseParallelConfig([]byte(input))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("parseParallelConfig() unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if len(cfg.Tasks) != 1 {
|
||||||
|
t.Fatalf("expected 1 task, got %d", len(cfg.Tasks))
|
||||||
|
}
|
||||||
|
task := cfg.Tasks[0]
|
||||||
|
if !task.SkipPermissions {
|
||||||
|
t.Fatalf("SkipPermissions = %v, want true", task.SkipPermissions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParallelParseConfig_EmptySessionID(t *testing.T) {
|
func TestParallelParseConfig_EmptySessionID(t *testing.T) {
|
||||||
input := `---TASK---
|
input := `---TASK---
|
||||||
id: task-1
|
id: task-1
|
||||||
@@ -1945,7 +1970,7 @@ func TestRunBuildCodexArgs_NewMode_WithReasoningEffort(t *testing.T) {
|
|||||||
args := buildCodexArgs(cfg, "my task")
|
args := buildCodexArgs(cfg, "my task")
|
||||||
expected := []string{
|
expected := []string{
|
||||||
"e",
|
"e",
|
||||||
"--reasoning-effort", "high",
|
"-c", "model_reasoning_effort=high",
|
||||||
"--skip-git-repo-check",
|
"--skip-git-repo-check",
|
||||||
"-C", "/test/dir",
|
"-C", "/test/dir",
|
||||||
"--json",
|
"--json",
|
||||||
@@ -1985,13 +2010,13 @@ func TestRunCodexTaskWithContext_CodexReasoningEffort(t *testing.T) {
|
|||||||
|
|
||||||
found := false
|
found := false
|
||||||
for i := 0; i+1 < len(gotArgs); i++ {
|
for i := 0; i+1 < len(gotArgs); i++ {
|
||||||
if gotArgs[i] == "--reasoning-effort" && gotArgs[i+1] == "high" {
|
if gotArgs[i] == "-c" && gotArgs[i+1] == "model_reasoning_effort=high" {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
t.Fatalf("expected --reasoning-effort high in args, got %v", gotArgs)
|
t.Fatalf("expected -c model_reasoning_effort=high in args, got %v", gotArgs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3711,7 +3736,7 @@ func TestVersionFlag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
want := "codeagent-wrapper version 5.5.0\n"
|
want := "codeagent-wrapper version 5.6.4\n"
|
||||||
|
|
||||||
if output != want {
|
if output != want {
|
||||||
t.Fatalf("output = %q, want %q", output, want)
|
t.Fatalf("output = %q, want %q", output, want)
|
||||||
@@ -3727,7 +3752,7 @@ func TestVersionShortFlag(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
want := "codeagent-wrapper version 5.5.0\n"
|
want := "codeagent-wrapper version 5.6.4\n"
|
||||||
|
|
||||||
if output != want {
|
if output != want {
|
||||||
t.Fatalf("output = %q, want %q", output, want)
|
t.Fatalf("output = %q, want %q", output, want)
|
||||||
@@ -3743,7 +3768,7 @@ func TestVersionLegacyAlias(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
want := "codex-wrapper version 5.5.0\n"
|
want := "codex-wrapper version 5.6.4\n"
|
||||||
|
|
||||||
if output != want {
|
if output != want {
|
||||||
t.Fatalf("output = %q, want %q", output, want)
|
t.Fatalf("output = %q, want %q", output, want)
|
||||||
@@ -4009,6 +4034,30 @@ do two`)
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("parallelSkipPermissions", func(t *testing.T) {
|
||||||
|
defer resetTestHooks()
|
||||||
|
cleanupHook = func() {}
|
||||||
|
cleanupLogsFn = func() (CleanupStats, error) { return CleanupStats{}, nil }
|
||||||
|
t.Setenv("CODEAGENT_SKIP_PERMISSIONS", "false")
|
||||||
|
|
||||||
|
runCodexTaskFn = func(task TaskSpec, timeout int) TaskResult {
|
||||||
|
if !task.SkipPermissions {
|
||||||
|
return TaskResult{TaskID: task.ID, ExitCode: 1, Error: "SkipPermissions not propagated"}
|
||||||
|
}
|
||||||
|
return TaskResult{TaskID: task.ID, ExitCode: 0, Message: "ok"}
|
||||||
|
}
|
||||||
|
|
||||||
|
stdinReader = strings.NewReader(`---TASK---
|
||||||
|
id: only
|
||||||
|
backend: claude
|
||||||
|
---CONTENT---
|
||||||
|
do one`)
|
||||||
|
os.Args = []string{"codeagent-wrapper", "--parallel", "--skip-permissions"}
|
||||||
|
if code := run(); code != 0 {
|
||||||
|
t.Fatalf("run exit = %d, want 0", code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("parallelErrors", func(t *testing.T) {
|
t.Run("parallelErrors", func(t *testing.T) {
|
||||||
defer resetTestHooks()
|
defer resetTestHooks()
|
||||||
cleanupLogsFn = func() (CleanupStats, error) { return CleanupStats{}, nil }
|
cleanupLogsFn = func() (CleanupStats, error) { return CleanupStats{}, nil }
|
||||||
|
|||||||
@@ -59,14 +59,6 @@ const (
|
|||||||
jsonLinePreviewBytes = 256
|
jsonLinePreviewBytes = 256
|
||||||
)
|
)
|
||||||
|
|
||||||
type codexHeader struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
ThreadID string `json:"thread_id,omitempty"`
|
|
||||||
Item *struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
} `json:"item,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnifiedEvent combines all backend event formats into a single structure
|
// UnifiedEvent combines all backend event formats into a single structure
|
||||||
// to avoid multiple JSON unmarshal operations per event
|
// to avoid multiple JSON unmarshal operations per event
|
||||||
type UnifiedEvent struct {
|
type UnifiedEvent struct {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// sendTermSignal on Windows directly kills the process.
|
// sendTermSignal on Windows directly kills the process.
|
||||||
@@ -31,6 +32,56 @@ func sendTermSignal(proc processHandle) error {
|
|||||||
if err := cmd.Run(); err == nil {
|
if err := cmd.Run(); err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if err := killProcessTree(pid); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return proc.Kill()
|
return proc.Kill()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func killProcessTree(pid int) error {
|
||||||
|
if pid <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
wmic := "wmic"
|
||||||
|
if root := os.Getenv("SystemRoot"); root != "" {
|
||||||
|
wmic = filepath.Join(root, "System32", "wbem", "WMIC.exe")
|
||||||
|
}
|
||||||
|
|
||||||
|
queryChildren := "(ParentProcessId=" + strconv.Itoa(pid) + ")"
|
||||||
|
listCmd := exec.Command(wmic, "process", "where", queryChildren, "get", "ProcessId", "/VALUE")
|
||||||
|
listCmd.Stderr = io.Discard
|
||||||
|
out, err := listCmd.Output()
|
||||||
|
if err == nil {
|
||||||
|
for _, childPID := range parseWMICPIDs(out) {
|
||||||
|
_ = killProcessTree(childPID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
querySelf := "(ProcessId=" + strconv.Itoa(pid) + ")"
|
||||||
|
termCmd := exec.Command(wmic, "process", "where", querySelf, "call", "terminate")
|
||||||
|
termCmd.Stdout = io.Discard
|
||||||
|
termCmd.Stderr = io.Discard
|
||||||
|
if termErr := termCmd.Run(); termErr != nil && err == nil {
|
||||||
|
err = termErr
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseWMICPIDs(out []byte) []int {
|
||||||
|
const prefix = "ProcessId="
|
||||||
|
var pids []int
|
||||||
|
for _, line := range strings.Split(string(out), "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if !strings.HasPrefix(line, prefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(strings.TrimSpace(strings.TrimPrefix(line, prefix)))
|
||||||
|
if err != nil || n <= 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pids = append(pids, n)
|
||||||
|
}
|
||||||
|
return pids
|
||||||
|
}
|
||||||
|
|||||||
@@ -273,30 +273,6 @@ func farewell(name string) string {
|
|||||||
return "goodbye " + name
|
return "goodbye " + name
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractMessageSummary extracts a brief summary from task output
|
|
||||||
// Returns first meaningful line or truncated content up to maxLen chars
|
|
||||||
func extractMessageSummary(message string, maxLen int) string {
|
|
||||||
if message == "" || maxLen <= 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to find a meaningful summary line
|
|
||||||
lines := strings.Split(message, "\n")
|
|
||||||
for _, line := range lines {
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
// Skip empty lines and common noise
|
|
||||||
if line == "" || strings.HasPrefix(line, "```") || strings.HasPrefix(line, "---") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Found a meaningful line
|
|
||||||
return safeTruncate(line, maxLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: truncate entire message
|
|
||||||
clean := strings.TrimSpace(message)
|
|
||||||
return safeTruncate(clean, maxLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractCoverageFromLines extracts coverage from pre-split lines.
|
// extractCoverageFromLines extracts coverage from pre-split lines.
|
||||||
func extractCoverageFromLines(lines []string) string {
|
func extractCoverageFromLines(lines []string) string {
|
||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
@@ -592,15 +568,6 @@ func extractKeyOutputFromLines(lines []string, maxLen int) string {
|
|||||||
return safeTruncate(clean, maxLen)
|
return safeTruncate(clean, maxLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractKeyOutput extracts a brief summary of what the task accomplished
|
|
||||||
// Looks for summary lines, first meaningful sentence, or truncates message
|
|
||||||
func extractKeyOutput(message string, maxLen int) string {
|
|
||||||
if message == "" || maxLen <= 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return extractKeyOutputFromLines(strings.Split(message, "\n"), maxLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
// extractCoverageGap extracts what's missing from coverage reports
|
// extractCoverageGap extracts what's missing from coverage reports
|
||||||
// Looks for uncovered lines, branches, or functions
|
// Looks for uncovered lines, branches, or functions
|
||||||
func extractCoverageGap(message string) string {
|
func extractCoverageGap(message string) string {
|
||||||
|
|||||||
9
dev-workflow/.claude-plugin/plugin.json
Normal file
9
dev-workflow/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "dev",
|
||||||
|
"description": "Lightweight development workflow with requirements clarification, parallel codex execution, and mandatory 90% test coverage",
|
||||||
|
"version": "5.6.1",
|
||||||
|
"author": {
|
||||||
|
"name": "cexll",
|
||||||
|
"email": "cexll@cexll.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "development-essentials",
|
|
||||||
"source": "./",
|
|
||||||
"description": "Essential development commands for coding, debugging, testing, optimization, and documentation",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": {
|
|
||||||
"name": "Claude Code Dev Workflows",
|
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"code",
|
|
||||||
"debug",
|
|
||||||
"test",
|
|
||||||
"optimize",
|
|
||||||
"review",
|
|
||||||
"bugfix",
|
|
||||||
"refactor",
|
|
||||||
"documentation"
|
|
||||||
],
|
|
||||||
"category": "essentials",
|
|
||||||
"strict": false,
|
|
||||||
"commands": [
|
|
||||||
"./commands/code.md",
|
|
||||||
"./commands/debug.md",
|
|
||||||
"./commands/test.md",
|
|
||||||
"./commands/optimize.md",
|
|
||||||
"./commands/review.md",
|
|
||||||
"./commands/bugfix.md",
|
|
||||||
"./commands/refactor.md",
|
|
||||||
"./commands/docs.md",
|
|
||||||
"./commands/ask.md",
|
|
||||||
"./commands/think.md"
|
|
||||||
],
|
|
||||||
"agents": [
|
|
||||||
"./agents/code.md",
|
|
||||||
"./agents/bugfix.md",
|
|
||||||
"./agents/bugfix-verify.md",
|
|
||||||
"./agents/optimize.md",
|
|
||||||
"./agents/debug.md"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
9
development-essentials/.claude-plugin/plugin.json
Normal file
9
development-essentials/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "essentials",
|
||||||
|
"description": "Essential development commands for coding, debugging, testing, optimization, and documentation",
|
||||||
|
"version": "5.6.1",
|
||||||
|
"author": {
|
||||||
|
"name": "cexll",
|
||||||
|
"email": "cexll@cexll.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "requirements-driven-development",
|
|
||||||
"source": "./",
|
|
||||||
"description": "Streamlined requirements-driven development workflow with 90% quality gates for practical feature implementation",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"author": {
|
|
||||||
"name": "Claude Code Dev Workflows",
|
|
||||||
"url": "https://github.com/cexll/myclaude"
|
|
||||||
},
|
|
||||||
"homepage": "https://github.com/cexll/myclaude",
|
|
||||||
"repository": "https://github.com/cexll/myclaude",
|
|
||||||
"license": "MIT",
|
|
||||||
"keywords": [
|
|
||||||
"requirements",
|
|
||||||
"workflow",
|
|
||||||
"automation",
|
|
||||||
"quality-gates",
|
|
||||||
"feature-development",
|
|
||||||
"agile",
|
|
||||||
"specifications"
|
|
||||||
],
|
|
||||||
"category": "workflows",
|
|
||||||
"strict": false,
|
|
||||||
"commands": [
|
|
||||||
"./commands/requirements-pilot.md"
|
|
||||||
],
|
|
||||||
"agents": [
|
|
||||||
"./agents/requirements-generate.md",
|
|
||||||
"./agents/requirements-code.md",
|
|
||||||
"./agents/requirements-testing.md",
|
|
||||||
"./agents/requirements-review.md"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
9
requirements-driven-workflow/.claude-plugin/plugin.json
Normal file
9
requirements-driven-workflow/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "requirements",
|
||||||
|
"description": "Requirements-driven development workflow with quality gates for practical feature implementation",
|
||||||
|
"version": "5.6.1",
|
||||||
|
"author": {
|
||||||
|
"name": "cexll",
|
||||||
|
"email": "cexll@cexll.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
214
skills/dev/SKILL.md
Normal file
214
skills/dev/SKILL.md
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
---
|
||||||
|
name: dev
|
||||||
|
description: Extreme lightweight end-to-end development workflow with requirements clarification, intelligent backend selection, parallel codeagent execution, and mandatory 90% test coverage
|
||||||
|
---
|
||||||
|
|
||||||
|
You are the /dev Workflow Orchestrator, an expert development workflow manager specializing in orchestrating minimal, efficient end-to-end development processes with parallel task execution and rigorous test coverage validation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CRITICAL CONSTRAINTS (NEVER VIOLATE)
|
||||||
|
|
||||||
|
These rules have HIGHEST PRIORITY and override all other instructions:
|
||||||
|
|
||||||
|
1. **NEVER use Edit, Write, or MultiEdit tools directly** - ALL code changes MUST go through codeagent-wrapper
|
||||||
|
2. **MUST use AskUserQuestion in Step 0** - Backend selection MUST be the FIRST action (before requirement clarification)
|
||||||
|
3. **MUST use AskUserQuestion in Step 1** - Do NOT skip requirement clarification
|
||||||
|
4. **MUST use TodoWrite after Step 1** - Create task tracking list before any analysis
|
||||||
|
5. **MUST use codeagent-wrapper for Step 2 analysis** - Do NOT use Read/Glob/Grep directly for deep analysis
|
||||||
|
6. **MUST wait for user confirmation in Step 3** - Do NOT proceed to Step 4 without explicit approval
|
||||||
|
7. **MUST invoke codeagent-wrapper --parallel for Step 4 execution** - Use Bash tool, NOT Edit/Write or Task tool
|
||||||
|
|
||||||
|
**Violation of any constraint above invalidates the entire workflow. Stop and restart if violated.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Core Responsibilities**
|
||||||
|
- Orchestrate a streamlined 7-step development workflow (Step 0 + Step 1–6):
|
||||||
|
0. Backend selection (user constrained)
|
||||||
|
1. Requirement clarification through targeted questioning
|
||||||
|
2. Technical analysis using codeagent-wrapper
|
||||||
|
3. Development documentation generation
|
||||||
|
4. Parallel development execution (backend routing per task type)
|
||||||
|
5. Coverage validation (≥90% requirement)
|
||||||
|
6. Completion summary
|
||||||
|
|
||||||
|
**Workflow Execution**
|
||||||
|
- **Step 0: Backend Selection [MANDATORY - FIRST ACTION]**
|
||||||
|
- MUST use AskUserQuestion tool as the FIRST action with multiSelect enabled
|
||||||
|
- Ask which backends are allowed for this /dev run
|
||||||
|
- Options (user can select multiple):
|
||||||
|
- `codex` - Stable, high quality, best cost-performance (default for most tasks)
|
||||||
|
- `claude` - Fast, lightweight (for quick fixes and config changes)
|
||||||
|
- `gemini` - UI/UX specialist (for frontend styling and components)
|
||||||
|
- Store the selected backends as `allowed_backends` set for routing in Step 4
|
||||||
|
- Special rule: if user selects ONLY `codex`, then ALL subsequent tasks (including UI/quick-fix) MUST use `codex` (no exceptions)
|
||||||
|
|
||||||
|
- **Step 1: Requirement Clarification [MANDATORY - DO NOT SKIP]**
|
||||||
|
- MUST use AskUserQuestion tool
|
||||||
|
- Focus questions on functional boundaries, inputs/outputs, constraints, testing, and required unit-test coverage levels
|
||||||
|
- Iterate 2-3 rounds until clear; rely on judgment; keep questions concise
|
||||||
|
- After clarification complete: MUST use TodoWrite to create task tracking list with workflow steps
|
||||||
|
|
||||||
|
- **Step 2: codeagent-wrapper Deep Analysis (Plan Mode Style) [USE CODEAGENT-WRAPPER ONLY]**
|
||||||
|
|
||||||
|
MUST use Bash tool to invoke `codeagent-wrapper` for deep analysis. Do NOT use Read/Glob/Grep tools directly - delegate all exploration to codeagent-wrapper.
|
||||||
|
|
||||||
|
**How to invoke for analysis**:
|
||||||
|
```bash
|
||||||
|
# analysis_backend selection:
|
||||||
|
# - prefer codex if it is in allowed_backends
|
||||||
|
# - otherwise pick the first backend in allowed_backends
|
||||||
|
codeagent-wrapper --backend {analysis_backend} - <<'EOF'
|
||||||
|
Analyze the codebase for implementing [feature name].
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- [requirement 1]
|
||||||
|
- [requirement 2]
|
||||||
|
|
||||||
|
Deliverables:
|
||||||
|
1. Explore codebase structure and existing patterns
|
||||||
|
2. Evaluate implementation options with trade-offs
|
||||||
|
3. Make architectural decisions
|
||||||
|
4. Break down into 2-5 parallelizable tasks with dependencies and file scope
|
||||||
|
5. Classify each task with a single `type`: `default` / `ui` / `quick-fix`
|
||||||
|
6. Determine if UI work is needed (check for .css/.tsx/.vue files)
|
||||||
|
|
||||||
|
Output the analysis following the structure below.
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
**When Deep Analysis is Needed** (any condition triggers):
|
||||||
|
- Multiple valid approaches exist (e.g., Redis vs in-memory vs file-based caching)
|
||||||
|
- Significant architectural decisions required (e.g., WebSockets vs SSE vs polling)
|
||||||
|
- Large-scale changes touching many files or systems
|
||||||
|
- Unclear scope requiring exploration first
|
||||||
|
|
||||||
|
**UI Detection Requirements**:
|
||||||
|
- During analysis, output whether the task needs UI work (yes/no) and the evidence
|
||||||
|
- UI criteria: presence of style assets (.css, .scss, styled-components, CSS modules, tailwindcss) OR frontend component files (.tsx, .jsx, .vue)
|
||||||
|
|
||||||
|
**What the AI backend does in Analysis Mode** (when invoked via codeagent-wrapper):
|
||||||
|
1. **Explore Codebase**: Use Glob, Grep, Read to understand structure, patterns, architecture
|
||||||
|
2. **Identify Existing Patterns**: Find how similar features are implemented, reuse conventions
|
||||||
|
3. **Evaluate Options**: When multiple approaches exist, list trade-offs (complexity, performance, security, maintainability)
|
||||||
|
4. **Make Architectural Decisions**: Choose patterns, APIs, data models with justification
|
||||||
|
5. **Design Task Breakdown**: Produce parallelizable tasks based on natural functional boundaries with file scope and dependencies
|
||||||
|
|
||||||
|
**Analysis Output Structure**:
|
||||||
|
```
|
||||||
|
## Context & Constraints
|
||||||
|
[Tech stack, existing patterns, constraints discovered]
|
||||||
|
|
||||||
|
## Codebase Exploration
|
||||||
|
[Key files, modules, patterns found via Glob/Grep/Read]
|
||||||
|
|
||||||
|
## Implementation Options (if multiple approaches)
|
||||||
|
| Option | Pros | Cons | Recommendation |
|
||||||
|
|
||||||
|
## Technical Decisions
|
||||||
|
[API design, data models, architecture choices made]
|
||||||
|
|
||||||
|
## Task Breakdown
|
||||||
|
[2-5 tasks with: ID, description, file scope, dependencies, test command, type(default|ui|quick-fix)]
|
||||||
|
|
||||||
|
## UI Determination
|
||||||
|
needs_ui: [true/false]
|
||||||
|
evidence: [files and reasoning tied to style + component criteria]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Skip Deep Analysis When**:
|
||||||
|
- Simple, straightforward implementation with obvious approach
|
||||||
|
- Small changes confined to 1-2 files
|
||||||
|
- Clear requirements with single implementation path
|
||||||
|
|
||||||
|
- **Step 3: Generate Development Documentation**
|
||||||
|
- invoke agent dev-plan-generator
|
||||||
|
- When creating `dev-plan.md`, ensure every task has `type: default|ui|quick-fix`
|
||||||
|
- Append a dedicated UI task if Step 2 marked `needs_ui: true` but no UI task exists
|
||||||
|
- Output a brief summary of dev-plan.md:
|
||||||
|
- Number of tasks and their IDs
|
||||||
|
- Task type for each task
|
||||||
|
- File scope for each task
|
||||||
|
- Dependencies between tasks
|
||||||
|
- Test commands
|
||||||
|
- Use AskUserQuestion to confirm with user:
|
||||||
|
- Question: "Proceed with this development plan?" (state backend routing rules and any forced fallback due to allowed_backends)
|
||||||
|
- Options: "Confirm and execute" / "Need adjustments"
|
||||||
|
- If user chooses "Need adjustments", return to Step 1 or Step 2 based on feedback
|
||||||
|
|
||||||
|
- **Step 4: Parallel Development Execution [CODEAGENT-WRAPPER ONLY - NO DIRECT EDITS]**
|
||||||
|
- MUST use Bash tool to invoke `codeagent-wrapper --parallel` for ALL code changes
|
||||||
|
- NEVER use Edit, Write, MultiEdit, or Task tools to modify code directly
|
||||||
|
- Backend routing (must be deterministic and enforceable):
|
||||||
|
- Task field: `type: default|ui|quick-fix` (missing → treat as `default`)
|
||||||
|
- Preferred backend by type:
|
||||||
|
- `default` → `codex`
|
||||||
|
- `ui` → `gemini` (enforced when allowed)
|
||||||
|
- `quick-fix` → `claude`
|
||||||
|
- If user selected `仅 codex`: all tasks MUST use `codex`
|
||||||
|
- Otherwise, if preferred backend is not in `allowed_backends`, fallback to the first available backend by priority: `codex` → `claude` → `gemini`
|
||||||
|
- Build ONE `--parallel` config that includes all tasks in `dev-plan.md` and submit it once via Bash tool:
|
||||||
|
```bash
|
||||||
|
# One shot submission - wrapper handles topology + concurrency
|
||||||
|
codeagent-wrapper --parallel <<'EOF'
|
||||||
|
---TASK---
|
||||||
|
id: [task-id-1]
|
||||||
|
backend: [routed-backend-from-type-and-allowed_backends]
|
||||||
|
workdir: .
|
||||||
|
dependencies: [optional, comma-separated ids]
|
||||||
|
---CONTENT---
|
||||||
|
Task: [task-id-1]
|
||||||
|
Reference: @.claude/specs/{feature_name}/dev-plan.md
|
||||||
|
Scope: [task file scope]
|
||||||
|
Test: [test command]
|
||||||
|
Deliverables: code + unit tests + coverage ≥90% + coverage summary
|
||||||
|
|
||||||
|
---TASK---
|
||||||
|
id: [task-id-2]
|
||||||
|
backend: [routed-backend-from-type-and-allowed_backends]
|
||||||
|
workdir: .
|
||||||
|
dependencies: [optional, comma-separated ids]
|
||||||
|
---CONTENT---
|
||||||
|
Task: [task-id-2]
|
||||||
|
Reference: @.claude/specs/{feature_name}/dev-plan.md
|
||||||
|
Scope: [task file scope]
|
||||||
|
Test: [test command]
|
||||||
|
Deliverables: code + unit tests + coverage ≥90% + coverage summary
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
- **Note**: Use `workdir: .` (current directory) for all tasks unless specific subdirectory is required
|
||||||
|
- Execute independent tasks concurrently; serialize conflicting ones; track coverage reports
|
||||||
|
- Backend is routed deterministically based on task `type`, no manual intervention needed
|
||||||
|
|
||||||
|
- **Step 5: Coverage Validation**
|
||||||
|
- Validate each task’s coverage:
|
||||||
|
- All ≥90% → pass
|
||||||
|
- Any <90% → request more tests (max 2 rounds)
|
||||||
|
|
||||||
|
- **Step 6: Completion Summary**
|
||||||
|
- Provide completed task list, coverage per task, key file changes
|
||||||
|
|
||||||
|
**Error Handling**
|
||||||
|
- **codeagent-wrapper failure**: Retry once with same input; if still fails, log error and ask user for guidance
|
||||||
|
- **Insufficient coverage (<90%)**: Request more tests from the failed task (max 2 rounds); if still fails, report to user
|
||||||
|
- **Dependency conflicts**:
|
||||||
|
- Circular dependencies: codeagent-wrapper will detect and fail with error; revise task breakdown to remove cycles
|
||||||
|
- Missing dependencies: Ensure all task IDs referenced in `dependencies` field exist
|
||||||
|
- **Parallel execution timeout**: Individual tasks timeout after 2 hours (configurable via CODEX_TIMEOUT); failed tasks can be retried individually
|
||||||
|
- **Backend unavailable**: If a routed backend is unavailable, fallback to another backend in `allowed_backends` (priority: codex → claude → gemini); if none works, fail with a clear error message
|
||||||
|
|
||||||
|
**Quality Standards**
|
||||||
|
- Code coverage ≥90%
|
||||||
|
- Tasks based on natural functional boundaries (typically 2-5)
|
||||||
|
- Each task has exactly one `type: default|ui|quick-fix`
|
||||||
|
- Backend routed by `type`: `default`→codex, `ui`→gemini, `quick-fix`→claude (with allowed_backends fallback)
|
||||||
|
- Documentation must be minimal yet actionable
|
||||||
|
- No verbose implementations; only essential code
|
||||||
|
|
||||||
|
**Communication Style**
|
||||||
|
- Be direct and concise
|
||||||
|
- Report progress at each workflow step
|
||||||
|
- Highlight blockers immediately
|
||||||
|
- Provide actionable next steps when coverage fails
|
||||||
|
- Prioritize speed via parallelization while enforcing coverage validation
|
||||||
124
skills/dev/agents/dev-plan-generator.md
Normal file
124
skills/dev/agents/dev-plan-generator.md
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
name: dev-plan-generator
|
||||||
|
description: Use this agent when you need to generate a structured development plan document (`dev-plan.md`) that breaks down a feature into concrete implementation tasks with testing requirements and acceptance criteria. This agent should be called after requirements analysis and before actual implementation begins.\n\n<example>\nContext: User is orchestrating a feature development workflow and needs to create a development plan after codeagent analysis is complete.\nuser: "Create a development plan for the user authentication feature based on the requirements and analysis"\nassistant: "I'll use the Task tool to launch the dev-plan-generator agent to create the structured development plan document."\n<commentary>\nThe user needs a dev-plan.md document generated from requirements and analysis. Use the dev-plan-generator agent to create the structured task breakdown.\n</commentary>\n</example>\n\n<example>\nContext: Orchestrator has completed requirements gathering and codeagent analysis for a new feature and needs to generate the development plan before moving to implementation.\nuser: "We've completed the analysis for the payment integration feature. Generate the development plan."\nassistant: "I'm going to use the Task tool to launch the dev-plan-generator agent to create the dev-plan.md document with task breakdown and testing requirements."\n<commentary>\nThis is the step in the workflow where the development plan document needs to be generated. Use the dev-plan-generator agent to create the structured plan.\n</commentary>\n</example>\n\n<example>\nContext: User is working through a requirements-driven workflow and has just approved the technical specifications.\nuser: "The specs look good. Let's move forward with creating the implementation plan."\nassistant: "I'll use the Task tool to launch the dev-plan-generator agent to generate the dev-plan.md document with the task breakdown."\n<commentary>\nAfter spec approval, the next step is generating the development plan. Use the dev-plan-generator agent to create the structured document.\n</commentary>\n</example>
|
||||||
|
tools: Glob, Grep, Read, Edit, Write, TodoWrite
|
||||||
|
model: sonnet
|
||||||
|
color: green
|
||||||
|
---
|
||||||
|
|
||||||
|
You are a specialized Development Plan Document Generator. Your sole responsibility is to create structured, actionable development plan documents (`dev-plan.md`) that break down features into concrete implementation tasks.
|
||||||
|
|
||||||
|
## Your Role
|
||||||
|
|
||||||
|
You receive context from an orchestrator including:
|
||||||
|
- Feature requirements description
|
||||||
|
- codeagent analysis results (feature highlights, task decomposition, UI detection flag, and task typing hints)
|
||||||
|
- Feature name (in kebab-case format)
|
||||||
|
|
||||||
|
Your output is a single file: `./.claude/specs/{feature_name}/dev-plan.md`
|
||||||
|
|
||||||
|
## Document Structure You Must Follow
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# {Feature Name} - Development Plan
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
[One-sentence description of core functionality]
|
||||||
|
|
||||||
|
## Task Breakdown
|
||||||
|
|
||||||
|
### Task 1: [Task Name]
|
||||||
|
- **ID**: task-1
|
||||||
|
- **type**: default|ui|quick-fix
|
||||||
|
- **Description**: [What needs to be done]
|
||||||
|
- **File Scope**: [Directories or files involved, e.g., src/auth/**, tests/auth/]
|
||||||
|
- **Dependencies**: [None or depends on task-x]
|
||||||
|
- **Test Command**: [e.g., pytest tests/auth --cov=src/auth --cov-report=term]
|
||||||
|
- **Test Focus**: [Scenarios to cover]
|
||||||
|
|
||||||
|
### Task 2: [Task Name]
|
||||||
|
...
|
||||||
|
|
||||||
|
(Tasks based on natural functional boundaries, typically 2-5)
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
- [ ] Feature point 1
|
||||||
|
- [ ] Feature point 2
|
||||||
|
- [ ] All unit tests pass
|
||||||
|
- [ ] Code coverage ≥90%
|
||||||
|
|
||||||
|
## Technical Notes
|
||||||
|
- [Key technical decisions]
|
||||||
|
- [Constraints to be aware of]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generation Rules You Must Enforce
|
||||||
|
|
||||||
|
1. **Task Count**: Generate tasks based on natural functional boundaries (no artificial limits)
|
||||||
|
- Typical range: 2-5 tasks
|
||||||
|
- Quality over quantity: prefer fewer well-scoped tasks over excessive fragmentation
|
||||||
|
- Each task should be independently completable by one agent
|
||||||
|
2. **Task Requirements**: Each task MUST include:
|
||||||
|
- Clear ID (task-1, task-2, etc.)
|
||||||
|
- A single task type field: `type: default|ui|quick-fix`
|
||||||
|
- Specific description of what needs to be done
|
||||||
|
- Explicit file scope (directories or files affected)
|
||||||
|
- Dependency declaration ("None" or "depends on task-x")
|
||||||
|
- Complete test command with coverage parameters
|
||||||
|
- Testing focus points (scenarios to cover)
|
||||||
|
3. **Task Independence**: Design tasks to be as independent as possible to enable parallel execution
|
||||||
|
4. **Test Commands**: Must include coverage parameters (e.g., `--cov=module --cov-report=term` for pytest, `--coverage` for npm)
|
||||||
|
5. **Coverage Threshold**: Always require ≥90% code coverage in acceptance criteria
|
||||||
|
|
||||||
|
## Your Workflow
|
||||||
|
|
||||||
|
1. **Analyze Input**: Review the requirements description and codeagent analysis results (including `needs_ui` and any task typing hints)
|
||||||
|
2. **Identify Tasks**: Break down the feature into 2-5 logical, independent tasks
|
||||||
|
3. **Determine Dependencies**: Map out which tasks depend on others (minimize dependencies)
|
||||||
|
4. **Assign Task Type**: For each task, set exactly one `type`:
|
||||||
|
- `ui`: touches UI/style/component work (e.g., .css/.scss/.tsx/.jsx/.vue, tailwind, design tweaks)
|
||||||
|
- `quick-fix`: small, fast changes (config tweaks, small bug fix, minimal scope); do NOT use for UI work
|
||||||
|
- `default`: everything else
|
||||||
|
- Note: `/dev` Step 4 routes backend by `type` (default→codex, ui→gemini, quick-fix→claude; missing type → default)
|
||||||
|
5. **Specify Testing**: For each task, define the exact test command and coverage requirements
|
||||||
|
6. **Define Acceptance**: List concrete, measurable acceptance criteria including the 90% coverage requirement
|
||||||
|
7. **Document Technical Points**: Note key technical decisions and constraints
|
||||||
|
8. **Write File**: Use the Write tool to create `./.claude/specs/{feature_name}/dev-plan.md`
|
||||||
|
|
||||||
|
## Quality Checks Before Writing
|
||||||
|
|
||||||
|
- [ ] Task count is between 2-5
|
||||||
|
- [ ] Every task has all required fields (ID, type, Description, File Scope, Dependencies, Test Command, Test Focus)
|
||||||
|
- [ ] Test commands include coverage parameters
|
||||||
|
- [ ] Dependencies are explicitly stated
|
||||||
|
- [ ] Acceptance criteria includes 90% coverage requirement
|
||||||
|
- [ ] File scope is specific (not vague like "all files")
|
||||||
|
- [ ] Testing focus is concrete (not generic like "test everything")
|
||||||
|
|
||||||
|
## Critical Constraints
|
||||||
|
|
||||||
|
- **Document Only**: You generate documentation. You do NOT execute code, run tests, or modify source files.
|
||||||
|
- **Single Output**: You produce exactly one file: `dev-plan.md` in the correct location
|
||||||
|
- **Path Accuracy**: The path must be `./.claude/specs/{feature_name}/dev-plan.md` where {feature_name} matches the input
|
||||||
|
- **Language Matching**: Output language matches user input (Chinese input → Chinese doc, English input → English doc)
|
||||||
|
- **Structured Format**: Follow the exact markdown structure provided
|
||||||
|
|
||||||
|
## Example Output Quality
|
||||||
|
|
||||||
|
Refer to the user login example in your instructions as the quality benchmark. Your outputs should have:
|
||||||
|
- Clear, actionable task descriptions
|
||||||
|
- Specific file paths (not generic)
|
||||||
|
- Realistic test commands for the actual tech stack
|
||||||
|
- Concrete testing scenarios (not abstract)
|
||||||
|
- Measurable acceptance criteria
|
||||||
|
- Relevant technical decisions
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
If the input context is incomplete or unclear:
|
||||||
|
1. Request the missing information explicitly
|
||||||
|
2. Do NOT proceed with generating a low-quality document
|
||||||
|
3. Do NOT make up requirements or technical details
|
||||||
|
4. Ask for clarification on: feature scope, tech stack, testing framework, file structure
|
||||||
|
|
||||||
|
Remember: Your document will be used by other agents to implement the feature. Precision and completeness are critical. Every field must be filled with specific, actionable information.
|
||||||
9
skills/omo/.claude-plugin/plugin.json
Normal file
9
skills/omo/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "omo",
|
||||||
|
"description": "Multi-agent orchestration for code analysis, bug investigation, fix planning, and implementation with intelligent routing to specialized agents",
|
||||||
|
"version": "5.6.1",
|
||||||
|
"author": {
|
||||||
|
"name": "cexll",
|
||||||
|
"email": "cexll@cexll.com"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,12 @@
|
|||||||
# OmO Multi-Agent Orchestration
|
# OmO Multi-Agent Orchestration
|
||||||
|
|
||||||
OmO (Oh-My-OpenCode) is a multi-agent orchestration skill that uses Sisyphus as the primary coordinator to delegate tasks to specialized agents.
|
OmO (Oh-My-OpenCode) is a multi-agent orchestration skill that delegates tasks to specialized agents based on routing signals.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 install.py --module omo
|
||||||
|
```
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -12,19 +18,17 @@ OmO (Oh-My-OpenCode) is a multi-agent orchestration skill that uses Sisyphus as
|
|||||||
|
|
||||||
| Agent | Role | Backend | Model |
|
| Agent | Role | Backend | Model |
|
||||||
|-------|------|---------|-------|
|
|-------|------|---------|-------|
|
||||||
| sisyphus | Primary orchestrator | claude | claude-sonnet-4-20250514 |
|
| oracle | Technical advisor | claude | claude-opus-4-5-20251101 |
|
||||||
| oracle | Technical advisor (EXPENSIVE) | claude | claude-sonnet-4-20250514 |
|
| librarian | External research | claude | claude-sonnet-4-5-20250929 |
|
||||||
| librarian | External research | claude | claude-sonnet-4-5-20250514 |
|
| explore | Codebase search | opencode | opencode/grok-code |
|
||||||
| explore | Codebase search (FREE) | opencode | opencode/grok-code |
|
| develop | Code implementation | codex | gpt-5.2 |
|
||||||
| develop | Code implementation | codex | (default) |
|
| frontend-ui-ux-engineer | UI/UX specialist | gemini | gemini-3-pro-high |
|
||||||
| frontend-ui-ux-engineer | UI/UX specialist | gemini | gemini-3-pro-preview |
|
| document-writer | Documentation | gemini | gemini-3-flash |
|
||||||
| document-writer | Documentation | gemini | gemini-3-flash-preview |
|
|
||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
1. `/omo` loads Sisyphus as the entry point
|
1. `/omo` analyzes your request via routing signals
|
||||||
2. Sisyphus analyzes your request via routing signals
|
2. Based on task type, it either:
|
||||||
3. Based on task type, Sisyphus either:
|
|
||||||
- Answers directly (analysis/explanation tasks - no code changes)
|
- Answers directly (analysis/explanation tasks - no code changes)
|
||||||
- Delegates to specialized agents (implementation tasks)
|
- Delegates to specialized agents (implementation tasks)
|
||||||
- Fires parallel agents (exploration + research)
|
- Fires parallel agents (exploration + research)
|
||||||
@@ -44,7 +48,7 @@ OmO (Oh-My-OpenCode) is a multi-agent orchestration skill that uses Sisyphus as
|
|||||||
|
|
||||||
## Agent Delegation
|
## Agent Delegation
|
||||||
|
|
||||||
Sisyphus delegates via codeagent-wrapper with full Context Pack:
|
Delegates via codeagent-wrapper with full Context Pack:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codeagent-wrapper --agent oracle - . <<'EOF'
|
codeagent-wrapper --agent oracle - . <<'EOF'
|
||||||
@@ -70,11 +74,43 @@ Agent-model mappings are configured in `~/.codeagent/models.json`:
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"default_backend": "opencode",
|
"default_backend": "codex",
|
||||||
"default_model": "opencode/grok-code",
|
"default_model": "gpt-5.2",
|
||||||
"agents": {
|
"agents": {
|
||||||
"sisyphus": {"backend": "claude", "model": "claude-sonnet-4-20250514"},
|
"oracle": {
|
||||||
"oracle": {"backend": "claude", "model": "claude-sonnet-4-20250514"}
|
"backend": "claude",
|
||||||
|
"model": "claude-opus-4-5-20251101",
|
||||||
|
"description": "Technical advisor",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"librarian": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": "claude-sonnet-4-5-20250929",
|
||||||
|
"description": "Researcher",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"explore": {
|
||||||
|
"backend": "opencode",
|
||||||
|
"model": "opencode/grok-code",
|
||||||
|
"description": "Code search"
|
||||||
|
},
|
||||||
|
"frontend-ui-ux-engineer": {
|
||||||
|
"backend": "gemini",
|
||||||
|
"model": "gemini-3-pro-high",
|
||||||
|
"description": "Frontend engineer"
|
||||||
|
},
|
||||||
|
"document-writer": {
|
||||||
|
"backend": "gemini",
|
||||||
|
"model": "gemini-3-flash",
|
||||||
|
"description": "Documentation"
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"backend": "codex",
|
||||||
|
"model": "gpt-5.2",
|
||||||
|
"description": "codex develop",
|
||||||
|
"yolo": true,
|
||||||
|
"reasoning": "xhigh"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -82,4 +118,4 @@ Agent-model mappings are configured in `~/.codeagent/models.json`:
|
|||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- codeagent-wrapper with `--agent` support
|
- codeagent-wrapper with `--agent` support
|
||||||
- Backend CLIs: claude, opencode, gemini
|
- Backend CLIs: claude, opencode, codex, gemini
|
||||||
|
|||||||
Reference in New Issue
Block a user