jvibe 1.0.9 → 1.1.1
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/JVIBE.md +2 -1
- package/README.md +6 -3
- package/bin/jvibe.js +15 -1
- package/lib/migrate.js +1 -2
- package/lib/migrations/index.js +7 -1
- package/package.json +1 -1
- package/scripts/init.js +1 -1
- package/scripts/uninstall.js +83 -0
- package/scripts/upgrade.js +36 -82
- package/scripts/validate.js +1 -1
- package/template/.claude/agents/developer.md +42 -3
- package/template/.claude/agents/doc-sync.md +8 -3
- package/template/.claude/agents/planner.md +13 -1
- package/template/.claude/agents/reviewer.md +3 -4
- package/template/.claude/agents/tester.md +226 -0
- package/template/.claude/commands/JVibe:init.md +11 -4
- package/template/.claude/commands/JVibe:keepgo.md +74 -38
- package/template/.claude/commands/JVibe:migrate.md +4 -1
- package/template/.claude/error-handling.md +60 -0
- package/template/.claude/permissions.yaml +134 -0
- package/template/README.md +5 -3
- package/template/docs/core/Project.md +9 -0
- package/template/docs/core/Standards.md +40 -0
package/JVIBE.md
CHANGED
|
@@ -52,7 +52,7 @@ TODO 完成情况 → 功能状态
|
|
|
52
52
|
### 3. 开发流程
|
|
53
53
|
|
|
54
54
|
```
|
|
55
|
-
需求分析 → 功能拆解 → 技术设计 → 编码实现 → 代码审查 → 文档同步
|
|
55
|
+
需求分析 → 功能拆解 → 技术设计 → 编码实现 → 测试验证 → 代码审查 → 文档同步
|
|
56
56
|
```
|
|
57
57
|
|
|
58
58
|
## Agent 职责
|
|
@@ -61,6 +61,7 @@ TODO 完成情况 → 功能状态
|
|
|
61
61
|
|-------|------|----------|
|
|
62
62
|
| **planner** | 需求分析、功能拆解、创建 F-XXX 条目 | Feature-List.md |
|
|
63
63
|
| **developer** | 代码实现、逐项完成 TODO、勾选完成项 | Feature-List.md + 源代码 |
|
|
64
|
+
| **tester** | 测试执行、结果分析、回归验证 | 测试文件(仅在明确要求时) |
|
|
64
65
|
| **reviewer** | 代码审查、规范检查、PR 描述生成 | 只读 |
|
|
65
66
|
| **doc-sync** | 状态推导、统计更新、格式检查 | Project.md |
|
|
66
67
|
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
JVibe 是一个**文档驱动的 AI 辅助开发系统**,专为 Claude Code 设计。它提供:
|
|
13
13
|
|
|
14
|
-
- 🤖 **
|
|
14
|
+
- 🤖 **5 个专业 Agent**:需求规划、代码开发、测试验证、代码审查、文档同步
|
|
15
15
|
- 📝 **结构化文档体系**:CORE-DOCS(4个核心文档)+ PROJECT-DOCS(按需扩展)
|
|
16
16
|
- 🔄 **自动化 Hooks**:自动加载上下文、同步功能状态、输出统计信息
|
|
17
17
|
- 🎯 **单一事实来源**:功能状态只在功能清单中维护(SoT 原则)
|
|
@@ -91,7 +91,7 @@ jvibe init
|
|
|
91
91
|
```
|
|
92
92
|
your-project/
|
|
93
93
|
├── .claude/ # Claude Code 配置
|
|
94
|
-
│ ├── agents/ #
|
|
94
|
+
│ ├── agents/ # 5 个 Sub-Agents
|
|
95
95
|
│ ├── commands/ # 3 个 JVibe Skills
|
|
96
96
|
│ ├── hooks/ # 4 个自动化 Hooks
|
|
97
97
|
│ └── settings.json
|
|
@@ -146,6 +146,7 @@ TODO 完成情况 → 功能状态
|
|
|
146
146
|
|-------|------|------|
|
|
147
147
|
| **planner** | 需求分析、功能拆解 | Sonnet |
|
|
148
148
|
| **developer** | 代码实现、TODO 完成 | Sonnet |
|
|
149
|
+
| **tester** | 测试执行、结果分析 | Sonnet |
|
|
149
150
|
| **reviewer** | 代码审查、规范检查 | Sonnet |
|
|
150
151
|
| **doc-sync** | 状态推导、统计更新 | Haiku |
|
|
151
152
|
|
|
@@ -158,8 +159,10 @@ TODO 完成情况 → 功能状态
|
|
|
158
159
|
| `jvibe init` | 初始化 JVibe 项目 |
|
|
159
160
|
| `jvibe init --mode=minimal` | 最小化初始化(仅 Core 文档) |
|
|
160
161
|
| `jvibe init --force` | 强制覆盖已存在的配置 |
|
|
161
|
-
| `jvibe upgrade` |
|
|
162
|
+
| `jvibe upgrade` | 升级到最新版本(默认卸载重装) |
|
|
162
163
|
| `jvibe upgrade --check` | 仅检查更新 |
|
|
164
|
+
| `jvibe upgrade --migrate` | 仅执行旧版迁移 |
|
|
165
|
+
| `jvibe uninstall` | 卸载项目内 JVibe 配置 |
|
|
163
166
|
| `jvibe status` | 查看项目配置状态 |
|
|
164
167
|
| `jvibe validate` | 验证项目配置 |
|
|
165
168
|
|
package/bin/jvibe.js
CHANGED
|
@@ -34,7 +34,7 @@ program
|
|
|
34
34
|
// upgrade 命令
|
|
35
35
|
program
|
|
36
36
|
.command('upgrade')
|
|
37
|
-
.description('
|
|
37
|
+
.description('升级到最新版本(默认卸载重装)')
|
|
38
38
|
.option('--check', '仅检查更新,不执行升级', false)
|
|
39
39
|
.option('--force', '强制升级,跳过确认', false)
|
|
40
40
|
.option('--migrate', '仅执行迁移,不更新到最新版本', false)
|
|
@@ -53,6 +53,20 @@ program
|
|
|
53
53
|
await upgrade({ ...options, migrate: true });
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
+
// uninstall 命令
|
|
57
|
+
program
|
|
58
|
+
.command('uninstall')
|
|
59
|
+
.description('卸载项目内的 JVibe 配置与核心文档')
|
|
60
|
+
.option('--purge-project-docs', '同时移除 docs/project', false)
|
|
61
|
+
.option('--no-backup', '不创建备份', false)
|
|
62
|
+
.action(async (options) => {
|
|
63
|
+
const uninstall = require('../scripts/uninstall');
|
|
64
|
+
await uninstall({
|
|
65
|
+
purgeProjectDocs: options.purgeProjectDocs,
|
|
66
|
+
backup: options.backup
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
56
70
|
// status 命令
|
|
57
71
|
program
|
|
58
72
|
.command('status')
|
package/lib/migrate.js
CHANGED
|
@@ -494,10 +494,9 @@ async function checkContentMigration(projectDir, currentVersion) {
|
|
|
494
494
|
description: '核心文档需要强制重构(以 template/docs/core 为准)'
|
|
495
495
|
});
|
|
496
496
|
}
|
|
497
|
-
return result;
|
|
498
497
|
}
|
|
499
498
|
|
|
500
|
-
//
|
|
499
|
+
// 模板检测后继续合并版本迁移配置
|
|
501
500
|
if (migrationsConfig && currentVersion) {
|
|
502
501
|
const configResult = migrationsConfig.checkAIMigrationRequired(currentVersion);
|
|
503
502
|
if (configResult.required) {
|
package/lib/migrations/index.js
CHANGED
|
@@ -226,7 +226,13 @@ function generateMigrationPrompt(fromVersion) {
|
|
|
226
226
|
if (result.changes.renamed.length > 0) {
|
|
227
227
|
prompt += `## 重命名的字段\n\n`;
|
|
228
228
|
for (const change of result.changes.renamed) {
|
|
229
|
-
|
|
229
|
+
const renameLabel = change.oldName && change.newName
|
|
230
|
+
? `${change.oldName} → ${change.newName}`
|
|
231
|
+
: (change.field || change.description || '重命名');
|
|
232
|
+
prompt += `- ${change.file}: ${renameLabel}\n`;
|
|
233
|
+
if (change.description && renameLabel !== change.description) {
|
|
234
|
+
prompt += ` - ${change.description}\n`;
|
|
235
|
+
}
|
|
230
236
|
}
|
|
231
237
|
prompt += `\n`;
|
|
232
238
|
}
|
package/package.json
CHANGED
package/scripts/init.js
CHANGED
|
@@ -100,7 +100,7 @@ async function init(options = {}) {
|
|
|
100
100
|
console.log(chalk.green('\n✅ JVibe 初始化完成!\n'));
|
|
101
101
|
|
|
102
102
|
console.log(chalk.white('已创建:'));
|
|
103
|
-
console.log(chalk.gray(' - .claude/agents/ (
|
|
103
|
+
console.log(chalk.gray(' - .claude/agents/ (5 个 Sub-Agents)'));
|
|
104
104
|
console.log(chalk.gray(' - .claude/commands/ (3 个 JVibe Skills)'));
|
|
105
105
|
console.log(chalk.gray(' - .claude/hooks/ (3 个自动化 Hooks)'));
|
|
106
106
|
console.log(chalk.gray(' - .claude/settings.json'));
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JVibe Uninstall Script
|
|
3
|
+
* 卸载项目内的 JVibe 配置与核心文档
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs-extra');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 卸载 JVibe 配置
|
|
12
|
+
* @param {Object} options - 卸载选项
|
|
13
|
+
* @param {boolean} options.purgeProjectDocs - 是否移除 docs/project
|
|
14
|
+
* @param {boolean} options.backup - 是否创建备份
|
|
15
|
+
* @param {boolean} options.showNextSteps - 是否输出下一步提示
|
|
16
|
+
*/
|
|
17
|
+
async function uninstall(options = {}) {
|
|
18
|
+
const purgeProjectDocs = options.purgeProjectDocs || false;
|
|
19
|
+
const backupEnabled = options.backup !== false;
|
|
20
|
+
const showNextSteps = options.showNextSteps !== false;
|
|
21
|
+
const cwd = process.cwd();
|
|
22
|
+
|
|
23
|
+
console.log(chalk.blue('\n🧹 正在卸载 JVibe...\n'));
|
|
24
|
+
|
|
25
|
+
const targets = [
|
|
26
|
+
{ relPath: '.claude', label: '.claude/' },
|
|
27
|
+
{ relPath: 'docs/core', label: 'docs/core/' },
|
|
28
|
+
{ relPath: 'docs/.jvibe', label: 'docs/.jvibe/' },
|
|
29
|
+
{ relPath: '.jvibe-state.json', label: '.jvibe-state.json' },
|
|
30
|
+
{ relPath: 'docs/.jvibe-state.json', label: 'docs/.jvibe-state.json' },
|
|
31
|
+
{ relPath: 'docs/project', label: 'docs/project/', optional: true }
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const existingTargets = [];
|
|
35
|
+
for (const target of targets) {
|
|
36
|
+
if (target.optional && !purgeProjectDocs) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const fullPath = path.join(cwd, target.relPath);
|
|
40
|
+
if (await fs.pathExists(fullPath)) {
|
|
41
|
+
existingTargets.push({ ...target, fullPath });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (existingTargets.length === 0) {
|
|
46
|
+
console.log(chalk.yellow('⚠️ 未发现可卸载的 JVibe 配置'));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let backupDir = null;
|
|
51
|
+
if (backupEnabled) {
|
|
52
|
+
backupDir = path.join(cwd, `.jvibe-uninstall-backup-${Date.now()}`);
|
|
53
|
+
await fs.ensureDir(backupDir);
|
|
54
|
+
|
|
55
|
+
for (const target of existingTargets) {
|
|
56
|
+
const destPath = path.join(backupDir, target.relPath);
|
|
57
|
+
await fs.ensureDir(path.dirname(destPath));
|
|
58
|
+
await fs.copy(target.fullPath, destPath);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const target of existingTargets) {
|
|
63
|
+
await fs.remove(target.fullPath);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
console.log(chalk.green('\n✅ JVibe 卸载完成!'));
|
|
67
|
+
console.log(chalk.white('\n已移除:'));
|
|
68
|
+
for (const target of existingTargets) {
|
|
69
|
+
console.log(chalk.gray(` - ${target.label}`));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (backupDir) {
|
|
73
|
+
console.log(chalk.gray(`\n备份位置:${path.basename(backupDir)}/`));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (showNextSteps) {
|
|
77
|
+
console.log(chalk.yellow('\n📝 下一步:'));
|
|
78
|
+
console.log(chalk.white(' 1. 重新运行 jvibe init 或 /JVibe:init 初始化'));
|
|
79
|
+
console.log(chalk.white(' 2. 如需恢复,可从备份目录手动还原\n'));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = uninstall;
|
package/scripts/upgrade.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* JVibe Upgrade Script
|
|
3
3
|
* 升级项目的 JVibe 配置到最新版本
|
|
4
|
-
*
|
|
4
|
+
* 默认执行卸载重装,可选保留旧迁移策略
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const fs = require('fs-extra');
|
|
@@ -13,6 +13,8 @@ const {
|
|
|
13
13
|
executeMigration,
|
|
14
14
|
printMigrationSummary
|
|
15
15
|
} = require('../lib/migrate');
|
|
16
|
+
const init = require('./init');
|
|
17
|
+
const uninstall = require('./uninstall');
|
|
16
18
|
|
|
17
19
|
const TEMPLATE_DIR = path.join(__dirname, '../template');
|
|
18
20
|
|
|
@@ -63,23 +65,47 @@ async function upgrade(options = {}) {
|
|
|
63
65
|
if (checkOnly) {
|
|
64
66
|
if (migrationPlan.needsMigration) {
|
|
65
67
|
console.log(chalk.yellow('\n📦 检测到旧版本,需要迁移'));
|
|
66
|
-
console.log(chalk.white(' 运行 jvibe upgrade
|
|
68
|
+
console.log(chalk.white(' 运行 jvibe upgrade 执行卸载重装\n'));
|
|
67
69
|
} else if (currentVersion === latestVersion) {
|
|
68
70
|
console.log(chalk.green('\n✅ 已是最新版本!\n'));
|
|
69
71
|
} else {
|
|
70
72
|
console.log(chalk.yellow(`\n📦 有新版本可用: ${latestVersion}`));
|
|
71
|
-
console.log(chalk.white(' 运行 jvibe upgrade
|
|
73
|
+
console.log(chalk.white(' 运行 jvibe upgrade 执行卸载重装\n'));
|
|
72
74
|
}
|
|
73
75
|
return;
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
|
|
78
|
+
if (!migrateOnly) {
|
|
79
|
+
if (!force) {
|
|
80
|
+
console.log(chalk.yellow('\n⚠️ 将执行卸载重装(重置 .claude/ 与 docs/core/)'));
|
|
81
|
+
console.log(chalk.white(' 使用 --force 选项跳过此确认'));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let mode = 'full';
|
|
85
|
+
if (await fs.pathExists(settingsPath)) {
|
|
86
|
+
try {
|
|
87
|
+
const settings = await fs.readJson(settingsPath);
|
|
88
|
+
mode = settings.jvibe?.mode || mode;
|
|
89
|
+
} catch (e) {
|
|
90
|
+
// 读取失败则使用默认模式
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
await uninstall({ purgeProjectDocs: false, backup: true, showNextSteps: false });
|
|
95
|
+
await init({ mode, force: false });
|
|
96
|
+
|
|
97
|
+
console.log(chalk.green(`\n✅ 升级完成!`));
|
|
98
|
+
console.log(chalk.green(` 版本: ${currentVersion} → ${latestVersion}`));
|
|
99
|
+
console.log(chalk.gray('\n 已执行卸载重装(保留 docs/project/)\n'));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// migrate-only 模式保留旧迁移逻辑
|
|
77
104
|
if (!migrationPlan.needsMigration && currentVersion === latestVersion) {
|
|
78
|
-
console.log(chalk.green('\n✅
|
|
105
|
+
console.log(chalk.green('\n✅ 已是最新版本,无需迁移!\n'));
|
|
79
106
|
return;
|
|
80
107
|
}
|
|
81
108
|
|
|
82
|
-
// 5. 确认升级(如果没有 --force)
|
|
83
109
|
if (!force && (migrationPlan.needsMigration || currentVersion !== latestVersion)) {
|
|
84
110
|
console.log(chalk.yellow('\n⚠️ 即将执行以下操作:'));
|
|
85
111
|
|
|
@@ -92,12 +118,8 @@ async function upgrade(options = {}) {
|
|
|
92
118
|
|
|
93
119
|
console.log(chalk.white('\n 使用 --force 选项跳过此确认'));
|
|
94
120
|
console.log(chalk.white(' 或重新运行命令继续...\n'));
|
|
95
|
-
|
|
96
|
-
// 在非交互模式下直接继续
|
|
97
|
-
// 实际项目中可能需要 readline 来获取用户确认
|
|
98
121
|
}
|
|
99
122
|
|
|
100
|
-
// 6. 创建备份
|
|
101
123
|
console.log(chalk.gray('\n 创建备份...'));
|
|
102
124
|
const backupDir = path.join(cwd, '.jvibe-backup-' + Date.now());
|
|
103
125
|
if (hasClaudeDir) {
|
|
@@ -108,78 +130,11 @@ async function upgrade(options = {}) {
|
|
|
108
130
|
}
|
|
109
131
|
console.log(chalk.gray(` 备份已保存到: ${path.basename(backupDir)}/`));
|
|
110
132
|
|
|
111
|
-
// 7. 执行迁移(如果需要)
|
|
112
133
|
if (migrationPlan.needsMigration) {
|
|
113
134
|
await executeMigration(cwd, TEMPLATE_DIR, migrationPlan, latestVersion);
|
|
114
135
|
}
|
|
115
136
|
|
|
116
|
-
|
|
117
|
-
if (!migrateOnly && currentVersion !== latestVersion) {
|
|
118
|
-
console.log(chalk.yellow(`\n📦 正在升级到 ${latestVersion}...\n`));
|
|
119
|
-
|
|
120
|
-
// 更新 agents(如果迁移时没有更新)
|
|
121
|
-
if (migrationPlan.details.agentsToUpdate.length === 0) {
|
|
122
|
-
console.log(chalk.gray(' 更新 agents...'));
|
|
123
|
-
await fs.copy(
|
|
124
|
-
path.join(TEMPLATE_DIR, '.claude/agents'),
|
|
125
|
-
path.join(cwd, '.claude/agents'),
|
|
126
|
-
{ overwrite: true }
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// 更新 commands(如果迁移时没有更新)
|
|
131
|
-
if (migrationPlan.details.commandsToRename.length === 0) {
|
|
132
|
-
console.log(chalk.gray(' 更新 commands...'));
|
|
133
|
-
await fs.copy(
|
|
134
|
-
path.join(TEMPLATE_DIR, '.claude/commands'),
|
|
135
|
-
path.join(cwd, '.claude/commands'),
|
|
136
|
-
{ overwrite: true }
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// 更新 hooks(如果迁移时没有更新)
|
|
141
|
-
if (migrationPlan.details.hooksToUpdate.length === 0) {
|
|
142
|
-
console.log(chalk.gray(' 更新 hooks...'));
|
|
143
|
-
await fs.copy(
|
|
144
|
-
path.join(TEMPLATE_DIR, '.claude/hooks'),
|
|
145
|
-
path.join(cwd, '.claude/hooks'),
|
|
146
|
-
{ overwrite: true }
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// 补充任务交接文件(如不存在)
|
|
151
|
-
const handoffSrc = path.join(TEMPLATE_DIR, 'docs/.jvibe/tasks.yaml');
|
|
152
|
-
const handoffDir = path.join(cwd, 'docs/.jvibe');
|
|
153
|
-
const handoffDest = path.join(handoffDir, 'tasks.yaml');
|
|
154
|
-
if (await fs.pathExists(handoffSrc) && !await fs.pathExists(handoffDest)) {
|
|
155
|
-
await fs.ensureDir(handoffDir);
|
|
156
|
-
await fs.copy(handoffSrc, handoffDest, { overwrite: false });
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// 更新版本信息
|
|
160
|
-
let settings = {};
|
|
161
|
-
if (await fs.pathExists(settingsPath)) {
|
|
162
|
-
try {
|
|
163
|
-
settings = await fs.readJson(settingsPath);
|
|
164
|
-
} catch (e) {
|
|
165
|
-
// 读取失败则创建新配置
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
settings.jvibe = {
|
|
170
|
-
...settings.jvibe,
|
|
171
|
-
version: latestVersion,
|
|
172
|
-
upgradedAt: new Date().toISOString()
|
|
173
|
-
};
|
|
174
|
-
await fs.writeJson(settingsPath, settings, { spaces: 2 });
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// 9. 清理旧备份(保留最新的)
|
|
178
|
-
// 可选:保留备份供用户手动清理
|
|
179
|
-
|
|
180
|
-
// 10. 输出成功信息
|
|
181
|
-
console.log(chalk.green(`\n✅ 升级完成!`));
|
|
182
|
-
|
|
137
|
+
console.log(chalk.green(`\n✅ 迁移完成!`));
|
|
183
138
|
if (migrationPlan.needsMigration) {
|
|
184
139
|
console.log(chalk.green(' 已完成旧版本迁移'));
|
|
185
140
|
}
|
|
@@ -190,7 +145,6 @@ async function upgrade(options = {}) {
|
|
|
190
145
|
console.log(chalk.gray(`\n 备份位置: ${path.basename(backupDir)}/`));
|
|
191
146
|
console.log(chalk.gray(' 如需回滚,请手动恢复备份文件'));
|
|
192
147
|
|
|
193
|
-
// 11. 检查是否需要 AI 内容迁移
|
|
194
148
|
if (migrationPlan.needsAIMigration) {
|
|
195
149
|
console.log(chalk.yellow('\n⚠️ 检测到文档内容需要智能迁移'));
|
|
196
150
|
console.log(chalk.yellow(' 以下内容需要 AI 介入处理:'));
|
|
@@ -207,7 +161,7 @@ async function upgrade(options = {}) {
|
|
|
207
161
|
console.error(chalk.red('\n❌ 升级失败:'), error.message);
|
|
208
162
|
|
|
209
163
|
// 提示备份位置
|
|
210
|
-
const backups = await findBackups(cwd);
|
|
164
|
+
const backups = await findBackups(cwd, ['.jvibe-backup-', '.jvibe-uninstall-backup-']);
|
|
211
165
|
if (backups.length > 0) {
|
|
212
166
|
console.log(chalk.yellow(` 最新备份: ${backups[0]}`));
|
|
213
167
|
}
|
|
@@ -221,11 +175,11 @@ async function upgrade(options = {}) {
|
|
|
221
175
|
* @param {string} dir - 项目目录
|
|
222
176
|
* @returns {Promise<string[]>}
|
|
223
177
|
*/
|
|
224
|
-
async function findBackups(dir) {
|
|
178
|
+
async function findBackups(dir, prefixes = ['.jvibe-backup-']) {
|
|
225
179
|
try {
|
|
226
180
|
const files = await fs.readdir(dir);
|
|
227
181
|
return files
|
|
228
|
-
.filter(f => f.startsWith(
|
|
182
|
+
.filter(f => prefixes.some(prefix => f.startsWith(prefix)))
|
|
229
183
|
.sort()
|
|
230
184
|
.reverse();
|
|
231
185
|
} catch (e) {
|
package/scripts/validate.js
CHANGED
|
@@ -39,7 +39,7 @@ async function validate() {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// 检查 agents
|
|
42
|
-
const requiredAgents = ['planner.md', 'developer.md', 'reviewer.md', 'doc-sync.md'];
|
|
42
|
+
const requiredAgents = ['planner.md', 'developer.md', 'reviewer.md', 'doc-sync.md', 'tester.md'];
|
|
43
43
|
const agentsDir = path.join(claudeDir, 'agents');
|
|
44
44
|
if (await fs.pathExists(agentsDir)) {
|
|
45
45
|
for (const agent of requiredAgents) {
|
|
@@ -41,6 +41,7 @@ model: sonnet
|
|
|
41
41
|
## 约束(硬规则)
|
|
42
42
|
|
|
43
43
|
```yaml
|
|
44
|
+
source_of_truth: .claude/permissions.yaml
|
|
44
45
|
constraints:
|
|
45
46
|
read_allowlist:
|
|
46
47
|
- docs/**
|
|
@@ -57,7 +58,11 @@ constraints:
|
|
|
57
58
|
- .claude/**
|
|
58
59
|
- .jvibe-state.json
|
|
59
60
|
- package.json
|
|
60
|
-
-
|
|
61
|
+
- package-lock.json
|
|
62
|
+
- pnpm-lock.yaml
|
|
63
|
+
- yarn.lock
|
|
64
|
+
- Pipfile.lock
|
|
65
|
+
- poetry.lock
|
|
61
66
|
- .gitignore
|
|
62
67
|
ops:
|
|
63
68
|
network: forbidden
|
|
@@ -103,8 +108,22 @@ constraints:
|
|
|
103
108
|
### TODO 执行规则
|
|
104
109
|
|
|
105
110
|
1. **按顺序执行**:通常按 TODO 列表顺序
|
|
106
|
-
2.
|
|
107
|
-
3.
|
|
111
|
+
2. **尽量一次完成**:单次调用应尝试完成该功能的所有 TODO
|
|
112
|
+
3. **完成即勾选**:完成一个就勾选一个,不要积攒
|
|
113
|
+
4. **遇阻即报告**:无法完成时说明原因并停止
|
|
114
|
+
|
|
115
|
+
### 交接协议
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
handoff_rules:
|
|
119
|
+
- when: todo_includes_test
|
|
120
|
+
target: tester
|
|
121
|
+
action: run_tests
|
|
122
|
+
payload:
|
|
123
|
+
feature: F-XXX
|
|
124
|
+
files: []
|
|
125
|
+
scope: unit|integration|e2e
|
|
126
|
+
```
|
|
108
127
|
|
|
109
128
|
### 勾选格式
|
|
110
129
|
|
|
@@ -136,6 +155,16 @@ update_requests: # 需要主 Agent 处理的更新
|
|
|
136
155
|
action: check_status
|
|
137
156
|
feature: F-XXX
|
|
138
157
|
reason: "TODO 全部完成,需要更新功能状态"
|
|
158
|
+
|
|
159
|
+
handoff:
|
|
160
|
+
target: tester
|
|
161
|
+
action: run_tests
|
|
162
|
+
payload:
|
|
163
|
+
feature: F-XXX
|
|
164
|
+
files:
|
|
165
|
+
- src/modules/auth/register.ts
|
|
166
|
+
- src/modules/auth/register.test.ts
|
|
167
|
+
scope: unit
|
|
139
168
|
```
|
|
140
169
|
|
|
141
170
|
## 示例
|
|
@@ -194,6 +223,16 @@ update_requests:
|
|
|
194
223
|
action: check_status
|
|
195
224
|
feature: F-018
|
|
196
225
|
reason: "所有 TODO 已完成,需要更新功能状态为 ✅"
|
|
226
|
+
|
|
227
|
+
handoff:
|
|
228
|
+
target: tester
|
|
229
|
+
action: run_tests
|
|
230
|
+
payload:
|
|
231
|
+
feature: F-018
|
|
232
|
+
files:
|
|
233
|
+
- src/modules/chat/thumbnail.service.ts
|
|
234
|
+
- src/modules/chat/file.test.ts
|
|
235
|
+
scope: integration
|
|
197
236
|
```
|
|
198
237
|
|
|
199
238
|
## 注意事项
|
|
@@ -14,7 +14,7 @@ model: haiku
|
|
|
14
14
|
1. **状态推导**:根据 TODO 完成情况推导功能状态
|
|
15
15
|
2. **统计更新**:更新项目文档中的统计表
|
|
16
16
|
3. **格式检查**:检查文档格式一致性
|
|
17
|
-
4. **Git
|
|
17
|
+
4. **Git 提交**:仅在用户明确要求或 keepgo `auto_commit=true` 时执行
|
|
18
18
|
|
|
19
19
|
## 权限范围
|
|
20
20
|
|
|
@@ -38,6 +38,7 @@ model: haiku
|
|
|
38
38
|
## 约束(硬规则)
|
|
39
39
|
|
|
40
40
|
```yaml
|
|
41
|
+
source_of_truth: .claude/permissions.yaml
|
|
41
42
|
constraints:
|
|
42
43
|
read_allowlist:
|
|
43
44
|
- docs/core/Feature-List.md
|
|
@@ -52,13 +53,17 @@ constraints:
|
|
|
52
53
|
- .claude/**
|
|
53
54
|
- .jvibe-state.json
|
|
54
55
|
- package.json
|
|
55
|
-
-
|
|
56
|
+
- package-lock.json
|
|
57
|
+
- pnpm-lock.yaml
|
|
58
|
+
- yarn.lock
|
|
59
|
+
- Pipfile.lock
|
|
60
|
+
- poetry.lock
|
|
56
61
|
- .gitignore
|
|
57
62
|
ops:
|
|
58
63
|
network: forbidden
|
|
59
64
|
install: forbidden
|
|
60
65
|
tests: forbidden
|
|
61
|
-
git: only_if_user_requested
|
|
66
|
+
git: only_if_user_requested # keepgo auto_commit=true counts as explicit request
|
|
62
67
|
```
|
|
63
68
|
|
|
64
69
|
## 状态推导规则
|
|
@@ -35,6 +35,7 @@ model: sonnet
|
|
|
35
35
|
## 约束(硬规则)
|
|
36
36
|
|
|
37
37
|
```yaml
|
|
38
|
+
source_of_truth: .claude/permissions.yaml
|
|
38
39
|
constraints:
|
|
39
40
|
read_allowlist:
|
|
40
41
|
- docs/**
|
|
@@ -46,7 +47,11 @@ constraints:
|
|
|
46
47
|
- .claude/**
|
|
47
48
|
- .jvibe-state.json
|
|
48
49
|
- package.json
|
|
49
|
-
-
|
|
50
|
+
- package-lock.json
|
|
51
|
+
- pnpm-lock.yaml
|
|
52
|
+
- yarn.lock
|
|
53
|
+
- Pipfile.lock
|
|
54
|
+
- poetry.lock
|
|
50
55
|
- .gitignore
|
|
51
56
|
ops:
|
|
52
57
|
network: forbidden
|
|
@@ -55,6 +60,13 @@ constraints:
|
|
|
55
60
|
git: forbidden
|
|
56
61
|
```
|
|
57
62
|
|
|
63
|
+
## 拒绝规划规则
|
|
64
|
+
|
|
65
|
+
当需求明显超出项目范围或违反约束时:
|
|
66
|
+
- 不写入 `Feature-List.md`
|
|
67
|
+
- 说明拒绝原因与可行替代方案
|
|
68
|
+
- 如可拆解,建议用户缩小范围后再规划
|
|
69
|
+
|
|
58
70
|
## 工作流程
|
|
59
71
|
|
|
60
72
|
```
|
|
@@ -38,6 +38,7 @@ model: sonnet
|
|
|
38
38
|
## 约束(硬规则)
|
|
39
39
|
|
|
40
40
|
```yaml
|
|
41
|
+
source_of_truth: .claude/permissions.yaml
|
|
41
42
|
constraints:
|
|
42
43
|
read_allowlist:
|
|
43
44
|
- docs/**
|
|
@@ -52,7 +53,7 @@ constraints:
|
|
|
52
53
|
network: forbidden
|
|
53
54
|
install: forbidden
|
|
54
55
|
tests: forbidden
|
|
55
|
-
git: read_only #
|
|
56
|
+
git: read_only # allowed: git diff, git status, git log --oneline, git show
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
## 工作流程
|
|
@@ -125,20 +126,18 @@ result:
|
|
|
125
126
|
summary: "审查通过/需要修改"
|
|
126
127
|
files_reviewed: 5
|
|
127
128
|
|
|
128
|
-
issues: #
|
|
129
|
+
issues: # 发现的问题(spec 可选,优先在 hit_specs 汇总)
|
|
129
130
|
- severity: error # error/warning/info
|
|
130
131
|
file: src/auth/login.ts
|
|
131
132
|
line: 42
|
|
132
133
|
message: "SQL 拼接存在注入风险"
|
|
133
134
|
suggestion: "使用参数化查询"
|
|
134
|
-
spec: SEC-001
|
|
135
135
|
|
|
136
136
|
- severity: warning
|
|
137
137
|
file: src/user/profile.ts
|
|
138
138
|
line: 78
|
|
139
139
|
message: "函数复杂度过高"
|
|
140
140
|
suggestion: "拆分为多个小函数"
|
|
141
|
-
spec: CS-003
|
|
142
141
|
|
|
143
142
|
hit_specs: # 命中的规范条目
|
|
144
143
|
- id: CS-001
|