kld-sdd 2.4.17 → 2.4.19
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 +62 -32
- package/package.json +2 -1
- package/skywalk-sdd/apply-worktree-finish.cjs +551 -0
- package/skywalk-sdd/index.cjs +6 -0
- package/templates/hooks/claude/hooks/sdd-apply-test-gate.cjs +315 -0
- package/templates/hooks/claude/hooks/sdd-skill-apply-gate.cjs +3 -2
- package/templates/hooks/claude/settings.json +8 -0
- package/templates/skills/kld-sdd/opsx-apply/SKILL.md +219 -11
- package/templates/skills/kld-sdd/opsx-apply/worktree-setup.md +64 -101
- package/templates/skills/kld-sdd/opsx-archive/SKILL.md +10 -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
|
|
|
@@ -547,8 +565,8 @@ function hookCommandText(hook) {
|
|
|
547
565
|
|
|
548
566
|
function isSddClaudeHook(hook) {
|
|
549
567
|
const text = hookCommandText(hook);
|
|
550
|
-
return /(?:^|\s|["'])\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop|apply-gate|skill-apply-gate)\.(?:cjs|js)(?=$|\s|["'])/i.test(text) ||
|
|
551
|
-
/(?:^|\s|["'])\$\{CLAUDE_PROJECT_DIR\}[\\/]+\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop|apply-gate|skill-apply-gate)\.(?:cjs|js)(?=$|\s|["'])/i.test(text);
|
|
568
|
+
return /(?:^|\s|["'])\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop|apply-gate|apply-test-gate|skill-apply-gate)\.(?:cjs|js)(?=$|\s|["'])/i.test(text) ||
|
|
569
|
+
/(?:^|\s|["'])\$\{CLAUDE_PROJECT_DIR\}[\\/]+\.claude[\\/]+hooks[\\/]+sdd-(?:prompt|pre-tool|post-tool|stop|apply-gate|apply-test-gate|skill-apply-gate)\.(?:cjs|js)(?=$|\s|["'])/i.test(text);
|
|
552
570
|
}
|
|
553
571
|
|
|
554
572
|
function sameHookCommand(left, right) {
|
|
@@ -804,7 +822,15 @@ function deployTelemetryDataDir() {
|
|
|
804
822
|
console.log(` ⚠️ Telemetry CLI 源文件缺失: ${telemetrySrc}`);
|
|
805
823
|
}
|
|
806
824
|
|
|
825
|
+
const worktreeFinishSrc = path.join(pkgPath, 'skywalk-sdd', 'apply-worktree-finish.cjs');
|
|
826
|
+
const worktreeFinishDst = path.join(dataDir, 'apply-worktree-finish.cjs');
|
|
827
|
+
if (fs.existsSync(worktreeFinishSrc)) {
|
|
828
|
+
fs.copyFileSync(worktreeFinishSrc, worktreeFinishDst);
|
|
829
|
+
console.log(' ✓ 部署 skywalk-sdd/apply-worktree-finish.cjs(Apply 收尾脚本)');
|
|
830
|
+
}
|
|
831
|
+
|
|
807
832
|
console.log(' ✓ 调用方式: node skywalk-sdd/log.cjs start|end|metrics');
|
|
833
|
+
console.log(' ✓ Apply worktree: record-base 在 §1.5;收尾 apply-worktree-finish.cjs --change=<name>');
|
|
808
834
|
console.log('✅ Telemetry 已就绪(数据存储在 skywalk-sdd/,无需配置 MCP)');
|
|
809
835
|
return true;
|
|
810
836
|
}
|
|
@@ -911,7 +937,8 @@ function updateGitignore() {
|
|
|
911
937
|
'.agents/commands/personal-*',
|
|
912
938
|
'skywalk-sdd/events/',
|
|
913
939
|
'skywalk-sdd/reports/',
|
|
914
|
-
'skywalk-sdd/state/'
|
|
940
|
+
'skywalk-sdd/state/',
|
|
941
|
+
'.worktrees/'
|
|
915
942
|
];
|
|
916
943
|
|
|
917
944
|
const sddConfig = `
|
|
@@ -928,6 +955,9 @@ function updateGitignore() {
|
|
|
928
955
|
skywalk-sdd/events/
|
|
929
956
|
skywalk-sdd/reports/
|
|
930
957
|
skywalk-sdd/state/
|
|
958
|
+
|
|
959
|
+
# SDD Apply 隔离 worktree(本地临时目录)
|
|
960
|
+
.worktrees/
|
|
931
961
|
`;
|
|
932
962
|
|
|
933
963
|
if (fs.existsSync(gitignorePath)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kld-sdd",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.19",
|
|
4
4
|
"description": "KLD SDD OpenSpec 项目初始化工具 - 一键部署 SDD skills",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"lib/",
|
|
32
32
|
"templates/",
|
|
33
33
|
"skywalk-sdd/index.cjs",
|
|
34
|
+
"skywalk-sdd/apply-worktree-finish.cjs",
|
|
34
35
|
"README.md"
|
|
35
36
|
]
|
|
36
37
|
}
|