jvibe 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -0
- package/JVIBE.md +1 -1
- package/README.md +182 -1
- package/bin/jvibe.js +14 -12
- package/lib/migrate.js +116 -24
- package/lib/migrations/index.js +56 -8
- package/lib/plugins/core-tools.js +398 -0
- package/lib/plugins/plugins-yaml.js +49 -0
- package/lib/plugins/registry.json +440 -0
- package/package.json +2 -1
- package/scripts/init.js +39 -0
- package/scripts/plugins.js +159 -0
- package/scripts/setup.js +365 -18
- package/scripts/status.js +87 -0
- package/scripts/upgrade.js +29 -106
- package/scripts/validate.js +125 -0
- package/template/.claude/agents/bugfix.md +14 -4
- package/template/.claude/agents/developer.md +12 -1
- package/template/.claude/agents/doc-sync.md +7 -0
- package/template/.claude/agents/planner.md +4 -0
- package/template/.claude/agents/reviewer.md +4 -0
- package/template/.claude/agents/tester.md +34 -9
- package/template/.claude/commands/JVibe:keepgo.md +43 -6
- package/template/.claude/error-handling.md +8 -2
- package/template/.claude/hooks/load-context.sh +3 -3
- package/template/.claude/hooks/load-jvibe-full-context.sh +113 -6
- package/template/.claude/hooks/sync-jvibe-context.sh +75 -34
- package/template/.claude/settings.json +2 -2
- package/template/.claude/skills/agent-browser/SKILL.md +252 -0
- package/template/.jvibe-doc-hash.json +1 -1
- package/template/.opencode/agent/bugfix.md +13 -4
- package/template/.opencode/agent/developer.md +12 -1
- package/template/.opencode/agent/doc-sync.md +7 -0
- package/template/.opencode/agent/planner.md +4 -0
- package/template/.opencode/agent/reviewer.md +4 -0
- package/template/.opencode/agent/tester.md +34 -9
- package/template/.opencode/command/jvibe-keepgo.md +43 -6
- package/template/.opencode/error-handling.md +8 -2
- package/template/docs/.jvibe/agent-contracts.yaml +188 -0
- package/template/docs/.jvibe/plugins.yaml +15 -0
- package/template/docs/core/Feature-List.md +0 -3
- package/template/docs/core/Standards.md +7 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.1.8] - 2026-01-19
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Agent I/O 协议统一** (`agent-contracts.yaml`)
|
|
13
|
+
- 新增 `docs/.jvibe/agent-contracts.yaml` 作为 subagent 输入输出的单一事实来源
|
|
14
|
+
- 定义了 `planner`、`developer`、`tester`、`bugfix`、`doc-sync` 的 `task_input` 与输出结构
|
|
15
|
+
- 包含硬规则 (HR-001 ~ HR-003) 约束 subagent 行为
|
|
16
|
+
|
|
17
|
+
- **插件管理配置** (`plugins.yaml`)
|
|
18
|
+
- 新增 `docs/.jvibe/plugins.yaml` 管理工具与插件启用状态
|
|
19
|
+
- 区分 `core_plugins`(核心工具)与 `project_plugins`(项目按需)
|
|
20
|
+
- SessionStart hook 会从 `plugins.yaml` 注入 Core Tools 摘要到上下文
|
|
21
|
+
- 新增 `jvibe plugins core`:将缺失的 Core MCP Server 追加写入 `.claude/settings.local.json`(已存在则跳过)
|
|
22
|
+
|
|
23
|
+
- **上下文最小化原则**
|
|
24
|
+
- 所有 Agent 新增"硬规则"章节,禁止全仓库扫描
|
|
25
|
+
- `developer`: 只在 `code_roots`/`test_roots` 范围内读取与修改
|
|
26
|
+
- `tester`: 新增 `mode: targeted | discover` 双模式
|
|
27
|
+
- `bugfix`: 优先使用 tester 报告的 `failures`/`modules_hit`/`files`
|
|
28
|
+
|
|
29
|
+
- **Tester 双模式支持**
|
|
30
|
+
- `targeted`: 给定 `files`,精确限制测试范围
|
|
31
|
+
- `discover`: 允许从测试输出反推落点文件,解决"用户报错但不知道 F-XXX"场景
|
|
32
|
+
- 新增 `issue` 字段用于 discover 模式的问题描述
|
|
33
|
+
|
|
34
|
+
- **Keepgo 用户报错判定**
|
|
35
|
+
- 新增关键词匹配(报错/失败/异常/bug/error 等)自动识别用户报告的问题
|
|
36
|
+
- 支持 `feature_id=null` 时进入 discover 测试流程
|
|
37
|
+
- 新增 `user_reported_issue`、`user_reported_feature_id`、`user_issue` 状态字段
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- **测试失败分流策略**
|
|
42
|
+
- 从简单的 `return_to_developer` 改为 `triage_then_fix` 策略
|
|
43
|
+
- 多模块/核心模块/用户强制 → 调用 `bugfix`
|
|
44
|
+
- 单模块/简单问题 → 回退到 `developer`
|
|
45
|
+
|
|
46
|
+
- **Handoff Payload 结构**
|
|
47
|
+
- 新增 `mode` 字段(`targeted`/`discover`)
|
|
48
|
+
- `files` 字段在 targeted 模式下必填且非空
|
|
49
|
+
- `feature_id` 允许为 `null`
|
|
50
|
+
|
|
51
|
+
- **文档更新条件**
|
|
52
|
+
- `doc_updates` 仅在 `pass` 且 `feature_id` 非空时执行
|
|
53
|
+
- 避免无法关联功能编号时错误更新状态
|
|
54
|
+
|
|
55
|
+
- **Standards.md**
|
|
56
|
+
- 新增 §2.6 Tools & Plugins 章节说明工具与插件概念
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- **Hook 脚本 grep 错误处理**
|
|
61
|
+
- 修复 `grep -c ... || true` 导致空字符串的问题
|
|
62
|
+
- 改为 `|| echo 0` 确保输出为数字,避免后续算术运算错误
|
|
63
|
+
- 影响文件:`load-context.sh`、`load-jvibe-full-context.sh`、`sync-jvibe-context.sh`
|
|
64
|
+
|
|
65
|
+
- **UserPromptSubmit hook 错误处理**
|
|
66
|
+
- 移除 `set -eo pipefail`,改用 fail-open trap 机制
|
|
67
|
+
- 添加 `_JVIBE_HOOK_SUCCESS` 标记避免重复输出
|
|
68
|
+
- 修复 Project.md 摘要提取时 grep 管道无匹配导致的错误
|
|
69
|
+
- 确保非 JVibe 项目也能正常放行
|
|
70
|
+
|
|
71
|
+
- **TUI 插件选择写回**
|
|
72
|
+
- 修复已有 `docs/.jvibe/plugins.yaml` 时项目插件勾选不生效的问题
|
|
73
|
+
- 默认更新 `project_plugins`;勾选 Force Overwrite 会重置整个文件
|
|
74
|
+
|
|
75
|
+
## [1.1.7] - 2026-01-18
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
|
|
79
|
+
- Hooks 自动加载和同步 JVibe 上下文
|
|
80
|
+
|
|
81
|
+
### Fixed
|
|
82
|
+
|
|
83
|
+
- Hooks 脚本 jq-free 重写,fail-open 模式
|
|
84
|
+
|
|
85
|
+
## [1.1.6] - 2026-01-17
|
|
86
|
+
|
|
87
|
+
### Added
|
|
88
|
+
|
|
89
|
+
- Context hooks 自动加载功能
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Summary of v1.1.8
|
|
94
|
+
|
|
95
|
+
This release introduces a major architectural improvement focused on **context minimization** and **unified I/O contracts** for subagents:
|
|
96
|
+
|
|
97
|
+
1. **Single Source of Truth**: `agent-contracts.yaml` defines all subagent input/output schemas
|
|
98
|
+
2. **Dual-mode Testing**: `targeted` (precise) vs `discover` (user-reported issues without F-XXX)
|
|
99
|
+
3. **Smarter Dispatch**: Main agent no longer directly fixes code; uses `bugfix` for complex issues
|
|
100
|
+
4. **Robust Hooks**: Fixed shell script arithmetic errors with proper fallback values
|
|
101
|
+
|
|
102
|
+
## [1.1.9] - 2026-01-20
|
|
103
|
+
|
|
104
|
+
### Added
|
|
105
|
+
|
|
106
|
+
- **Project Tools 注册表**:新增 `lib/plugins/registry.json` 的 Project Tools 完整条目(含 MCP 模板与依赖)
|
|
107
|
+
- **Core Tools: Skill 支持**:支持 Core Tools 以 `skill` 形态集成(Agent Browser)
|
|
108
|
+
- 固定 Agent Browser Skill 到 `v0.6.0`,并将 `SKILL.md` vendoring 到 `template/.claude/skills/agent-browser/SKILL.md`
|
|
109
|
+
|
|
110
|
+
### Changed
|
|
111
|
+
|
|
112
|
+
- **Core Tools 配置输出**:分离 MCP Server 与 Skill 的计数与提示(init/setup/plugins core)
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
|
|
116
|
+
- **Core Tools env 占位符**:写入 `.claude/settings.local.json` 时自动填充当前环境变量,并避免写入未解析的 `{{VAR}}` 占位符
|
|
117
|
+
- **Skill 下载鲁棒性**:为 Skill 下载增加超时/重定向/体积上限,避免卡死或异常大文件
|
|
118
|
+
- **非交互 stdin**:`jvibe plugins core` 在 CI/重定向 stdin 下默认跳过交互安装提示,避免挂起
|
package/JVIBE.md
CHANGED
|
@@ -75,7 +75,7 @@ TODO 完成情况 → 功能状态
|
|
|
75
75
|
5. **测试自动派发**:TODO 包含“测试/test”时,进入测试阶段必须自动调用 tester,无需用户手动指定
|
|
76
76
|
6. **已有项目初始化**:若项目已有代码/文档,/JVibe:init 应先扫描现有项目并用扫描结果填充 Project 与 Feature-List
|
|
77
77
|
7. **Bugfix 调用**:tester 报告失败且问题涉及**多模块**或**核心模块**时才调用 bugfix;否则回退给 developer。用户明确要求时可直接调用
|
|
78
|
-
8. **
|
|
78
|
+
8. **Tools/Plugins 权限**:主 Agent 与所有 Sub-Agents 允许直接调用 Tools/Plugins 进行查询/集成操作(包括 MCP Server、Skills、Daemon 等)
|
|
79
79
|
|
|
80
80
|
保持此管理块,以便 `jvibe upgrade` 更新指令。
|
|
81
81
|
<!-- JVIBE:END -->
|
package/README.md
CHANGED
|
@@ -1,9 +1,40 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# JVibe
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
**文档驱动的 AI 辅助开发系统**
|
|
6
|
+
|
|
7
|
+
*Doc-driven AI-assisted Development System for Claude Code & OpenCode*
|
|
4
8
|
|
|
5
9
|
[](https://badge.fury.io/js/jvibe)
|
|
10
|
+
[](https://www.npmjs.com/package/jvibe)
|
|
6
11
|
[](https://opensource.org/licenses/MIT)
|
|
12
|
+
[](https://nodejs.org/)
|
|
13
|
+
[](https://github.com/9963KK/VibeCoding-Tech/pulls)
|
|
14
|
+
|
|
15
|
+
[快速开始](#-快速开始) · [使用方法](#-使用方法一览) · [文档](#-文档) · [贡献](#-贡献)
|
|
16
|
+
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 目录
|
|
22
|
+
|
|
23
|
+
- [什么是 JVibe?](#-什么是-jvibe)
|
|
24
|
+
- [为什么选择 JVibe?](#-为什么选择-jvibe)
|
|
25
|
+
- [快速开始](#-快速开始)
|
|
26
|
+
- [使用方法一览](#-使用方法一览)
|
|
27
|
+
- [典型使用场景](#-典型使用场景)
|
|
28
|
+
- [项目结构](#-项目结构)
|
|
29
|
+
- [文档体系](#-文档体系)
|
|
30
|
+
- [Agent 架构](#-agent-架构)
|
|
31
|
+
- [CLI 命令](#-cli-命令)
|
|
32
|
+
- [Core Tools 维护](#-core-tools-维护)
|
|
33
|
+
- [核心原则](#-核心原则)
|
|
34
|
+
- [���见问题](#-常见问题)
|
|
35
|
+
- [文档](#-文档)
|
|
36
|
+
- [贡献](#-贡献)
|
|
37
|
+
- [许可证](#-许可证)
|
|
7
38
|
|
|
8
39
|
---
|
|
9
40
|
|
|
@@ -18,6 +49,35 @@ JVibe 是一个**文档驱动的 AI 辅助开发系统**,面向 Claude Code
|
|
|
18
49
|
|
|
19
50
|
---
|
|
20
51
|
|
|
52
|
+
## 💡 为什么选择 JVibe?
|
|
53
|
+
|
|
54
|
+
| 痛点 | JVibe 解决方案 |
|
|
55
|
+
|------|---------------|
|
|
56
|
+
| AI 缺乏项目上下文,每次都要重复解释 | 自动加载项目文档,AI 开箱即知项目全貌 |
|
|
57
|
+
| 功能状态散落各处,难以追踪 | 单一事实来源(SoT),状态只在一处维护 |
|
|
58
|
+
| AI 生成代码质量参差不齐 | 多 Agent 分工协作,专业的事交给专业的 Agent |
|
|
59
|
+
| 文档与代码脱节,维护困难 | 文档驱动开发,代码变更自动触发文档同步 |
|
|
60
|
+
| 团队协作时上下文丢失 | 结构化任务交接文件,无缝衔接工作进度 |
|
|
61
|
+
|
|
62
|
+
**核心优势**:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
66
|
+
│ JVibe 工作流 │
|
|
67
|
+
├─────────────────────────────────────────────────────────────┤
|
|
68
|
+
│ │
|
|
69
|
+
│ 需求 ──→ planner ──→ developer ──→ tester ──→ reviewer │
|
|
70
|
+
│ │ │ │ │ │
|
|
71
|
+
│ └──────────────────────┴────────────┴───────────┘ │
|
|
72
|
+
│ ↓ │
|
|
73
|
+
│ doc-sync │
|
|
74
|
+
│ (自动同步状态) │
|
|
75
|
+
│ │
|
|
76
|
+
└─────────────────────────────────────────────────────────────┘
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
21
81
|
## 🚀 快速开始
|
|
22
82
|
|
|
23
83
|
### 初始化方式(选一种)
|
|
@@ -270,6 +330,44 @@ TODO 完成情况 → 功能状态
|
|
|
270
330
|
|
|
271
331
|
---
|
|
272
332
|
|
|
333
|
+
## 🔌 Core Tools 维护
|
|
334
|
+
|
|
335
|
+
### Agent Browser Skill 更新
|
|
336
|
+
|
|
337
|
+
Agent Browser Skill 当前固定在 **v0.6.0** 版本,以确保稳定性。如需更新到最新版本:
|
|
338
|
+
|
|
339
|
+
#### 方法 1:手动更新(推荐)
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# 1. 访问 GitHub Releases 页面查看最新版本
|
|
343
|
+
# https://github.com/vercel-labs/agent-browser/releases
|
|
344
|
+
|
|
345
|
+
# 2. 下载最新版本的 SKILL.md
|
|
346
|
+
curl -o .claude/skills/agent-browser/SKILL.md \
|
|
347
|
+
https://raw.githubusercontent.com/vercel-labs/agent-browser/v0.7.0/skills/agent-browser/SKILL.md
|
|
348
|
+
|
|
349
|
+
# 3. 更新 CLI 到对应版本
|
|
350
|
+
npm install -g agent-browser@latest
|
|
351
|
+
agent-browser install
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### 方法 2:修改 registry.json(高级用户)
|
|
355
|
+
|
|
356
|
+
如果你想让 `jvibe plugins core` 自动使用新版本:
|
|
357
|
+
|
|
358
|
+
1. 编辑 `lib/plugins/registry.json`
|
|
359
|
+
2. 找到 `agent-browser` 配置(约第 80 行)
|
|
360
|
+
3. 修改 `skillSource` 指向新版本:
|
|
361
|
+
```json
|
|
362
|
+
"skillSource": "https://raw.githubusercontent.com/vercel-labs/agent-browser/v0.7.0/skills/agent-browser/SKILL.md"
|
|
363
|
+
```
|
|
364
|
+
4. 删除现有 Skill 文件:`rm -rf .claude/skills/agent-browser`
|
|
365
|
+
5. 重新运行:`jvibe plugins core`
|
|
366
|
+
|
|
367
|
+
> **注意**:更新前请查看 [Agent Browser Changelog](https://github.com/vercel-labs/agent-browser/releases) 确认兼容性。
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
273
371
|
## 🎯 核心原则
|
|
274
372
|
|
|
275
373
|
JVibe 基于以下原则设计:
|
|
@@ -281,12 +379,83 @@ JVibe 基于以下原则设计:
|
|
|
281
379
|
|
|
282
380
|
---
|
|
283
381
|
|
|
382
|
+
## ❓ 常见问题
|
|
383
|
+
|
|
384
|
+
<details>
|
|
385
|
+
<summary><b>JVibe 支持哪些 AI 编码工具?</b></summary>
|
|
386
|
+
|
|
387
|
+
目前支持:
|
|
388
|
+
- **Claude Code** - Anthropic 官方 CLI 工具
|
|
389
|
+
- **OpenCode** - 开源 AI 编码助手
|
|
390
|
+
|
|
391
|
+
通过 `--adapter` 参数选择适配器,或使用 `--adapter=both` 同时支持两者。
|
|
392
|
+
</details>
|
|
393
|
+
|
|
394
|
+
<details>
|
|
395
|
+
<summary><b>已有项目如何接入 JVibe?</b></summary>
|
|
396
|
+
|
|
397
|
+
推荐使用 `/JVibe:init` 命令(在 Claude Code 中)或 `/jvibe-init`(在 OpenCode 中)。AI 会自动扫描现有代码和文档,生成符合项目现状的 Feature-List 和 Project 文档。
|
|
398
|
+
</details>
|
|
399
|
+
|
|
400
|
+
<details>
|
|
401
|
+
<summary><b>CORE-DOCS 和 PROJECT-DOCS 有什么区别?</b></summary>
|
|
402
|
+
|
|
403
|
+
- **CORE-DOCS**:固定 4 个核心文档,所有项目结构相同,自动存在
|
|
404
|
+
- **PROJECT-DOCS**:按需创建的扩展文档(如 API 文档、数据库文档),必须在规范文档中注册
|
|
405
|
+
|
|
406
|
+
详见 [CORE vs PROJECT 文档](docs/CORE_VS_PROJECT_DOCS.md)。
|
|
407
|
+
</details>
|
|
408
|
+
|
|
409
|
+
<details>
|
|
410
|
+
<summary><b>如何升级到新版本?</b></summary>
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# 检查是否有新版本
|
|
414
|
+
jvibe upgrade --check
|
|
415
|
+
|
|
416
|
+
# 执行升级(会提示确认)
|
|
417
|
+
jvibe upgrade
|
|
418
|
+
|
|
419
|
+
# 强制升级(跳过确认)
|
|
420
|
+
jvibe upgrade --force
|
|
421
|
+
```
|
|
422
|
+
</details>
|
|
423
|
+
|
|
424
|
+
<details>
|
|
425
|
+
<summary><b>Agent 之间如何协作?</b></summary>
|
|
426
|
+
|
|
427
|
+
JVibe 采用流水线式协作:
|
|
428
|
+
1. `planner` 分析需求,拆解为 TODO 列表
|
|
429
|
+
2. `developer` 逐项完成 TODO,编写代码
|
|
430
|
+
3. `tester` 执行测试,验证功能
|
|
431
|
+
4. `bugfix` 处理复杂 bug(多模块/核心模块问题)
|
|
432
|
+
5. `reviewer` 代码审查,确保质量
|
|
433
|
+
6. `doc-sync` 自动同步文档状态
|
|
434
|
+
|
|
435
|
+
使用 `/JVibe:keepgo` 可自动推进到下一阶段。
|
|
436
|
+
</details>
|
|
437
|
+
|
|
438
|
+
<details>
|
|
439
|
+
<summary><b>如何卸载 JVibe?</b></summary>
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
# 卸载项目内的 JVibe 配置
|
|
443
|
+
jvibe uninstall
|
|
444
|
+
|
|
445
|
+
# 全局卸载
|
|
446
|
+
npm uninstall -g jvibe
|
|
447
|
+
```
|
|
448
|
+
</details>
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
284
452
|
## 📖 文档
|
|
285
453
|
|
|
286
454
|
- [快速开始指南](docs/GETTING_STARTED.md)
|
|
287
455
|
- [CLI 命令参考](docs/CLI_COMMANDS.md)
|
|
288
456
|
- [架构说明](docs/ARCHITECTURE.md)
|
|
289
457
|
- [CORE vs PROJECT 文档](docs/CORE_VS_PROJECT_DOCS.md)
|
|
458
|
+
- [Tools & Plugins(工具与插件)](docs/TOOLS_AND_PLUGINS.md)
|
|
290
459
|
- [贡献指南](docs/CONTRIBUTING.md)
|
|
291
460
|
|
|
292
461
|
---
|
|
@@ -314,3 +483,15 @@ JVibe 基于以下原则设计:
|
|
|
314
483
|
- [Claude Code 官方文档](https://docs.anthropic.com/claude-code)
|
|
315
484
|
- [OpenCode 官方文档](https://opencode.ai/docs)
|
|
316
485
|
- [OpenSpec](https://github.com/openspec/openspec) - 灵感来源
|
|
486
|
+
- [GitHub Issues](https://github.com/9963KK/VibeCoding-Tech/issues) - 问题反馈
|
|
487
|
+
- [NPM Package](https://www.npmjs.com/package/jvibe) - NPM 主页
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
<div align="center">
|
|
492
|
+
|
|
493
|
+
**如果 JVibe 对你有帮助,请给个 ⭐ Star 支持一下!**
|
|
494
|
+
|
|
495
|
+
Made with ❤️ by [9963KK](https://github.com/9963KK)
|
|
496
|
+
|
|
497
|
+
</div>
|
package/bin/jvibe.js
CHANGED
|
@@ -69,25 +69,14 @@ program
|
|
|
69
69
|
// upgrade 命令
|
|
70
70
|
program
|
|
71
71
|
.command('upgrade')
|
|
72
|
-
.description('
|
|
72
|
+
.description('升级到最新版本(卸载重装)')
|
|
73
73
|
.option('--check', '仅检查更新,不执行升级', false)
|
|
74
74
|
.option('--force', '强制升级,跳过确认', false)
|
|
75
|
-
.option('--migrate', '仅执行迁移,不更新到最新版本', false)
|
|
76
75
|
.action(async (options) => {
|
|
77
76
|
const upgrade = require('../scripts/upgrade');
|
|
78
77
|
await upgrade(options);
|
|
79
78
|
});
|
|
80
79
|
|
|
81
|
-
// migrate 命令(upgrade --migrate 的别名)
|
|
82
|
-
program
|
|
83
|
-
.command('migrate')
|
|
84
|
-
.description('迁移旧版本配置到新格式')
|
|
85
|
-
.option('--force', '强制迁移,跳过确认', false)
|
|
86
|
-
.action(async (options) => {
|
|
87
|
-
const upgrade = require('../scripts/upgrade');
|
|
88
|
-
await upgrade({ ...options, migrate: true });
|
|
89
|
-
});
|
|
90
|
-
|
|
91
80
|
// uninstall 命令
|
|
92
81
|
program
|
|
93
82
|
.command('uninstall')
|
|
@@ -120,6 +109,19 @@ program
|
|
|
120
109
|
await validate();
|
|
121
110
|
});
|
|
122
111
|
|
|
112
|
+
// plugins 命令
|
|
113
|
+
const plugins = program
|
|
114
|
+
.command('plugins')
|
|
115
|
+
.description('插件相关操作(Core Tools 等)');
|
|
116
|
+
|
|
117
|
+
plugins
|
|
118
|
+
.command('core')
|
|
119
|
+
.description('配置 Core Tools(写入缺失的 MCP Server 到 .claude/settings.local.json)')
|
|
120
|
+
.action(async () => {
|
|
121
|
+
const { configureCore } = require('../scripts/plugins');
|
|
122
|
+
await configureCore();
|
|
123
|
+
});
|
|
124
|
+
|
|
123
125
|
(async () => {
|
|
124
126
|
try {
|
|
125
127
|
const handled = await maybeRunSetup();
|
package/lib/migrate.js
CHANGED
|
@@ -471,6 +471,7 @@ async function inferOpencodeVersionFromStructure(opencodeDir) {
|
|
|
471
471
|
path.join('agent', 'planner.md'),
|
|
472
472
|
path.join('agent', 'developer.md'),
|
|
473
473
|
path.join('agent', 'tester.md'),
|
|
474
|
+
path.join('agent', 'bugfix.md'),
|
|
474
475
|
path.join('agent', 'reviewer.md'),
|
|
475
476
|
path.join('agent', 'doc-sync.md')
|
|
476
477
|
];
|
|
@@ -584,16 +585,25 @@ async function checkContentMigration(projectDir, currentVersion) {
|
|
|
584
585
|
* @returns {Promise<MigrationPlan>}
|
|
585
586
|
*/
|
|
586
587
|
async function getMigrationPlan(projectDir, versionInfo) {
|
|
588
|
+
const latestVersion = pkg.version || null;
|
|
589
|
+
const currentVersion = versionInfo.version || null;
|
|
590
|
+
const versionMismatch = Boolean(latestVersion && currentVersion && currentVersion !== latestVersion);
|
|
591
|
+
|
|
587
592
|
const plan = {
|
|
588
|
-
needsMigration
|
|
593
|
+
// needsMigration 表示“是否需要执行自动迁移动作”,不等同于 isLegacy
|
|
594
|
+
needsMigration: false,
|
|
589
595
|
needsAIMigration: versionInfo.contentMigration.required,
|
|
590
596
|
tasks: [],
|
|
591
597
|
aiTasks: [],
|
|
592
598
|
details: {
|
|
593
599
|
docsToMove: [],
|
|
600
|
+
hooksNeedUpdate: false,
|
|
594
601
|
hooksToUpdate: [],
|
|
602
|
+
commandsNeedUpdate: false,
|
|
595
603
|
commandsToRename: [],
|
|
604
|
+
agentsNeedUpdate: false,
|
|
596
605
|
agentsToUpdate: [],
|
|
606
|
+
opencodeNeedUpdate: false,
|
|
597
607
|
configToUpdate: false,
|
|
598
608
|
contentChanges: versionInfo.contentMigration.changes || []
|
|
599
609
|
}
|
|
@@ -606,7 +616,7 @@ async function getMigrationPlan(projectDir, versionInfo) {
|
|
|
606
616
|
}
|
|
607
617
|
}
|
|
608
618
|
|
|
609
|
-
if (!versionInfo.isLegacy && !versionInfo.contentMigration.required) {
|
|
619
|
+
if (!versionInfo.isLegacy && !versionInfo.contentMigration.required && !versionMismatch) {
|
|
610
620
|
return plan;
|
|
611
621
|
}
|
|
612
622
|
|
|
@@ -642,7 +652,8 @@ async function getMigrationPlan(projectDir, versionInfo) {
|
|
|
642
652
|
if (await fs.pathExists(hooksDir)) {
|
|
643
653
|
const hookFiles = await fs.readdir(hooksDir);
|
|
644
654
|
const legacyHookIssues = await checkLegacyHooks(hooksDir);
|
|
645
|
-
if (legacyHookIssues.length > 0) {
|
|
655
|
+
if (legacyHookIssues.length > 0 || versionMismatch) {
|
|
656
|
+
plan.details.hooksNeedUpdate = true;
|
|
646
657
|
plan.details.hooksToUpdate = hookFiles.filter(f => f.endsWith('.sh'));
|
|
647
658
|
plan.tasks.push('更新 hooks 脚本到最新版本');
|
|
648
659
|
}
|
|
@@ -660,21 +671,49 @@ async function getMigrationPlan(projectDir, versionInfo) {
|
|
|
660
671
|
plan.details.commandsToRename.push({ from: cmd, to: newName });
|
|
661
672
|
plan.tasks.push(`重命名 command: ${cmd} → ${newName}`);
|
|
662
673
|
}
|
|
674
|
+
|
|
675
|
+
if (legacyCommands.length > 0 || versionMismatch) {
|
|
676
|
+
plan.details.commandsNeedUpdate = true;
|
|
677
|
+
if (legacyCommands.length === 0) {
|
|
678
|
+
plan.tasks.push('更新 commands 到最新版本');
|
|
679
|
+
}
|
|
680
|
+
}
|
|
663
681
|
}
|
|
664
682
|
|
|
665
683
|
// 4. 检查 agents 更新需求
|
|
666
684
|
const agentsDir = path.join(projectDir, '.claude/agents');
|
|
667
685
|
if (await fs.pathExists(agentsDir)) {
|
|
668
|
-
plan.details.
|
|
686
|
+
plan.details.agentsNeedUpdate = true;
|
|
687
|
+
plan.details.agentsToUpdate = ['planner.md', 'developer.md', 'tester.md', 'reviewer.md', 'doc-sync.md', 'bugfix.md'];
|
|
669
688
|
plan.tasks.push('更新所有 agents 到最新版本');
|
|
670
689
|
}
|
|
671
690
|
|
|
672
|
-
// 5. 配置更新
|
|
673
|
-
|
|
691
|
+
// 5. OpenCode 配置更新
|
|
692
|
+
const opencodeDir = path.join(projectDir, '.opencode');
|
|
693
|
+
if (await fs.pathExists(opencodeDir)) {
|
|
694
|
+
if (versionInfo.isLegacy || versionMismatch) {
|
|
695
|
+
plan.details.opencodeNeedUpdate = true;
|
|
696
|
+
plan.tasks.push('更新 OpenCode 配置到最新版本');
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// 6. 配置更新
|
|
701
|
+
if (!versionInfo.version || versionMismatch) {
|
|
674
702
|
plan.details.configToUpdate = true;
|
|
675
|
-
plan.tasks.push('
|
|
703
|
+
plan.tasks.push('更新版本信息(settings.json / jvibe.json)');
|
|
676
704
|
}
|
|
677
705
|
|
|
706
|
+
// 最终 needsMigration:只要存在任一自动迁移动作即可
|
|
707
|
+
plan.needsMigration = Boolean(
|
|
708
|
+
plan.details.docsToMove.length > 0 ||
|
|
709
|
+
plan.details.hooksNeedUpdate ||
|
|
710
|
+
plan.details.commandsNeedUpdate ||
|
|
711
|
+
plan.details.commandsToRename.length > 0 ||
|
|
712
|
+
plan.details.agentsNeedUpdate ||
|
|
713
|
+
plan.details.opencodeNeedUpdate ||
|
|
714
|
+
plan.details.configToUpdate
|
|
715
|
+
);
|
|
716
|
+
|
|
678
717
|
return plan;
|
|
679
718
|
}
|
|
680
719
|
|
|
@@ -760,30 +799,76 @@ async function migrateAgents(projectDir, templateDir) {
|
|
|
760
799
|
console.log(chalk.gray(' 已更新 agents'));
|
|
761
800
|
}
|
|
762
801
|
|
|
802
|
+
/**
|
|
803
|
+
* 执行 OpenCode 配置迁移(覆盖同步)
|
|
804
|
+
* @param {string} projectDir - 项目目录
|
|
805
|
+
* @param {string} templateDir - 模板目录
|
|
806
|
+
*/
|
|
807
|
+
async function migrateOpencode(projectDir, templateDir) {
|
|
808
|
+
const projectOpencodeDir = path.join(projectDir, '.opencode');
|
|
809
|
+
const templateOpencodeDir = path.join(templateDir, '.opencode');
|
|
810
|
+
|
|
811
|
+
if (!await fs.pathExists(projectOpencodeDir)) {
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
if (!await fs.pathExists(templateOpencodeDir)) {
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
await fs.copy(templateOpencodeDir, projectOpencodeDir, { overwrite: true });
|
|
819
|
+
console.log(chalk.gray(' 已更新 OpenCode 配置'));
|
|
820
|
+
}
|
|
821
|
+
|
|
763
822
|
/**
|
|
764
823
|
* 更新配置文件
|
|
765
824
|
* @param {string} projectDir - 项目目录
|
|
766
825
|
* @param {string} newVersion - 新版本号
|
|
767
826
|
*/
|
|
768
827
|
async function updateConfig(projectDir, newVersion) {
|
|
769
|
-
const
|
|
828
|
+
const migratedAt = new Date().toISOString();
|
|
770
829
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
830
|
+
// Claude Code settings
|
|
831
|
+
const claudeDir = path.join(projectDir, '.claude');
|
|
832
|
+
if (await fs.pathExists(claudeDir)) {
|
|
833
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
834
|
+
let settings = {};
|
|
835
|
+
if (await fs.pathExists(settingsPath)) {
|
|
836
|
+
try {
|
|
837
|
+
settings = await fs.readJson(settingsPath);
|
|
838
|
+
} catch (e) {
|
|
839
|
+
// 如果读取失败,创建新的配置
|
|
840
|
+
}
|
|
777
841
|
}
|
|
842
|
+
|
|
843
|
+
settings.jvibe = {
|
|
844
|
+
...settings.jvibe,
|
|
845
|
+
version: newVersion,
|
|
846
|
+
migratedAt
|
|
847
|
+
};
|
|
848
|
+
|
|
849
|
+
await fs.writeJson(settingsPath, settings, { spaces: 2 });
|
|
778
850
|
}
|
|
779
851
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
852
|
+
// OpenCode meta
|
|
853
|
+
const opencodeDir = path.join(projectDir, '.opencode');
|
|
854
|
+
if (await fs.pathExists(opencodeDir)) {
|
|
855
|
+
const opencodeMetaPath = path.join(opencodeDir, 'jvibe.json');
|
|
856
|
+
let meta = {};
|
|
857
|
+
if (await fs.pathExists(opencodeMetaPath)) {
|
|
858
|
+
try {
|
|
859
|
+
meta = await fs.readJson(opencodeMetaPath);
|
|
860
|
+
} catch (e) {
|
|
861
|
+
// ignore
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
meta = {
|
|
865
|
+
...meta,
|
|
866
|
+
version: newVersion,
|
|
867
|
+
migratedAt
|
|
868
|
+
};
|
|
869
|
+
await fs.writeJson(opencodeMetaPath, meta, { spaces: 2 });
|
|
870
|
+
}
|
|
785
871
|
|
|
786
|
-
await fs.writeJson(settingsPath, settings, { spaces: 2 });
|
|
787
872
|
console.log(chalk.gray(' 已更新版本信息'));
|
|
788
873
|
}
|
|
789
874
|
|
|
@@ -857,24 +942,30 @@ async function executeMigration(projectDir, templateDir, plan, newVersion) {
|
|
|
857
942
|
await migrateFeatureList(projectDir);
|
|
858
943
|
|
|
859
944
|
// 3. 迁移 hooks
|
|
860
|
-
if (plan.details.
|
|
945
|
+
if (plan.details.hooksNeedUpdate) {
|
|
861
946
|
console.log(chalk.gray(' 更新 hooks...'));
|
|
862
947
|
await migrateHooks(projectDir, templateDir);
|
|
863
948
|
}
|
|
864
949
|
|
|
865
950
|
// 4. 迁移 commands
|
|
866
|
-
if (plan.details.commandsToRename.length > 0) {
|
|
951
|
+
if (plan.details.commandsNeedUpdate || plan.details.commandsToRename.length > 0) {
|
|
867
952
|
console.log(chalk.gray(' 更新 commands...'));
|
|
868
953
|
await migrateCommands(projectDir, templateDir, plan);
|
|
869
954
|
}
|
|
870
955
|
|
|
871
956
|
// 5. 迁移 agents
|
|
872
|
-
if (plan.details.
|
|
957
|
+
if (plan.details.agentsNeedUpdate) {
|
|
873
958
|
console.log(chalk.gray(' 更新 agents...'));
|
|
874
959
|
await migrateAgents(projectDir, templateDir);
|
|
875
960
|
}
|
|
876
961
|
|
|
877
|
-
// 6.
|
|
962
|
+
// 6. 迁移 OpenCode
|
|
963
|
+
if (plan.details.opencodeNeedUpdate) {
|
|
964
|
+
console.log(chalk.gray(' 更新 OpenCode 配置...'));
|
|
965
|
+
await migrateOpencode(projectDir, templateDir);
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// 7. 更新配置
|
|
878
969
|
if (plan.details.configToUpdate) {
|
|
879
970
|
console.log(chalk.gray(' 更新配置...'));
|
|
880
971
|
await updateConfig(projectDir, newVersion);
|
|
@@ -925,6 +1016,7 @@ module.exports = {
|
|
|
925
1016
|
migrateHooks,
|
|
926
1017
|
migrateCommands,
|
|
927
1018
|
migrateAgents,
|
|
1019
|
+
migrateOpencode,
|
|
928
1020
|
migrateFeatureList,
|
|
929
1021
|
updateConfig
|
|
930
1022
|
};
|