kld-sdd 2.7.3 → 2.7.8

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.
Files changed (65) hide show
  1. package/README.md +12 -5
  2. package/USABILITY.md +84 -0
  3. package/kld-sdd-guide.html +16 -4
  4. package/lib/hook-gate-core.js +327 -0
  5. package/lib/init.js +221 -37
  6. package/lib/scale-thresholds.json +19 -0
  7. package/lib/skills-bundle.js +2 -1
  8. package/package.json +5 -3
  9. package/skywalk-sdd/context-client.cjs +50 -30
  10. package/skywalk-sdd/index.cjs +36 -16
  11. package/skywalk-sdd/kb-sync-identity.cjs +99 -451
  12. package/skywalk-sdd/kb-upload.cjs +67 -44
  13. package/skywalk-sdd/lib/usage-contract.cjs +3 -2
  14. package/skywalk-sdd/lib/usage-reporter.cjs +27 -2
  15. package/skywalk-sdd/metrics-v3.cjs +2 -2
  16. package/skywalk-sdd/ontology/active-changes.cjs +2 -1
  17. package/skywalk-sdd/ontology/archive-package.cjs +1 -1
  18. package/skywalk-sdd/ontology/artifact-parser.cjs +7 -4
  19. package/skywalk-sdd/ontology/id.cjs +5 -4
  20. package/skywalk-sdd/ontology/identity-index.cjs +4 -3
  21. package/skywalk-sdd/ontology/list-changes.cjs +1 -1
  22. package/skywalk-sdd/ontology/runtime.cjs +7 -3
  23. package/skywalk-sdd/ontology/schema.cjs +2 -0
  24. package/skywalk-sdd/ontology/traceability-validator.cjs +74 -4
  25. package/skywalk-sdd/ontology/workspace-layout.cjs +25 -5
  26. package/skywalk-sdd/reporting/change-report-model.cjs +4 -3
  27. package/templates/git-hooks/commit-msg +22 -21
  28. package/templates/git-hooks/consistency-check-core.cjs +1087 -0
  29. package/templates/git-hooks/hooks.config +20 -1
  30. package/templates/git-hooks/pre-commit +22 -21
  31. package/templates/git-hooks/pre-commit-consistency-check.cjs +29 -332
  32. package/templates/git-hooks/pre-commit-sdd-check.cjs +98 -0
  33. package/templates/git-hooks/pre-push +22 -21
  34. package/templates/git-hooks/pre-push-consistency-check.cjs +58 -406
  35. package/templates/hooks/codebuddy/hooks/sdd-tdd-rhythm-gate.cjs +1 -1
  36. package/templates/openspec/tasks.md +3 -3
  37. package/templates/skills/kld-sdd/opsx-apply/SKILL.md +43 -6
  38. package/templates/skills/kld-sdd/opsx-apply/checklist.md +1 -1
  39. package/templates/skills/kld-sdd/opsx-apply/reference.md +1 -1
  40. package/templates/skills/kld-sdd/opsx-archive/SKILL.md +9 -13
  41. package/templates/skills/kld-sdd/opsx-check/SKILL.md +54 -328
  42. package/templates/skills/kld-sdd/opsx-check/checklist.md +7 -4
  43. package/templates/skills/kld-sdd/opsx-check/reference.md +58 -0
  44. package/templates/skills/kld-sdd/opsx-check/result-template.json +52 -0
  45. package/templates/skills/kld-sdd/opsx-check/reviewer.md +100 -0
  46. package/templates/skills/kld-sdd/opsx-consistency-check/SKILL.md +82 -451
  47. package/templates/skills/kld-sdd/opsx-consistency-check/{reference.md → references/reference.md} +0 -1
  48. package/templates/skills/kld-sdd/opsx-consistency-check/scripts/scripts.cjs +517 -0
  49. package/templates/skills/kld-sdd/opsx-design/SKILL.md +10 -30
  50. package/templates/skills/kld-sdd/opsx-design/checklist.md +3 -4
  51. package/templates/skills/kld-sdd/opsx-design/reference.md +1 -1
  52. package/templates/skills/kld-sdd/opsx-kb-ingest/SKILL.md +12 -74
  53. package/templates/skills/kld-sdd/opsx-ontology-query/SKILL.md +7 -5
  54. package/templates/skills/kld-sdd/opsx-ontology-query/phase-1-prechange.md +2 -2
  55. package/templates/skills/kld-sdd/opsx-ontology-query/reference.md +1 -1
  56. package/templates/skills/kld-sdd/opsx-propose/SKILL.md +28 -73
  57. package/templates/skills/kld-sdd/opsx-propose/checklist.md +8 -8
  58. package/templates/skills/kld-sdd/opsx-propose/interaction-policy.md +28 -0
  59. package/templates/skills/kld-sdd/opsx-propose/reference.md +12 -46
  60. package/templates/skills/kld-sdd/opsx-spec/SKILL.md +14 -61
  61. package/templates/skills/kld-sdd/opsx-spec/checklist.md +3 -3
  62. package/templates/skills/kld-sdd/opsx-task/SKILL.md +38 -32
  63. package/templates/skills/kld-sdd/opsx-task/checklist.md +5 -6
  64. package/templates/skills/kld-sdd/opsx-test/SKILL.md +2 -0
  65. package/templates/skills/kld-sdd/tdd-rules/rules/tdd-strategy-selection.md +1 -1
@@ -26,11 +26,17 @@ function isGitRepo(dir) {
26
26
 
27
27
  function looksLikeSpecRepo(dir) {
28
28
  const name = path.basename(dir).toLowerCase();
29
+ // 命名约定:*-sdd-specs 目录名直接命中
29
30
  if (/-sdd-specs$/.test(name) || name.endsWith('sdd-specs')) return true;
30
- if (fs.existsSync(path.join(dir, 'modules.yaml'))) return true;
31
- if (fs.existsSync(path.join(dir, 'openspec', 'changes'))) return true;
32
- if (fs.existsSync(path.join(dir, 'openspec', 'specs', 'overview.md'))) return true;
33
- return false;
31
+ // 结构判据(四项同时满足):
32
+ // modules.yaml(模块登记)+ sdd.config.yaml(活动变更登记)
33
+ // + openspec/changes(变更结构)+ openspec/specs/overview.md(全局契约)
34
+ return (
35
+ fs.existsSync(path.join(dir, 'modules.yaml'))
36
+ && fs.existsSync(path.join(dir, 'sdd.config.yaml'))
37
+ && fs.existsSync(path.join(dir, 'openspec', 'changes'))
38
+ && fs.existsSync(path.join(dir, 'openspec', 'specs', 'overview.md'))
39
+ );
34
40
  }
35
41
 
36
42
  function listChildGitRepos(workspaceRoot) {
@@ -231,7 +237,10 @@ function findNestedSpecPackage(parentDir) {
231
237
  function ensureSpecPackage(parentDir, options = {}) {
232
238
  const { execFileSync } = require('child_process');
233
239
  const root = path.resolve(parentDir);
234
- const existing = findNestedSpecPackage(root);
240
+ // 显式指定目录名(--spec-path)时,以该路径为准,不再回退到"探测到的其它 spec 包",
241
+ // 避免用户想指定 erp-sdd-specs 却被同级已存在的 *-sdd-specs 抢占。
242
+ const explicit = Boolean(options.name);
243
+ const existing = explicit ? null : findNestedSpecPackage(root);
235
244
  if (existing) {
236
245
  return {
237
246
  name: existing.name,
@@ -243,6 +252,17 @@ function ensureSpecPackage(parentDir, options = {}) {
243
252
 
244
253
  const name = options.name || deriveSpecPackageName(root);
245
254
  const abs = path.join(root, name);
255
+
256
+ // 显式路径且该目录本身已存在并具备 spec 包特征 → 直接复用(幂等)
257
+ if (explicit && fs.existsSync(abs) && looksLikeSpecRepo(abs)) {
258
+ return {
259
+ name,
260
+ abs,
261
+ created: false,
262
+ isGit: isGitRepo(abs),
263
+ };
264
+ }
265
+
246
266
  const existed = fs.existsSync(abs);
247
267
  fs.mkdirSync(abs, { recursive: true });
248
268
 
@@ -273,7 +273,8 @@ function normalizeEvidenceSummary(report) {
273
273
  })),
274
274
  ];
275
275
  const issueByKey = new Map();
276
- history.map(normalizeIssue).forEach((issue) => {
276
+ // 显式只传元素,避免 map index/array 参数透传(S6544 类)
277
+ history.map(issue => normalizeIssue(issue)).forEach((issue) => {
277
278
  const stableKey = issue.issue_id
278
279
  || `${issue.code}:${issue.task_id || issue.pair_id || issue.subject || 'change'}`;
279
280
  const previous = issueByKey.get(stableKey);
@@ -369,8 +370,8 @@ function normalizeChangedFiles(changedFiles = {}) {
369
370
  ?? null;
370
371
  const taskSet = new Set(taskEventFiles || []);
371
372
  const finalSet = new Set(finalOutputFiles || []);
372
- const onlyInTaskEvents = [...taskSet].filter(file => !finalSet.has(file)).sort();
373
- const onlyInFinalOutput = [...finalSet].filter(file => !taskSet.has(file)).sort();
373
+ const onlyInTaskEvents = [...taskSet].filter(file => !finalSet.has(file)).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
374
+ const onlyInFinalOutput = [...finalSet].filter(file => !taskSet.has(file)).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
374
375
  const countsDiffer = taskCount != null && finalCount != null && taskCount !== finalCount;
375
376
  const listsDiffer = taskEventFiles != null
376
377
  && finalOutputFiles != null
@@ -4,25 +4,24 @@
4
4
  # 删除某行 = 禁用该插件
5
5
  # marker: KLD SDD quality gate
6
6
 
7
- # hook 所在目录推算 git 根目录
8
- hook_dir="$(cd "$(dirname "$0")" && pwd)"
9
- git_dir="$(dirname "$hook_dir")"
10
- git_root="$(dirname "$git_dir")"
11
-
7
+ # Git supplies the working tree context; this also supports worktrees and core.hooksPath.
8
+ git_root=$(git rev-parse --show-toplevel 2>/dev/null) || {
9
+ echo "[SDD] 无法定位当前 Git 工作区"
10
+ exit 1
11
+ }
12
12
  hooks_dir=""
13
-
14
- # 方法1: git config sdd.specPath(多仓布局:spec 是独立 clone)
15
- spec_path=$(git config --local sdd.specPath 2>/dev/null)
16
- if [ -n "$spec_path" ] && [ -d "$spec_path/skywalk-sdd/git-hooks" ]; then
13
+ spec_path=$(git -C "$git_root" config --local sdd.specPath 2>/dev/null)
14
+ if [ -n "$spec_path" ]; then
15
+ case "$spec_path" in /*) ;; *) spec_path="$git_root/$spec_path" ;; esac
17
16
  hooks_dir="$spec_path/skywalk-sdd/git-hooks"
17
+ elif [ -f "$git_root/.sdd-spec-root" ]; then
18
+ spec_rel=$(head -1 "$git_root/.sdd-spec-root" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
19
+ case "$spec_rel" in /*) hooks_dir="$spec_rel/skywalk-sdd/git-hooks" ;; *) hooks_dir="$git_root/$spec_rel/skywalk-sdd/git-hooks" ;; esac
18
20
  fi
19
-
20
- # 方法2: .sdd-spec-root(单仓 mono 布局:skywalk-sdd 在 spec 包裹包子目录内)
21
- if [ -z "$hooks_dir" ] && [ -f "$git_root/.sdd-spec-root" ]; then
22
- spec_rel=$(cat "$git_root/.sdd-spec-root" | head -1 | tr -d '[:space:]')
23
- if [ -n "$spec_rel" ] && [ -d "$git_root/$spec_rel/skywalk-sdd/git-hooks" ]; then
24
- hooks_dir="$git_root/$spec_rel/skywalk-sdd/git-hooks"
25
- fi
21
+ if [ -n "$hooks_dir" ] && [ ! -d "$hooks_dir" ]; then
22
+ echo "[SDD] 已配置的 Spec 路径失效:$hooks_dir"
23
+ echo "[SDD] 请恢复 Spec 仓,或修正 sdd.specPath / .sdd-spec-root 后重试"
24
+ exit 1
26
25
  fi
27
26
 
28
27
  # 方法3: 从 git 根向上搜索 skywalk-sdd/git-hooks(spec 仓本身或父级)
@@ -51,8 +50,9 @@ else
51
50
  # 读取 [commit-msg] 段落的配置
52
51
  in_section=0
53
52
  SCRIPTS=""
53
+ CR=$(printf '\r')
54
54
  while IFS= read -r line; do
55
- line=$(printf '%s' "$line" | tr -d '\r')
55
+ line=${line%"$CR"}
56
56
  case "$line" in
57
57
  "[commit-msg]") in_section=1 ;;
58
58
  "["*) in_section=0 ;;
@@ -71,7 +71,8 @@ failed=0
71
71
  for script_name in $SCRIPTS; do
72
72
  script="$hooks_dir/$script_name"
73
73
  if [ ! -f "$script" ]; then
74
- echo "[SDD] ⚠️ 插件不存在:$script_name"
74
+ echo "[SDD] ❌ 已配置的插件不存在:$script_name"
75
+ failed=$((failed + 1))
75
76
  continue
76
77
  fi
77
78
  executed=$((executed + 1))
@@ -79,11 +80,11 @@ for script_name in $SCRIPTS; do
79
80
  node "$script" "$1" --project="$git_root" || failed=$((failed + 1))
80
81
  done
81
82
 
82
- if [ "$executed" -eq 0 ]; then
83
- echo "[SDD] 无 commit-msg 插件,跳过"
84
- elif [ "$failed" -gt 0 ]; then
83
+ if [ "$failed" -gt 0 ]; then
85
84
  echo "[SDD] ❌ 共执行 $executed 个 commit-msg 插件,$failed 个失败"
86
85
  exit 1
86
+ elif [ "$executed" -eq 0 ]; then
87
+ echo "[SDD] 配置已禁用 commit-msg 插件"
87
88
  else
88
89
  echo "[SDD] ✅ 共执行 $executed 个 commit-msg 插件,全部通过"
89
90
  fi