kld-sdd 2.4.9 → 2.4.11
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 +9 -6
- package/lib/init.js +76 -21
- package/lib/skills-bundle.js +32 -0
- package/package.json +3 -3
- package/skywalk-sdd/{index.js → index.cjs} +31 -25
- package/templates/ci/github-actions-sdd.yml +3 -3
- package/templates/ci/gitlab-ci-sdd.yml +3 -3
- package/templates/git-hooks/{pre-push-sdd-check.js → pre-push-sdd-check.cjs} +1 -1
- package/templates/hooks/claude/hooks/{sdd-prompt.js → sdd-prompt.cjs} +2 -2
- package/templates/hooks/claude/hooks/{sdd-stop.js → sdd-stop.cjs} +1 -1
- package/templates/hooks/claude/settings.json +4 -4
- package/templates/opsx-commands/apply.md +11 -9
- package/templates/opsx-commands/archive.md +8 -8
- package/templates/opsx-commands/check.md +8 -8
- package/templates/opsx-commands/design.md +3 -3
- package/templates/opsx-commands/explore.md +3 -3
- package/templates/opsx-commands/propose.md +3 -3
- package/templates/opsx-commands/spec.md +3 -3
- package/templates/opsx-commands/task.md +3 -3
- package/templates/opsx-commands/test.md +5 -5
- package/templates/skills/kld-sdd/SKILLS.md +28 -0
- package/templates/skills/{opsx-apply → kld-sdd/opsx-apply}/SKILL.md +12 -4
- package/templates/skills/{opsx-archive → kld-sdd/opsx-archive}/SKILL.md +8 -8
- package/templates/skills/{opsx-check → kld-sdd/opsx-check}/SKILL.md +6 -6
- package/templates/skills/{opsx-design → kld-sdd/opsx-design}/SKILL.md +6 -2
- package/templates/skills/{opsx-explore → kld-sdd/opsx-explore}/SKILL.md +2 -2
- package/templates/skills/kld-sdd/opsx-knowledge/SKILL.md +132 -0
- package/templates/skills/kld-sdd/opsx-knowledge/references/modules.md +26 -0
- package/templates/skills/kld-sdd/opsx-knowledge/scripts/config.json +39 -0
- package/templates/skills/kld-sdd/opsx-knowledge/scripts/retrieve.cjs +199 -0
- package/templates/skills/{opsx-propose → kld-sdd/opsx-propose}/SKILL.md +6 -2
- package/templates/skills/{opsx-spec → kld-sdd/opsx-spec}/SKILL.md +6 -2
- package/templates/skills/{opsx-task → kld-sdd/opsx-task}/SKILL.md +2 -2
- package/templates/skills/{opsx-test → kld-sdd/opsx-test}/SKILL.md +2 -2
- /package/templates/git-hooks/{pre-commit-sdd-check.js → pre-commit-sdd-check.cjs} +0 -0
- /package/templates/hooks/claude/hooks/{sdd-post-tool.js → sdd-post-tool.cjs} +0 -0
- /package/templates/hooks/claude/hooks/{sdd-pre-tool.js → sdd-pre-tool.cjs} +0 -0
package/README.md
CHANGED
|
@@ -136,9 +136,9 @@ propose → spec → design → task → check
|
|
|
136
136
|
|
|
137
137
|
---
|
|
138
138
|
|
|
139
|
-
## 预置技能:`
|
|
139
|
+
## 预置技能:`kld-sdd`
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
初始化后,SDD 全套技能会统一打包部署到 `.*/skills/kld-sdd/`(与 `gitnexus/` 目录模式一致),包含 `opsx-propose`、`opsx-spec`、`opsx-design`、`opsx-task`、`opsx-check`、`opsx-apply`、`opsx-test`、`opsx-archive`、`opsx-explore`、`opsx-knowledge` 等子技能。
|
|
142
142
|
|
|
143
143
|
激活后,AI 会化身 **SDD 工作流专家**,检测当前项目的文档状态,引导你从当前进度继续:
|
|
144
144
|
|
|
@@ -190,16 +190,19 @@ your-project/
|
|
|
190
190
|
│ └── task.md
|
|
191
191
|
├── .cursor/
|
|
192
192
|
│ ├── commands/opsx/ # opsx 命令(9个)
|
|
193
|
-
│ └── skills/
|
|
193
|
+
│ └── skills/kld-sdd/ # SDD 技能统一目录
|
|
194
|
+
│ ├── opsx-propose/
|
|
195
|
+
│ ├── opsx-spec/
|
|
196
|
+
│ └── ... # 其他 opsx-* 子技能
|
|
194
197
|
├── .claude/
|
|
195
198
|
│ ├── commands/opsx/ # opsx 命令(9个)
|
|
196
|
-
│ └── skills/
|
|
199
|
+
│ └── skills/kld-sdd/ # SDD 技能统一目录
|
|
197
200
|
├── .codebuddy/
|
|
198
201
|
│ ├── commands/opsx/ # opsx 命令(9个)
|
|
199
|
-
│ └── skills/
|
|
202
|
+
│ └── skills/kld-sdd/ # SDD 技能统一目录
|
|
200
203
|
└── .agents/
|
|
201
204
|
├── commands/opsx/ # Codex opsx 命令(9个)
|
|
202
|
-
└── skills/
|
|
205
|
+
└── skills/kld-sdd/ # Codex 项目级技能
|
|
203
206
|
```
|
|
204
207
|
|
|
205
208
|
---
|
package/lib/init.js
CHANGED
|
@@ -327,9 +327,7 @@ function copyDir(source, target) {
|
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
function renderTemplate(content, config, toolKey) {
|
|
330
|
-
return content
|
|
331
|
-
.replace(/^\uFEFF/, '')
|
|
332
|
-
.replace(/<Agent(?:\u7c7b\u578b|\u7eeb\u8bf2\u7037)>/g, config.agentType || toolKey);
|
|
330
|
+
return require('./skills-bundle').renderTemplate(content, config, toolKey);
|
|
333
331
|
}
|
|
334
332
|
|
|
335
333
|
function copyDirRendered(source, target, config, toolKey) {
|
|
@@ -504,9 +502,50 @@ function overrideOpsxCommands(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
|
504
502
|
return true;
|
|
505
503
|
}
|
|
506
504
|
|
|
505
|
+
const {
|
|
506
|
+
SKILLS_BUNDLE_NAME,
|
|
507
|
+
OPSX_SKILL_DIRS,
|
|
508
|
+
renderTemplate
|
|
509
|
+
} = require('./skills-bundle');
|
|
510
|
+
|
|
511
|
+
/**
|
|
512
|
+
* 清理旧版扁平 opsx-* skills(迁移到 skills/kld-sdd/ 统一目录)
|
|
513
|
+
* @param {string[]} selectedTools - 用户选择的编辑器列表
|
|
514
|
+
*/
|
|
515
|
+
function cleanupLegacyFlatOpsxSkills(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
516
|
+
console.log('🧹 正在清理旧版扁平 opsx-* skills...');
|
|
517
|
+
|
|
518
|
+
const cwd = process.cwd();
|
|
519
|
+
const legacySkillDirs = [...OPSX_SKILL_DIRS, 'opsx-sdd'];
|
|
520
|
+
|
|
521
|
+
for (const toolKey of selectedTools) {
|
|
522
|
+
const config = TOOL_CONFIGS[toolKey];
|
|
523
|
+
if (!config || !config.skillsDir) continue;
|
|
524
|
+
|
|
525
|
+
const skillsDir = path.join(cwd, config.skillsDir);
|
|
526
|
+
if (!fs.existsSync(skillsDir)) continue;
|
|
527
|
+
|
|
528
|
+
let removed = 0;
|
|
529
|
+
for (const legacySkill of legacySkillDirs) {
|
|
530
|
+
const legacySkillDir = path.join(skillsDir, legacySkill);
|
|
531
|
+
if (fs.existsSync(legacySkillDir)) {
|
|
532
|
+
fs.rmSync(legacySkillDir, { recursive: true, force: true });
|
|
533
|
+
removed++;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (removed > 0) {
|
|
538
|
+
console.log(` 🗑 ${config.name}: 删除 ${removed} 个旧版扁平 opsx skills`);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
console.log('✅ 旧版扁平 opsx skills 清理完成');
|
|
543
|
+
return true;
|
|
544
|
+
}
|
|
545
|
+
|
|
507
546
|
/**
|
|
508
|
-
* 部署 SDD opsx skills
|
|
509
|
-
* 从 templates/skills/
|
|
547
|
+
* 部署 SDD opsx skills
|
|
548
|
+
* 从 templates/skills/kld-sdd/ 复制到各编辑器的 skills/kld-sdd/ 目录
|
|
510
549
|
* @param {string[]} selectedTools - 用户选择的编辑器列表
|
|
511
550
|
*/
|
|
512
551
|
function deployOpsxSkills(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
@@ -515,14 +554,14 @@ function deployOpsxSkills(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
|
515
554
|
const pkgPath = getPackagePath();
|
|
516
555
|
const cwd = process.cwd();
|
|
517
556
|
|
|
518
|
-
const skillsTemplatePath = path.join(pkgPath, 'templates', 'skills');
|
|
557
|
+
const skillsTemplatePath = path.join(pkgPath, 'templates', 'skills', SKILLS_BUNDLE_NAME);
|
|
519
558
|
|
|
520
559
|
if (!fs.existsSync(skillsTemplatePath)) {
|
|
521
560
|
console.log(`⚠️ SDD skills 模板目录不存在: ${skillsTemplatePath}`);
|
|
522
561
|
return false;
|
|
523
562
|
}
|
|
524
563
|
|
|
525
|
-
//
|
|
564
|
+
// 获取 bundle 内所有 skill 目录
|
|
526
565
|
const skillDirs = fs.readdirSync(skillsTemplatePath).filter(d => {
|
|
527
566
|
return fs.statSync(path.join(skillsTemplatePath, d)).isDirectory();
|
|
528
567
|
});
|
|
@@ -537,17 +576,21 @@ function deployOpsxSkills(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
|
537
576
|
if (!config || !config.skillsDir) continue;
|
|
538
577
|
|
|
539
578
|
const targetSkillsDir = path.join(cwd, config.skillsDir);
|
|
579
|
+
const targetBundleDir = path.join(targetSkillsDir, SKILLS_BUNDLE_NAME);
|
|
540
580
|
|
|
541
581
|
// 确保 skills 目录存在
|
|
542
582
|
if (!fs.existsSync(targetSkillsDir)) {
|
|
543
583
|
fs.mkdirSync(targetSkillsDir, { recursive: true });
|
|
544
584
|
}
|
|
585
|
+
if (!fs.existsSync(targetBundleDir)) {
|
|
586
|
+
fs.mkdirSync(targetBundleDir, { recursive: true });
|
|
587
|
+
}
|
|
545
588
|
|
|
546
|
-
console.log(` 部署 ${config.name} 的
|
|
589
|
+
console.log(` 部署 ${config.name} 的 ${SKILLS_BUNDLE_NAME} skills(${skillDirs.length} 个)...`);
|
|
547
590
|
|
|
548
591
|
for (const skillDir of skillDirs) {
|
|
549
592
|
const sourceDir = path.join(skillsTemplatePath, skillDir);
|
|
550
|
-
const targetDir = path.join(
|
|
593
|
+
const targetDir = path.join(targetBundleDir, skillDir);
|
|
551
594
|
|
|
552
595
|
if (!fs.existsSync(targetDir)) {
|
|
553
596
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
@@ -555,9 +598,18 @@ function deployOpsxSkills(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
|
555
598
|
|
|
556
599
|
if (fs.existsSync(sourceDir)) {
|
|
557
600
|
copyDirRendered(sourceDir, targetDir, config, toolKey);
|
|
558
|
-
console.log(` ✓ ${skillDir}`);
|
|
601
|
+
console.log(` ✓ ${SKILLS_BUNDLE_NAME}/${skillDir}`);
|
|
559
602
|
}
|
|
560
603
|
}
|
|
604
|
+
|
|
605
|
+
// 复制 bundle 根目录说明文件(如 SKILLS.md)
|
|
606
|
+
for (const file of fs.readdirSync(skillsTemplatePath)) {
|
|
607
|
+
const sourceFile = path.join(skillsTemplatePath, file);
|
|
608
|
+
if (!fs.statSync(sourceFile).isFile()) continue;
|
|
609
|
+
const rendered = renderTemplate(fs.readFileSync(sourceFile, 'utf8'), config, toolKey);
|
|
610
|
+
fs.writeFileSync(path.join(targetBundleDir, file), rendered, 'utf8');
|
|
611
|
+
console.log(` ✓ ${SKILLS_BUNDLE_NAME}/${file}`);
|
|
612
|
+
}
|
|
561
613
|
}
|
|
562
614
|
|
|
563
615
|
console.log('✅ opsx skills 部署完成');
|
|
@@ -566,7 +618,7 @@ function deployOpsxSkills(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
|
566
618
|
|
|
567
619
|
/**
|
|
568
620
|
* 部署 Claude Code Hook Pack(可选增强)
|
|
569
|
-
* Hook 只调用 skywalk-sdd/log.
|
|
621
|
+
* Hook 只调用 skywalk-sdd/log.cjs,不写私有日志,不替代 OPSX 模板采集。
|
|
570
622
|
*/
|
|
571
623
|
function deployClaudeHookPack(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
572
624
|
if (!selectedTools.includes('claude')) {
|
|
@@ -593,7 +645,7 @@ function deployClaudeHookPack(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
|
593
645
|
}
|
|
594
646
|
|
|
595
647
|
copyDir(hookSourceDir, targetHookDir);
|
|
596
|
-
console.log(' ✓ 部署 .claude/hooks/sdd-*.
|
|
648
|
+
console.log(' ✓ 部署 .claude/hooks/sdd-*.cjs');
|
|
597
649
|
|
|
598
650
|
const targetSettingsPath = path.join(claudeDir, 'settings.json');
|
|
599
651
|
const templateSettings = JSON.parse(fs.readFileSync(settingsTemplatePath, 'utf8'));
|
|
@@ -790,16 +842,16 @@ function deployTelemetryDataDir() {
|
|
|
790
842
|
}
|
|
791
843
|
|
|
792
844
|
// 部署项目内 Telemetry CLI(不依赖 npm 发布)
|
|
793
|
-
const telemetrySrc = path.join(pkgPath, 'skywalk-sdd', 'index.
|
|
794
|
-
const telemetryDst = path.join(dataDir, 'log.
|
|
845
|
+
const telemetrySrc = path.join(pkgPath, 'skywalk-sdd', 'index.cjs');
|
|
846
|
+
const telemetryDst = path.join(dataDir, 'log.cjs');
|
|
795
847
|
if (fs.existsSync(telemetrySrc)) {
|
|
796
848
|
fs.copyFileSync(telemetrySrc, telemetryDst);
|
|
797
|
-
console.log(' ✓ 部署 skywalk-sdd/log.
|
|
849
|
+
console.log(' ✓ 部署 skywalk-sdd/log.cjs(本地 Telemetry CLI)');
|
|
798
850
|
} else {
|
|
799
851
|
console.log(` ⚠️ Telemetry CLI 源文件缺失: ${telemetrySrc}`);
|
|
800
852
|
}
|
|
801
853
|
|
|
802
|
-
console.log(' ✓ 调用方式: node skywalk-sdd/log.
|
|
854
|
+
console.log(' ✓ 调用方式: node skywalk-sdd/log.cjs start|end|metrics');
|
|
803
855
|
console.log('✅ Telemetry 已就绪(数据存储在 skywalk-sdd/,无需配置 MCP)');
|
|
804
856
|
return true;
|
|
805
857
|
}
|
|
@@ -869,8 +921,8 @@ function deployQualityGateTemplates() {
|
|
|
869
921
|
console.log(` ⚠️ CI 模板缺失: ${ciTemplateDir}`);
|
|
870
922
|
}
|
|
871
923
|
|
|
872
|
-
installGitHookShim(cwd, 'pre-commit', 'skywalk-sdd/git-hooks/pre-commit-sdd-check.
|
|
873
|
-
installGitHookShim(cwd, 'pre-push', 'skywalk-sdd/git-hooks/pre-push-sdd-check.
|
|
924
|
+
installGitHookShim(cwd, 'pre-commit', 'skywalk-sdd/git-hooks/pre-commit-sdd-check.cjs');
|
|
925
|
+
installGitHookShim(cwd, 'pre-push', 'skywalk-sdd/git-hooks/pre-push-sdd-check.cjs');
|
|
874
926
|
|
|
875
927
|
console.log('✅ Git hooks / CI 兜底模板已就绪');
|
|
876
928
|
return true;
|
|
@@ -1019,10 +1071,13 @@ async function main() {
|
|
|
1019
1071
|
// 3. 部署 SDD opsx 命令(根据编辑器类型使用不同模板)
|
|
1020
1072
|
overrideOpsxCommands(selectedTools);
|
|
1021
1073
|
|
|
1022
|
-
// 4.
|
|
1074
|
+
// 4. 清理旧版扁平 opsx-* skills(迁移到 skills/kld-sdd/)
|
|
1075
|
+
cleanupLegacyFlatOpsxSkills(selectedTools);
|
|
1076
|
+
|
|
1077
|
+
// 4.1 部署 SDD opsx skills(统一打包到 skills/kld-sdd/)
|
|
1023
1078
|
deployOpsxSkills(selectedTools);
|
|
1024
1079
|
|
|
1025
|
-
// 4.
|
|
1080
|
+
// 4.2 清理原生 openspec-* skills(防止残留)
|
|
1026
1081
|
cleanupNativeOpenspecSkills(selectedTools);
|
|
1027
1082
|
|
|
1028
1083
|
// 4.2 部署 Claude Code Hook Pack(可选增强)
|
|
@@ -1086,7 +1141,7 @@ async function main() {
|
|
|
1086
1141
|
console.log();
|
|
1087
1142
|
console.log('📊 SDD Telemetry(嵌入在命令流程中,自动执行,无需配置):');
|
|
1088
1143
|
console.log(' - 度量数据自动采集到 skywalk-sdd/events/');
|
|
1089
|
-
console.log(' - 运行 node skywalk-sdd/log.
|
|
1144
|
+
console.log(' - 运行 node skywalk-sdd/log.cjs metrics --project=. 查看四维度指标');
|
|
1090
1145
|
console.log();
|
|
1091
1146
|
|
|
1092
1147
|
rl.close();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDD skills bundle 共享配置与模板渲染
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const SKILLS_BUNDLE_NAME = 'kld-sdd';
|
|
6
|
+
|
|
7
|
+
const OPSX_SKILL_DIRS = [
|
|
8
|
+
'opsx-propose',
|
|
9
|
+
'opsx-spec',
|
|
10
|
+
'opsx-design',
|
|
11
|
+
'opsx-task',
|
|
12
|
+
'opsx-check',
|
|
13
|
+
'opsx-apply',
|
|
14
|
+
'opsx-test',
|
|
15
|
+
'opsx-archive',
|
|
16
|
+
'opsx-explore',
|
|
17
|
+
'opsx-knowledge'
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
function renderTemplate(content, config, toolKey) {
|
|
21
|
+
const skillsBundlePath = `${config.skillsDir}/${SKILLS_BUNDLE_NAME}`;
|
|
22
|
+
return content
|
|
23
|
+
.replace(/^\uFEFF/, '')
|
|
24
|
+
.replace(/<Agent(?:\u7c7b\u578b|\u7eeb\u8bf2\u7037)>/g, config.agentType || toolKey)
|
|
25
|
+
.replace(/<SkillsBundlePath>/g, skillsBundlePath);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = {
|
|
29
|
+
SKILLS_BUNDLE_NAME,
|
|
30
|
+
OPSX_SKILL_DIRS,
|
|
31
|
+
renderTemplate
|
|
32
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kld-sdd",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.11",
|
|
4
4
|
"description": "KLD SDD OpenSpec 项目初始化工具 - 内置模版一键初始化",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"kld-sdd-init": "bin/kld-sdd-init.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "
|
|
11
|
+
"test": "node test/validate-skills-bundle.cjs"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
14
|
"kld",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"bin/",
|
|
31
31
|
"lib/",
|
|
32
32
|
"templates/",
|
|
33
|
-
"skywalk-sdd/index.
|
|
33
|
+
"skywalk-sdd/index.cjs",
|
|
34
34
|
"README.md"
|
|
35
35
|
]
|
|
36
36
|
}
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* AI Agent 通过终端命令调用,将事件写入项目本地 skywalk-sdd/ 目录。
|
|
7
7
|
*
|
|
8
8
|
* 用法:
|
|
9
|
-
* node skywalk-sdd/log.
|
|
10
|
-
* node skywalk-sdd/log.
|
|
11
|
-
* node skywalk-sdd/log.
|
|
9
|
+
* node skywalk-sdd/log.cjs start --command=propose --project=/path --change=xxx [--agent=cursor]
|
|
10
|
+
* node skywalk-sdd/log.cjs end --event-id=evt_xxx --result=success --summary="..."
|
|
11
|
+
* node skywalk-sdd/log.cjs metrics --project=/path [--change=xxx]
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const fs = require('fs');
|
|
@@ -1395,7 +1395,9 @@ function computeAiAdoptionMetrics(events) {
|
|
|
1395
1395
|
const review = getAiAdoptionReview(e);
|
|
1396
1396
|
return review?.review_status === 'final' || e.status === 'final';
|
|
1397
1397
|
});
|
|
1398
|
-
|
|
1398
|
+
// 优先使用 final 事件,无 final 时 fallback 到 snapshot(AI 产出快照)
|
|
1399
|
+
const candidates = finalEvents.length > 0 ? finalEvents : adoptionEvents;
|
|
1400
|
+
const latestEvent = latestByTimestamp(candidates);
|
|
1399
1401
|
const latestReview = getAiAdoptionReview(latestEvent);
|
|
1400
1402
|
if (!latestReview) {
|
|
1401
1403
|
return {
|
|
@@ -1665,7 +1667,7 @@ function computeSinglePdfMvpMetrics(events, options = {}) {
|
|
|
1665
1667
|
const gitDocumentMetrics = options.projectRoot && options.change
|
|
1666
1668
|
? computeGitDocumentMetrics(options.projectRoot, options.change)
|
|
1667
1669
|
: null;
|
|
1668
|
-
const specIterationCount = gitDocumentMetrics
|
|
1670
|
+
const specIterationCount = gitDocumentMetrics?.spec_iteration_count != null
|
|
1669
1671
|
? gitDocumentMetrics.spec_iteration_count
|
|
1670
1672
|
: stageSpecIterationCount;
|
|
1671
1673
|
|
|
@@ -1902,6 +1904,10 @@ function renderExecutiveReportMarkdown(report) {
|
|
|
1902
1904
|
'',
|
|
1903
1905
|
'## 说明',
|
|
1904
1906
|
'- `null` 表示当前还没有采集到对应事件或该指标暂不适用。',
|
|
1907
|
+
'- E4 AI 一次成码率:依赖 `task_update` 事件中的 `task_id` 和首次执行结果,若 apply 阶段未正确记录则显示 null。',
|
|
1908
|
+
'- P1 文档迭代次数:优先使用 Git 提交历史统计,无 Git 仓库或无提交历史时使用阶段 start 事件数。',
|
|
1909
|
+
'- P2 AI 代码保留率:优先使用 `ai_adoption_review` 的 final 状态,无 final 时 fallback 到 AI 产出快照(ai_snapshot)。',
|
|
1910
|
+
'- Q4 规约驱动测试覆盖率:依赖 check/test 阶段记录 spec 断言到测试用例的映射数据(spec_test_coverage 字段),属高级功能。',
|
|
1905
1911
|
'- Q1 规约符合度与人工反馈类指标属于评审信号,默认不作为强阻断门禁。',
|
|
1906
1912
|
].join('\n');
|
|
1907
1913
|
}
|
|
@@ -2064,7 +2070,7 @@ function cmdStart(args) {
|
|
|
2064
2070
|
|
|
2065
2071
|
if (!command) {
|
|
2066
2072
|
console.error('错误: 缺少 --command 参数');
|
|
2067
|
-
console.error('用法: node skywalk-sdd/log.
|
|
2073
|
+
console.error('用法: node skywalk-sdd/log.cjs start --command=propose --project=/path');
|
|
2068
2074
|
process.exit(1);
|
|
2069
2075
|
}
|
|
2070
2076
|
|
|
@@ -2556,7 +2562,7 @@ function cmdArchiveDocs(args) {
|
|
|
2556
2562
|
function main() {
|
|
2557
2563
|
// 支持两种调用方式:
|
|
2558
2564
|
// 1) npx kld-sdd log start ... → argv 含 'log'
|
|
2559
|
-
// 2) node skywalk-sdd/log.
|
|
2565
|
+
// 2) node skywalk-sdd/log.cjs start ... → argv 直接以子命令开头
|
|
2560
2566
|
const argv = process.argv.slice(2);
|
|
2561
2567
|
const logIdx = argv.indexOf('log');
|
|
2562
2568
|
const subArgs = logIdx === -1 ? argv : argv.slice(logIdx + 1);
|
|
@@ -2604,12 +2610,12 @@ function showHelp() {
|
|
|
2604
2610
|
SDD Telemetry CLI - 流程度量采集工具
|
|
2605
2611
|
|
|
2606
2612
|
用法:
|
|
2607
|
-
node skywalk-sdd/log.
|
|
2608
|
-
node skywalk-sdd/log.
|
|
2609
|
-
node skywalk-sdd/log.
|
|
2610
|
-
node skywalk-sdd/log.
|
|
2611
|
-
node skywalk-sdd/log.
|
|
2612
|
-
node skywalk-sdd/log.
|
|
2613
|
+
node skywalk-sdd/log.cjs start --command=<cmd> --project=<path> [--change=<name>] [--agent=<type>]
|
|
2614
|
+
node skywalk-sdd/log.cjs end --event-id=<id> --result=<success|failure|partial> --summary="..."
|
|
2615
|
+
node skywalk-sdd/log.cjs metrics --project=<path> [--change=<name>] [--pdf-mvp] [--format=json|markdown]
|
|
2616
|
+
node skywalk-sdd/log.cjs report --project=<path> [--change=<name>] [--format=json|markdown] [--output=<file>]
|
|
2617
|
+
node skywalk-sdd/log.cjs tasks-status --project=<path> --change=<name> [--require-complete]
|
|
2618
|
+
node skywalk-sdd/log.cjs archive-docs --project=<path> --change=<name> [--reason=<text>] [--event-id=<id>] [--report-output=<file>]
|
|
2613
2619
|
|
|
2614
2620
|
子命令:
|
|
2615
2621
|
start 记录 SDD 阶段开始,返回 event_id
|
|
@@ -2622,18 +2628,18 @@ SDD Telemetry CLI - 流程度量采集工具
|
|
|
2622
2628
|
archive-docs 将 Simple/Full spec 变更真实移动到 openspec/changes/archive/,并可结束 archive 阶段生成报告
|
|
2623
2629
|
|
|
2624
2630
|
示例:
|
|
2625
|
-
node skywalk-sdd/log.
|
|
2626
|
-
node skywalk-sdd/log.
|
|
2627
|
-
node skywalk-sdd/log.
|
|
2628
|
-
node skywalk-sdd/log.
|
|
2629
|
-
node skywalk-sdd/log.
|
|
2630
|
-
node skywalk-sdd/log.
|
|
2631
|
-
node skywalk-sdd/log.
|
|
2632
|
-
node skywalk-sdd/log.
|
|
2633
|
-
node skywalk-sdd/log.
|
|
2634
|
-
node skywalk-sdd/log.
|
|
2635
|
-
node skywalk-sdd/log.
|
|
2636
|
-
node skywalk-sdd/log.
|
|
2631
|
+
node skywalk-sdd/log.cjs start --command=propose --project=/my/project --change=user-auth --agent=cursor
|
|
2632
|
+
node skywalk-sdd/log.cjs end --event-id=evt_abc123 --result=success --summary="创建 proposal.md"
|
|
2633
|
+
node skywalk-sdd/log.cjs record --type=task_update --command=apply --project=/my/project --change=user-auth --task-id=TASK-01 --status=completed
|
|
2634
|
+
node skywalk-sdd/log.cjs record --type=conformance_review --command=check --project=/my/project --change=user-auth --source=manual --details-file=conformance-review.json
|
|
2635
|
+
node skywalk-sdd/log.cjs record --type=ai_adoption_review --command=apply --project=/my/project --change=user-auth --status=final --details-file=ai-adoption.json
|
|
2636
|
+
node skywalk-sdd/log.cjs record --type=survey_result --project=/my/project --change=user-auth --source=manual --details-file=survey.json
|
|
2637
|
+
node skywalk-sdd/log.cjs metrics --project=/my/project --change=user-auth
|
|
2638
|
+
node skywalk-sdd/log.cjs metrics --project=/my/project --change=user-auth --pdf-mvp --format=markdown
|
|
2639
|
+
node skywalk-sdd/log.cjs report --project=/my/project --change=user-auth --format=markdown
|
|
2640
|
+
node skywalk-sdd/log.cjs doctor --project=/my/project --change=user-auth
|
|
2641
|
+
node skywalk-sdd/log.cjs tasks-status --project=/my/project --change=user-auth --require-complete
|
|
2642
|
+
node skywalk-sdd/log.cjs archive-docs --project=/my/project --change=user-auth --reason="变更已完成实施" --event-id=evt_archive --report-output=skywalk-sdd/reports/user-auth-report.md
|
|
2637
2643
|
`);
|
|
2638
2644
|
}
|
|
2639
2645
|
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
run: npm install
|
|
29
29
|
|
|
30
30
|
- name: SDD doctor
|
|
31
|
-
run: node skywalk-sdd/log.
|
|
31
|
+
run: node skywalk-sdd/log.cjs doctor --project="$SDD_PROJECT" --change="$SDD_CHANGE"
|
|
32
32
|
|
|
33
33
|
- name: Build and record SDD result
|
|
34
34
|
shell: bash
|
|
@@ -45,7 +45,7 @@ jobs:
|
|
|
45
45
|
result="failure"
|
|
46
46
|
success="false"
|
|
47
47
|
fi
|
|
48
|
-
node skywalk-sdd/log.
|
|
48
|
+
node skywalk-sdd/log.cjs record --type=build_result --command=ci --project="$SDD_PROJECT" --change="$SDD_CHANGE" --agent="$SDD_AGENT" --source=ci --session-id="$SDD_SESSION" --result="$result" --summary="CI build $result" --details-json="{\"build_results\":{\"command\":\"$SDD_BUILD_COMMAND\",\"success\":$success,\"duration_ms\":$duration,\"error_count\":0}}"
|
|
49
49
|
exit "$status"
|
|
50
50
|
|
|
51
51
|
- name: Test and record SDD result
|
|
@@ -63,5 +63,5 @@ jobs:
|
|
|
63
63
|
result="failure"
|
|
64
64
|
failed=1
|
|
65
65
|
fi
|
|
66
|
-
node skywalk-sdd/log.
|
|
66
|
+
node skywalk-sdd/log.cjs record --type=test_result --command=ci --project="$SDD_PROJECT" --change="$SDD_CHANGE" --agent="$SDD_AGENT" --source=ci --session-id="$SDD_SESSION" --result="$result" --summary="CI test $result" --details-json="{\"test_results\":{\"command\":\"$SDD_TEST_COMMAND\",\"passed\":0,\"failed\":$failed,\"skipped\":0,\"coverage\":null,\"duration_ms\":$duration}}"
|
|
67
67
|
exit "$status"
|
|
@@ -11,7 +11,7 @@ sdd_quality_gate:
|
|
|
11
11
|
before_script:
|
|
12
12
|
- npm install
|
|
13
13
|
script:
|
|
14
|
-
- node skywalk-sdd/log.
|
|
14
|
+
- node skywalk-sdd/log.cjs doctor --project="$SDD_PROJECT" --change="$SDD_CHANGE"
|
|
15
15
|
- |
|
|
16
16
|
set +e
|
|
17
17
|
start_ms=$(date +%s%3N)
|
|
@@ -25,7 +25,7 @@ sdd_quality_gate:
|
|
|
25
25
|
result="failure"
|
|
26
26
|
success="false"
|
|
27
27
|
fi
|
|
28
|
-
node skywalk-sdd/log.
|
|
28
|
+
node skywalk-sdd/log.cjs record --type=build_result --command=ci --project="$SDD_PROJECT" --change="$SDD_CHANGE" --agent="$SDD_AGENT" --source=ci --session-id="$SDD_SESSION" --result="$result" --summary="CI build $result" --details-json="{\"build_results\":{\"command\":\"$SDD_BUILD_COMMAND\",\"success\":$success,\"duration_ms\":$duration,\"error_count\":0}}"
|
|
29
29
|
if [ "$status" -ne 0 ]; then exit "$status"; fi
|
|
30
30
|
- |
|
|
31
31
|
set +e
|
|
@@ -40,5 +40,5 @@ sdd_quality_gate:
|
|
|
40
40
|
result="failure"
|
|
41
41
|
failed=1
|
|
42
42
|
fi
|
|
43
|
-
node skywalk-sdd/log.
|
|
43
|
+
node skywalk-sdd/log.cjs record --type=test_result --command=ci --project="$SDD_PROJECT" --change="$SDD_CHANGE" --agent="$SDD_AGENT" --source=ci --session-id="$SDD_SESSION" --result="$result" --summary="CI test $result" --details-json="{\"test_results\":{\"command\":\"$SDD_TEST_COMMAND\",\"passed\":0,\"failed\":$failed,\"skipped\":0,\"coverage\":null,\"duration_ms\":$duration}}"
|
|
44
44
|
if [ "$status" -ne 0 ]; then exit "$status"; fi
|
|
@@ -16,7 +16,7 @@ function main() {
|
|
|
16
16
|
const logCli = path.join(projectRoot, 'skywalk-sdd', 'log.js');
|
|
17
17
|
|
|
18
18
|
if (!fs.existsSync(logCli)) {
|
|
19
|
-
console.log('SDD pre-push: skywalk-sdd/log.
|
|
19
|
+
console.log('SDD pre-push: skywalk-sdd/log.cjs not found; doctor gate skipped.');
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -54,8 +54,8 @@ const activeStages = readActiveStages(projectRoot)
|
|
|
54
54
|
|
|
55
55
|
const lines = [
|
|
56
56
|
'SDD Telemetry reminder:',
|
|
57
|
-
'- Run skywalk-sdd/log.
|
|
58
|
-
'- Run skywalk-sdd/log.
|
|
57
|
+
'- Run skywalk-sdd/log.cjs start before the OPSX stage work begins.',
|
|
58
|
+
'- Run skywalk-sdd/log.cjs end before stopping the stage.',
|
|
59
59
|
'- Hooks are only an enhancement; OPSX command instructions remain authoritative.',
|
|
60
60
|
];
|
|
61
61
|
|
|
@@ -78,5 +78,5 @@ for (const event of activeStages) {
|
|
|
78
78
|
console.log([
|
|
79
79
|
'SDD Telemetry warning: open stage(s) detected.',
|
|
80
80
|
...activeStages.map(event => `- ${event.change || 'general'}:${event.command || event.stage || 'unknown'} event_id=${event.event_id}`),
|
|
81
|
-
'Run skywalk-sdd/log.
|
|
81
|
+
'Run skywalk-sdd/log.cjs end before closing the OPSX stage, or explicitly mark it partial/failure.',
|
|
82
82
|
].join('\n'));
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "command",
|
|
8
|
-
"command": "node .claude/hooks/sdd-prompt.
|
|
8
|
+
"command": "node .claude/hooks/sdd-prompt.cjs"
|
|
9
9
|
}
|
|
10
10
|
]
|
|
11
11
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"hooks": [
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"command": "node .claude/hooks/sdd-pre-tool.
|
|
19
|
+
"command": "node .claude/hooks/sdd-pre-tool.cjs"
|
|
20
20
|
}
|
|
21
21
|
]
|
|
22
22
|
}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"hooks": [
|
|
28
28
|
{
|
|
29
29
|
"type": "command",
|
|
30
|
-
"command": "node .claude/hooks/sdd-post-tool.
|
|
30
|
+
"command": "node .claude/hooks/sdd-post-tool.cjs"
|
|
31
31
|
}
|
|
32
32
|
]
|
|
33
33
|
}
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"hooks": [
|
|
38
38
|
{
|
|
39
39
|
"type": "command",
|
|
40
|
-
"command": "node .claude/hooks/sdd-stop.
|
|
40
|
+
"command": "node .claude/hooks/sdd-stop.cjs"
|
|
41
41
|
}
|
|
42
42
|
]
|
|
43
43
|
}
|
|
@@ -12,7 +12,7 @@ argument-hint: "[change-name] [capability-name] [上下文文件...]"
|
|
|
12
12
|
> - 在 Windows Bash / Git Bash / Claude Bash 中,禁止裸写 Windows 反斜杠绝对路径(如 `D:\project\demo`);如必须使用绝对路径,请写成正斜杠路径或加引号。
|
|
13
13
|
> - 不要省略 `--source=opsx-command` 与 `--session-id=<会话ID>`。
|
|
14
14
|
> **📊 Telemetry(必做,不得跳过)**
|
|
15
|
-
> 在终端执行(必须成功):`node skywalk-sdd/log.
|
|
15
|
+
> 在终端执行(必须成功):`node skywalk-sdd/log.cjs start --command=apply --project=. --change=<变更名称> --capability=<capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --git-sha=<base_git_sha_or_none>`,记录返回的 event_id。
|
|
16
16
|
|
|
17
17
|
> **🔒 Git 策略(只读增强,不改变开发流)**
|
|
18
18
|
> - Git 只作为可选度量数据源,不是 apply 前置条件。
|
|
@@ -65,7 +65,7 @@ argument-hint: "[change-name] [capability-name] [上下文文件...]"
|
|
|
65
65
|
|
|
66
66
|
在终端执行(若命令失败必须中止本阶段,不得跳过):
|
|
67
67
|
```bash
|
|
68
|
-
node skywalk-sdd/log.
|
|
68
|
+
node skywalk-sdd/log.cjs start --command=apply --project=. --change=<变更名称> --capability=<capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --git-sha=<base_git_sha_or_none>
|
|
69
69
|
```
|
|
70
70
|
保存输出 JSON 中的 `event_id`,供阶段结束使用。
|
|
71
71
|
|
|
@@ -350,7 +350,7 @@ argument-hint: "[change-name] [capability-name] [上下文文件...]"
|
|
|
350
350
|
|
|
351
351
|
5. **记录构建 Telemetry**:
|
|
352
352
|
```bash
|
|
353
|
-
node skywalk-sdd/log.
|
|
353
|
+
node skywalk-sdd/log.cjs record --type=build_result --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --result=success/failure --summary="编译检查结果" --details-json="{\"build_results\":{\"command\":\"<实际编译命令>\",\"success\":true,\"duration_ms\":0,\"error_count\":0}}"
|
|
354
354
|
```
|
|
355
355
|
`build_results` 字段口径:
|
|
356
356
|
- `command`: 实际执行的编译/构建命令。
|
|
@@ -402,8 +402,10 @@ argument-hint: "[change-name] [capability-name] [上下文文件...]"
|
|
|
402
402
|
|
|
403
403
|
4. **记录任务级 Telemetry**:
|
|
404
404
|
```bash
|
|
405
|
-
node skywalk-sdd/log.
|
|
405
|
+
node skywalk-sdd/log.cjs record --type=task_update --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=completed --result=success --summary="<TASK-ID> 完成" --details-json="{\"files_changed\":[],\"build_results\":{\"command\":\"<实际编译命令>\",\"success\":true,\"duration_ms\":0,\"error_count\":0},\"test_results\":{\"command\":\"<实际测试命令>\",\"passed\":0,\"failed\":0,\"skipped\":0,\"coverage\":null,\"duration_ms\":0}}"
|
|
406
406
|
```
|
|
407
|
+
**⚠️ 注意**:`--task-id=<TASK-ID>` 中的 `<TASK-ID>` 必须替换为当前任务的实际 ID(如 `TASK-USER-AUTH-01`),不得保留占位符,否则 E4 指标无法计算。
|
|
408
|
+
|
|
407
409
|
若任务失败或暂停,`--status` 使用 `failed` / `blocked`,`--result` 使用 `failure` / `partial`,并在 details 中记录失败原因。
|
|
408
410
|
|
|
409
411
|
g. **继续下一个可执行任务**
|
|
@@ -481,8 +483,8 @@ argument-hint: "[change-name] [capability-name] [上下文文件...]"
|
|
|
481
483
|
> - 在 Windows Bash / Git Bash / Claude Bash 中,禁止裸写 Windows 反斜杠绝对路径(如 `D:\project\demo`);如必须使用绝对路径,请写成正斜杠路径或加引号。
|
|
482
484
|
> - 不要省略 `--source=opsx-command` 与 `--session-id=<会话ID>`。
|
|
483
485
|
> **📊 Telemetry(必做,不得跳过)**
|
|
484
|
-
> 每次编译检查后,必须记录构建事件:`node skywalk-sdd/log.
|
|
485
|
-
> 每完成一个任务,必须记录任务级结构化事件:`node skywalk-sdd/log.
|
|
486
|
-
> AI 代码产出完成后,必须记录采纳率快照,但不得为了采集快照自动提交 commit。Git 可用时只读统计 SHA/diff;Git 不可用时使用 `vcs_mode=no-git` 和 `base_git_sha=null`:`node skywalk-sdd/log.
|
|
487
|
-
> 若后续发生人工修改并完成采纳确认,必须补录最终采纳统计;若非 Git 项目,SHA 可填 `null`,采纳行数由人工或工具统计补录:`node skywalk-sdd/log.
|
|
488
|
-
> 阶段结束时执行(必须成功):`node skywalk-sdd/log.
|
|
486
|
+
> 每次编译检查后,必须记录构建事件:`node skywalk-sdd/log.cjs record --type=build_result --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --result=success/failure --summary="编译检查结果" --details-json="{\"build_results\":{\"command\":\"<实际编译命令>\",\"success\":true,\"duration_ms\":0,\"error_count\":0}}"`
|
|
487
|
+
> 每完成一个任务,必须记录任务级结构化事件:`node skywalk-sdd/log.cjs record --type=task_update --command=apply --project=. --change=<变更名称> --capability=<capability-name> --task-id=<TASK-ID> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=completed --result=success --summary="<TASK-ID> 完成" --details-json="{\"files_changed\":[],\"build_results\":{\"command\":\"<实际编译命令>\",\"success\":true,\"duration_ms\":0,\"error_count\":0},\"test_results\":{\"command\":\"<实际测试命令>\",\"passed\":0,\"failed\":0,\"skipped\":0,\"coverage\":null,\"duration_ms\":0}}"`
|
|
488
|
+
> AI 代码产出完成后,必须记录采纳率快照,但不得为了采集快照自动提交 commit。Git 可用时只读统计 SHA/diff;Git 不可用时使用 `vcs_mode=no-git` 和 `base_git_sha=null`:`node skywalk-sdd/log.cjs record --type=ai_adoption_review --command=apply --project=. --change=<变更名称> --capability=<capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --status=ai_snapshot --result=success --summary="AI 代码产出快照" --details-json="{\"ai_adoption\":{\"review_status\":\"ai_snapshot\",\"vcs_mode\":\"<readonly|no-git>\",\"base_git_sha\":\"<base_git_sha_or_null>\",\"ai_git_sha\":\"<ai_git_sha_or_null>\",\"ai_diff\":{\"files_changed\":0,\"added_lines\":null,\"deleted_lines\":null},\"notes\":\"未自动创建 Git 仓库,未自动提交 commit;仅记录可用统计\"}}"`
|
|
489
|
+
> 若后续发生人工修改并完成采纳确认,必须补录最终采纳统计;若非 Git 项目,SHA 可填 `null`,采纳行数由人工或工具统计补录:`node skywalk-sdd/log.cjs record --type=ai_adoption_review --command=apply --project=. --change=<变更名称> --capability=<capability-name> --agent=<Agent类型> --source=manual --session-id=<会话ID> --status=final --result=success --summary="AI 代码采纳率人工确认" --details-json="{\"ai_adoption\":{\"review_status\":\"final\",\"vcs_mode\":\"<readonly|no-git>\",\"base_git_sha\":\"<base_git_sha_or_null>\",\"ai_git_sha\":\"<ai_git_sha_or_null>\",\"final_git_sha\":\"<final_git_sha_or_null>\",\"retained_lines\":0,\"rewritten_lines\":0,\"deleted_lines\":0,\"ai_diff\":{\"files_changed\":0,\"added_lines\":null,\"deleted_lines\":null},\"final_diff\":{\"files_changed\":0,\"added_lines\":null,\"deleted_lines\":null},\"notes\":\"只记录行数统计,不记录源码;非 Git 项目允许 SHA 为 null\"}}"`
|
|
490
|
+
> 阶段结束时执行(必须成功):`node skywalk-sdd/log.cjs end --event-id=<开头记录的event_id> --command=apply --project=. --change=<变更名称> --capability=<capability-name> --agent=<Agent类型> --source=opsx-command --session-id=<会话ID> --result=success/failure --summary="实施结果摘要"`
|