dev-playbooks 1.4.0 → 1.5.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/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 Install Scope
|
|
50
|
+
// ============================================================================
|
|
51
|
+
|
|
52
|
+
const INSTALL_SCOPE = {
|
|
53
|
+
GLOBAL: 'global', // Global installation (~/.claude/skills etc.)
|
|
54
|
+
PROJECT: 'project' // Project-level installation (.claude/skills etc.)
|
|
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
|
+
// Check if any tools support full 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; // No full Skills support tools, default to project-level
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Load saved config
|
|
564
|
+
const config = loadConfig(projectDir);
|
|
565
|
+
const savedScope = config.installScope;
|
|
566
|
+
|
|
567
|
+
console.log();
|
|
568
|
+
console.log(chalk.bold('📦 Skills Installation Location'));
|
|
569
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
570
|
+
console.log();
|
|
571
|
+
|
|
572
|
+
const scope = await select({
|
|
573
|
+
message: 'Where should Skills be installed?',
|
|
574
|
+
choices: [
|
|
575
|
+
{
|
|
576
|
+
name: `Project-level ${chalk.gray('(.claude/skills etc., only for this project)')}`,
|
|
577
|
+
value: INSTALL_SCOPE.PROJECT,
|
|
578
|
+
description: 'Recommended: Skills stay with the project, no impact on other projects'
|
|
579
|
+
},
|
|
580
|
+
{
|
|
581
|
+
name: `Global ${chalk.gray('(~/.claude/skills etc., shared across all projects)')}`,
|
|
582
|
+
value: INSTALL_SCOPE.GLOBAL,
|
|
583
|
+
description: 'All projects share the same set of Skills'
|
|
584
|
+
}
|
|
585
|
+
],
|
|
586
|
+
default: savedScope || INSTALL_SCOPE.PROJECT
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
return scope;
|
|
590
|
+
}
|
|
591
|
+
|
|
543
592
|
|
|
544
593
|
// ============================================================================
|
|
545
|
-
//
|
|
594
|
+
// Install Skills (Claude Code, Codex CLI, Qoder)
|
|
546
595
|
// ============================================================================
|
|
547
596
|
|
|
548
|
-
function
|
|
597
|
+
function getSkillsDestDir(tool, scope, projectDir) {
|
|
598
|
+
// Determine destination directory based on install scope
|
|
599
|
+
if (scope === INSTALL_SCOPE.PROJECT) {
|
|
600
|
+
// Project-level installation: use relative path within project directory
|
|
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
|
+
// Global installation: use tool's defined global directory
|
|
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 (incl. oh-my-opencode) share the same Skills format
|
|
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,13 +666,15 @@ 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
|
|
|
608
|
-
// Qoder:
|
|
675
|
+
// Qoder: Create agents directory structure (but don't copy Skills, different format)
|
|
609
676
|
if (toolId === 'qoder') {
|
|
610
|
-
results.push({ tool: 'Qoder', type: 'agents', count: 0, total: 0, note: '
|
|
677
|
+
results.push({ tool: 'Qoder', type: 'agents', count: 0, total: 0, note: 'Manual agents/ creation required' });
|
|
611
678
|
}
|
|
612
679
|
}
|
|
613
680
|
|
|
@@ -1006,29 +1073,40 @@ function createProjectStructure(projectDir) {
|
|
|
1006
1073
|
}
|
|
1007
1074
|
|
|
1008
1075
|
// ============================================================================
|
|
1009
|
-
//
|
|
1076
|
+
// Save Configuration
|
|
1010
1077
|
// ============================================================================
|
|
1011
1078
|
|
|
1012
|
-
function saveConfig(toolIds, projectDir) {
|
|
1079
|
+
function saveConfig(toolIds, projectDir, installScope = INSTALL_SCOPE.PROJECT) {
|
|
1013
1080
|
const configPath = path.join(projectDir, '.devbooks', 'config.yaml');
|
|
1014
1081
|
|
|
1015
|
-
//
|
|
1082
|
+
// Read existing config or create new
|
|
1016
1083
|
let configContent = '';
|
|
1017
1084
|
if (fs.existsSync(configPath)) {
|
|
1018
1085
|
configContent = fs.readFileSync(configPath, 'utf-8');
|
|
1019
1086
|
}
|
|
1020
1087
|
|
|
1021
|
-
//
|
|
1088
|
+
// Update ai_tools section
|
|
1022
1089
|
const toolsYaml = `ai_tools:\n${toolIds.map(id => ` - ${id}`).join('\n')}`;
|
|
1023
1090
|
|
|
1024
1091
|
if (configContent.includes('ai_tools:')) {
|
|
1025
|
-
//
|
|
1092
|
+
// Replace existing ai_tools section
|
|
1026
1093
|
configContent = configContent.replace(/ai_tools:[\s\S]*?(?=\n\w|\n$|$)/, toolsYaml + '\n');
|
|
1027
1094
|
} else {
|
|
1028
|
-
//
|
|
1095
|
+
// Append ai_tools section
|
|
1029
1096
|
configContent = configContent.trimEnd() + '\n\n' + toolsYaml + '\n';
|
|
1030
1097
|
}
|
|
1031
1098
|
|
|
1099
|
+
// Update install_scope section
|
|
1100
|
+
const scopeYaml = `install_scope: ${installScope}`;
|
|
1101
|
+
|
|
1102
|
+
if (configContent.includes('install_scope:')) {
|
|
1103
|
+
// Replace existing install_scope section
|
|
1104
|
+
configContent = configContent.replace(/install_scope:.*/, scopeYaml);
|
|
1105
|
+
} else {
|
|
1106
|
+
// Append install_scope section
|
|
1107
|
+
configContent = configContent.trimEnd() + '\n\n' + scopeYaml + '\n';
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1032
1110
|
fs.writeFileSync(configPath, configContent);
|
|
1033
1111
|
}
|
|
1034
1112
|
|
|
@@ -1036,38 +1114,42 @@ function loadConfig(projectDir) {
|
|
|
1036
1114
|
const configPath = path.join(projectDir, '.devbooks', 'config.yaml');
|
|
1037
1115
|
|
|
1038
1116
|
if (!fs.existsSync(configPath)) {
|
|
1039
|
-
return { aiTools: [] };
|
|
1117
|
+
return { aiTools: [], installScope: null };
|
|
1040
1118
|
}
|
|
1041
1119
|
|
|
1042
1120
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
1043
|
-
const match = content.match(/ai_tools:\s*([\s\S]*?)(?=\n\w|\n$|$)/);
|
|
1044
|
-
|
|
1045
|
-
if (!match) {
|
|
1046
|
-
return { aiTools: [] };
|
|
1047
|
-
}
|
|
1048
1121
|
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1122
|
+
// Parse ai_tools
|
|
1123
|
+
const toolsMatch = content.match(/ai_tools:\s*([\s\S]*?)(?=\n\w|\n$|$)/);
|
|
1124
|
+
const tools = toolsMatch
|
|
1125
|
+
? toolsMatch[1]
|
|
1126
|
+
.split('\n')
|
|
1127
|
+
.map(line => line.trim())
|
|
1128
|
+
.filter(line => line.startsWith('-'))
|
|
1129
|
+
.map(line => line.replace(/^-\s*/, '').trim())
|
|
1130
|
+
: [];
|
|
1131
|
+
|
|
1132
|
+
// Parse install_scope
|
|
1133
|
+
const scopeMatch = content.match(/install_scope:\s*(\w+)/);
|
|
1134
|
+
const installScope = scopeMatch ? scopeMatch[1] : null;
|
|
1135
|
+
|
|
1136
|
+
return { aiTools: tools, installScope };
|
|
1056
1137
|
}
|
|
1057
1138
|
|
|
1058
1139
|
// ============================================================================
|
|
1059
|
-
// Init
|
|
1140
|
+
// Init Command
|
|
1060
1141
|
// ============================================================================
|
|
1061
1142
|
|
|
1062
1143
|
async function initCommand(projectDir, options) {
|
|
1063
1144
|
console.log();
|
|
1064
1145
|
console.log(chalk.cyan('╔══════════════════════════════════════╗'));
|
|
1065
|
-
console.log(chalk.cyan('║') + chalk.bold('
|
|
1146
|
+
console.log(chalk.cyan('║') + chalk.bold(' DevBooks Initialization ') + chalk.cyan('║'));
|
|
1066
1147
|
console.log(chalk.cyan('╚══════════════════════════════════════╝'));
|
|
1067
1148
|
console.log();
|
|
1068
1149
|
|
|
1069
|
-
//
|
|
1150
|
+
// Determine selected tools
|
|
1070
1151
|
let selectedTools;
|
|
1152
|
+
let installScope = INSTALL_SCOPE.PROJECT; // Default to project-level installation
|
|
1071
1153
|
|
|
1072
1154
|
if (options.tools) {
|
|
1073
1155
|
if (options.tools === 'all') {
|
|
@@ -1079,27 +1161,35 @@ async function initCommand(projectDir, options) {
|
|
|
1079
1161
|
AI_TOOLS.some(tool => tool.id === t)
|
|
1080
1162
|
);
|
|
1081
1163
|
}
|
|
1082
|
-
console.log(chalk.blue('ℹ') + `
|
|
1164
|
+
console.log(chalk.blue('ℹ') + ` Non-interactive mode: ${selectedTools.length > 0 ? selectedTools.join(', ') : 'none'}`);
|
|
1165
|
+
|
|
1166
|
+
// In non-interactive mode, check --scope option
|
|
1167
|
+
if (options.scope) {
|
|
1168
|
+
installScope = options.scope === 'global' ? INSTALL_SCOPE.GLOBAL : INSTALL_SCOPE.PROJECT;
|
|
1169
|
+
}
|
|
1083
1170
|
} else {
|
|
1084
1171
|
selectedTools = await promptToolSelection(projectDir);
|
|
1172
|
+
|
|
1173
|
+
// Interactive scope selection
|
|
1174
|
+
installScope = await promptInstallScope(projectDir, selectedTools);
|
|
1085
1175
|
}
|
|
1086
1176
|
|
|
1087
|
-
//
|
|
1088
|
-
const spinner = ora('
|
|
1177
|
+
// Create project structure
|
|
1178
|
+
const spinner = ora('Creating project structure...').start();
|
|
1089
1179
|
const templateCount = createProjectStructure(projectDir);
|
|
1090
|
-
spinner.succeed(
|
|
1180
|
+
spinner.succeed(`Created ${templateCount} template files`);
|
|
1091
1181
|
|
|
1092
|
-
//
|
|
1093
|
-
saveConfig(selectedTools, projectDir);
|
|
1182
|
+
// Save configuration (including install scope)
|
|
1183
|
+
saveConfig(selectedTools, projectDir, installScope);
|
|
1094
1184
|
|
|
1095
1185
|
if (selectedTools.length === 0) {
|
|
1096
1186
|
console.log();
|
|
1097
|
-
console.log(chalk.green('✓') + ' DevBooks
|
|
1098
|
-
console.log(chalk.gray(`
|
|
1187
|
+
console.log(chalk.green('✓') + ' DevBooks project structure created!');
|
|
1188
|
+
console.log(chalk.gray(` Run \`${CLI_COMMAND} init\` and select AI tools to configure integration.`));
|
|
1099
1189
|
return;
|
|
1100
1190
|
}
|
|
1101
1191
|
|
|
1102
|
-
//
|
|
1192
|
+
// Install Skills (only for full support tools)
|
|
1103
1193
|
const fullSupportTools = selectedTools.filter(id => {
|
|
1104
1194
|
const tool = AI_TOOLS.find(t => t.id === id);
|
|
1105
1195
|
return tool && tool.skillsSupport === SKILLS_SUPPORT.FULL;
|
|
@@ -1107,12 +1197,16 @@ async function initCommand(projectDir, options) {
|
|
|
1107
1197
|
|
|
1108
1198
|
if (fullSupportTools.length > 0) {
|
|
1109
1199
|
const skillsSpinner = ora('Installing Skills...').start();
|
|
1110
|
-
const skillsResults = installSkills(fullSupportTools);
|
|
1200
|
+
const skillsResults = installSkills(fullSupportTools, projectDir, installScope);
|
|
1111
1201
|
skillsSpinner.succeed('Skills installed');
|
|
1112
1202
|
|
|
1113
1203
|
for (const result of skillsResults) {
|
|
1114
1204
|
if (result.count > 0) {
|
|
1115
|
-
|
|
1205
|
+
const scopeLabel = result.scope === INSTALL_SCOPE.PROJECT ? 'project-level' : 'global';
|
|
1206
|
+
console.log(chalk.gray(` └ ${result.tool}: ${result.count}/${result.total} ${result.type} (${scopeLabel})`));
|
|
1207
|
+
if (result.path) {
|
|
1208
|
+
console.log(chalk.gray(` → ${result.path}`));
|
|
1209
|
+
}
|
|
1116
1210
|
} else if (result.note) {
|
|
1117
1211
|
console.log(chalk.gray(` └ ${result.tool}: ${result.note}`));
|
|
1118
1212
|
}
|
|
@@ -1127,14 +1221,14 @@ async function initCommand(projectDir, options) {
|
|
|
1127
1221
|
}
|
|
1128
1222
|
}
|
|
1129
1223
|
|
|
1130
|
-
//
|
|
1224
|
+
// Install Rules (for Rules-like system tools)
|
|
1131
1225
|
const rulesTools = selectedTools.filter(id => {
|
|
1132
1226
|
const tool = AI_TOOLS.find(t => t.id === id);
|
|
1133
1227
|
return tool && tool.skillsSupport === SKILLS_SUPPORT.RULES;
|
|
1134
1228
|
});
|
|
1135
1229
|
|
|
1136
1230
|
if (rulesTools.length > 0) {
|
|
1137
|
-
const rulesSpinner = ora('
|
|
1231
|
+
const rulesSpinner = ora('Installing Rules...').start();
|
|
1138
1232
|
const rulesResults = installRules(rulesTools, projectDir);
|
|
1139
1233
|
rulesSpinner.succeed(`创建了 ${rulesResults.length} 个规则文件`);
|
|
1140
1234
|
|
|
@@ -1213,6 +1307,7 @@ async function updateCommand(projectDir) {
|
|
|
1213
1307
|
// Load config
|
|
1214
1308
|
const config = loadConfig(projectDir);
|
|
1215
1309
|
const configuredTools = config.aiTools;
|
|
1310
|
+
const installScope = config.installScope || INSTALL_SCOPE.PROJECT;
|
|
1216
1311
|
|
|
1217
1312
|
if (configuredTools.length === 0) {
|
|
1218
1313
|
console.log(chalk.yellow('⚠') + ` No AI tools configured. Run \`${CLI_COMMAND} init\` to configure.`);
|
|
@@ -1223,13 +1318,17 @@ async function updateCommand(projectDir) {
|
|
|
1223
1318
|
const tool = AI_TOOLS.find(t => t.id === id);
|
|
1224
1319
|
return tool ? tool.name : id;
|
|
1225
1320
|
});
|
|
1226
|
-
|
|
1321
|
+
const scopeLabel = installScope === INSTALL_SCOPE.PROJECT ? 'project-level' : 'global';
|
|
1322
|
+
console.log(chalk.blue('ℹ') + ` Detected configured tools: ${toolNames.join(', ')} (${scopeLabel} installation)`);
|
|
1227
1323
|
|
|
1228
|
-
// Update Skills (
|
|
1229
|
-
const skillsResults = installSkills(configuredTools, true);
|
|
1324
|
+
// Update Skills (using saved install scope from config)
|
|
1325
|
+
const skillsResults = installSkills(configuredTools, projectDir, installScope, true);
|
|
1230
1326
|
for (const result of skillsResults) {
|
|
1231
1327
|
if (result.count > 0) {
|
|
1232
1328
|
console.log(chalk.green('✓') + ` ${result.tool} ${result.type}: updated ${result.count}/${result.total}`);
|
|
1329
|
+
if (result.path) {
|
|
1330
|
+
console.log(chalk.gray(` → ${result.path}`));
|
|
1331
|
+
}
|
|
1233
1332
|
}
|
|
1234
1333
|
if (result.removed && result.removed > 0) {
|
|
1235
1334
|
console.log(chalk.green('✓') + ` ${result.tool} ${result.type}: removed ${result.removed} obsolete skills`);
|
|
@@ -1356,31 +1455,33 @@ async function migrateCommand(projectDir, options) {
|
|
|
1356
1455
|
}
|
|
1357
1456
|
|
|
1358
1457
|
// ============================================================================
|
|
1359
|
-
//
|
|
1458
|
+
// Help Information
|
|
1360
1459
|
// ============================================================================
|
|
1361
1460
|
|
|
1362
1461
|
function showHelp() {
|
|
1363
1462
|
console.log();
|
|
1364
1463
|
console.log(chalk.bold('DevBooks') + ' - AI-agnostic spec-driven development workflow');
|
|
1365
1464
|
console.log();
|
|
1366
|
-
console.log(chalk.cyan('
|
|
1367
|
-
console.log(` ${CLI_COMMAND} init [path] [options]
|
|
1368
|
-
console.log(` ${CLI_COMMAND} update [path]
|
|
1369
|
-
console.log(` ${CLI_COMMAND} migrate --from <framework> [opts]
|
|
1465
|
+
console.log(chalk.cyan('Usage:'));
|
|
1466
|
+
console.log(` ${CLI_COMMAND} init [path] [options] Initialize DevBooks`);
|
|
1467
|
+
console.log(` ${CLI_COMMAND} update [path] Update configured tools`);
|
|
1468
|
+
console.log(` ${CLI_COMMAND} migrate --from <framework> [opts] Migrate from other frameworks`);
|
|
1370
1469
|
console.log();
|
|
1371
|
-
console.log(chalk.cyan('
|
|
1372
|
-
console.log(' --tools <tools>
|
|
1373
|
-
console.log('
|
|
1374
|
-
console.log(' --
|
|
1375
|
-
console.log('
|
|
1376
|
-
console.log(' --
|
|
1377
|
-
console.log(' --
|
|
1378
|
-
console.log(' -
|
|
1470
|
+
console.log(chalk.cyan('Options:'));
|
|
1471
|
+
console.log(' --tools <tools> Non-interactive AI tool selection');
|
|
1472
|
+
console.log(' Values: all, none, or comma-separated tool IDs');
|
|
1473
|
+
console.log(' --scope <scope> Skills installation location (non-interactive mode)');
|
|
1474
|
+
console.log(' Values: project (default), global');
|
|
1475
|
+
console.log(' --from <framework> Migration source framework (openspec, speckit)');
|
|
1476
|
+
console.log(' --dry-run Dry run, no actual file modifications');
|
|
1477
|
+
console.log(' --keep-old Keep original directory after migration');
|
|
1478
|
+
console.log(' --force Force re-execute all steps');
|
|
1479
|
+
console.log(' -h, --help Show this help message');
|
|
1379
1480
|
console.log(' -v, --version Show version');
|
|
1380
1481
|
console.log();
|
|
1381
|
-
console.log(chalk.cyan('
|
|
1482
|
+
console.log(chalk.cyan('Supported AI Tools:'));
|
|
1382
1483
|
|
|
1383
|
-
//
|
|
1484
|
+
// Group tools by Skills support level
|
|
1384
1485
|
const groupedTools = {
|
|
1385
1486
|
[SKILLS_SUPPORT.FULL]: [],
|
|
1386
1487
|
[SKILLS_SUPPORT.RULES]: [],
|
|
@@ -1393,43 +1494,44 @@ function showHelp() {
|
|
|
1393
1494
|
}
|
|
1394
1495
|
|
|
1395
1496
|
console.log();
|
|
1396
|
-
console.log(chalk.green(' ★
|
|
1497
|
+
console.log(chalk.green(' ★ Full Skills Support:'));
|
|
1397
1498
|
for (const tool of groupedTools[SKILLS_SUPPORT.FULL]) {
|
|
1398
1499
|
console.log(` ${tool.id.padEnd(15)} ${tool.name}`);
|
|
1399
1500
|
}
|
|
1400
1501
|
|
|
1401
1502
|
console.log();
|
|
1402
|
-
console.log(chalk.blue(' ◆ Rules
|
|
1503
|
+
console.log(chalk.blue(' ◆ Rules System Support:'));
|
|
1403
1504
|
for (const tool of groupedTools[SKILLS_SUPPORT.RULES]) {
|
|
1404
1505
|
console.log(` ${tool.id.padEnd(15)} ${tool.name}`);
|
|
1405
1506
|
}
|
|
1406
1507
|
|
|
1407
1508
|
console.log();
|
|
1408
|
-
console.log(chalk.yellow(' ●
|
|
1509
|
+
console.log(chalk.yellow(' ● Custom Instructions Support:'));
|
|
1409
1510
|
for (const tool of groupedTools[SKILLS_SUPPORT.AGENTS]) {
|
|
1410
1511
|
console.log(` ${tool.id.padEnd(15)} ${tool.name}`);
|
|
1411
1512
|
}
|
|
1412
1513
|
|
|
1413
1514
|
console.log();
|
|
1414
1515
|
console.log();
|
|
1415
|
-
console.log(chalk.cyan('
|
|
1416
|
-
console.log(` ${CLI_COMMAND} init #
|
|
1417
|
-
console.log(` ${CLI_COMMAND} init my-project #
|
|
1418
|
-
console.log(` ${CLI_COMMAND} init --tools claude,cursor #
|
|
1419
|
-
console.log(` ${CLI_COMMAND}
|
|
1420
|
-
console.log(` ${CLI_COMMAND}
|
|
1421
|
-
console.log(` ${CLI_COMMAND} migrate --from
|
|
1422
|
-
console.log(` ${CLI_COMMAND} migrate --from
|
|
1516
|
+
console.log(chalk.cyan('Examples:'));
|
|
1517
|
+
console.log(` ${CLI_COMMAND} init # Interactive initialization`);
|
|
1518
|
+
console.log(` ${CLI_COMMAND} init my-project # Initialize in my-project directory`);
|
|
1519
|
+
console.log(` ${CLI_COMMAND} init --tools claude,cursor # Non-interactive (project-level by default)`);
|
|
1520
|
+
console.log(` ${CLI_COMMAND} init --tools claude --scope global # Non-interactive (global installation)`);
|
|
1521
|
+
console.log(` ${CLI_COMMAND} update # Update configured tools`);
|
|
1522
|
+
console.log(` ${CLI_COMMAND} migrate --from openspec # Migrate from OpenSpec`);
|
|
1523
|
+
console.log(` ${CLI_COMMAND} migrate --from speckit # Migrate from spec-kit`);
|
|
1524
|
+
console.log(` ${CLI_COMMAND} migrate --from openspec --dry-run # Dry run migration`);
|
|
1423
1525
|
}
|
|
1424
1526
|
|
|
1425
1527
|
// ============================================================================
|
|
1426
|
-
//
|
|
1528
|
+
// Main Entry
|
|
1427
1529
|
// ============================================================================
|
|
1428
1530
|
|
|
1429
1531
|
async function main() {
|
|
1430
1532
|
const args = process.argv.slice(2);
|
|
1431
1533
|
|
|
1432
|
-
//
|
|
1534
|
+
// Parse arguments
|
|
1433
1535
|
let command = null;
|
|
1434
1536
|
let projectPath = null;
|
|
1435
1537
|
const options = {};
|
|
@@ -1445,6 +1547,8 @@ async function main() {
|
|
|
1445
1547
|
process.exit(0);
|
|
1446
1548
|
} else if (arg === '--tools') {
|
|
1447
1549
|
options.tools = args[++i];
|
|
1550
|
+
} else if (arg === '--scope') {
|
|
1551
|
+
options.scope = args[++i];
|
|
1448
1552
|
} else if (arg === '--from') {
|
|
1449
1553
|
options.from = args[++i];
|
|
1450
1554
|
} else if (arg === '--dry-run') {
|
package/package.json
CHANGED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devbooks-convergence-audit
|
|
3
|
+
description: devbooks-convergence-audit: Evaluates DevBooks workflow convergence using "evidence first, distrust declarations" principle, detects "Sisyphus anti-patterns" and "fake completion". Actively verifies rather than trusting document claims. Use when user says "evaluate convergence/check upgrade health/Sisyphus detection/workflow audit" etc.
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Glob
|
|
6
|
+
- Grep
|
|
7
|
+
- Read
|
|
8
|
+
- Bash
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# DevBooks: Convergence Audit
|
|
12
|
+
|
|
13
|
+
## Core Principle: Anti-Deception Design
|
|
14
|
+
|
|
15
|
+
> **Golden Rule**: **Evidence > Declarations**. Never trust any assertions in documents; must confirm through verifiable evidence.
|
|
16
|
+
|
|
17
|
+
### Scenarios Where AI Gets Deceived (Must Prevent)
|
|
18
|
+
|
|
19
|
+
| Deception Scenario | AI Wrong Behavior | Correct Behavior |
|
|
20
|
+
|--------------------|-------------------|------------------|
|
|
21
|
+
| Document says `Status: Done` | Believes it's complete | Verify: Are tests actually all green? Does evidence exist? |
|
|
22
|
+
| AC matrix all `[x]` | Believes full coverage | Verify: Does test file for each AC exist and pass? |
|
|
23
|
+
| Document says "tests passed" | Believes passed | Verify: Actually run tests or check CI log timestamps |
|
|
24
|
+
| `evidence/` directory exists | Believes evidence exists | Verify: Is directory non-empty? Is content valid test logs? |
|
|
25
|
+
| tasks.md all `[x]` | Believes implemented | Verify: Do corresponding code files exist with substance? |
|
|
26
|
+
| Commit message says "fixed" | Believes fixed | Verify: Did related tests change from red to green? |
|
|
27
|
+
|
|
28
|
+
### Three Anti-Deception Principles
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
1. Distrust Declarations
|
|
32
|
+
- Any "complete/passed/covered" claims in documents are hypotheses to verify
|
|
33
|
+
- Default stance: Claims may be wrong, outdated, or optimistic
|
|
34
|
+
|
|
35
|
+
2. Evidence First
|
|
36
|
+
- Code/test results are the only truth
|
|
37
|
+
- Log timestamps must be later than last code modification
|
|
38
|
+
- Empty directory/file = no evidence
|
|
39
|
+
|
|
40
|
+
3. Cross Validation
|
|
41
|
+
- Declaration vs evidence: Check consistency
|
|
42
|
+
- Code vs tests: Check if they match
|
|
43
|
+
- Multiple documents: Check for contradictions
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Verification Checklist (Execute Each)
|
|
49
|
+
|
|
50
|
+
### Check 1: Status Field Truthfulness Verification
|
|
51
|
+
|
|
52
|
+
**Document Claim**: `verification.md` contains `Status: Done` or `Status: Verified`
|
|
53
|
+
|
|
54
|
+
**Verification Steps**:
|
|
55
|
+
```bash
|
|
56
|
+
# 1. Check if verification.md exists
|
|
57
|
+
[[ -f "verification.md" ]] || echo "❌ verification.md does not exist"
|
|
58
|
+
|
|
59
|
+
# 2. Check if evidence/green-final/ has content
|
|
60
|
+
if [[ -z "$(ls -A evidence/green-final/ 2>/dev/null)" ]]; then
|
|
61
|
+
echo "❌ Status claims complete, but evidence/green-final/ is empty"
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# 3. Check if evidence timestamp is later than last code modification
|
|
65
|
+
code_mtime=$(stat -f %m src/ 2>/dev/null || stat -c %Y src/)
|
|
66
|
+
evidence_mtime=$(stat -f %m evidence/green-final/* 2>/dev/null | sort -n | tail -1)
|
|
67
|
+
if [[ $evidence_mtime -lt $code_mtime ]]; then
|
|
68
|
+
echo "❌ Evidence time is earlier than code modification, evidence may be stale"
|
|
69
|
+
fi
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Deception Detection**:
|
|
73
|
+
- ⚠️ Status=Done but evidence/ empty → **Fake Completion**
|
|
74
|
+
- ⚠️ Status=Done but evidence timestamp too old → **Stale Evidence**
|
|
75
|
+
- ⚠️ Status=Done but tests actually fail → **False Status**
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### Check 2: AC Coverage Matrix Truthfulness Verification
|
|
80
|
+
|
|
81
|
+
**Document Claim**: `[x]` in AC matrix means covered
|
|
82
|
+
|
|
83
|
+
**Verification Steps**:
|
|
84
|
+
```bash
|
|
85
|
+
# 1. Extract all ACs claimed as covered
|
|
86
|
+
grep -E '^\| AC-[0-9]+.*\[x\]' verification.md | while read line; do
|
|
87
|
+
ac_id=$(echo "$line" | grep -oE 'AC-[0-9]+')
|
|
88
|
+
test_id=$(echo "$line" | grep -oE 'T-[0-9]+')
|
|
89
|
+
|
|
90
|
+
# 2. Verify corresponding test exists
|
|
91
|
+
if ! grep -rq "$test_id\|$ac_id" tests/; then
|
|
92
|
+
echo "❌ $ac_id claims covered, but no corresponding test found"
|
|
93
|
+
fi
|
|
94
|
+
done
|
|
95
|
+
|
|
96
|
+
# 3. Actually run tests to verify (most reliable)
|
|
97
|
+
npm test 2>&1 | tee /tmp/test-output.log
|
|
98
|
+
if grep -q "FAIL\|Error\|failed" /tmp/test-output.log; then
|
|
99
|
+
echo "❌ ACs claim full coverage, but tests actually have failures"
|
|
100
|
+
fi
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Deception Detection**:
|
|
104
|
+
- ⚠️ AC checked but corresponding test file doesn't exist → **False Coverage**
|
|
105
|
+
- ⚠️ AC checked but test actually fails → **Fake Green**
|
|
106
|
+
- ⚠️ AC checked but test content is empty/placeholder → **Placeholder Test**
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### Check 3: tasks.md Completion Truthfulness Verification
|
|
111
|
+
|
|
112
|
+
**Document Claim**: `[x]` in tasks.md means completed
|
|
113
|
+
|
|
114
|
+
**Verification Steps**:
|
|
115
|
+
```bash
|
|
116
|
+
# 1. Extract all tasks claimed as complete
|
|
117
|
+
grep -E '^\- \[x\]' tasks.md | while read line; do
|
|
118
|
+
# 2. Extract keywords from task description (function name/file name/feature)
|
|
119
|
+
keywords=$(echo "$line" | grep -oE '[A-Za-z]+[A-Za-z0-9]*' | head -5)
|
|
120
|
+
|
|
121
|
+
# 3. Verify code has corresponding implementation
|
|
122
|
+
for kw in $keywords; do
|
|
123
|
+
if ! grep -rq "$kw" src/; then
|
|
124
|
+
echo "⚠️ Task claims complete, but keyword not found in code: $kw"
|
|
125
|
+
fi
|
|
126
|
+
done
|
|
127
|
+
done
|
|
128
|
+
|
|
129
|
+
# 4. Check for "skeleton code" (only function signatures without implementation)
|
|
130
|
+
grep -rE 'throw new Error\(.*not implemented|TODO|FIXME|pass$|\.\.\.}' src/ && \
|
|
131
|
+
echo "⚠️ Found unimplemented placeholder code"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Deception Detection**:
|
|
135
|
+
- ⚠️ Task checked but code doesn't exist → **False Completion**
|
|
136
|
+
- ⚠️ Task checked but code is placeholder → **Skeleton Code**
|
|
137
|
+
- ⚠️ Task checked but feature not callable → **Dead Code**
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### Check 4: Evidence Validity Verification
|
|
142
|
+
|
|
143
|
+
**Document Claim**: `evidence/` directory contains test evidence
|
|
144
|
+
|
|
145
|
+
**Verification Steps**:
|
|
146
|
+
```bash
|
|
147
|
+
# 1. Check if directory exists and is non-empty
|
|
148
|
+
if [[ ! -d "evidence" ]] || [[ -z "$(ls -A evidence/)" ]]; then
|
|
149
|
+
echo "❌ evidence/ does not exist or is empty"
|
|
150
|
+
exit 1
|
|
151
|
+
fi
|
|
152
|
+
|
|
153
|
+
# 2. Check if evidence files have substantial content
|
|
154
|
+
for f in evidence/**/*; do
|
|
155
|
+
if [[ -f "$f" ]]; then
|
|
156
|
+
lines=$(wc -l < "$f")
|
|
157
|
+
if [[ $lines -lt 5 ]]; then
|
|
158
|
+
echo "⚠️ Evidence file has too little content: $f ($lines lines)"
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# 3. Check if it's a valid test log (contains test framework output characteristics)
|
|
162
|
+
if ! grep -qE 'PASS|FAIL|✓|✗|passed|failed|test|spec' "$f"; then
|
|
163
|
+
echo "⚠️ Evidence file doesn't look like test log: $f"
|
|
164
|
+
fi
|
|
165
|
+
fi
|
|
166
|
+
done
|
|
167
|
+
|
|
168
|
+
# 4. Check if red-baseline evidence really is red (has failures)
|
|
169
|
+
if [[ -d "evidence/red-baseline" ]]; then
|
|
170
|
+
if ! grep -rqE 'FAIL|Error|✗|failed' evidence/red-baseline/; then
|
|
171
|
+
echo "❌ red-baseline claims to be red, but no failure records"
|
|
172
|
+
fi
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# 5. Check if green-final evidence really is green (all pass)
|
|
176
|
+
if [[ -d "evidence/green-final" ]]; then
|
|
177
|
+
if grep -rqE 'FAIL|Error|✗|failed' evidence/green-final/; then
|
|
178
|
+
echo "❌ green-final claims to be green, but contains failure records"
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Deception Detection**:
|
|
184
|
+
- ⚠️ evidence/ exists but content is empty → **Empty Evidence**
|
|
185
|
+
- ⚠️ Evidence file too small (< 5 lines) → **Placeholder Evidence**
|
|
186
|
+
- ⚠️ red-baseline has no failure records → **Fake Red**
|
|
187
|
+
- ⚠️ green-final contains failure records → **Fake Green**
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
### Check 5: Git History Cross Validation
|
|
192
|
+
|
|
193
|
+
**Principle**: Git history doesn't lie; use it to verify document claims
|
|
194
|
+
|
|
195
|
+
**Verification Steps**:
|
|
196
|
+
```bash
|
|
197
|
+
# 1. Check if claimed-complete change has corresponding code commits
|
|
198
|
+
change_id="xxx"
|
|
199
|
+
commits=$(git log --oneline --all --grep="$change_id" | wc -l)
|
|
200
|
+
if [[ $commits -eq 0 ]]; then
|
|
201
|
+
echo "❌ Change $change_id claims complete, but no related commits in git history"
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
# 2. Check if test files were added after code (TDD violation detection)
|
|
205
|
+
for test_file in tests/**/*.test.*; do
|
|
206
|
+
test_added=$(git log --format=%at --follow -- "$test_file" | tail -1)
|
|
207
|
+
# Find corresponding source file
|
|
208
|
+
src_file=$(echo "$test_file" | sed 's/tests/src/' | sed 's/.test//')
|
|
209
|
+
if [[ -f "$src_file" ]]; then
|
|
210
|
+
src_added=$(git log --format=%at --follow -- "$src_file" | tail -1)
|
|
211
|
+
if [[ $test_added -gt $src_added ]]; then
|
|
212
|
+
echo "⚠️ Test added after code (non-TDD): $test_file"
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
done
|
|
216
|
+
|
|
217
|
+
# 3. Check for "one-time big commits" (may be bypassing process)
|
|
218
|
+
git log --oneline -20 | while read line; do
|
|
219
|
+
commit=$(echo "$line" | cut -d' ' -f1)
|
|
220
|
+
files_changed=$(git show --stat "$commit" | grep -E '[0-9]+ file' | grep -oE '[0-9]+' | head -1)
|
|
221
|
+
if [[ $files_changed -gt 20 ]]; then
|
|
222
|
+
echo "⚠️ Big commit detected: $commit modified $files_changed files, may bypass incremental verification"
|
|
223
|
+
fi
|
|
224
|
+
done
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Deception Detection**:
|
|
228
|
+
- ⚠️ Claims complete but no git commits → **Fake Change**
|
|
229
|
+
- ⚠️ Tests added after code → **Retroactive Testing**
|
|
230
|
+
- ⚠️ Many files in one commit → **Bypassing Incremental Verification**
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
### Check 6: Live Test Run Verification (Most Reliable)
|
|
235
|
+
|
|
236
|
+
**Principle**: Don't trust any logs; actually run tests
|
|
237
|
+
|
|
238
|
+
**Verification Steps**:
|
|
239
|
+
```bash
|
|
240
|
+
# 1. Run full tests
|
|
241
|
+
echo "=== Live Test Verification ==="
|
|
242
|
+
npm test 2>&1 | tee /tmp/live-test.log
|
|
243
|
+
|
|
244
|
+
# 2. Check results
|
|
245
|
+
if grep -qE 'FAIL|Error|failed' /tmp/live-test.log; then
|
|
246
|
+
echo "❌ Live tests failed, document claims not trustworthy"
|
|
247
|
+
grep -E 'FAIL|Error|failed' /tmp/live-test.log
|
|
248
|
+
else
|
|
249
|
+
echo "✅ Live tests passed"
|
|
250
|
+
fi
|
|
251
|
+
|
|
252
|
+
# 3. Compare live results with evidence files
|
|
253
|
+
if [[ -f "evidence/green-final/latest.log" ]]; then
|
|
254
|
+
live_pass=$(grep -c 'PASS\|✓\|passed' /tmp/live-test.log)
|
|
255
|
+
evidence_pass=$(grep -c 'PASS\|✓\|passed' evidence/green-final/latest.log)
|
|
256
|
+
if [[ $live_pass -ne $evidence_pass ]]; then
|
|
257
|
+
echo "⚠️ Live pass count ($live_pass) ≠ evidence pass count ($evidence_pass)"
|
|
258
|
+
fi
|
|
259
|
+
fi
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Deception Detection**:
|
|
263
|
+
- ⚠️ Evidence says green but live run fails → **Stale Evidence/Fake Green**
|
|
264
|
+
- ⚠️ Live pass count differs from evidence → **Evidence Fabrication/Environment Difference**
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Composite Scoring Algorithm
|
|
269
|
+
|
|
270
|
+
### Trustworthiness Score (0-100)
|
|
271
|
+
|
|
272
|
+
```python
|
|
273
|
+
def calculate_trustworthiness(checks):
|
|
274
|
+
score = 100
|
|
275
|
+
|
|
276
|
+
# Critical issues (each -20 points)
|
|
277
|
+
critical = [
|
|
278
|
+
"Evidence empty",
|
|
279
|
+
"Live tests failed",
|
|
280
|
+
"Status claims complete but tests fail",
|
|
281
|
+
"green-final contains failure records"
|
|
282
|
+
]
|
|
283
|
+
|
|
284
|
+
# Warning issues (each -10 points)
|
|
285
|
+
warnings = [
|
|
286
|
+
"Evidence timestamp too old",
|
|
287
|
+
"AC corresponding test doesn't exist",
|
|
288
|
+
"Placeholder code",
|
|
289
|
+
"Big commit detected"
|
|
290
|
+
]
|
|
291
|
+
|
|
292
|
+
# Minor issues (each -5 points)
|
|
293
|
+
minor = [
|
|
294
|
+
"Tests added after code",
|
|
295
|
+
"Evidence file too small"
|
|
296
|
+
]
|
|
297
|
+
|
|
298
|
+
for issue in checks.critical_issues:
|
|
299
|
+
score -= 20
|
|
300
|
+
for issue in checks.warnings:
|
|
301
|
+
score -= 10
|
|
302
|
+
for issue in checks.minor_issues:
|
|
303
|
+
score -= 5
|
|
304
|
+
|
|
305
|
+
return max(0, score)
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Convergence Determination
|
|
309
|
+
|
|
310
|
+
| Trustworthiness | Determination | Recommendation |
|
|
311
|
+
|-----------------|---------------|----------------|
|
|
312
|
+
| 90-100 | ✅ Trustworthy Convergence | Continue current process |
|
|
313
|
+
| 70-89 | ⚠️ Partially Trustworthy | Need supplementary verification |
|
|
314
|
+
| 50-69 | 🟠 Questionable | Need to rework some steps |
|
|
315
|
+
| < 50 | 🔴 Untrustworthy | Sisyphus trap, need comprehensive review |
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Output Format
|
|
320
|
+
|
|
321
|
+
```markdown
|
|
322
|
+
# DevBooks Convergence Audit Report (Anti-Deception Edition)
|
|
323
|
+
|
|
324
|
+
## Audit Principle
|
|
325
|
+
This report uses "evidence first, distrust declarations" principle. All conclusions are based on verifiable evidence, not document claims.
|
|
326
|
+
|
|
327
|
+
## Declaration vs Evidence Comparison
|
|
328
|
+
|
|
329
|
+
| Check Item | Document Claim | Actual Verification | Conclusion |
|
|
330
|
+
|------------|----------------|---------------------|------------|
|
|
331
|
+
| Status | Done | Tests actually fail | ❌ Fake Completion |
|
|
332
|
+
| AC Coverage | 5/5 checked | 2 ACs have no corresponding tests | ❌ False Coverage |
|
|
333
|
+
| Test Status | All green | Live run 3 failures | ❌ Stale Evidence |
|
|
334
|
+
| tasks.md | 10/10 complete | 3 tasks have no code | ❌ False Completion |
|
|
335
|
+
| evidence/ | Exists | Non-empty, content valid | ✅ Valid |
|
|
336
|
+
|
|
337
|
+
## Trustworthiness Score
|
|
338
|
+
|
|
339
|
+
**Total Score**: 45/100 🔴 Untrustworthy
|
|
340
|
+
|
|
341
|
+
**Deduction Details**:
|
|
342
|
+
- -20: Status=Done but live tests fail
|
|
343
|
+
- -20: ACs claim full coverage but 2 have no tests
|
|
344
|
+
- -10: tasks.md 3 tasks have no code
|
|
345
|
+
- -5: Evidence timestamp earlier than code modification
|
|
346
|
+
|
|
347
|
+
## Deception Detection Results
|
|
348
|
+
|
|
349
|
+
### 🔴 Detected Fake Completions
|
|
350
|
+
1. `change-auth`: Status=Done, but `npm test` fails 3
|
|
351
|
+
2. `fix-cache`: AC-003 checked, but `tests/cache.test.ts` doesn't exist
|
|
352
|
+
|
|
353
|
+
### 🟡 Suspicious Items
|
|
354
|
+
1. `refactor-api`: evidence/green-final/ timestamp 2 days earlier than last code commit
|
|
355
|
+
2. `feature-login`: tasks.md all checked, but `src/login.ts` contains TODO
|
|
356
|
+
|
|
357
|
+
## True Status Determination
|
|
358
|
+
|
|
359
|
+
| Change Package | Claimed Status | True Status | Gap |
|
|
360
|
+
|----------------|----------------|-------------|-----|
|
|
361
|
+
| change-auth | Done | Tests failing | 🔴 Severe |
|
|
362
|
+
| fix-cache | Verified | Coverage incomplete | 🟠 Medium |
|
|
363
|
+
| refactor-api | Ready | Evidence stale | 🟡 Minor |
|
|
364
|
+
|
|
365
|
+
## Recommended Actions
|
|
366
|
+
|
|
367
|
+
### Immediate Action
|
|
368
|
+
1. Revert `change-auth` status to `In Progress`
|
|
369
|
+
2. Add tests for `fix-cache` AC-003
|
|
370
|
+
|
|
371
|
+
### Short-term Improvement
|
|
372
|
+
1. Establish evidence timeliness check (evidence must be later than code)
|
|
373
|
+
2. Force run corresponding tests before AC check-off
|
|
374
|
+
|
|
375
|
+
### Process Improvement
|
|
376
|
+
1. Prohibit manual Status modification; only allow auto-update after script verification
|
|
377
|
+
2. Integrate convergence check in CI, block fake completion from merging
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Completion Status
|
|
383
|
+
|
|
384
|
+
**Status**: ✅ AUDIT_COMPLETED
|
|
385
|
+
|
|
386
|
+
**Core Findings**:
|
|
387
|
+
- Document claim trustworthiness: X%
|
|
388
|
+
- Detected fake completions: N
|
|
389
|
+
- Changes needing rework: M
|
|
390
|
+
|
|
391
|
+
**Next Step**:
|
|
392
|
+
- Fake completion → Immediately revert status, re-verify
|
|
393
|
+
- Suspicious items → Supplement evidence or re-run tests
|
|
394
|
+
- Trustworthy items → Continue current process
|
|
@@ -28,7 +28,42 @@ Before execution, **must** search for configuration in the following order (stop
|
|
|
28
28
|
|
|
29
29
|
## Output Location
|
|
30
30
|
|
|
31
|
-
-
|
|
31
|
+
- **Must** write to: The Impact section of `<change-root>/<change-id>/proposal.md`
|
|
32
|
+
- Alternative: Separate `impact-analysis.md` file (to be backfilled to proposal.md later)
|
|
33
|
+
|
|
34
|
+
## Output Behavior (Critical Constraint)
|
|
35
|
+
|
|
36
|
+
> **Golden Rule**: **Write directly to document, do NOT output to conversation window**
|
|
37
|
+
|
|
38
|
+
### Must Follow
|
|
39
|
+
|
|
40
|
+
1. **Direct Write**: Use `Edit` or `Write` tool to write analysis results directly to target document
|
|
41
|
+
2. **No Echo**: Do NOT display the complete analysis content in the conversation
|
|
42
|
+
3. **Brief Notification**: After completion, only inform the user "Impact analysis written to `<file-path>`"
|
|
43
|
+
|
|
44
|
+
### Correct vs Incorrect Behavior
|
|
45
|
+
|
|
46
|
+
| Scenario | ❌ Incorrect Behavior | ✅ Correct Behavior |
|
|
47
|
+
|----------|----------------------|---------------------|
|
|
48
|
+
| Analysis complete | Output full Impact table in conversation | Use Edit tool to write to proposal.md |
|
|
49
|
+
| Notify user | Repeat analysis content | "Impact analysis written to `changes/xxx/proposal.md`" |
|
|
50
|
+
| Large results | Paginate output to conversation | Write all to file, inform file location |
|
|
51
|
+
|
|
52
|
+
### Example Conversation
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
User: Analyze the impact of modifying UserService
|
|
56
|
+
|
|
57
|
+
AI: [Uses Grep/CKB to analyze references]
|
|
58
|
+
[Uses Edit tool to write to proposal.md]
|
|
59
|
+
|
|
60
|
+
Impact analysis written to the Impact section of `changes/refactor-user/proposal.md`.
|
|
61
|
+
- Direct impact: 8 files
|
|
62
|
+
- Indirect impact: 12 files
|
|
63
|
+
- Risk level: Medium
|
|
64
|
+
|
|
65
|
+
Open the file to view details.
|
|
66
|
+
```
|
|
32
67
|
|
|
33
68
|
## Execution Method
|
|
34
69
|
|