mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-11 03:23:50 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebd795c583 |
41
CHANGELOG.md
41
CHANGELOG.md
@@ -2,6 +2,47 @@
|
||||
|
||||
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
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
34
README.md
34
README.md
@@ -19,13 +19,30 @@ npx github:cexll/myclaude
|
||||
|
||||
| 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 |
|
||||
| [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 |
|
||||
| [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 |
|
||||
| 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
|
||||
|
||||
@@ -87,17 +104,20 @@ Edit `config.json` to enable/disable modules:
|
||||
| Codex | `codex e`, `--json`, `-C`, `resume` |
|
||||
| Claude | `--output-format stream-json`, `-r` |
|
||||
| Gemini | `-o stream-json`, `-y`, `-r` |
|
||||
| OpenCode | `opencode`, stdin mode |
|
||||
|
||||
## Directory Structure After Installation
|
||||
|
||||
```
|
||||
~/.claude/
|
||||
├── bin/codeagent-wrapper
|
||||
├── CLAUDE.md
|
||||
├── commands/
|
||||
├── agents/
|
||||
├── skills/
|
||||
└── config.json
|
||||
├── CLAUDE.md (installed by default)
|
||||
├── commands/ (from essentials module)
|
||||
├── agents/ (from bmad/requirements modules)
|
||||
├── skills/ (from do/omo/sparv/course modules)
|
||||
├── hooks/ (from claudekit module)
|
||||
├── settings.json (auto-generated, hooks config)
|
||||
└── installed_modules.json (auto-generated, tracks modules)
|
||||
```
|
||||
|
||||
## 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` 命令 |
|
||||
| [bmad](agents/bmad/README.md) | BMAD 敏捷工作流 + 6 个专业智能体 | `/bmad-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` 命令 |
|
||||
| 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 工作流(推荐)
|
||||
|
||||
7 阶段功能开发,通过 codeagent-wrapper 编排多个智能体。**大多数功能开发任务的首选工作流。**
|
||||
5 阶段功能开发,通过 codeagent-wrapper 编排多个智能体。**大多数功能开发任务的首选工作流。**
|
||||
|
||||
```bash
|
||||
/do "添加用户登录功能"
|
||||
```
|
||||
|
||||
**7 阶段:**
|
||||
**5 阶段:**
|
||||
| 阶段 | 名称 | 目标 |
|
||||
|------|------|------|
|
||||
| 1 | Discovery | 理解需求 |
|
||||
| 2 | Exploration | 映射代码库模式 |
|
||||
| 3 | Clarification | 解决歧义(**强制**)|
|
||||
| 4 | Architecture | 设计实现方案 |
|
||||
| 5 | Implementation | 构建功能(**需审批**)|
|
||||
| 6 | Review | 捕获缺陷 |
|
||||
| 7 | Summary | 记录结果 |
|
||||
| 1 | Understand | 并行探索理解需求和映射代码库 |
|
||||
| 2 | Clarify | 解决阻塞性歧义(条件触发)|
|
||||
| 3 | Design | 产出最小变更实现方案 |
|
||||
| 4 | Implement + Review | 构建功能并审查 |
|
||||
| 5 | Complete | 记录构建结果 |
|
||||
|
||||
**智能体:**
|
||||
- `code-explorer` - 代码追踪、架构映射
|
||||
@@ -162,6 +177,10 @@ npx github:cexll/myclaude
|
||||
| `/optimize` | 性能优化 |
|
||||
| `/refactor` | 代码重构 |
|
||||
| `/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` |
|
||||
| Claude | `--output-format stream-json`, `-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 readline = require("readline");
|
||||
const zlib = require("zlib");
|
||||
const { spawn } = require("child_process");
|
||||
const { spawn, spawnSync } = require("child_process");
|
||||
|
||||
const REPO = { owner: "cexll", name: "myclaude" };
|
||||
const API_HEADERS = {
|
||||
@@ -931,6 +931,63 @@ async function uninstallModule(moduleName, config, repoRoot, installDir, dryRun)
|
||||
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) {
|
||||
const needRepo = 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 {
|
||||
await rmTree(tmp);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# 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
|
||||
|
||||
`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
|
||||
- Session management and resumption
|
||||
- Parallel task execution with dependency resolution
|
||||
@@ -42,6 +42,24 @@ Implement user authentication:
|
||||
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 | Command | Best For |
|
||||
@@ -49,6 +67,7 @@ EOF
|
||||
| **Codex** | `--backend codex` | General code tasks (default) |
|
||||
| **Claude** | `--backend claude` | Complex reasoning, architecture |
|
||||
| **Gemini** | `--backend gemini` | Fast iteration, prototyping |
|
||||
| **OpenCode** | `--backend opencode` | Open-source alternative |
|
||||
|
||||
## Core Features
|
||||
|
||||
|
||||
56
config.json
56
config.json
@@ -39,6 +39,36 @@
|
||||
"omo": {
|
||||
"enabled": false,
|
||||
"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": [
|
||||
{
|
||||
"type": "copy_file",
|
||||
@@ -98,7 +128,27 @@
|
||||
},
|
||||
"do": {
|
||||
"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": [
|
||||
{
|
||||
"type": "copy_dir",
|
||||
@@ -148,7 +198,7 @@
|
||||
},
|
||||
"claudekit": {
|
||||
"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": [
|
||||
{
|
||||
"type": "copy_dir",
|
||||
@@ -160,7 +210,7 @@
|
||||
"type": "copy_dir",
|
||||
"source": "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)
|
||||
|
||||
|
||||
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:
|
||||
"""Compare two hooks ignoring the __module__ marker."""
|
||||
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()
|
||||
removed_paths.append(str(target))
|
||||
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":
|
||||
if not merge_dir_files:
|
||||
write_log(
|
||||
@@ -604,6 +718,13 @@ def uninstall_module(name: str, cfg: Dict[str, Any], ctx: Dict[str, Any]) -> Dic
|
||||
except Exception as exc:
|
||||
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
|
||||
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:
|
||||
"""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:
|
||||
installed_status = get_installed_modules(config, ctx)
|
||||
modules = config.get("modules", {})
|
||||
@@ -695,6 +818,7 @@ def interactive_manage(config: Dict[str, Any], ctx: Dict[str, Any]) -> int:
|
||||
for r in results:
|
||||
if r.get("status") == "success":
|
||||
current_status.setdefault("modules", {})[r["module"]] = r
|
||||
ctx["_did_install"] = True
|
||||
current_status["updated_at"] = datetime.now().isoformat()
|
||||
with Path(ctx["status_file"]).open("w", encoding="utf-8") as fh:
|
||||
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)
|
||||
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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
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:
|
||||
status_path = Path(ctx["status_file"])
|
||||
if status_path.exists():
|
||||
@@ -1208,6 +1404,8 @@ def main(argv: Optional[Iterable[str]] = None) -> int:
|
||||
failed = len(results) - success
|
||||
if failed == 0:
|
||||
print(f"\n✓ Update complete: {success} module(s) updated")
|
||||
install_default_configs(ctx)
|
||||
print_post_install_info(ctx)
|
||||
else:
|
||||
print(f"\n⚠ Update finished with errors: {success} success, {failed} failed")
|
||||
if not args.force:
|
||||
@@ -1221,7 +1419,11 @@ def main(argv: Optional[Iterable[str]] = None) -> int:
|
||||
except Exception as exc:
|
||||
print(f"Failed to prepare install dir: {exc}", file=sys.stderr)
|
||||
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
|
||||
modules = select_modules(config, args.module)
|
||||
@@ -1280,6 +1482,10 @@ def main(argv: Optional[Iterable[str]] = None) -> int:
|
||||
if not args.force:
|
||||
return 1
|
||||
|
||||
if failed == 0:
|
||||
install_default_configs(ctx)
|
||||
print_post_install_info(ctx)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "myclaude",
|
||||
"version": "0.0.0",
|
||||
"version": "6.7.0",
|
||||
"private": true,
|
||||
"description": "Claude Code multi-agent workflows (npx installer)",
|
||||
"license": "AGPL-3.0",
|
||||
@@ -13,6 +13,7 @@
|
||||
"agents/",
|
||||
"skills/",
|
||||
"memorys/",
|
||||
"templates/",
|
||||
"codeagent-wrapper/",
|
||||
"config.json",
|
||||
"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