mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-12 03:27:47 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7cc7f50f46 | ||
|
|
ebd795c583 |
41
CHANGELOG.md
41
CHANGELOG.md
@@ -2,6 +2,47 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [6.7.0] - 2026-02-10
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- feat(install): per-module agent merge/unmerge for ~/.codeagent/models.json
|
||||||
|
- feat(install): post-install verification (wrapper version, PATH, backend CLIs)
|
||||||
|
- feat(install): install CLAUDE.md by default
|
||||||
|
- feat(docs): document 9 skills, 11 commands, claudekit module, OpenCode backend
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- fix(docs): correct 7-phase → 5-phase for do skill across all docs
|
||||||
|
- fix(install): best-effort default config install (never crashes main flow)
|
||||||
|
- fix(install): interactive quit no longer triggers post-install actions
|
||||||
|
- fix(install): empty parent directory cleanup on copy_file uninstall
|
||||||
|
- fix(install): agent restore on uninstall when shared by multiple modules
|
||||||
|
- fix(docs): remove non-existent on-stop hook references
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Updated USER_GUIDE.md with 13 CLI flags and OpenCode backend
|
||||||
|
- Updated README.md/README_CN.md with complete module and skill listings
|
||||||
|
- Added templates/models.json.example with all agent presets (do + omo)
|
||||||
|
|
||||||
|
## [6.6.0] - 2026-02-10
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- feat(skills): add per-task skill spec auto-detection and injection
|
||||||
|
- feat: add worktree support and refactor do skill to Python
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- fix(test): set USERPROFILE on Windows for skills tests
|
||||||
|
- fix(do): reuse worktree across phases via DO_WORKTREE_DIR env var
|
||||||
|
- fix(release): auto-generate release notes from git history
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- audit and fix documentation, installation scripts, and default configuration
|
||||||
|
|
||||||
## [6.0.0] - 2026-01-26
|
## [6.0.0] - 2026-01-26
|
||||||
|
|
||||||
### 🚀 Features
|
### 🚀 Features
|
||||||
|
|||||||
34
README.md
34
README.md
@@ -19,13 +19,30 @@ npx github:cexll/myclaude
|
|||||||
|
|
||||||
| Module | Description | Documentation |
|
| Module | Description | Documentation |
|
||||||
|--------|-------------|---------------|
|
|--------|-------------|---------------|
|
||||||
| [do](skills/do/README.md) | **Recommended** - 7-phase feature development with codeagent orchestration | `/do` command |
|
| [do](skills/do/README.md) | **Recommended** - 5-phase feature development with codeagent orchestration | `/do` command |
|
||||||
| [omo](skills/omo/README.md) | Multi-agent orchestration with intelligent routing | `/omo` command |
|
| [omo](skills/omo/README.md) | Multi-agent orchestration with intelligent routing | `/omo` command |
|
||||||
| [bmad](agents/bmad/README.md) | BMAD agile workflow with 6 specialized agents | `/bmad-pilot` command |
|
| [bmad](agents/bmad/README.md) | BMAD agile workflow with 6 specialized agents | `/bmad-pilot` command |
|
||||||
| [requirements](agents/requirements/README.md) | Lightweight requirements-to-code pipeline | `/requirements-pilot` command |
|
| [requirements](agents/requirements/README.md) | Lightweight requirements-to-code pipeline | `/requirements-pilot` command |
|
||||||
| [essentials](agents/development-essentials/README.md) | Core development commands and utilities | `/code`, `/debug`, etc. |
|
| [essentials](agents/development-essentials/README.md) | 11 core dev commands: ask, bugfix, code, debug, docs, enhance-prompt, optimize, refactor, review, test, think | `/code`, `/debug`, etc. |
|
||||||
| [sparv](skills/sparv/README.md) | SPARV workflow (Specify→Plan→Act→Review→Vault) | `/sparv` command |
|
| [sparv](skills/sparv/README.md) | SPARV workflow (Specify→Plan→Act→Review→Vault) | `/sparv` command |
|
||||||
| course | Course development (combines dev + product-requirements + test-cases) | Composite module |
|
| course | Course development (combines dev + product-requirements + test-cases) | Composite module |
|
||||||
|
| claudekit | ClaudeKit: do skill + global hooks (pre-bash, inject-spec, log-prompt) | Composite module |
|
||||||
|
|
||||||
|
### Available Skills
|
||||||
|
|
||||||
|
Individual skills can be installed separately via `npx github:cexll/myclaude --list` (skills bundled in modules like do, omo, sparv are listed above):
|
||||||
|
|
||||||
|
| Skill | Description |
|
||||||
|
|-------|-------------|
|
||||||
|
| browser | Browser automation for web testing and data extraction |
|
||||||
|
| codeagent | codeagent-wrapper invocation for multi-backend AI code tasks |
|
||||||
|
| codex | Direct Codex backend execution |
|
||||||
|
| dev | Lightweight end-to-end development workflow |
|
||||||
|
| gemini | Direct Gemini backend execution |
|
||||||
|
| product-requirements | Interactive PRD generation with quality scoring |
|
||||||
|
| prototype-prompt-generator | Structured UI/UX prototype prompt generation |
|
||||||
|
| skill-install | Install skills from GitHub with security scanning |
|
||||||
|
| test-cases | Comprehensive test case generation from requirements |
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -87,17 +104,20 @@ Edit `config.json` to enable/disable modules:
|
|||||||
| Codex | `codex e`, `--json`, `-C`, `resume` |
|
| Codex | `codex e`, `--json`, `-C`, `resume` |
|
||||||
| Claude | `--output-format stream-json`, `-r` |
|
| Claude | `--output-format stream-json`, `-r` |
|
||||||
| Gemini | `-o stream-json`, `-y`, `-r` |
|
| Gemini | `-o stream-json`, `-y`, `-r` |
|
||||||
|
| OpenCode | `opencode`, stdin mode |
|
||||||
|
|
||||||
## Directory Structure After Installation
|
## Directory Structure After Installation
|
||||||
|
|
||||||
```
|
```
|
||||||
~/.claude/
|
~/.claude/
|
||||||
├── bin/codeagent-wrapper
|
├── bin/codeagent-wrapper
|
||||||
├── CLAUDE.md
|
├── CLAUDE.md (installed by default)
|
||||||
├── commands/
|
├── commands/ (from essentials module)
|
||||||
├── agents/
|
├── agents/ (from bmad/requirements modules)
|
||||||
├── skills/
|
├── skills/ (from do/omo/sparv/course modules)
|
||||||
└── config.json
|
├── hooks/ (from claudekit module)
|
||||||
|
├── settings.json (auto-generated, hooks config)
|
||||||
|
└── installed_modules.json (auto-generated, tracks modules)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|||||||
42
README_CN.md
42
README_CN.md
@@ -16,13 +16,30 @@ npx github:cexll/myclaude
|
|||||||
|
|
||||||
| 模块 | 描述 | 文档 |
|
| 模块 | 描述 | 文档 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| [do](skills/do/README.md) | **推荐** - 7 阶段功能开发 + codeagent 编排 | `/do` 命令 |
|
| [do](skills/do/README.md) | **推荐** - 5 阶段功能开发 + codeagent 编排 | `/do` 命令 |
|
||||||
| [omo](skills/omo/README.md) | 多智能体编排 + 智能路由 | `/omo` 命令 |
|
| [omo](skills/omo/README.md) | 多智能体编排 + 智能路由 | `/omo` 命令 |
|
||||||
| [bmad](agents/bmad/README.md) | BMAD 敏捷工作流 + 6 个专业智能体 | `/bmad-pilot` 命令 |
|
| [bmad](agents/bmad/README.md) | BMAD 敏捷工作流 + 6 个专业智能体 | `/bmad-pilot` 命令 |
|
||||||
| [requirements](agents/requirements/README.md) | 轻量级需求到代码流水线 | `/requirements-pilot` 命令 |
|
| [requirements](agents/requirements/README.md) | 轻量级需求到代码流水线 | `/requirements-pilot` 命令 |
|
||||||
| [essentials](agents/development-essentials/README.md) | 核心开发命令和工具 | `/code`, `/debug` 等 |
|
| [essentials](agents/development-essentials/README.md) | 11 个核心开发命令:ask、bugfix、code、debug、docs、enhance-prompt、optimize、refactor、review、test、think | `/code`, `/debug` 等 |
|
||||||
| [sparv](skills/sparv/README.md) | SPARV 工作流 (Specify→Plan→Act→Review→Vault) | `/sparv` 命令 |
|
| [sparv](skills/sparv/README.md) | SPARV 工作流 (Specify→Plan→Act→Review→Vault) | `/sparv` 命令 |
|
||||||
| course | 课程开发(组合 dev + product-requirements + test-cases) | 组合模块 |
|
| course | 课程开发(组合 dev + product-requirements + test-cases) | 组合模块 |
|
||||||
|
| claudekit | ClaudeKit:do 技能 + 全局钩子(pre-bash、inject-spec、log-prompt)| 组合模块 |
|
||||||
|
|
||||||
|
### 可用技能
|
||||||
|
|
||||||
|
可通过 `npx github:cexll/myclaude --list` 单独安装技能(模块内置技能如 do、omo、sparv 见上表):
|
||||||
|
|
||||||
|
| 技能 | 描述 |
|
||||||
|
|------|------|
|
||||||
|
| browser | 浏览器自动化测试和数据提取 |
|
||||||
|
| codeagent | codeagent-wrapper 多后端 AI 代码任务调用 |
|
||||||
|
| codex | Codex 后端直接执行 |
|
||||||
|
| dev | 轻量级端到端开发工作流 |
|
||||||
|
| gemini | Gemini 后端直接执行 |
|
||||||
|
| product-requirements | 交互式 PRD 生成(含质量评分)|
|
||||||
|
| prototype-prompt-generator | 结构化 UI/UX 原型提示词生成 |
|
||||||
|
| skill-install | 从 GitHub 安装技能(含安全扫描)|
|
||||||
|
| test-cases | 从需求生成全面测试用例 |
|
||||||
|
|
||||||
## 核心架构
|
## 核心架构
|
||||||
|
|
||||||
@@ -35,22 +52,20 @@ npx github:cexll/myclaude
|
|||||||
|
|
||||||
### do 工作流(推荐)
|
### do 工作流(推荐)
|
||||||
|
|
||||||
7 阶段功能开发,通过 codeagent-wrapper 编排多个智能体。**大多数功能开发任务的首选工作流。**
|
5 阶段功能开发,通过 codeagent-wrapper 编排多个智能体。**大多数功能开发任务的首选工作流。**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
/do "添加用户登录功能"
|
/do "添加用户登录功能"
|
||||||
```
|
```
|
||||||
|
|
||||||
**7 阶段:**
|
**5 阶段:**
|
||||||
| 阶段 | 名称 | 目标 |
|
| 阶段 | 名称 | 目标 |
|
||||||
|------|------|------|
|
|------|------|------|
|
||||||
| 1 | Discovery | 理解需求 |
|
| 1 | Understand | 并行探索理解需求和映射代码库 |
|
||||||
| 2 | Exploration | 映射代码库模式 |
|
| 2 | Clarify | 解决阻塞性歧义(条件触发)|
|
||||||
| 3 | Clarification | 解决歧义(**强制**)|
|
| 3 | Design | 产出最小变更实现方案 |
|
||||||
| 4 | Architecture | 设计实现方案 |
|
| 4 | Implement + Review | 构建功能并审查 |
|
||||||
| 5 | Implementation | 构建功能(**需审批**)|
|
| 5 | Complete | 记录构建结果 |
|
||||||
| 6 | Review | 捕获缺陷 |
|
|
||||||
| 7 | Summary | 记录结果 |
|
|
||||||
|
|
||||||
**智能体:**
|
**智能体:**
|
||||||
- `code-explorer` - 代码追踪、架构映射
|
- `code-explorer` - 代码追踪、架构映射
|
||||||
@@ -162,6 +177,10 @@ npx github:cexll/myclaude
|
|||||||
| `/optimize` | 性能优化 |
|
| `/optimize` | 性能优化 |
|
||||||
| `/refactor` | 代码重构 |
|
| `/refactor` | 代码重构 |
|
||||||
| `/docs` | 编写文档 |
|
| `/docs` | 编写文档 |
|
||||||
|
| `/ask` | 提问和咨询 |
|
||||||
|
| `/bugfix` | Bug 修复 |
|
||||||
|
| `/enhance-prompt` | 提示词优化 |
|
||||||
|
| `/think` | 深度思考分析 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -218,6 +237,7 @@ npx github:cexll/myclaude --install-dir ~/.claude --force
|
|||||||
| Codex | `codex e`, `--json`, `-C`, `resume` |
|
| Codex | `codex e`, `--json`, `-C`, `resume` |
|
||||||
| Claude | `--output-format stream-json`, `-r` |
|
| Claude | `--output-format stream-json`, `-r` |
|
||||||
| Gemini | `-o stream-json`, `-y`, `-r` |
|
| Gemini | `-o stream-json`, `-y`, `-r` |
|
||||||
|
| OpenCode | `opencode`, stdin 模式 |
|
||||||
|
|
||||||
## 故障排查
|
## 故障排查
|
||||||
|
|
||||||
|
|||||||
62
bin/cli.js
62
bin/cli.js
@@ -8,7 +8,7 @@ const os = require("os");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const readline = require("readline");
|
const readline = require("readline");
|
||||||
const zlib = require("zlib");
|
const zlib = require("zlib");
|
||||||
const { spawn } = require("child_process");
|
const { spawn, spawnSync } = require("child_process");
|
||||||
|
|
||||||
const REPO = { owner: "cexll", name: "myclaude" };
|
const REPO = { owner: "cexll", name: "myclaude" };
|
||||||
const API_HEADERS = {
|
const API_HEADERS = {
|
||||||
@@ -931,6 +931,63 @@ async function uninstallModule(moduleName, config, repoRoot, installDir, dryRun)
|
|||||||
deleteModuleStatus(installDir, moduleName);
|
deleteModuleStatus(installDir, moduleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function installDefaultConfigs(installDir, repoRoot) {
|
||||||
|
try {
|
||||||
|
const claudeMdTarget = path.join(installDir, "CLAUDE.md");
|
||||||
|
const claudeMdSrc = path.join(repoRoot, "memorys", "CLAUDE.md");
|
||||||
|
if (!fs.existsSync(claudeMdTarget) && fs.existsSync(claudeMdSrc)) {
|
||||||
|
await fs.promises.copyFile(claudeMdSrc, claudeMdTarget);
|
||||||
|
process.stdout.write(`Installed CLAUDE.md to ${claudeMdTarget}\n`);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
process.stderr.write(`Warning: could not install default configs: ${err.message}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function printPostInstallInfo(installDir) {
|
||||||
|
process.stdout.write("\n");
|
||||||
|
|
||||||
|
// Check codeagent-wrapper version
|
||||||
|
const wrapperBin = path.join(installDir, "bin", "codeagent-wrapper");
|
||||||
|
let wrapperVersion = null;
|
||||||
|
try {
|
||||||
|
const r = spawnSync(wrapperBin, ["--version"], { timeout: 5000 });
|
||||||
|
if (r.status === 0 && r.stdout) {
|
||||||
|
wrapperVersion = r.stdout.toString().trim();
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
// Check PATH
|
||||||
|
const binDir = path.join(installDir, "bin");
|
||||||
|
const envPath = process.env.PATH || "";
|
||||||
|
const pathOk = envPath.split(path.delimiter).some((p) => {
|
||||||
|
try { return fs.realpathSync(p) === fs.realpathSync(binDir); } catch { return p === binDir; }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check backend CLIs
|
||||||
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
||||||
|
const backends = ["codex", "claude", "gemini", "opencode"];
|
||||||
|
const detected = {};
|
||||||
|
for (const name of backends) {
|
||||||
|
try {
|
||||||
|
const r = spawnSync(whichCmd, [name], { timeout: 3000 });
|
||||||
|
detected[name] = r.status === 0;
|
||||||
|
} catch {
|
||||||
|
detected[name] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stdout.write("Setup Complete!\n");
|
||||||
|
process.stdout.write(` codeagent-wrapper: ${wrapperVersion || "(not found)"} ${wrapperVersion ? "✓" : "✗"}\n`);
|
||||||
|
process.stdout.write(` PATH: ${binDir} ${pathOk ? "✓" : "✗ (not in PATH)"}\n`);
|
||||||
|
process.stdout.write("\nBackend CLIs detected:\n");
|
||||||
|
process.stdout.write(" " + backends.map((b) => `${b} ${detected[b] ? "✓" : "✗"}`).join(" | ") + "\n");
|
||||||
|
process.stdout.write("\nNext steps:\n");
|
||||||
|
process.stdout.write(" 1. Configure API keys in ~/.codeagent/models.json\n");
|
||||||
|
process.stdout.write(' 2. Try: /do "your first task"\n');
|
||||||
|
process.stdout.write("\n");
|
||||||
|
}
|
||||||
|
|
||||||
async function installSelected(picks, tag, config, installDir, force, dryRun) {
|
async function installSelected(picks, tag, config, installDir, force, dryRun) {
|
||||||
const needRepo = picks.some((p) => p.kind !== "wrapper");
|
const needRepo = picks.some((p) => p.kind !== "wrapper");
|
||||||
const needWrapper = picks.some((p) => p.kind === "wrapper");
|
const needWrapper = picks.some((p) => p.kind === "wrapper");
|
||||||
@@ -985,6 +1042,9 @@ async function installSelected(picks, tag, config, installDir, force, dryRun) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await installDefaultConfigs(installDir, repoRoot);
|
||||||
|
printPostInstallInfo(installDir);
|
||||||
} finally {
|
} finally {
|
||||||
await rmTree(tmp);
|
await rmTree(tmp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,97 +1,158 @@
|
|||||||
# codeagent-wrapper
|
# codeagent-wrapper
|
||||||
|
|
||||||
`codeagent-wrapper` 是一个用 Go 编写的“多后端 AI 代码代理”命令行包装器:用统一的 CLI 入口封装不同的 AI 工具后端(Codex / Claude / Gemini / Opencode),并提供一致的参数、配置与会话恢复体验。
|
[English](README.md) | [中文](README_CN.md)
|
||||||
|
|
||||||
入口:`cmd/codeagent/main.go`(生成二进制名:`codeagent`)和 `cmd/codeagent-wrapper/main.go`(生成二进制名:`codeagent-wrapper`)。两者行为一致。
|
A multi-backend AI code agent CLI wrapper written in Go. Provides a unified CLI entry point wrapping different AI tool backends (Codex / Claude / Gemini / OpenCode) with consistent flags, configuration, skill injection, and session resumption.
|
||||||
|
|
||||||
## 功能特性
|
Entry point: `cmd/codeagent-wrapper/main.go` (binary: `codeagent-wrapper`).
|
||||||
|
|
||||||
- 多后端支持:`codex` / `claude` / `gemini` / `opencode`
|
## Features
|
||||||
- 统一命令行:`codeagent [flags] <task>` / `codeagent resume <session_id> <task> [workdir]`
|
|
||||||
- 自动 stdin:遇到换行/特殊字符/超长任务自动走 stdin,避免 shell quoting 地狱;也可显式使用 `-`
|
|
||||||
- 配置合并:支持配置文件与 `CODEAGENT_*` 环境变量(viper)
|
|
||||||
- Agent 预设:从 `~/.codeagent/models.json` 读取 backend/model/prompt 等预设
|
|
||||||
- 并行执行:`--parallel` 从 stdin 读取多任务配置,支持依赖拓扑并发执行
|
|
||||||
- 日志清理:`codeagent cleanup` 清理旧日志(日志写入系统临时目录)
|
|
||||||
|
|
||||||
## 安装
|
- **Multi-backend support**: `codex` / `claude` / `gemini` / `opencode`
|
||||||
|
- **Unified CLI**: `codeagent-wrapper [flags] <task>` / `codeagent-wrapper resume <session_id> <task> [workdir]`
|
||||||
|
- **Auto stdin**: Automatically pipes via stdin when task contains newlines, special characters, or exceeds length; also supports explicit `-`
|
||||||
|
- **Config merging**: Config files + `CODEAGENT_*` environment variables (viper)
|
||||||
|
- **Agent presets**: Read backend/model/prompt/reasoning/yolo/allowed_tools from `~/.codeagent/models.json`
|
||||||
|
- **Dynamic agents**: Place a `{name}.md` prompt file in `~/.codeagent/agents/` to use as an agent
|
||||||
|
- **Skill auto-injection**: `--skills` for manual specification, or auto-detect from project tech stack (Go/Rust/Python/Node.js/Vue)
|
||||||
|
- **Git worktree isolation**: `--worktree` executes tasks in an isolated git worktree with auto-generated task_id and branch
|
||||||
|
- **Parallel execution**: `--parallel` reads multi-task config from stdin with dependency-aware topological concurrent execution and structured summary reports
|
||||||
|
- **Backend config**: `backends` section in `models.json` supports per-backend `base_url` / `api_key` injection
|
||||||
|
- **Claude tool control**: `allowed_tools` / `disallowed_tools` to restrict available tools for Claude backend
|
||||||
|
- **Stderr noise filtering**: Automatically filters noisy stderr output from Gemini and Codex backends
|
||||||
|
- **Log cleanup**: `codeagent-wrapper cleanup` cleans old logs (logs written to system temp directory)
|
||||||
|
- **Cross-platform**: macOS / Linux / Windows
|
||||||
|
|
||||||
要求:Go 1.21+。
|
## Installation
|
||||||
|
|
||||||
在仓库根目录执行:
|
### Recommended (interactive installer)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go install ./cmd/codeagent
|
npx github:cexll/myclaude
|
||||||
go install ./cmd/codeagent-wrapper
|
|
||||||
```
|
```
|
||||||
|
|
||||||
安装后确认:
|
Select the `codeagent-wrapper` module to install.
|
||||||
|
|
||||||
|
### Manual build
|
||||||
|
|
||||||
|
Requires: Go 1.21+.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codeagent version
|
# Build from source
|
||||||
codeagent-wrapper version
|
make build
|
||||||
|
|
||||||
|
# Or install to $GOPATH/bin
|
||||||
|
make install
|
||||||
```
|
```
|
||||||
|
|
||||||
## 使用示例
|
Verify installation:
|
||||||
|
|
||||||
最简单用法(默认后端:`codex`):
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codeagent "分析 internal/app/cli.go 的入口逻辑,给出改进建议"
|
codeagent-wrapper --version
|
||||||
```
|
```
|
||||||
|
|
||||||
指定后端:
|
## Usage
|
||||||
|
|
||||||
|
Basic usage (default backend: `codex`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codeagent --backend claude "解释 internal/executor/parallel_config.go 的并行配置格式"
|
codeagent-wrapper "analyze the entry logic of internal/app/cli.go"
|
||||||
```
|
```
|
||||||
|
|
||||||
指定工作目录(第 2 个位置参数):
|
Specify backend:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codeagent "在当前 repo 下搜索潜在数据竞争" .
|
codeagent-wrapper --backend claude "explain the parallel config format in internal/executor/parallel_config.go"
|
||||||
```
|
```
|
||||||
|
|
||||||
显式从 stdin 读取 task(使用 `-`):
|
Specify working directory (2nd positional argument):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cat task.txt | codeagent -
|
codeagent-wrapper "search for potential data races in this repo" .
|
||||||
```
|
```
|
||||||
|
|
||||||
恢复会话:
|
Explicit stdin (using `-`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codeagent resume <session_id> "继续上次任务"
|
cat task.txt | codeagent-wrapper -
|
||||||
```
|
```
|
||||||
|
|
||||||
并行模式(从 stdin 读取任务配置;禁止位置参数):
|
HEREDOC (recommended for multi-line tasks):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
codeagent --parallel <<'EOF'
|
codeagent-wrapper --backend claude - <<'EOF'
|
||||||
|
Implement user authentication:
|
||||||
|
- JWT tokens
|
||||||
|
- bcrypt password hashing
|
||||||
|
- Session management
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Resume session:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper resume <session_id> "continue the previous task"
|
||||||
|
```
|
||||||
|
|
||||||
|
Execute in isolated git worktree:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --worktree "refactor the auth module"
|
||||||
|
```
|
||||||
|
|
||||||
|
Manual skill injection:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --skills golang-base-practices "optimize database queries"
|
||||||
|
```
|
||||||
|
|
||||||
|
Parallel mode (task config from stdin):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --parallel <<'EOF'
|
||||||
---TASK---
|
---TASK---
|
||||||
id: t1
|
id: t1
|
||||||
workdir: .
|
workdir: .
|
||||||
backend: codex
|
backend: codex
|
||||||
---CONTENT---
|
---CONTENT---
|
||||||
列出本项目的主要模块以及它们的职责。
|
List the main modules and their responsibilities.
|
||||||
---TASK---
|
---TASK---
|
||||||
id: t2
|
id: t2
|
||||||
dependencies: t1
|
dependencies: t1
|
||||||
backend: claude
|
backend: claude
|
||||||
---CONTENT---
|
---CONTENT---
|
||||||
基于 t1 的结论,提出重构风险点与建议。
|
Based on t1's findings, identify refactoring risks and suggestions.
|
||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
## 配置说明
|
## CLI Flags
|
||||||
|
|
||||||
### 配置文件
|
| Flag | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `--backend <name>` | Backend selection (codex/claude/gemini/opencode) |
|
||||||
|
| `--model <name>` | Model override |
|
||||||
|
| `--agent <name>` | Agent preset name (from models.json or ~/.codeagent/agents/) |
|
||||||
|
| `--prompt-file <path>` | Read prompt from file |
|
||||||
|
| `--skills <names>` | Comma-separated skill names for spec injection |
|
||||||
|
| `--reasoning-effort <level>` | Reasoning effort (backend-specific) |
|
||||||
|
| `--skip-permissions` | Skip permission prompts |
|
||||||
|
| `--dangerously-skip-permissions` | Alias for `--skip-permissions` |
|
||||||
|
| `--worktree` | Execute in a new git worktree (auto-generates task_id) |
|
||||||
|
| `--parallel` | Parallel task mode (config from stdin) |
|
||||||
|
| `--full-output` | Full output in parallel mode (default: summary only) |
|
||||||
|
| `--config <path>` | Config file path (default: `$HOME/.codeagent/config.*`) |
|
||||||
|
| `--version`, `-v` | Print version |
|
||||||
|
| `--cleanup` | Clean up old logs |
|
||||||
|
|
||||||
默认查找路径(当 `--config` 为空时):
|
## Configuration
|
||||||
|
|
||||||
|
### Config File
|
||||||
|
|
||||||
|
Default search path (when `--config` is empty):
|
||||||
|
|
||||||
- `$HOME/.codeagent/config.(yaml|yml|json|toml|...)`
|
- `$HOME/.codeagent/config.(yaml|yml|json|toml|...)`
|
||||||
|
|
||||||
示例(YAML):
|
Example (YAML):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
backend: codex
|
backend: codex
|
||||||
@@ -99,59 +160,113 @@ model: gpt-4.1
|
|||||||
skip-permissions: false
|
skip-permissions: false
|
||||||
```
|
```
|
||||||
|
|
||||||
也可以通过 `--config /path/to/config.yaml` 显式指定。
|
Can also be specified explicitly via `--config /path/to/config.yaml`.
|
||||||
|
|
||||||
### 环境变量(`CODEAGENT_*`)
|
### Environment Variables (`CODEAGENT_*`)
|
||||||
|
|
||||||
通过 viper 读取并自动映射 `-` 为 `_`,常用项:
|
Read via viper with automatic `-` to `_` mapping:
|
||||||
|
|
||||||
- `CODEAGENT_BACKEND`(`codex|claude|gemini|opencode`)
|
| Variable | Description |
|
||||||
- `CODEAGENT_MODEL`
|
|----------|-------------|
|
||||||
- `CODEAGENT_AGENT`
|
| `CODEAGENT_BACKEND` | Backend name (codex/claude/gemini/opencode) |
|
||||||
- `CODEAGENT_PROMPT_FILE`
|
| `CODEAGENT_MODEL` | Model name |
|
||||||
- `CODEAGENT_REASONING_EFFORT`
|
| `CODEAGENT_AGENT` | Agent preset name |
|
||||||
- `CODEAGENT_SKIP_PERMISSIONS`
|
| `CODEAGENT_PROMPT_FILE` | Prompt file path |
|
||||||
- `CODEAGENT_FULL_OUTPUT`(并行模式 legacy 输出)
|
| `CODEAGENT_REASONING_EFFORT` | Reasoning effort |
|
||||||
- `CODEAGENT_MAX_PARALLEL_WORKERS`(0 表示不限制,上限 100)
|
| `CODEAGENT_SKIP_PERMISSIONS` | Skip permission prompts (default true; set `false` to disable) |
|
||||||
|
| `CODEAGENT_FULL_OUTPUT` | Full output in parallel mode |
|
||||||
|
| `CODEAGENT_MAX_PARALLEL_WORKERS` | Parallel worker count (0=unlimited, max 100) |
|
||||||
|
| `CODEAGENT_TMPDIR` | Custom temp directory (for macOS permission issues) |
|
||||||
|
| `CODEX_TIMEOUT` | Timeout in ms (default 7200000 = 2 hours) |
|
||||||
|
| `CODEX_BYPASS_SANDBOX` | Codex sandbox bypass (default true; set `false` to disable) |
|
||||||
|
| `DO_WORKTREE_DIR` | Reuse existing worktree directory (set by /do workflow) |
|
||||||
|
|
||||||
### Agent 预设(`~/.codeagent/models.json`)
|
### Agent Presets (`~/.codeagent/models.json`)
|
||||||
|
|
||||||
可在 `~/.codeagent/models.json` 定义 agent → backend/model/prompt 等映射,用 `--agent <name>` 选择:
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"default_backend": "opencode",
|
"default_backend": "codex",
|
||||||
"default_model": "opencode/grok-code",
|
"default_model": "gpt-4.1",
|
||||||
|
"backends": {
|
||||||
|
"codex": { "api_key": "..." },
|
||||||
|
"claude": { "base_url": "http://localhost:23001", "api_key": "..." }
|
||||||
|
},
|
||||||
"agents": {
|
"agents": {
|
||||||
"develop": {
|
"develop": {
|
||||||
"backend": "codex",
|
"backend": "codex",
|
||||||
"model": "gpt-4.1",
|
"model": "gpt-4.1",
|
||||||
"prompt_file": "~/.codeagent/prompts/develop.md",
|
"prompt_file": "~/.codeagent/prompts/develop.md",
|
||||||
"description": "Code development"
|
"reasoning": "high",
|
||||||
|
"yolo": true,
|
||||||
|
"allowed_tools": ["Read", "Write", "Bash"],
|
||||||
|
"disallowed_tools": ["WebFetch"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 支持的后端
|
Use `--agent <name>` to select a preset. Agents inherit `base_url` / `api_key` from the corresponding `backends` entry.
|
||||||
|
|
||||||
该项目本身不内置模型能力,依赖你本机安装并可在 `PATH` 中找到对应 CLI:
|
### Dynamic Agents
|
||||||
|
|
||||||
- `codex`:执行 `codex e ...`(默认会添加 `--dangerously-bypass-approvals-and-sandbox`;如需关闭请设置 `CODEX_BYPASS_SANDBOX=false`)
|
Place a `{name}.md` file in `~/.codeagent/agents/` to use it via `--agent {name}`. The Markdown file is read as the prompt, using `default_backend` and `default_model`.
|
||||||
- `claude`:执行 `claude -p ... --output-format stream-json`(默认会跳过权限提示;如需开启请设置 `CODEAGENT_SKIP_PERMISSIONS=false`)
|
|
||||||
- `gemini`:执行 `gemini ... -o stream-json`(可从 `~/.gemini/.env` 加载环境变量)
|
|
||||||
- `opencode`:执行 `opencode run --format json`
|
|
||||||
|
|
||||||
## 开发
|
### Skill Auto-Detection
|
||||||
|
|
||||||
|
When no skills are specified via `--skills`, codeagent-wrapper auto-detects the tech stack from files in the working directory:
|
||||||
|
|
||||||
|
| Detected Files | Injected Skills |
|
||||||
|
|----------------|-----------------|
|
||||||
|
| `go.mod` / `go.sum` | `golang-base-practices` |
|
||||||
|
| `Cargo.toml` | `rust-best-practices` |
|
||||||
|
| `pyproject.toml` / `setup.py` / `requirements.txt` | `python-best-practices` |
|
||||||
|
| `package.json` | `vercel-react-best-practices`, `frontend-design` |
|
||||||
|
| `vue.config.js` / `vite.config.ts` / `nuxt.config.ts` | `vue-web-app` |
|
||||||
|
|
||||||
|
Skill specs are read from `~/.claude/skills/{name}/SKILL.md`, subject to a 16000-character budget.
|
||||||
|
|
||||||
|
## Supported Backends
|
||||||
|
|
||||||
|
This project does not embed model capabilities. It requires the corresponding CLI tools installed and available in `PATH`:
|
||||||
|
|
||||||
|
| Backend | Command | Notes |
|
||||||
|
|---------|---------|-------|
|
||||||
|
| `codex` | `codex e ...` | Adds `--dangerously-bypass-approvals-and-sandbox` by default; set `CODEX_BYPASS_SANDBOX=false` to disable |
|
||||||
|
| `claude` | `claude -p ... --output-format stream-json` | Skips permissions and disables setting-sources to prevent recursion; set `CODEAGENT_SKIP_PERMISSIONS=false` to enable prompts; auto-reads env and model from `~/.claude/settings.json` |
|
||||||
|
| `gemini` | `gemini -o stream-json -y ...` | Auto-loads env vars from `~/.gemini/.env` (GEMINI_API_KEY, GEMINI_MODEL, etc.) |
|
||||||
|
| `opencode` | `opencode run --format json` | — |
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
cmd/codeagent-wrapper/main.go # CLI entry point
|
||||||
|
internal/
|
||||||
|
app/ # CLI command definitions, argument parsing, main orchestration
|
||||||
|
backend/ # Backend abstraction and implementations (codex/claude/gemini/opencode)
|
||||||
|
config/ # Config loading, agent resolution, viper bindings
|
||||||
|
executor/ # Task execution engine: single/parallel/worktree/skill injection
|
||||||
|
logger/ # Structured logging system
|
||||||
|
parser/ # JSON stream parser
|
||||||
|
utils/ # Common utility functions
|
||||||
|
worktree/ # Git worktree management
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make build
|
make build # Build binary
|
||||||
make test
|
make test # Run tests
|
||||||
make lint
|
make lint # golangci-lint + staticcheck
|
||||||
make clean
|
make clean # Clean build artifacts
|
||||||
|
make install # Install to $GOPATH/bin
|
||||||
```
|
```
|
||||||
|
|
||||||
## 故障排查
|
CI uses GitHub Actions with Go 1.21 / 1.22 matrix testing.
|
||||||
|
|
||||||
- macOS 下如果看到临时目录相关的 `permission denied`(例如临时可执行文件无法在 `/var/folders/.../T` 执行),可设置一个可执行的临时目录:`CODEAGENT_TMPDIR=$HOME/.codeagent/tmp`。
|
## Troubleshooting
|
||||||
- `claude` 后端的 `base_url/api_key`(来自 `~/.codeagent/models.json`)会注入到子进程环境变量:`ANTHROPIC_BASE_URL` / `ANTHROPIC_API_KEY`。若 `base_url` 指向本地代理(如 `localhost:23001`),请确认代理进程在运行。
|
|
||||||
|
- On macOS, if you see `permission denied` related to temp directories, set: `CODEAGENT_TMPDIR=$HOME/.codeagent/tmp`
|
||||||
|
- `claude` backend's `base_url` / `api_key` (from `~/.codeagent/models.json` `backends.claude`) are injected as `ANTHROPIC_BASE_URL` / `ANTHROPIC_API_KEY` env vars
|
||||||
|
- `gemini` backend's API key is loaded from `~/.gemini/.env`, injected as `GEMINI_API_KEY` with `GEMINI_API_KEY_AUTH_MECHANISM=bearer` auto-set
|
||||||
|
- Exit codes: 127 = backend not found, 124 = timeout, 130 = interrupted
|
||||||
|
- Parallel mode outputs structured summary by default; use `--full-output` for complete output when debugging
|
||||||
|
|||||||
272
codeagent-wrapper/README_CN.md
Normal file
272
codeagent-wrapper/README_CN.md
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
# codeagent-wrapper
|
||||||
|
|
||||||
|
[English](README.md) | [中文](README_CN.md)
|
||||||
|
|
||||||
|
`codeagent-wrapper` 是一个用 Go 编写的多后端 AI 代码代理命令行包装器:用统一的 CLI 入口封装不同的 AI 工具后端(Codex / Claude / Gemini / OpenCode),并提供一致的参数、配置、技能注入与会话恢复体验。
|
||||||
|
|
||||||
|
入口:`cmd/codeagent-wrapper/main.go`(生成二进制名:`codeagent-wrapper`)。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- **多后端支持**:`codex` / `claude` / `gemini` / `opencode`
|
||||||
|
- **统一命令行**:`codeagent-wrapper [flags] <task>` / `codeagent-wrapper resume <session_id> <task> [workdir]`
|
||||||
|
- **自动 stdin**:遇到换行/特殊字符/超长任务自动走 stdin,避免 shell quoting 问题;也可显式使用 `-`
|
||||||
|
- **配置合并**:支持配置文件与 `CODEAGENT_*` 环境变量(viper)
|
||||||
|
- **Agent 预设**:从 `~/.codeagent/models.json` 读取 backend/model/prompt/reasoning/yolo/allowed_tools 等预设
|
||||||
|
- **动态 Agent**:在 `~/.codeagent/agents/{name}.md` 放置 prompt 文件即可作为 agent 使用
|
||||||
|
- **技能自动注入**:`--skills` 手动指定,或根据项目技术栈自动检测(Go/Rust/Python/Node.js/Vue)并注入对应技能规范
|
||||||
|
- **Git Worktree 隔离**:`--worktree` 在独立 git worktree 中执行任务,自动生成 task_id 和分支
|
||||||
|
- **并行执行**:`--parallel` 从 stdin 读取多任务配置,支持依赖拓扑并发执行,带结构化摘要报告
|
||||||
|
- **后端配置**:`models.json` 的 `backends` 节支持 per-backend 的 `base_url` / `api_key` 注入
|
||||||
|
- **Claude 工具控制**:`allowed_tools` / `disallowed_tools` 限制 Claude 后端可用工具
|
||||||
|
- **Stderr 降噪**:自动过滤 Gemini 和 Codex 后端的噪声 stderr 输出
|
||||||
|
- **日志清理**:`codeagent-wrapper cleanup` 清理旧日志(日志写入系统临时目录)
|
||||||
|
- **跨平台**:支持 macOS / Linux / Windows
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
### 推荐方式(交互式安装器)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx github:cexll/myclaude
|
||||||
|
```
|
||||||
|
|
||||||
|
选择 `codeagent-wrapper` 模块进行安装。
|
||||||
|
|
||||||
|
### 手动构建
|
||||||
|
|
||||||
|
要求:Go 1.21+。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 从源码构建
|
||||||
|
make build
|
||||||
|
|
||||||
|
# 或直接安装到 $GOPATH/bin
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
安装后确认:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --version
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用示例
|
||||||
|
|
||||||
|
最简单用法(默认后端:`codex`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper "分析 internal/app/cli.go 的入口逻辑,给出改进建议"
|
||||||
|
```
|
||||||
|
|
||||||
|
指定后端:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --backend claude "解释 internal/executor/parallel_config.go 的并行配置格式"
|
||||||
|
```
|
||||||
|
|
||||||
|
指定工作目录(第 2 个位置参数):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper "在当前 repo 下搜索潜在数据竞争" .
|
||||||
|
```
|
||||||
|
|
||||||
|
显式从 stdin 读取 task(使用 `-`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat task.txt | codeagent-wrapper -
|
||||||
|
```
|
||||||
|
|
||||||
|
使用 HEREDOC(推荐用于多行任务):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --backend claude - <<'EOF'
|
||||||
|
实现用户认证系统:
|
||||||
|
- JWT 令牌
|
||||||
|
- bcrypt 密码哈希
|
||||||
|
- 会话管理
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
恢复会话:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper resume <session_id> "继续上次任务"
|
||||||
|
```
|
||||||
|
|
||||||
|
在 git worktree 中隔离执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --worktree "重构认证模块"
|
||||||
|
```
|
||||||
|
|
||||||
|
手动指定技能注入:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --skills golang-base-practices "优化数据库查询"
|
||||||
|
```
|
||||||
|
|
||||||
|
并行模式(从 stdin 读取任务配置):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
codeagent-wrapper --parallel <<'EOF'
|
||||||
|
---TASK---
|
||||||
|
id: t1
|
||||||
|
workdir: .
|
||||||
|
backend: codex
|
||||||
|
---CONTENT---
|
||||||
|
列出本项目的主要模块以及它们的职责。
|
||||||
|
---TASK---
|
||||||
|
id: t2
|
||||||
|
dependencies: t1
|
||||||
|
backend: claude
|
||||||
|
---CONTENT---
|
||||||
|
基于 t1 的结论,提出重构风险点与建议。
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
## CLI 参数
|
||||||
|
|
||||||
|
| 参数 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `--backend <name>` | 后端选择(codex/claude/gemini/opencode) |
|
||||||
|
| `--model <name>` | 覆盖模型 |
|
||||||
|
| `--agent <name>` | Agent 预设名(来自 models.json 或 ~/.codeagent/agents/) |
|
||||||
|
| `--prompt-file <path>` | 从文件读取 prompt |
|
||||||
|
| `--skills <names>` | 逗号分隔的技能名,注入对应规范 |
|
||||||
|
| `--reasoning-effort <level>` | 推理力度(后端相关) |
|
||||||
|
| `--skip-permissions` | 跳过权限提示 |
|
||||||
|
| `--dangerously-skip-permissions` | `--skip-permissions` 的别名 |
|
||||||
|
| `--worktree` | 在新 git worktree 中执行(自动生成 task_id) |
|
||||||
|
| `--parallel` | 并行任务模式(从 stdin 读取配置) |
|
||||||
|
| `--full-output` | 并行模式下输出完整消息(默认仅输出摘要) |
|
||||||
|
| `--config <path>` | 配置文件路径(默认:`$HOME/.codeagent/config.*`) |
|
||||||
|
| `--version`, `-v` | 打印版本号 |
|
||||||
|
| `--cleanup` | 清理旧日志 |
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### 配置文件
|
||||||
|
|
||||||
|
默认查找路径(当 `--config` 为空时):
|
||||||
|
|
||||||
|
- `$HOME/.codeagent/config.(yaml|yml|json|toml|...)`
|
||||||
|
|
||||||
|
示例(YAML):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
backend: codex
|
||||||
|
model: gpt-4.1
|
||||||
|
skip-permissions: false
|
||||||
|
```
|
||||||
|
|
||||||
|
也可以通过 `--config /path/to/config.yaml` 显式指定。
|
||||||
|
|
||||||
|
### 环境变量(`CODEAGENT_*`)
|
||||||
|
|
||||||
|
通过 viper 读取并自动映射 `-` 为 `_`,常用项:
|
||||||
|
|
||||||
|
| 变量 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `CODEAGENT_BACKEND` | 后端名(codex/claude/gemini/opencode) |
|
||||||
|
| `CODEAGENT_MODEL` | 模型名 |
|
||||||
|
| `CODEAGENT_AGENT` | Agent 预设名 |
|
||||||
|
| `CODEAGENT_PROMPT_FILE` | Prompt 文件路径 |
|
||||||
|
| `CODEAGENT_REASONING_EFFORT` | 推理力度 |
|
||||||
|
| `CODEAGENT_SKIP_PERMISSIONS` | 跳过权限提示(默认 true;设 `false` 关闭) |
|
||||||
|
| `CODEAGENT_FULL_OUTPUT` | 并行模式完整输出 |
|
||||||
|
| `CODEAGENT_MAX_PARALLEL_WORKERS` | 并行 worker 数(0=不限制,上限 100) |
|
||||||
|
| `CODEAGENT_TMPDIR` | 自定义临时目录(macOS 权限问题时使用) |
|
||||||
|
| `CODEX_TIMEOUT` | 超时(毫秒,默认 7200000 即 2 小时) |
|
||||||
|
| `CODEX_BYPASS_SANDBOX` | Codex sandbox bypass(默认 true;设 `false` 关闭) |
|
||||||
|
| `DO_WORKTREE_DIR` | 复用已有 worktree 目录(由 /do 工作流设置) |
|
||||||
|
|
||||||
|
### Agent 预设(`~/.codeagent/models.json`)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"default_backend": "codex",
|
||||||
|
"default_model": "gpt-4.1",
|
||||||
|
"backends": {
|
||||||
|
"codex": { "api_key": "..." },
|
||||||
|
"claude": { "base_url": "http://localhost:23001", "api_key": "..." }
|
||||||
|
},
|
||||||
|
"agents": {
|
||||||
|
"develop": {
|
||||||
|
"backend": "codex",
|
||||||
|
"model": "gpt-4.1",
|
||||||
|
"prompt_file": "~/.codeagent/prompts/develop.md",
|
||||||
|
"reasoning": "high",
|
||||||
|
"yolo": true,
|
||||||
|
"allowed_tools": ["Read", "Write", "Bash"],
|
||||||
|
"disallowed_tools": ["WebFetch"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
用 `--agent <name>` 选择预设,agent 会继承 `backends` 下对应后端的 `base_url` / `api_key`。
|
||||||
|
|
||||||
|
### 动态 Agent
|
||||||
|
|
||||||
|
在 `~/.codeagent/agents/` 目录放置 `{name}.md` 文件,即可通过 `--agent {name}` 使用,自动读取该 Markdown 作为 prompt,使用 `default_backend` 和 `default_model`。
|
||||||
|
|
||||||
|
### 技能自动检测
|
||||||
|
|
||||||
|
当未通过 `--skills` 显式指定技能时,codeagent-wrapper 会根据工作目录中的文件自动检测技术栈:
|
||||||
|
|
||||||
|
| 检测文件 | 注入技能 |
|
||||||
|
|----------|----------|
|
||||||
|
| `go.mod` / `go.sum` | `golang-base-practices` |
|
||||||
|
| `Cargo.toml` | `rust-best-practices` |
|
||||||
|
| `pyproject.toml` / `setup.py` / `requirements.txt` | `python-best-practices` |
|
||||||
|
| `package.json` | `vercel-react-best-practices`, `frontend-design` |
|
||||||
|
| `vue.config.js` / `vite.config.ts` / `nuxt.config.ts` | `vue-web-app` |
|
||||||
|
|
||||||
|
技能规范从 `~/.claude/skills/{name}/SKILL.md` 读取,受 16000 字符预算限制。
|
||||||
|
|
||||||
|
## 支持的后端
|
||||||
|
|
||||||
|
该项目本身不内置模型能力,依赖本机安装并可在 `PATH` 中找到对应 CLI:
|
||||||
|
|
||||||
|
| 后端 | 执行命令 | 说明 |
|
||||||
|
|------|----------|------|
|
||||||
|
| `codex` | `codex e ...` | 默认添加 `--dangerously-bypass-approvals-and-sandbox`;设 `CODEX_BYPASS_SANDBOX=false` 关闭 |
|
||||||
|
| `claude` | `claude -p ... --output-format stream-json` | 默认跳过权限并禁用 setting-sources 防止递归;设 `CODEAGENT_SKIP_PERMISSIONS=false` 开启权限;自动读取 `~/.claude/settings.json` 中的 env 和 model |
|
||||||
|
| `gemini` | `gemini -o stream-json -y ...` | 自动从 `~/.gemini/.env` 加载环境变量(GEMINI_API_KEY, GEMINI_MODEL 等) |
|
||||||
|
| `opencode` | `opencode run --format json` | — |
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
cmd/codeagent-wrapper/main.go # CLI 入口
|
||||||
|
internal/
|
||||||
|
app/ # CLI 命令定义、参数解析、主逻辑编排
|
||||||
|
backend/ # 后端抽象与实现(codex/claude/gemini/opencode)
|
||||||
|
config/ # 配置加载、agent 解析、viper 绑定
|
||||||
|
executor/ # 任务执行引擎:单任务/并行/worktree/技能注入
|
||||||
|
logger/ # 结构化日志系统
|
||||||
|
parser/ # JSON stream 解析器
|
||||||
|
utils/ # 通用工具函数
|
||||||
|
worktree/ # Git worktree 管理
|
||||||
|
```
|
||||||
|
|
||||||
|
## 开发
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make build # 构建
|
||||||
|
make test # 运行测试
|
||||||
|
make lint # golangci-lint + staticcheck
|
||||||
|
make clean # 清理构建产物
|
||||||
|
make install # 安装到 $GOPATH/bin
|
||||||
|
```
|
||||||
|
|
||||||
|
CI 使用 GitHub Actions,Go 1.21 / 1.22 矩阵测试。
|
||||||
|
|
||||||
|
## 故障排查
|
||||||
|
|
||||||
|
- macOS 下如果看到临时目录相关的 `permission denied`,可设置:`CODEAGENT_TMPDIR=$HOME/.codeagent/tmp`
|
||||||
|
- `claude` 后端的 `base_url` / `api_key`(来自 `~/.codeagent/models.json` 的 `backends.claude`)会注入到子进程环境变量 `ANTHROPIC_BASE_URL` / `ANTHROPIC_API_KEY`
|
||||||
|
- `gemini` 后端的 API key 从 `~/.gemini/.env` 加载,注入 `GEMINI_API_KEY` 并自动设置 `GEMINI_API_KEY_AUTH_MECHANISM=bearer`
|
||||||
|
- 后端命令未找到时返回退出码 127,超时返回 124,中断返回 130
|
||||||
|
- 并行模式默认输出结构化摘要,使用 `--full-output` 查看完整输出以便调试
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
# Codeagent-Wrapper User Guide
|
# Codeagent-Wrapper User Guide
|
||||||
|
|
||||||
Multi-backend AI code execution wrapper supporting Codex, Claude, and Gemini.
|
Multi-backend AI code execution wrapper supporting Codex, Claude, Gemini, and OpenCode.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
`codeagent-wrapper` is a Go-based CLI tool that provides a unified interface to multiple AI coding backends. It handles:
|
`codeagent-wrapper` is a Go-based CLI tool that provides a unified interface to multiple AI coding backends. It handles:
|
||||||
- Multi-backend execution (Codex, Claude, Gemini)
|
- Multi-backend execution (Codex, Claude, Gemini, OpenCode)
|
||||||
- JSON stream parsing and output formatting
|
- JSON stream parsing and output formatting
|
||||||
- Session management and resumption
|
- Session management and resumption
|
||||||
- Parallel task execution with dependency resolution
|
- Parallel task execution with dependency resolution
|
||||||
@@ -42,6 +42,24 @@ Implement user authentication:
|
|||||||
EOF
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### CLI Flags
|
||||||
|
|
||||||
|
| Flag | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `--backend <name>` | Select backend (codex/claude/gemini/opencode) |
|
||||||
|
| `--model <name>` | Override model for this invocation |
|
||||||
|
| `--agent <name>` | Agent preset name (from ~/.codeagent/models.json) |
|
||||||
|
| `--config <path>` | Path to models.json config file |
|
||||||
|
| `--cleanup` | Clean up log files on startup |
|
||||||
|
| `--worktree` | Execute in a new git worktree (auto-generates task ID) |
|
||||||
|
| `--skills <names>` | Comma-separated skill names for spec injection |
|
||||||
|
| `--prompt-file <path>` | Read prompt from file |
|
||||||
|
| `--reasoning-effort <level>` | Set reasoning effort (low/medium/high) |
|
||||||
|
| `--skip-permissions` | Skip permission prompts |
|
||||||
|
| `--parallel` | Enable parallel task execution |
|
||||||
|
| `--full-output` | Show full output in parallel mode |
|
||||||
|
| `--version`, `-v` | Print version and exit |
|
||||||
|
|
||||||
### Backend Selection
|
### Backend Selection
|
||||||
|
|
||||||
| Backend | Command | Best For |
|
| Backend | Command | Best For |
|
||||||
@@ -49,6 +67,7 @@ EOF
|
|||||||
| **Codex** | `--backend codex` | General code tasks (default) |
|
| **Codex** | `--backend codex` | General code tasks (default) |
|
||||||
| **Claude** | `--backend claude` | Complex reasoning, architecture |
|
| **Claude** | `--backend claude` | Complex reasoning, architecture |
|
||||||
| **Gemini** | `--backend gemini` | Fast iteration, prototyping |
|
| **Gemini** | `--backend gemini` | Fast iteration, prototyping |
|
||||||
|
| **OpenCode** | `--backend opencode` | Open-source alternative |
|
||||||
|
|
||||||
## Core Features
|
## Core Features
|
||||||
|
|
||||||
|
|||||||
56
config.json
56
config.json
@@ -39,6 +39,36 @@
|
|||||||
"omo": {
|
"omo": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"description": "OmO multi-agent orchestration with Sisyphus coordinator",
|
"description": "OmO multi-agent orchestration with Sisyphus coordinator",
|
||||||
|
"agents": {
|
||||||
|
"oracle": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": "claude-opus-4-5-20251101",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"librarian": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": "claude-sonnet-4-5-20250929",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"explore": {
|
||||||
|
"backend": "opencode",
|
||||||
|
"model": "opencode/grok-code"
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"backend": "codex",
|
||||||
|
"model": "gpt-5.2",
|
||||||
|
"reasoning": "xhigh",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"frontend-ui-ux-engineer": {
|
||||||
|
"backend": "gemini",
|
||||||
|
"model": "gemini-3-pro-preview"
|
||||||
|
},
|
||||||
|
"document-writer": {
|
||||||
|
"backend": "gemini",
|
||||||
|
"model": "gemini-3-flash-preview"
|
||||||
|
}
|
||||||
|
},
|
||||||
"operations": [
|
"operations": [
|
||||||
{
|
{
|
||||||
"type": "copy_file",
|
"type": "copy_file",
|
||||||
@@ -98,7 +128,27 @@
|
|||||||
},
|
},
|
||||||
"do": {
|
"do": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"description": "7-phase feature development workflow with codeagent orchestration",
|
"description": "5-phase feature development workflow with codeagent orchestration",
|
||||||
|
"agents": {
|
||||||
|
"develop": {
|
||||||
|
"backend": "codex",
|
||||||
|
"model": "gpt-4.1",
|
||||||
|
"reasoning": "high",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"code-explorer": {
|
||||||
|
"backend": "opencode",
|
||||||
|
"model": ""
|
||||||
|
},
|
||||||
|
"code-architect": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": ""
|
||||||
|
},
|
||||||
|
"code-reviewer": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"operations": [
|
"operations": [
|
||||||
{
|
{
|
||||||
"type": "copy_dir",
|
"type": "copy_dir",
|
||||||
@@ -148,7 +198,7 @@
|
|||||||
},
|
},
|
||||||
"claudekit": {
|
"claudekit": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
"description": "ClaudeKit workflow: skills/do + global hooks (pre-bash, inject-spec, log-prompt, on-stop)",
|
"description": "ClaudeKit workflow: skills/do + global hooks (pre-bash, inject-spec, log-prompt)",
|
||||||
"operations": [
|
"operations": [
|
||||||
{
|
{
|
||||||
"type": "copy_dir",
|
"type": "copy_dir",
|
||||||
@@ -160,7 +210,7 @@
|
|||||||
"type": "copy_dir",
|
"type": "copy_dir",
|
||||||
"source": "hooks",
|
"source": "hooks",
|
||||||
"target": "hooks",
|
"target": "hooks",
|
||||||
"description": "Install global hooks (pre-bash, inject-spec, log-prompt, on-stop)"
|
"description": "Install global hooks (pre-bash, inject-spec, log-prompt)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
210
install.py
210
install.py
@@ -244,6 +244,112 @@ def unmerge_hooks_from_settings(module_name: str, ctx: Dict[str, Any]) -> None:
|
|||||||
write_log({"level": "INFO", "message": f"Removed hooks for module: {module_name}"}, ctx)
|
write_log({"level": "INFO", "message": f"Removed hooks for module: {module_name}"}, ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def merge_agents_to_models(module_name: str, agents: Dict[str, Any], ctx: Dict[str, Any]) -> None:
|
||||||
|
"""Merge module agent configs into ~/.codeagent/models.json."""
|
||||||
|
models_path = Path.home() / ".codeagent" / "models.json"
|
||||||
|
models_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
if models_path.exists():
|
||||||
|
with models_path.open("r", encoding="utf-8") as fh:
|
||||||
|
models = json.load(fh)
|
||||||
|
else:
|
||||||
|
template = ctx["config_dir"] / "templates" / "models.json.example"
|
||||||
|
if template.exists():
|
||||||
|
with template.open("r", encoding="utf-8") as fh:
|
||||||
|
models = json.load(fh)
|
||||||
|
# Clear template agents so modules populate with __module__ tags
|
||||||
|
models["agents"] = {}
|
||||||
|
else:
|
||||||
|
models = {
|
||||||
|
"default_backend": "codex",
|
||||||
|
"default_model": "gpt-4.1",
|
||||||
|
"backends": {},
|
||||||
|
"agents": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
models.setdefault("agents", {})
|
||||||
|
for agent_name, agent_cfg in agents.items():
|
||||||
|
entry = dict(agent_cfg)
|
||||||
|
entry["__module__"] = module_name
|
||||||
|
|
||||||
|
existing = models["agents"].get(agent_name, {})
|
||||||
|
if not existing or existing.get("__module__"):
|
||||||
|
models["agents"][agent_name] = entry
|
||||||
|
|
||||||
|
with models_path.open("w", encoding="utf-8") as fh:
|
||||||
|
json.dump(models, fh, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
write_log(
|
||||||
|
{
|
||||||
|
"level": "INFO",
|
||||||
|
"message": (
|
||||||
|
f"Merged {len(agents)} agent(s) from {module_name} "
|
||||||
|
"into models.json"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def unmerge_agents_from_models(module_name: str, ctx: Dict[str, Any]) -> None:
|
||||||
|
"""Remove module's agent configs from ~/.codeagent/models.json.
|
||||||
|
|
||||||
|
If another installed module also declares a removed agent, restore that
|
||||||
|
module's version so shared agents (e.g. 'develop') are not lost.
|
||||||
|
"""
|
||||||
|
models_path = Path.home() / ".codeagent" / "models.json"
|
||||||
|
if not models_path.exists():
|
||||||
|
return
|
||||||
|
|
||||||
|
with models_path.open("r", encoding="utf-8") as fh:
|
||||||
|
models = json.load(fh)
|
||||||
|
|
||||||
|
agents = models.get("agents", {})
|
||||||
|
to_remove = [
|
||||||
|
name
|
||||||
|
for name, cfg in agents.items()
|
||||||
|
if isinstance(cfg, dict) and cfg.get("__module__") == module_name
|
||||||
|
]
|
||||||
|
|
||||||
|
if not to_remove:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Load config to find other modules that declare the same agents
|
||||||
|
config_path = ctx["config_dir"] / "config.json"
|
||||||
|
config = _load_json(config_path) if config_path.exists() else {}
|
||||||
|
installed = load_installed_status(ctx).get("modules", {})
|
||||||
|
|
||||||
|
for name in to_remove:
|
||||||
|
del agents[name]
|
||||||
|
# Check if another installed module also declares this agent
|
||||||
|
for other_mod, other_status in installed.items():
|
||||||
|
if other_mod == module_name:
|
||||||
|
continue
|
||||||
|
if other_status.get("status") != "success":
|
||||||
|
continue
|
||||||
|
other_cfg = config.get("modules", {}).get(other_mod, {})
|
||||||
|
other_agents = other_cfg.get("agents", {})
|
||||||
|
if name in other_agents:
|
||||||
|
restored = dict(other_agents[name])
|
||||||
|
restored["__module__"] = other_mod
|
||||||
|
agents[name] = restored
|
||||||
|
break
|
||||||
|
|
||||||
|
with models_path.open("w", encoding="utf-8") as fh:
|
||||||
|
json.dump(models, fh, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
write_log(
|
||||||
|
{
|
||||||
|
"level": "INFO",
|
||||||
|
"message": (
|
||||||
|
f"Removed {len(to_remove)} agent(s) from {module_name} "
|
||||||
|
"in models.json"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _hooks_equal(hook1: Dict[str, Any], hook2: Dict[str, Any]) -> bool:
|
def _hooks_equal(hook1: Dict[str, Any], hook2: Dict[str, Any]) -> bool:
|
||||||
"""Compare two hooks ignoring the __module__ marker."""
|
"""Compare two hooks ignoring the __module__ marker."""
|
||||||
h1 = {k: v for k, v in hook1.items() if k != "__module__"}
|
h1 = {k: v for k, v in hook1.items() if k != "__module__"}
|
||||||
@@ -545,6 +651,14 @@ def uninstall_module(name: str, cfg: Dict[str, Any], ctx: Dict[str, Any]) -> Dic
|
|||||||
target.unlink()
|
target.unlink()
|
||||||
removed_paths.append(str(target))
|
removed_paths.append(str(target))
|
||||||
write_log({"level": "INFO", "message": f"Removed: {target}"}, ctx)
|
write_log({"level": "INFO", "message": f"Removed: {target}"}, ctx)
|
||||||
|
# Clean up empty parent directories up to install_dir
|
||||||
|
parent = target.parent
|
||||||
|
while parent != install_dir and parent.exists():
|
||||||
|
try:
|
||||||
|
parent.rmdir()
|
||||||
|
except OSError:
|
||||||
|
break
|
||||||
|
parent = parent.parent
|
||||||
elif op_type == "merge_dir":
|
elif op_type == "merge_dir":
|
||||||
if not merge_dir_files:
|
if not merge_dir_files:
|
||||||
write_log(
|
write_log(
|
||||||
@@ -604,6 +718,13 @@ def uninstall_module(name: str, cfg: Dict[str, Any], ctx: Dict[str, Any]) -> Dic
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
write_log({"level": "WARNING", "message": f"Failed to remove hooks for {name}: {exc}"}, ctx)
|
write_log({"level": "WARNING", "message": f"Failed to remove hooks for {name}: {exc}"}, ctx)
|
||||||
|
|
||||||
|
# Remove module agents from ~/.codeagent/models.json
|
||||||
|
try:
|
||||||
|
unmerge_agents_from_models(name, ctx)
|
||||||
|
result["agents_removed"] = True
|
||||||
|
except Exception as exc:
|
||||||
|
write_log({"level": "WARNING", "message": f"Failed to remove agents for {name}: {exc}"}, ctx)
|
||||||
|
|
||||||
result["removed_paths"] = removed_paths
|
result["removed_paths"] = removed_paths
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@@ -626,7 +747,9 @@ def update_status_after_uninstall(uninstalled_modules: List[str], ctx: Dict[str,
|
|||||||
|
|
||||||
|
|
||||||
def interactive_manage(config: Dict[str, Any], ctx: Dict[str, Any]) -> int:
|
def interactive_manage(config: Dict[str, Any], ctx: Dict[str, Any]) -> int:
|
||||||
"""Interactive module management menu."""
|
"""Interactive module management menu. Returns 0 on success, 1 on error.
|
||||||
|
Sets ctx['_did_install'] = True if any module was installed."""
|
||||||
|
ctx.setdefault("_did_install", False)
|
||||||
while True:
|
while True:
|
||||||
installed_status = get_installed_modules(config, ctx)
|
installed_status = get_installed_modules(config, ctx)
|
||||||
modules = config.get("modules", {})
|
modules = config.get("modules", {})
|
||||||
@@ -695,6 +818,7 @@ def interactive_manage(config: Dict[str, Any], ctx: Dict[str, Any]) -> int:
|
|||||||
for r in results:
|
for r in results:
|
||||||
if r.get("status") == "success":
|
if r.get("status") == "success":
|
||||||
current_status.setdefault("modules", {})[r["module"]] = r
|
current_status.setdefault("modules", {})[r["module"]] = r
|
||||||
|
ctx["_did_install"] = True
|
||||||
current_status["updated_at"] = datetime.now().isoformat()
|
current_status["updated_at"] = datetime.now().isoformat()
|
||||||
with Path(ctx["status_file"]).open("w", encoding="utf-8") as fh:
|
with Path(ctx["status_file"]).open("w", encoding="utf-8") as fh:
|
||||||
json.dump(current_status, fh, indent=2, ensure_ascii=False)
|
json.dump(current_status, fh, indent=2, ensure_ascii=False)
|
||||||
@@ -819,6 +943,17 @@ def execute_module(name: str, cfg: Dict[str, Any], ctx: Dict[str, Any]) -> Dict[
|
|||||||
write_log({"level": "WARNING", "message": f"Failed to merge hooks for {name}: {exc}"}, ctx)
|
write_log({"level": "WARNING", "message": f"Failed to merge hooks for {name}: {exc}"}, ctx)
|
||||||
result["operations"].append({"type": "merge_hooks", "status": "failed", "error": str(exc)})
|
result["operations"].append({"type": "merge_hooks", "status": "failed", "error": str(exc)})
|
||||||
|
|
||||||
|
# Handle agents: merge module agent configs into ~/.codeagent/models.json
|
||||||
|
module_agents = cfg.get("agents", {})
|
||||||
|
if module_agents:
|
||||||
|
try:
|
||||||
|
merge_agents_to_models(name, module_agents, ctx)
|
||||||
|
result["operations"].append({"type": "merge_agents", "status": "success"})
|
||||||
|
result["has_agents"] = True
|
||||||
|
except Exception as exc:
|
||||||
|
write_log({"level": "WARNING", "message": f"Failed to merge agents for {name}: {exc}"}, ctx)
|
||||||
|
result["operations"].append({"type": "merge_agents", "status": "failed", "error": str(exc)})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -1060,6 +1195,67 @@ def write_status(results: List[Dict[str, Any]], ctx: Dict[str, Any]) -> None:
|
|||||||
json.dump(status, fh, indent=2, ensure_ascii=False)
|
json.dump(status, fh, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
|
def install_default_configs(ctx: Dict[str, Any]) -> None:
|
||||||
|
"""Copy default config files if they don't already exist. Best-effort: never raises."""
|
||||||
|
try:
|
||||||
|
install_dir = ctx["install_dir"]
|
||||||
|
config_dir = ctx["config_dir"]
|
||||||
|
|
||||||
|
# Copy memorys/CLAUDE.md -> {install_dir}/CLAUDE.md
|
||||||
|
claude_md_src = config_dir / "memorys" / "CLAUDE.md"
|
||||||
|
claude_md_dst = install_dir / "CLAUDE.md"
|
||||||
|
if not claude_md_dst.exists() and claude_md_src.exists():
|
||||||
|
shutil.copy2(claude_md_src, claude_md_dst)
|
||||||
|
print(f" Installed CLAUDE.md to {claude_md_dst}")
|
||||||
|
write_log({"level": "INFO", "message": f"Installed CLAUDE.md to {claude_md_dst}"}, ctx)
|
||||||
|
except Exception as exc:
|
||||||
|
print(f" Warning: could not install default configs: {exc}", file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def print_post_install_info(ctx: Dict[str, Any]) -> None:
|
||||||
|
"""Print post-install verification and setup guidance."""
|
||||||
|
install_dir = ctx["install_dir"]
|
||||||
|
|
||||||
|
# Check codeagent-wrapper version
|
||||||
|
wrapper_bin = install_dir / "bin" / "codeagent-wrapper"
|
||||||
|
wrapper_version = None
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
[str(wrapper_bin), "--version"],
|
||||||
|
capture_output=True, text=True, timeout=5,
|
||||||
|
)
|
||||||
|
if result.returncode == 0:
|
||||||
|
wrapper_version = result.stdout.strip()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Check PATH
|
||||||
|
bin_dir = str(install_dir / "bin")
|
||||||
|
env_path = os.environ.get("PATH", "")
|
||||||
|
path_ok = any(
|
||||||
|
os.path.realpath(p) == os.path.realpath(bin_dir)
|
||||||
|
if os.path.exists(p) else p == bin_dir
|
||||||
|
for p in env_path.split(os.pathsep)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check backend CLIs
|
||||||
|
backends = ["codex", "claude", "gemini", "opencode"]
|
||||||
|
detected = {name: shutil.which(name) is not None for name in backends}
|
||||||
|
|
||||||
|
print("\nSetup Complete!")
|
||||||
|
v_mark = "✓" if wrapper_version else "✗"
|
||||||
|
print(f" codeagent-wrapper: {wrapper_version or '(not found)'} {v_mark}")
|
||||||
|
p_mark = "✓" if path_ok else "✗ (not in PATH)"
|
||||||
|
print(f" PATH: {bin_dir} {p_mark}")
|
||||||
|
print("\nBackend CLIs detected:")
|
||||||
|
cli_parts = [f"{b} {'✓' if detected[b] else '✗'}" for b in backends]
|
||||||
|
print(" " + " | ".join(cli_parts))
|
||||||
|
print("\nNext steps:")
|
||||||
|
print(" 1. Configure API keys in ~/.codeagent/models.json")
|
||||||
|
print(' 2. Try: /do "your first task"')
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
def prepare_status_backup(ctx: Dict[str, Any]) -> None:
|
def prepare_status_backup(ctx: Dict[str, Any]) -> None:
|
||||||
status_path = Path(ctx["status_file"])
|
status_path = Path(ctx["status_file"])
|
||||||
if status_path.exists():
|
if status_path.exists():
|
||||||
@@ -1208,6 +1404,8 @@ def main(argv: Optional[Iterable[str]] = None) -> int:
|
|||||||
failed = len(results) - success
|
failed = len(results) - success
|
||||||
if failed == 0:
|
if failed == 0:
|
||||||
print(f"\n✓ Update complete: {success} module(s) updated")
|
print(f"\n✓ Update complete: {success} module(s) updated")
|
||||||
|
install_default_configs(ctx)
|
||||||
|
print_post_install_info(ctx)
|
||||||
else:
|
else:
|
||||||
print(f"\n⚠ Update finished with errors: {success} success, {failed} failed")
|
print(f"\n⚠ Update finished with errors: {success} success, {failed} failed")
|
||||||
if not args.force:
|
if not args.force:
|
||||||
@@ -1221,7 +1419,11 @@ def main(argv: Optional[Iterable[str]] = None) -> int:
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print(f"Failed to prepare install dir: {exc}", file=sys.stderr)
|
print(f"Failed to prepare install dir: {exc}", file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
return interactive_manage(config, ctx)
|
result = interactive_manage(config, ctx)
|
||||||
|
if result == 0 and ctx.get("_did_install"):
|
||||||
|
install_default_configs(ctx)
|
||||||
|
print_post_install_info(ctx)
|
||||||
|
return result
|
||||||
|
|
||||||
# Install specified modules
|
# Install specified modules
|
||||||
modules = select_modules(config, args.module)
|
modules = select_modules(config, args.module)
|
||||||
@@ -1280,6 +1482,10 @@ def main(argv: Optional[Iterable[str]] = None) -> int:
|
|||||||
if not args.force:
|
if not args.force:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
if failed == 0:
|
||||||
|
install_default_configs(ctx)
|
||||||
|
print_post_install_info(ctx)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "myclaude",
|
"name": "myclaude",
|
||||||
"version": "0.0.0",
|
"version": "6.7.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Claude Code multi-agent workflows (npx installer)",
|
"description": "Claude Code multi-agent workflows (npx installer)",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"agents/",
|
"agents/",
|
||||||
"skills/",
|
"skills/",
|
||||||
"memorys/",
|
"memorys/",
|
||||||
|
"templates/",
|
||||||
"codeagent-wrapper/",
|
"codeagent-wrapper/",
|
||||||
"config.json",
|
"config.json",
|
||||||
"install.py",
|
"install.py",
|
||||||
|
|||||||
52
templates/models.json.example
Normal file
52
templates/models.json.example
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"default_backend": "codex",
|
||||||
|
"default_model": "gpt-5.2",
|
||||||
|
"backends": {
|
||||||
|
"codex": { "api_key": "" },
|
||||||
|
"claude": { "api_key": "" },
|
||||||
|
"gemini": { "api_key": "" },
|
||||||
|
"opencode": { "api_key": "" }
|
||||||
|
},
|
||||||
|
"agents": {
|
||||||
|
"develop": {
|
||||||
|
"backend": "codex",
|
||||||
|
"model": "gpt-5.2",
|
||||||
|
"reasoning": "xhigh",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"code-explorer": {
|
||||||
|
"backend": "opencode",
|
||||||
|
"model": ""
|
||||||
|
},
|
||||||
|
"code-architect": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": ""
|
||||||
|
},
|
||||||
|
"code-reviewer": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": ""
|
||||||
|
},
|
||||||
|
"oracle": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": "claude-opus-4-5-20251101",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"librarian": {
|
||||||
|
"backend": "claude",
|
||||||
|
"model": "claude-sonnet-4-5-20250929",
|
||||||
|
"yolo": true
|
||||||
|
},
|
||||||
|
"explore": {
|
||||||
|
"backend": "opencode",
|
||||||
|
"model": "opencode/grok-code"
|
||||||
|
},
|
||||||
|
"frontend-ui-ux-engineer": {
|
||||||
|
"backend": "gemini",
|
||||||
|
"model": "gemini-3-pro-preview"
|
||||||
|
},
|
||||||
|
"document-writer": {
|
||||||
|
"backend": "gemini",
|
||||||
|
"model": "gemini-3-flash-preview"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user