dev-playbooks-cn 1.5.0 → 1.5.2
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/README.md
CHANGED
|
@@ -81,10 +81,21 @@ npx dev-playbooks-cn@latest init
|
|
|
81
81
|
|
|
82
82
|
### 安装落点
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
初始化时可选择 Skills 安装位置:
|
|
85
|
+
|
|
86
|
+
| 安装范围 | 说明 | 路径示例 |
|
|
87
|
+
|----------|------|----------|
|
|
88
|
+
| **项目级**(默认) | 仅当前项目可用 | `.claude/skills/devbooks-*` |
|
|
89
|
+
| **全局** | 所有项目共享 | `~/.claude/skills/devbooks-*` |
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# 交互式选择
|
|
93
|
+
dev-playbooks-cn init
|
|
94
|
+
|
|
95
|
+
# 非交互式指定
|
|
96
|
+
dev-playbooks-cn init --tools claude --scope project # 项目级
|
|
97
|
+
dev-playbooks-cn init --tools claude --scope global # 全局
|
|
98
|
+
```
|
|
88
99
|
|
|
89
100
|
### 快速集成
|
|
90
101
|
|
|
@@ -193,6 +204,7 @@ DevBooks 使用两个目录根:
|
|
|
193
204
|
|-------|------|
|
|
194
205
|
| `devbooks-entropy-monitor` | 系统熵度量 |
|
|
195
206
|
| `devbooks-brownfield-bootstrap` | 存量项目初始化 |
|
|
207
|
+
| `devbooks-convergence-audit` | 收敛性审计(反迷惑设计) |
|
|
196
208
|
|
|
197
209
|
---
|
|
198
210
|
|
package/bin/devbooks.js
CHANGED
|
@@ -24,7 +24,7 @@ import path from 'path';
|
|
|
24
24
|
import os from 'os';
|
|
25
25
|
import { fileURLToPath } from 'url';
|
|
26
26
|
import { spawn } from 'child_process';
|
|
27
|
-
import { checkbox, confirm } from '@inquirer/prompts';
|
|
27
|
+
import { checkbox, confirm, select } from '@inquirer/prompts';
|
|
28
28
|
import chalk from 'chalk';
|
|
29
29
|
import ora from 'ora';
|
|
30
30
|
|
|
@@ -45,6 +45,15 @@ const SKILLS_SUPPORT = {
|
|
|
45
45
|
BASIC: 'basic' // 仅基础指令(无独立 Skills 概念)
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// Skills 安装范围
|
|
50
|
+
// ============================================================================
|
|
51
|
+
|
|
52
|
+
const INSTALL_SCOPE = {
|
|
53
|
+
GLOBAL: 'global', // 全局安装(~/.claude/skills 等)
|
|
54
|
+
PROJECT: 'project' // 项目级安装(.claude/skills 等)
|
|
55
|
+
};
|
|
56
|
+
|
|
48
57
|
// ============================================================================
|
|
49
58
|
// AI 工具配置
|
|
50
59
|
// ============================================================================
|
|
@@ -540,12 +549,68 @@ async function promptToolSelection(projectDir) {
|
|
|
540
549
|
return selectedTools;
|
|
541
550
|
}
|
|
542
551
|
|
|
552
|
+
async function promptInstallScope(projectDir, selectedTools) {
|
|
553
|
+
// 检查是否有需要安装 Skills 的工具
|
|
554
|
+
const fullSupportTools = selectedTools.filter(id => {
|
|
555
|
+
const tool = AI_TOOLS.find(t => t.id === id);
|
|
556
|
+
return tool && tool.skillsSupport === SKILLS_SUPPORT.FULL;
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
if (fullSupportTools.length === 0) {
|
|
560
|
+
return INSTALL_SCOPE.PROJECT; // 没有完整 Skills 支持的工具,默认项目级
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// 读取已保存的配置
|
|
564
|
+
const config = loadConfig(projectDir);
|
|
565
|
+
const savedScope = config.installScope;
|
|
566
|
+
|
|
567
|
+
console.log();
|
|
568
|
+
console.log(chalk.bold('📦 Skills 安装位置'));
|
|
569
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
570
|
+
console.log();
|
|
571
|
+
|
|
572
|
+
const scope = await select({
|
|
573
|
+
message: 'Skills 安装到哪里?',
|
|
574
|
+
choices: [
|
|
575
|
+
{
|
|
576
|
+
name: `项目级 ${chalk.gray('(.claude/skills 等,仅当前项目可用)')}`,
|
|
577
|
+
value: INSTALL_SCOPE.PROJECT,
|
|
578
|
+
description: '推荐:Skills 随项目走,不影响其他项目'
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
name: `全局 ${chalk.gray('(~/.claude/skills 等,所有项目共享)')}`,
|
|
582
|
+
value: INSTALL_SCOPE.GLOBAL,
|
|
583
|
+
description: '所有项目共享同一套 Skills'
|
|
584
|
+
}
|
|
585
|
+
],
|
|
586
|
+
default: savedScope || INSTALL_SCOPE.PROJECT
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
return scope;
|
|
590
|
+
}
|
|
591
|
+
|
|
543
592
|
|
|
544
593
|
// ============================================================================
|
|
545
594
|
// 安装 Skills(Claude Code, Codex CLI, Qoder)
|
|
546
595
|
// ============================================================================
|
|
547
596
|
|
|
548
|
-
function
|
|
597
|
+
function getSkillsDestDir(tool, scope, projectDir) {
|
|
598
|
+
// 根据安装范围确定目标目录
|
|
599
|
+
if (scope === INSTALL_SCOPE.PROJECT) {
|
|
600
|
+
// 项目级安装:使用项目目录下的相对路径
|
|
601
|
+
if (tool.id === 'claude') {
|
|
602
|
+
return path.join(projectDir, '.claude', 'skills');
|
|
603
|
+
} else if (tool.id === 'codex') {
|
|
604
|
+
return path.join(projectDir, '.codex', 'skills');
|
|
605
|
+
} else if (tool.id === 'opencode') {
|
|
606
|
+
return path.join(projectDir, '.opencode', 'skill');
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
// 全局安装:使用工具定义的全局目录
|
|
610
|
+
return tool.skillsDir;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
function installSkills(toolIds, projectDir, scope = INSTALL_SCOPE.GLOBAL, update = false) {
|
|
549
614
|
const results = [];
|
|
550
615
|
|
|
551
616
|
for (const toolId of toolIds) {
|
|
@@ -555,7 +620,7 @@ function installSkills(toolIds, update = false) {
|
|
|
555
620
|
// Claude Code / Codex CLI / OpenCode(含 oh-my-opencode)支持相同格式的 Skills
|
|
556
621
|
if ((toolId === 'claude' || toolId === 'codex' || toolId === 'opencode') && tool.skillsDir) {
|
|
557
622
|
const skillsSrcDir = path.join(__dirname, '..', 'skills');
|
|
558
|
-
const skillsDestDir = tool
|
|
623
|
+
const skillsDestDir = getSkillsDestDir(tool, scope, projectDir);
|
|
559
624
|
|
|
560
625
|
if (!fs.existsSync(skillsSrcDir)) continue;
|
|
561
626
|
|
|
@@ -601,7 +666,9 @@ function installSkills(toolIds, update = false) {
|
|
|
601
666
|
type: 'skills',
|
|
602
667
|
count: installedCount,
|
|
603
668
|
total: skillDirs.length,
|
|
604
|
-
removed: removedCount
|
|
669
|
+
removed: removedCount,
|
|
670
|
+
scope: scope,
|
|
671
|
+
path: skillsDestDir
|
|
605
672
|
});
|
|
606
673
|
}
|
|
607
674
|
|
|
@@ -1013,7 +1080,7 @@ function createProjectStructure(projectDir) {
|
|
|
1013
1080
|
// 保存配置
|
|
1014
1081
|
// ============================================================================
|
|
1015
1082
|
|
|
1016
|
-
function saveConfig(toolIds, projectDir) {
|
|
1083
|
+
function saveConfig(toolIds, projectDir, installScope = INSTALL_SCOPE.PROJECT) {
|
|
1017
1084
|
const configPath = path.join(projectDir, '.devbooks', 'config.yaml');
|
|
1018
1085
|
|
|
1019
1086
|
// 读取现有配置或创建新配置
|
|
@@ -1033,6 +1100,17 @@ function saveConfig(toolIds, projectDir) {
|
|
|
1033
1100
|
configContent = configContent.trimEnd() + '\n\n' + toolsYaml + '\n';
|
|
1034
1101
|
}
|
|
1035
1102
|
|
|
1103
|
+
// 更新 install_scope 部分
|
|
1104
|
+
const scopeYaml = `install_scope: ${installScope}`;
|
|
1105
|
+
|
|
1106
|
+
if (configContent.includes('install_scope:')) {
|
|
1107
|
+
// 替换现有的 install_scope 部分
|
|
1108
|
+
configContent = configContent.replace(/install_scope:.*/, scopeYaml);
|
|
1109
|
+
} else {
|
|
1110
|
+
// 追加 install_scope 部分
|
|
1111
|
+
configContent = configContent.trimEnd() + '\n\n' + scopeYaml + '\n';
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1036
1114
|
fs.writeFileSync(configPath, configContent);
|
|
1037
1115
|
}
|
|
1038
1116
|
|
|
@@ -1040,23 +1118,26 @@ function loadConfig(projectDir) {
|
|
|
1040
1118
|
const configPath = path.join(projectDir, '.devbooks', 'config.yaml');
|
|
1041
1119
|
|
|
1042
1120
|
if (!fs.existsSync(configPath)) {
|
|
1043
|
-
return { aiTools: [] };
|
|
1121
|
+
return { aiTools: [], installScope: null };
|
|
1044
1122
|
}
|
|
1045
1123
|
|
|
1046
1124
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
1047
|
-
const match = content.match(/ai_tools:\s*([\s\S]*?)(?=\n\w|\n$|$)/);
|
|
1048
|
-
|
|
1049
|
-
if (!match) {
|
|
1050
|
-
return { aiTools: [] };
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
const tools = match[1]
|
|
1054
|
-
.split('\n')
|
|
1055
|
-
.map(line => line.trim())
|
|
1056
|
-
.filter(line => line.startsWith('-'))
|
|
1057
|
-
.map(line => line.replace(/^-\s*/, '').trim());
|
|
1058
1125
|
|
|
1059
|
-
|
|
1126
|
+
// 解析 ai_tools
|
|
1127
|
+
const toolsMatch = content.match(/ai_tools:\s*([\s\S]*?)(?=\n\w|\n$|$)/);
|
|
1128
|
+
const tools = toolsMatch
|
|
1129
|
+
? toolsMatch[1]
|
|
1130
|
+
.split('\n')
|
|
1131
|
+
.map(line => line.trim())
|
|
1132
|
+
.filter(line => line.startsWith('-'))
|
|
1133
|
+
.map(line => line.replace(/^-\s*/, '').trim())
|
|
1134
|
+
: [];
|
|
1135
|
+
|
|
1136
|
+
// 解析 install_scope
|
|
1137
|
+
const scopeMatch = content.match(/install_scope:\s*(\w+)/);
|
|
1138
|
+
const installScope = scopeMatch ? scopeMatch[1] : null;
|
|
1139
|
+
|
|
1140
|
+
return { aiTools: tools, installScope };
|
|
1060
1141
|
}
|
|
1061
1142
|
|
|
1062
1143
|
// ============================================================================
|
|
@@ -1072,6 +1153,7 @@ async function initCommand(projectDir, options) {
|
|
|
1072
1153
|
|
|
1073
1154
|
// 确定选择的工具
|
|
1074
1155
|
let selectedTools;
|
|
1156
|
+
let installScope = INSTALL_SCOPE.PROJECT; // 默认项目级安装
|
|
1075
1157
|
|
|
1076
1158
|
if (options.tools) {
|
|
1077
1159
|
if (options.tools === 'all') {
|
|
@@ -1084,8 +1166,16 @@ async function initCommand(projectDir, options) {
|
|
|
1084
1166
|
);
|
|
1085
1167
|
}
|
|
1086
1168
|
console.log(chalk.blue('ℹ') + ` 非交互式模式:${selectedTools.length > 0 ? selectedTools.join(', ') : '无'}`);
|
|
1169
|
+
|
|
1170
|
+
// 非交互式模式下,检查 --scope 选项
|
|
1171
|
+
if (options.scope) {
|
|
1172
|
+
installScope = options.scope === 'global' ? INSTALL_SCOPE.GLOBAL : INSTALL_SCOPE.PROJECT;
|
|
1173
|
+
}
|
|
1087
1174
|
} else {
|
|
1088
1175
|
selectedTools = await promptToolSelection(projectDir);
|
|
1176
|
+
|
|
1177
|
+
// 交互式选择安装范围
|
|
1178
|
+
installScope = await promptInstallScope(projectDir, selectedTools);
|
|
1089
1179
|
}
|
|
1090
1180
|
|
|
1091
1181
|
// 创建项目结构
|
|
@@ -1093,8 +1183,8 @@ async function initCommand(projectDir, options) {
|
|
|
1093
1183
|
const templateCount = createProjectStructure(projectDir);
|
|
1094
1184
|
spinner.succeed(`创建了 ${templateCount} 个模板文件`);
|
|
1095
1185
|
|
|
1096
|
-
//
|
|
1097
|
-
saveConfig(selectedTools, projectDir);
|
|
1186
|
+
// 保存配置(包含安装范围)
|
|
1187
|
+
saveConfig(selectedTools, projectDir, installScope);
|
|
1098
1188
|
|
|
1099
1189
|
if (selectedTools.length === 0) {
|
|
1100
1190
|
console.log();
|
|
@@ -1111,12 +1201,16 @@ async function initCommand(projectDir, options) {
|
|
|
1111
1201
|
|
|
1112
1202
|
if (fullSupportTools.length > 0) {
|
|
1113
1203
|
const skillsSpinner = ora('安装 Skills...').start();
|
|
1114
|
-
const skillsResults = installSkills(fullSupportTools);
|
|
1204
|
+
const skillsResults = installSkills(fullSupportTools, projectDir, installScope);
|
|
1115
1205
|
skillsSpinner.succeed('Skills 安装完成');
|
|
1116
1206
|
|
|
1117
1207
|
for (const result of skillsResults) {
|
|
1118
1208
|
if (result.count > 0) {
|
|
1119
|
-
|
|
1209
|
+
const scopeLabel = result.scope === INSTALL_SCOPE.PROJECT ? '项目级' : '全局';
|
|
1210
|
+
console.log(chalk.gray(` └ ${result.tool}: ${result.count}/${result.total} 个 ${result.type} (${scopeLabel})`));
|
|
1211
|
+
if (result.path) {
|
|
1212
|
+
console.log(chalk.gray(` → ${result.path}`));
|
|
1213
|
+
}
|
|
1120
1214
|
} else if (result.note) {
|
|
1121
1215
|
console.log(chalk.gray(` └ ${result.tool}: ${result.note}`));
|
|
1122
1216
|
}
|
|
@@ -1217,6 +1311,7 @@ async function updateCommand(projectDir) {
|
|
|
1217
1311
|
// 加载配置
|
|
1218
1312
|
const config = loadConfig(projectDir);
|
|
1219
1313
|
const configuredTools = config.aiTools;
|
|
1314
|
+
const installScope = config.installScope || INSTALL_SCOPE.PROJECT;
|
|
1220
1315
|
|
|
1221
1316
|
if (configuredTools.length === 0) {
|
|
1222
1317
|
console.log(chalk.yellow('⚠') + ` 未配置任何 AI 工具。运行 \`${CLI_COMMAND} init\` 进行配置。`);
|
|
@@ -1227,13 +1322,17 @@ async function updateCommand(projectDir) {
|
|
|
1227
1322
|
const tool = AI_TOOLS.find(t => t.id === id);
|
|
1228
1323
|
return tool ? tool.name : id;
|
|
1229
1324
|
});
|
|
1230
|
-
|
|
1325
|
+
const scopeLabel = installScope === INSTALL_SCOPE.PROJECT ? '项目级' : '全局';
|
|
1326
|
+
console.log(chalk.blue('ℹ') + ` 检测到已配置的工具: ${toolNames.join(', ')} (${scopeLabel}安装)`);
|
|
1231
1327
|
|
|
1232
|
-
// 更新 Skills
|
|
1233
|
-
const skillsResults = installSkills(configuredTools, true);
|
|
1328
|
+
// 更新 Skills(使用配置中保存的安装范围)
|
|
1329
|
+
const skillsResults = installSkills(configuredTools, projectDir, installScope, true);
|
|
1234
1330
|
for (const result of skillsResults) {
|
|
1235
1331
|
if (result.count > 0) {
|
|
1236
1332
|
console.log(chalk.green('✓') + ` ${result.tool} ${result.type}: 更新了 ${result.count}/${result.total} 个`);
|
|
1333
|
+
if (result.path) {
|
|
1334
|
+
console.log(chalk.gray(` → ${result.path}`));
|
|
1335
|
+
}
|
|
1237
1336
|
}
|
|
1238
1337
|
if (result.removed && result.removed > 0) {
|
|
1239
1338
|
console.log(chalk.green('✓') + ` ${result.tool} ${result.type}: 清理了 ${result.removed} 个已删除的技能`);
|
|
@@ -1375,6 +1474,8 @@ function showHelp() {
|
|
|
1375
1474
|
console.log(chalk.cyan('选项:'));
|
|
1376
1475
|
console.log(' --tools <tools> 非交互式指定 AI 工具');
|
|
1377
1476
|
console.log(' 可用值: all, none, 或逗号分隔的工具 ID');
|
|
1477
|
+
console.log(' --scope <scope> Skills 安装位置 (非交互式模式)');
|
|
1478
|
+
console.log(' 可用值: project (默认), global');
|
|
1378
1479
|
console.log(' --from <framework> 迁移来源框架 (openspec, speckit)');
|
|
1379
1480
|
console.log(' --dry-run 模拟运行,不实际修改文件');
|
|
1380
1481
|
console.log(' --keep-old 迁移后保留原目录');
|
|
@@ -1419,7 +1520,8 @@ function showHelp() {
|
|
|
1419
1520
|
console.log(chalk.cyan('示例:'));
|
|
1420
1521
|
console.log(` ${CLI_COMMAND} init # 交互式初始化`);
|
|
1421
1522
|
console.log(` ${CLI_COMMAND} init my-project # 在 my-project 目录初始化`);
|
|
1422
|
-
console.log(` ${CLI_COMMAND} init --tools claude,cursor #
|
|
1523
|
+
console.log(` ${CLI_COMMAND} init --tools claude,cursor # 非交互式(默认项目级安装)`);
|
|
1524
|
+
console.log(` ${CLI_COMMAND} init --tools claude --scope global # 非交互式(全局安装)`);
|
|
1423
1525
|
console.log(` ${CLI_COMMAND} update # 更新已配置的工具`);
|
|
1424
1526
|
console.log(` ${CLI_COMMAND} migrate --from openspec # 从 OpenSpec 迁移`);
|
|
1425
1527
|
console.log(` ${CLI_COMMAND} migrate --from speckit # 从 spec-kit 迁移`);
|
|
@@ -1449,6 +1551,8 @@ async function main() {
|
|
|
1449
1551
|
process.exit(0);
|
|
1450
1552
|
} else if (arg === '--tools') {
|
|
1451
1553
|
options.tools = args[++i];
|
|
1554
|
+
} else if (arg === '--scope') {
|
|
1555
|
+
options.scope = args[++i];
|
|
1452
1556
|
} else if (arg === '--from') {
|
|
1453
1557
|
options.from = args[++i];
|
|
1454
1558
|
} else if (arg === '--dry-run') {
|
package/package.json
CHANGED
|
@@ -357,3 +357,35 @@
|
|
|
357
357
|
输入:`tests/**` + `dev-playbooks/changes/<change-id>/verification.md`(如有)
|
|
358
358
|
输出:覆盖盲区 / 边界条件遗漏 / 可维护性风险 / 改进建议。
|
|
359
359
|
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## `devbooks-convergence-audit`(Convergence Auditor)【新】
|
|
364
|
+
|
|
365
|
+
- 作用:以证据优先、声明存疑的原则评估 DevBooks 工作流收敛性,检测"西西弗斯反模式"和"假完成"。主动验证而非信任文档声明。
|
|
366
|
+
- **反迷惑设计**:不相信文档中的任何断言(Status: Done、AC 打勾等),必须通过可验证证据确认。
|
|
367
|
+
- 使用场景:
|
|
368
|
+
- 你想评估工作流的真实收敛性(而非文档声明)
|
|
369
|
+
- 你怀疑某个变更包是"假完成"或"过时证据"
|
|
370
|
+
- 你想检测西西弗斯困境(反复返工但无法收敛)
|
|
371
|
+
- 使用话术:
|
|
372
|
+
```text
|
|
373
|
+
你现在是 Convergence Auditor。请点名使用 `devbooks-convergence-audit`。
|
|
374
|
+
先读:`dev-playbooks/project.md`(如存在)
|
|
375
|
+
目标:对指定变更包进行收敛性审计。
|
|
376
|
+
|
|
377
|
+
请按反迷惑原则执行:
|
|
378
|
+
1) 读取 `dev-playbooks/changes/<change-id>/` 下的所有文档
|
|
379
|
+
2) 对每个"声明"(Status=Done、AC 打勾等)进行证据验证
|
|
380
|
+
3) 实际运行测试验证(如可能)
|
|
381
|
+
4) 输出:声明 vs 证据对比表 + 可信度评分 + 迷惑检测结果
|
|
382
|
+
|
|
383
|
+
变更包:<change-id>
|
|
384
|
+
truth-root:dev-playbooks/specs
|
|
385
|
+
change-root:dev-playbooks/changes
|
|
386
|
+
```
|
|
387
|
+
- 可信度评分说明:
|
|
388
|
+
- 90-100:✅ 可信收敛,继续当前流程
|
|
389
|
+
- 70-89:⚠️ 部分可信,需要补充验证
|
|
390
|
+
- 50-69:🟠 存疑,需要返工部分环节
|
|
391
|
+
- < 50:🔴 不可信(西西弗斯困境),需要全面审查
|
|
@@ -28,7 +28,42 @@ allowed-tools:
|
|
|
28
28
|
|
|
29
29
|
## 产物落点
|
|
30
30
|
|
|
31
|
-
-
|
|
31
|
+
- **必须**写入:`<change-root>/<change-id>/proposal.md` 的 Impact 部分
|
|
32
|
+
- 备选:独立 `impact-analysis.md` 文件(后续回填到 proposal.md)
|
|
33
|
+
|
|
34
|
+
## 输出行为(关键约束)
|
|
35
|
+
|
|
36
|
+
> **黄金法则**:**直接写入文档,禁止输出到对话窗口**
|
|
37
|
+
|
|
38
|
+
### 必须遵守
|
|
39
|
+
|
|
40
|
+
1. **直接写入**:使用 `Edit` 或 `Write` 工具将分析结果直接写入目标文档
|
|
41
|
+
2. **禁止回显**:不要在对话中显示完整的分析内容
|
|
42
|
+
3. **简短通知**:完成后只需告知用户"影响分析已写入 `<文件路径>`"
|
|
43
|
+
|
|
44
|
+
### 正确行为 vs 错误行为
|
|
45
|
+
|
|
46
|
+
| 场景 | ❌ 错误行为 | ✅ 正确行为 |
|
|
47
|
+
|------|------------|------------|
|
|
48
|
+
| 分析完成 | 在对话中输出完整 Impact 表格 | 使用 Edit 工具写入 proposal.md |
|
|
49
|
+
| 通知用户 | 复述分析内容 | "影响分析已写入 `changes/xxx/proposal.md`" |
|
|
50
|
+
| 大量结果 | 分页输出到对话 | 全部写入文件,告知文件位置 |
|
|
51
|
+
|
|
52
|
+
### 示例对话
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
用户:分析一下修改 UserService 的影响
|
|
56
|
+
|
|
57
|
+
AI:[使用 Grep/CKB 分析引用]
|
|
58
|
+
[使用 Edit 工具写入 proposal.md]
|
|
59
|
+
|
|
60
|
+
影响分析已写入 `changes/refactor-user/proposal.md` 的 Impact 部分。
|
|
61
|
+
- 直接影响:8 个文件
|
|
62
|
+
- 间接影响:12 个文件
|
|
63
|
+
- 风险等级:中等
|
|
64
|
+
|
|
65
|
+
如需查看详情,请打开该文件。
|
|
66
|
+
```
|
|
32
67
|
|
|
33
68
|
## 执行方式
|
|
34
69
|
|