kld-sdd 2.6.16 → 2.6.17

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 (58) hide show
  1. package/lib/init.js +65 -6
  2. package/lib/skills-bundle.js +20 -1
  3. package/lib/tool-profiles.js +8 -0
  4. package/package.json +5 -1
  5. package/skywalk-sdd/apply-worktree-finish.cjs +2 -23
  6. package/skywalk-sdd/context-client.cjs +38 -87
  7. package/skywalk-sdd/index.cjs +719 -108
  8. package/skywalk-sdd/kb-sync-identity.cjs +780 -0
  9. package/skywalk-sdd/kb-upload.cjs +505 -0
  10. package/skywalk-sdd/lib/shared.cjs +663 -0
  11. package/skywalk-sdd/metrics-v3.cjs +138 -8
  12. package/skywalk-sdd/ontology/archive-package.cjs +19 -34
  13. package/skywalk-sdd/ontology/change-lock.cjs +3 -7
  14. package/skywalk-sdd/ontology/external-key.cjs +18 -4
  15. package/skywalk-sdd/ontology/id.cjs +26 -5
  16. package/skywalk-sdd/ontology/identity-index.cjs +3 -7
  17. package/skywalk-sdd/ontology/resolve-spec-root.cjs +20 -6
  18. package/skywalk-sdd/ontology/runtime.cjs +16 -12
  19. package/skywalk-sdd/ontology/traceability-validator.cjs +7 -4
  20. package/skywalk-sdd/reporting/change-report-markdown.cjs +137 -19
  21. package/skywalk-sdd/reporting/change-report-model.cjs +993 -14
  22. package/skywalk-sdd/reporting/change-report-renderer.cjs +106 -41
  23. package/skywalk-sdd/reporting/change-report-view-model.cjs +272 -43
  24. package/skywalk-sdd/reporting/core-metric-definitions.cjs +192 -0
  25. package/skywalk-sdd/spec-root.cjs +31 -0
  26. package/templates/hooks/codebuddy/hooks/hook-gate-core.cjs +327 -0
  27. package/templates/hooks/codebuddy/hooks/sdd-apply-test-gate.cjs +54 -9
  28. package/templates/hooks/codebuddy/hooks/sdd-mid-checkpoint.cjs +63 -6
  29. package/templates/hooks/codebuddy/hooks/sdd-tdd-rhythm-gate.cjs +113 -65
  30. package/templates/openspec/proposal.md +7 -3
  31. package/templates/openspec/spec.md +3 -3
  32. package/templates/skills/kld-sdd/opsx-apply/SKILL.md +8 -6
  33. package/templates/skills/kld-sdd/opsx-apply/checklist.md +2 -0
  34. package/templates/skills/kld-sdd/opsx-apply/reference.md +29 -7
  35. package/templates/skills/kld-sdd/opsx-archive/SKILL.md +6 -5
  36. package/templates/skills/kld-sdd/opsx-check/SKILL.md +48 -16
  37. package/templates/skills/kld-sdd/opsx-check/checklist.md +4 -2
  38. package/templates/skills/kld-sdd/opsx-design/SKILL.md +2 -2
  39. package/templates/skills/kld-sdd/opsx-explore/SKILL.md +2 -2
  40. package/templates/skills/kld-sdd/opsx-kb-config/SKILL.md +164 -0
  41. package/templates/skills/kld-sdd/opsx-kb-config/reference.md +116 -0
  42. package/templates/skills/kld-sdd/opsx-kb-ingest/SKILL.md +218 -53
  43. package/templates/skills/kld-sdd/opsx-kb-ingest/reference.md +51 -9
  44. package/templates/skills/kld-sdd/opsx-ontology-query/SKILL.md +12 -50
  45. package/templates/skills/kld-sdd/opsx-ontology-query/phase-3-postchange.md +2 -2
  46. package/templates/skills/kld-sdd/opsx-ontology-query/reference.md +1 -1
  47. package/templates/skills/kld-sdd/opsx-propose/SKILL.md +35 -23
  48. package/templates/skills/kld-sdd/opsx-propose/checklist.md +2 -0
  49. package/templates/skills/kld-sdd/opsx-propose/reference.md +22 -17
  50. package/templates/skills/kld-sdd/opsx-rules/SKILL.md +2 -2
  51. package/templates/skills/kld-sdd/opsx-spec/SKILL.md +19 -15
  52. package/templates/skills/kld-sdd/opsx-spec/checklist.md +2 -0
  53. package/templates/skills/kld-sdd/opsx-task/SKILL.md +2 -4
  54. package/templates/skills/kld-sdd/opsx-test/SKILL.md +2 -2
  55. package/templates/skills/kld-sdd/tdd-core/reference.md +1 -1
  56. package/templates/skills/kld-sdd/tdd-rules/rules/test-skeleton-telemetry.md +1 -1
  57. package/templates/skills/kld-sdd/opsx-kb-ingest/state.example.json +0 -7
  58. package/templates/skills/kld-sdd/opsx-ontology-query/state.example.json +0 -7
@@ -1,6 +1,32 @@
1
1
  'use strict';
2
2
 
3
3
  const { buildChangeReportViewModel } = require('./change-report-view-model.cjs');
4
+ const { buildChangeReportModel } = require('./change-report-model.cjs');
5
+
6
+ function escapeMarkdownText(value) {
7
+ return String(value)
8
+ .replace(/&/g, '&')
9
+ .replace(/\\/g, '\')
10
+ .replace(/\[/g, '[')
11
+ .replace(/\]/g, ']')
12
+ .replace(/`/g, '`')
13
+ .replace(/</g, '&lt;')
14
+ .replace(/>/g, '&gt;')
15
+ .replace(/"/g, '&quot;')
16
+ .replace(/'/g, '&#39;')
17
+ .replace(/[\r\n]+/g, ' ');
18
+ }
19
+
20
+ function sanitizeMarkdownValue(value) {
21
+ if (typeof value === 'string') return escapeMarkdownText(value);
22
+ if (Array.isArray(value)) return value.map(sanitizeMarkdownValue);
23
+ if (!value || typeof value !== 'object') return value;
24
+ const sanitized = {};
25
+ for (const [key, item] of Object.entries(value)) {
26
+ sanitized[escapeMarkdownText(key)] = sanitizeMarkdownValue(item);
27
+ }
28
+ return sanitized;
29
+ }
4
30
 
5
31
  function formatValue(value) {
6
32
  if (value == null || value === '') return '暂无数据';
@@ -12,6 +38,59 @@ function formatRatioToPercent(ratio) {
12
38
  return `${(Number(ratio) * 100).toFixed(1)}%`;
13
39
  }
14
40
 
41
+ function renderMetricDetail(detail) {
42
+ if (!detail) return [];
43
+ const lines = [
44
+ '',
45
+ `### ${detail.name}(${detail.code})`,
46
+ '',
47
+ `- 指标定义:${detail.definition}`,
48
+ `- 指标用途:${detail.purpose}`,
49
+ `- 计算公式:${detail.formula}`,
50
+ `- 数据来源:${detail.source_description}`,
51
+ `- 对应方案:${detail.scheme_reference}`,
52
+ '',
53
+ '#### 本次原始数据',
54
+ ];
55
+ const inputs = detail.raw_inputs || [];
56
+ if (inputs.length === 0) {
57
+ lines.push('- 暂无可展示的原始数据。');
58
+ } else {
59
+ for (const input of inputs) {
60
+ const value = input.display_value ?? input.value ?? '暂无数据';
61
+ const inclusion = input.included === false
62
+ ? `;不计入公式:${input.exclusion_reason || '仅作辅助说明'}`
63
+ : '';
64
+ lines.push(`- ${input.label}:${value}(来源:${input.source || '未记录'}${inclusion})`);
65
+ }
66
+ }
67
+ lines.push('', '#### 计算步骤');
68
+ for (const step of detail.calculation_steps || ['暂无可复算步骤。']) {
69
+ lines.push(`- ${step}`);
70
+ }
71
+ lines.push(
72
+ '',
73
+ '#### 本次结果',
74
+ `- ${detail.result?.display_value || '暂无数据'}`,
75
+ `- 可信度:${detail.trust?.explanation || '未记录'}`,
76
+ '',
77
+ '#### 证据与限制',
78
+ );
79
+ const evidence = detail.evidence || [];
80
+ if (evidence.length === 0) {
81
+ lines.push('- 当前没有可定位的证据编号;计算值可能来自兼容字段。');
82
+ } else {
83
+ for (const item of evidence) {
84
+ lines.push(`- ${item.path || item.event_id || item.type || '证据'}${item.count == null ? '' : `(${item.count} 条)`}`);
85
+ for (const scenario of item.scenarios || []) {
86
+ lines.push(` - 场景:${scenario.title || '未命名'}(第 ${scenario.line ?? '未知'} 行)`);
87
+ }
88
+ }
89
+ }
90
+ for (const caveat of detail.caveats || []) lines.push(`- ${caveat}`);
91
+ return lines;
92
+ }
93
+
15
94
  function renderSectionOverview(section, report) {
16
95
  const minSet = report.minimum_metric_set || {};
17
96
  const lines = [
@@ -47,7 +126,7 @@ function renderSectionOverview(section, report) {
47
126
 
48
127
  function renderSectionMetrics(section, report) {
49
128
  const tdd = section.tdd_pairs || {};
50
- const reasons = report.metrics?.process?.rework_summary?.reasons;
129
+ const reasons = report.metric_details?.p_r?.raw_values?.reasons;
51
130
  const lines = [
52
131
  `## ${section.title}`,
53
132
  '',
@@ -58,9 +137,12 @@ function renderSectionMetrics(section, report) {
58
137
  for (const metric of section.metric_cards || []) {
59
138
  lines.push(`- ${metric.name}(${metric.code}):${metric.value} · ${metric.state}`);
60
139
  }
61
- if (reasons?.by_category) {
62
- const parts = Object.entries(reasons.by_category)
63
- .map(([k, v]) => `${k}=${v}`)
140
+ for (const metric of section.metric_cards || []) {
141
+ lines.push(...renderMetricDetail(metric.detail));
142
+ }
143
+ if (reasons) {
144
+ const parts = Object.values(reasons)
145
+ .map(item => `${item.label}=${item.count}`)
64
146
  .join(', ');
65
147
  lines.push(`- 重复执行原因分布:${parts || '无'}`);
66
148
  }
@@ -97,6 +179,11 @@ function renderSectionIssues(section, report) {
97
179
  '',
98
180
  section.summary,
99
181
  '',
182
+ '### 这些内容是怎么收集的',
183
+ `- ${section.collection_method}`,
184
+ `- 功能验证:${section.functional_result?.summary || '未记录'}${section.functional_result?.explanation ? ` ${section.functional_result.explanation}` : ''}`,
185
+ `- 证据链判断:${section.traceability_result?.summary || '未记录'}${section.traceability_result?.explanation ? ` ${section.traceability_result.explanation}` : ''}`,
186
+ '',
100
187
  ];
101
188
  const audit = section.task_evidence_audit || {};
102
189
  if (audit.direct_test_backlink || audit.strict_test_coverage) {
@@ -129,7 +216,7 @@ function renderSectionIssues(section, report) {
129
216
  lines.push('', '### 问题明细');
130
217
  for (const issue of issues) {
131
218
  lines.push(
132
- `- [${issue.code}] ${issue.subject || '本次变更'} · 状态:${issue.status} · 判定:${issue.verdict}`,
219
+ `- [${issue.code}] ${issue.subject || '本次变更'} · 状态:${issue.status_label || issue.status}`,
133
220
  ` - 根因:${issue.root_cause}`,
134
221
  ` - 预期:${issue.expected}`,
135
222
  ` - 实际:${issue.actual}`,
@@ -150,7 +237,7 @@ function renderSectionIssues(section, report) {
150
237
  if (dispositions.length > 0) {
151
238
  lines.push('', '### 告警处置');
152
239
  for (const item of dispositions) {
153
- lines.push(`- [告警处置] ${item.warning || item.code || 'UNKNOWN'}:${item.disposition || 'open'}`);
240
+ lines.push(`- [告警处置] ${item.warning || item.code || 'UNKNOWN'}:${item.disposition_label || '待处理'}`);
154
241
  }
155
242
  }
156
243
 
@@ -168,8 +255,16 @@ function renderSectionIssues(section, report) {
168
255
  lines.push(`- 警告:${warning.command || 'check'} 阶段 ${count} 个${statusLabel}`);
169
256
  if (items && items.length > 0) {
170
257
  for (const item of items) {
258
+ const itemStatus = ({
259
+ fixed: '已解决',
260
+ accepted: '已接受,保留观察',
261
+ waived: '已豁免,不阻断',
262
+ ignored: '不重要,已标记',
263
+ needs_input: '等待补充信息',
264
+ open: '待处理',
265
+ }[item.disposition] || statusLabel);
171
266
  lines.push(
172
- ` - ${item.description || '待确认项'}${item.target ? `(${item.target})` : ''}`,
267
+ ` - [${itemStatus}] ${item.description || '待确认项'}${item.target ? `(${item.target})` : ''}`,
173
268
  );
174
269
  }
175
270
  }
@@ -178,12 +273,12 @@ function renderSectionIssues(section, report) {
178
273
  lines.push('- 无警告(无需修复)');
179
274
  }
180
275
 
181
- const notes = report.process_notes || {};
276
+ const notes = section.process_notes || {};
182
277
  lines.push('', '## 过程记录');
183
278
  lines.push(`- 数据可用:${notes._available ? '是' : '否'}`);
184
279
  lines.push(`- 过程事件总数:${notes.total ?? 'null'}`);
185
280
  if (notes.by_kind) {
186
- lines.push(`- 按 kind 分布:${JSON.stringify(notes.by_kind)}`);
281
+ lines.push(`- 按类型分布:${JSON.stringify(notes.by_kind)}`);
187
282
  }
188
283
  if (Array.isArray(notes.notes) && notes.notes.length > 0) {
189
284
  for (const note of notes.notes) {
@@ -209,10 +304,34 @@ function renderSectionArtifacts(section, report) {
209
304
  '',
210
305
  '### 变更文件',
211
306
  `- 数据可用:${rawChanged._available ? '是' : '否'}`,
212
- `- 最终变更文件数:${formatValue(changed.files_changed)}`,
213
307
  `- 新增行数:${formatValue(changed.added_lines)}`,
214
- `- 对账状态:${formatValue(changed.reconciliation_status)}`,
308
+ `- 对账状态:${formatValue(changed.reconciliation_status_label)}`,
215
309
  ];
310
+ const taskScope = changed.task_scope || {};
311
+ const finalScope = changed.final_scope || {};
312
+ lines.push(
313
+ '',
314
+ `#### ${taskScope.label || '任务过程中涉及的文件'}`,
315
+ `- 口径说明:${taskScope.explanation || '汇总任务完成事件中记录的文件。'}`,
316
+ `- 文件数:${formatValue(taskScope.count)}`,
317
+ `- 文件清单:${Array.isArray(taskScope.files) ? (taskScope.files.join(', ') || '无') : '暂无数据'}`,
318
+ `- 来源:${formatValue(taskScope.source)};任务:${(taskScope.task_ids || []).join(', ') || '未记录'};最新记录时间:${formatValue(taskScope.latest_at)}`,
319
+ );
320
+ if ((taskScope.no_file_change_reasons || []).length > 0) {
321
+ for (const item of taskScope.no_file_change_reasons) {
322
+ lines.push(`- 未改文件说明:${item.task_id || '未标识任务'}:${item.reason || item}`);
323
+ }
324
+ }
325
+ lines.push(
326
+ '',
327
+ `#### ${finalScope.label || '最终实际交付的文件'}`,
328
+ `- 口径说明:${finalScope.explanation || '读取最后一次输出快照。'}`,
329
+ `- 文件数:${formatValue(finalScope.count)}`,
330
+ `- 文件清单:${Array.isArray(finalScope.files) ? (finalScope.files.join(', ') || '无') : '暂无数据'}`,
331
+ `- 来源:${formatValue(finalScope.source)};事件:${formatValue(finalScope.event_id)};快照时间:${formatValue(finalScope.captured_at)}`,
332
+ `- 未产生交付文件的原因:${formatValue(finalScope.no_output_reason)}`,
333
+ `- 行数统计说明:${finalScope.line_statistics_explanation || '未记录'}`,
334
+ );
216
335
  if ((changed.only_in_task_events || []).length > 0) {
217
336
  lines.push(`- 仅任务事件:${changed.only_in_task_events.join(', ')}`);
218
337
  }
@@ -237,12 +356,6 @@ function renderSectionArtifacts(section, report) {
237
356
  `- 迁移文件数:${Array.isArray(copied) ? copied.length : 'null'}`,
238
357
  );
239
358
  lines.push(
240
- '',
241
- '### 归因审计',
242
- `- 显式关联历史事件:${section.attribution_summary?.linked_source_event_count ?? 0}`,
243
- `- 有效关联:${section.attribution_summary?.active_link_count ?? 0}`,
244
- `- 未归属候选:${section.attribution_summary?.unassigned_candidate_count ?? 0}`,
245
- `- 被拒绝的跨变更碰撞:${section.attribution_summary?.rejected_collision_count ?? 0}`,
246
359
  '',
247
360
  '### 归档结果',
248
361
  `- 归档原因:${archive?.reason || 'null'}`,
@@ -261,15 +374,20 @@ function renderSectionArtifacts(section, report) {
261
374
  }
262
375
 
263
376
  function renderChangeReportMarkdown(report) {
264
- const view = buildChangeReportViewModel(report);
377
+ if (!report.change_summary || !report.artifacts?.files || !report.metric_details) {
378
+ report = buildChangeReportModel(report);
379
+ }
265
380
  const projectLabel = report.project_root
266
381
  ? String(report.project_root).replace(/[\\/]+$/, '').split(/[\\/]/).pop()
267
382
  : null;
383
+ const view = sanitizeMarkdownValue(buildChangeReportViewModel(report));
384
+ report = sanitizeMarkdownValue(report);
385
+ const safeProjectLabel = projectLabel ? escapeMarkdownText(projectLabel) : null;
268
386
  const lines = [
269
387
  `# SDD 效果度量报告${view.change ? ` - ${view.change}` : ''}`,
270
388
  '',
271
389
  `- 生成时间:${report.generated_at || '未知'}`,
272
- ...(projectLabel ? [`- 项目路径:${projectLabel}`] : []),
390
+ ...(safeProjectLabel ? [`- 项目路径:${safeProjectLabel}`] : []),
273
391
  `- 统计范围:change/${view.change || 'unknown'}`,
274
392
  `- 报告 Schema:${view.schema_version || 'unknown'}(指标契约 ${view.metrics_contract || 'unknown'})`,
275
393
  `<!-- sdd-semantic-digest:${view.semantic_digest} -->`,