kld-sdd 2.4.18 → 2.5.0
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/lib/init.js +56 -41
- package/package.json +1 -1
- package/skywalk-sdd/index.cjs +1808 -129
- package/templates/hooks/claude/hooks/sdd-apply-test-gate.cjs +175 -28
- package/templates/hooks/claude/hooks/sdd-post-tool.cjs +42 -21
- package/templates/openspec/proposal.md +0 -1
- package/templates/openspec/spec.md +2 -2
- package/templates/skills/kld-sdd/opsx-apply/SKILL.md +64 -355
- package/templates/skills/kld-sdd/opsx-apply/checklist.md +94 -0
- package/templates/skills/kld-sdd/opsx-apply/reference.md +403 -0
- package/templates/skills/kld-sdd/opsx-archive/SKILL.md +21 -5
- package/templates/skills/kld-sdd/opsx-archive/checklist.md +33 -0
- package/templates/skills/kld-sdd/opsx-check/SKILL.md +28 -4
- package/templates/skills/kld-sdd/opsx-check/checklist.md +37 -0
- package/templates/skills/kld-sdd/opsx-design/SKILL.md +46 -50
- package/templates/skills/kld-sdd/opsx-design/checklist.md +46 -0
- package/templates/skills/kld-sdd/opsx-design/reference.md +44 -0
- package/templates/skills/kld-sdd/opsx-propose/SKILL.md +51 -95
- package/templates/skills/kld-sdd/opsx-propose/checklist.md +44 -0
- package/templates/skills/kld-sdd/opsx-propose/reference.md +94 -0
- package/templates/skills/kld-sdd/opsx-spec/SKILL.md +46 -50
- package/templates/skills/kld-sdd/opsx-spec/checklist.md +46 -0
- package/templates/skills/kld-sdd/opsx-spec/reference.md +49 -0
- package/templates/skills/kld-sdd/opsx-task/SKILL.md +42 -45
- package/templates/skills/kld-sdd/opsx-task/checklist.md +46 -0
- package/templates/skills/kld-sdd/opsx-task/reference.md +40 -0
- package/templates/skills/kld-sdd/opsx-test/SKILL.md +12 -0
package/lib/init.js
CHANGED
|
@@ -350,23 +350,40 @@ function copyDirRendered(source, target, config, toolKey) {
|
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
+
/** OpenSpec init 生成的 4 个官方 slash command(KLD-SDD 使用 skills,不保留 command) */
|
|
354
|
+
const NATIVE_OPSX_CMDS_HYPHEN = [
|
|
355
|
+
'opsx-propose.md',
|
|
356
|
+
'opsx-apply.md',
|
|
357
|
+
'opsx-archive.md',
|
|
358
|
+
'opsx-explore.md'
|
|
359
|
+
];
|
|
360
|
+
const NATIVE_OPSX_CMDS_SLASH = ['propose.md', 'apply.md', 'archive.md', 'explore.md'];
|
|
361
|
+
|
|
353
362
|
/**
|
|
354
|
-
*
|
|
355
|
-
|
|
356
|
-
|
|
363
|
+
* SDD 自定义 command 标记(init 不部署;用户手动维护时保留)
|
|
364
|
+
*/
|
|
365
|
+
function isSddCustomCommand(content) {
|
|
366
|
+
return content.includes('# SDD') || content.includes('skywalk-sdd/log.cjs');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* 清理原生 openspec 命令,所有编辑器与 Cursor 行为一致:初始化时删除官方 command。
|
|
371
|
+
* 同时清理 openspec 遗留的 JSON 文件。
|
|
372
|
+
*
|
|
373
|
+
* 覆盖 TOOL_CONFIGS 中的全部编辑器(cursor/claude/codebuddy/qoder/opencode/kunlunzhima/workbuddy/codex),
|
|
374
|
+
* 与 Cursor 行为一致:初始化时删除 OpenSpec 官方 command,仅保留 skills。
|
|
375
|
+
*
|
|
357
376
|
* openspec 对不同工具生成的目录结构:
|
|
358
377
|
* - Cursor: commands/opsx-*.md(根目录,连字符)
|
|
359
|
-
* - Claude/CodeBuddy/Qoder
|
|
360
|
-
* - OpenCode: command/opsx-*.md(command
|
|
361
|
-
*
|
|
378
|
+
* - Claude/CodeBuddy/Qoder 等: commands/opsx/*.md(opsx 子目录)
|
|
379
|
+
* - OpenCode: command/opsx-*.md(command 单数目录,整目录删除)
|
|
380
|
+
*
|
|
362
381
|
* @param {string[]} selectedTools - 用户选择的编辑器列表
|
|
363
382
|
*/
|
|
364
383
|
function cleanupNativeOpenspecCommands(selectedTools = Object.keys(TOOL_CONFIGS)) {
|
|
365
|
-
console.log('🗑 正在清理原生 openspec
|
|
384
|
+
console.log('🗑 正在清理原生 openspec 命令(所有编辑器与 Cursor 一致,仅保留 skills)...');
|
|
366
385
|
|
|
367
386
|
const cwd = process.cwd();
|
|
368
|
-
// 原生 openspec 根目录命令文件(使用连字符,与 opsx:* 冒号命令混淆)
|
|
369
|
-
const nativeCmds = ['opsx-propose.md', 'opsx-apply.md', 'opsx-archive.md', 'opsx-explore.md'];
|
|
370
387
|
|
|
371
388
|
for (const toolKey of selectedTools) {
|
|
372
389
|
const config = TOOL_CONFIGS[toolKey];
|
|
@@ -392,40 +409,41 @@ function cleanupNativeOpenspecCommands(selectedTools = Object.keys(TOOL_CONFIGS)
|
|
|
392
409
|
console.log(` 🗑 ${config.name}: 删除 ${deletedJson} 个 JSON 命令文件`);
|
|
393
410
|
}
|
|
394
411
|
|
|
395
|
-
// 删除 commands/
|
|
412
|
+
// 删除 commands/ 根目录下的原生 opsx-* 命令(Cursor 等,与 Claude 行为一致)
|
|
396
413
|
let deletedCmds = 0;
|
|
397
|
-
for (const
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
414
|
+
for (const file of fs.readdirSync(commandsDir)) {
|
|
415
|
+
const isNativeHyphen = NATIVE_OPSX_CMDS_HYPHEN.includes(file) || /^opsx-.*\.md$/i.test(file);
|
|
416
|
+
if (!isNativeHyphen) continue;
|
|
417
|
+
const filePath = path.join(commandsDir, file);
|
|
418
|
+
if (!fs.statSync(filePath).isFile()) continue;
|
|
419
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
420
|
+
if (isSddCustomCommand(content)) continue;
|
|
421
|
+
fs.unlinkSync(filePath);
|
|
422
|
+
deletedCmds++;
|
|
403
423
|
}
|
|
404
424
|
if (deletedCmds > 0) {
|
|
405
425
|
console.log(` ✓ ${config.name}: 删除 ${deletedCmds} 个原生 opsx-* 命令(commands/)`);
|
|
406
426
|
}
|
|
407
427
|
|
|
408
|
-
// 删除 commands/opsx/
|
|
428
|
+
// 删除 commands/opsx/ 子目录下的官方命令(Claude/CodeBuddy/Qoder 等,与 Cursor 一致无条件删除)
|
|
409
429
|
const opsxDir = path.join(commandsDir, 'opsx');
|
|
410
430
|
if (fs.existsSync(opsxDir)) {
|
|
411
|
-
const opsxFiles = fs.readdirSync(opsxDir);
|
|
412
431
|
let deletedOpsxCmds = 0;
|
|
413
|
-
|
|
414
|
-
const nativeOpsxCmds = ['propose.md', 'apply.md', 'archive.md', 'explore.md'];
|
|
415
|
-
for (const file of nativeOpsxCmds) {
|
|
432
|
+
for (const file of NATIVE_OPSX_CMDS_SLASH) {
|
|
416
433
|
const filePath = path.join(opsxDir, file);
|
|
417
|
-
if (fs.existsSync(filePath))
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
deletedOpsxCmds++;
|
|
423
|
-
}
|
|
424
|
-
}
|
|
434
|
+
if (!fs.existsSync(filePath)) continue;
|
|
435
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
436
|
+
if (isSddCustomCommand(content)) continue;
|
|
437
|
+
fs.unlinkSync(filePath);
|
|
438
|
+
deletedOpsxCmds++;
|
|
425
439
|
}
|
|
426
440
|
if (deletedOpsxCmds > 0) {
|
|
427
441
|
console.log(` ✓ ${config.name}: 删除 ${deletedOpsxCmds} 个原生命令(commands/opsx/)`);
|
|
428
442
|
}
|
|
443
|
+
// 子目录为空则移除
|
|
444
|
+
if (fs.readdirSync(opsxDir).length === 0) {
|
|
445
|
+
fs.rmdirSync(opsxDir);
|
|
446
|
+
}
|
|
429
447
|
}
|
|
430
448
|
}
|
|
431
449
|
|
|
@@ -764,7 +782,7 @@ function initGlobalOverview() {
|
|
|
764
782
|
|
|
765
783
|
/**
|
|
766
784
|
* 部署 SDD Telemetry 数据目录
|
|
767
|
-
*
|
|
785
|
+
* 创建本地数据目录用于存储事件和活跃状态(最终报告落 openspec/changes/<change>/reports/,不再写 skywalk-sdd/reports/)
|
|
768
786
|
*/
|
|
769
787
|
function deployTelemetryDataDir() {
|
|
770
788
|
console.log('📊 正在初始化 SDD Telemetry 数据目录...');
|
|
@@ -777,18 +795,13 @@ function deployTelemetryDataDir() {
|
|
|
777
795
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
778
796
|
}
|
|
779
797
|
|
|
780
|
-
//
|
|
798
|
+
// 创建本地数据目录(事件和活跃状态存储;报告落 change 子目录,不在此创建)
|
|
781
799
|
const eventsDir = path.join(dataDir, 'events');
|
|
782
|
-
const reportsDir = path.join(dataDir, 'reports');
|
|
783
800
|
const stateDir = path.join(dataDir, 'state');
|
|
784
801
|
if (!fs.existsSync(eventsDir)) {
|
|
785
802
|
fs.mkdirSync(eventsDir, { recursive: true });
|
|
786
803
|
console.log(' ✓ 创建 skywalk-sdd/events/ 数据目录');
|
|
787
804
|
}
|
|
788
|
-
if (!fs.existsSync(reportsDir)) {
|
|
789
|
-
fs.mkdirSync(reportsDir, { recursive: true });
|
|
790
|
-
console.log(' ✓ 创建 skywalk-sdd/reports/ 报告目录');
|
|
791
|
-
}
|
|
792
805
|
if (!fs.existsSync(stateDir)) {
|
|
793
806
|
fs.mkdirSync(stateDir, { recursive: true });
|
|
794
807
|
console.log(' ✓ 创建 skywalk-sdd/state/ 活跃阶段状态目录');
|
|
@@ -858,10 +871,14 @@ function installGitHookShim(cwd, hookName, scriptPath) {
|
|
|
858
871
|
* 这些脚本只做质量门禁和 CI 补充记录,不替代 OPSX 主采集链路。
|
|
859
872
|
*/
|
|
860
873
|
function deployQualityGateTemplates() {
|
|
861
|
-
console.log('🧰 正在部署 SDD Git hooks / CI 兜底模板...');
|
|
862
|
-
|
|
863
874
|
const pkgPath = getPackagePath();
|
|
864
875
|
const cwd = process.cwd();
|
|
876
|
+
// U4: 非 Git 项目跳过 Git hooks / CI 兜底模板(按需部署,不污染非 Git 项目根)
|
|
877
|
+
if (!fs.existsSync(path.join(cwd, '.git'))) {
|
|
878
|
+
console.log('🧰 非 Git 项目,跳过 Git hooks / CI 兜底模板部署');
|
|
879
|
+
return false;
|
|
880
|
+
}
|
|
881
|
+
console.log('🧰 正在部署 SDD Git hooks / CI 兜底模板...');
|
|
865
882
|
const dataDir = path.join(cwd, 'skywalk-sdd');
|
|
866
883
|
const gitHooksTemplateDir = path.join(pkgPath, 'templates', 'git-hooks');
|
|
867
884
|
const ciTemplateDir = path.join(pkgPath, 'templates', 'ci');
|
|
@@ -918,7 +935,6 @@ function updateGitignore() {
|
|
|
918
935
|
'.workbuddy/commands/personal-*',
|
|
919
936
|
'.agents/commands/personal-*',
|
|
920
937
|
'skywalk-sdd/events/',
|
|
921
|
-
'skywalk-sdd/reports/',
|
|
922
938
|
'skywalk-sdd/state/',
|
|
923
939
|
'.worktrees/'
|
|
924
940
|
];
|
|
@@ -933,9 +949,8 @@ function updateGitignore() {
|
|
|
933
949
|
.workbuddy/commands/personal-*
|
|
934
950
|
.agents/commands/personal-*
|
|
935
951
|
|
|
936
|
-
# SDD Telemetry
|
|
952
|
+
# SDD Telemetry 数据(本地度量,可选提交;最终报告落 openspec/changes/<change>/reports/ 随 change 提交)
|
|
937
953
|
skywalk-sdd/events/
|
|
938
|
-
skywalk-sdd/reports/
|
|
939
954
|
skywalk-sdd/state/
|
|
940
955
|
|
|
941
956
|
# SDD Apply 隔离 worktree(本地临时目录)
|