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.
- package/lib/init.js +65 -6
- package/lib/skills-bundle.js +20 -1
- package/lib/tool-profiles.js +8 -0
- package/package.json +5 -1
- package/skywalk-sdd/apply-worktree-finish.cjs +2 -23
- package/skywalk-sdd/context-client.cjs +38 -87
- package/skywalk-sdd/index.cjs +719 -108
- package/skywalk-sdd/kb-sync-identity.cjs +780 -0
- package/skywalk-sdd/kb-upload.cjs +505 -0
- package/skywalk-sdd/lib/shared.cjs +663 -0
- package/skywalk-sdd/metrics-v3.cjs +138 -8
- package/skywalk-sdd/ontology/archive-package.cjs +19 -34
- package/skywalk-sdd/ontology/change-lock.cjs +3 -7
- package/skywalk-sdd/ontology/external-key.cjs +18 -4
- package/skywalk-sdd/ontology/id.cjs +26 -5
- package/skywalk-sdd/ontology/identity-index.cjs +3 -7
- package/skywalk-sdd/ontology/resolve-spec-root.cjs +20 -6
- package/skywalk-sdd/ontology/runtime.cjs +16 -12
- package/skywalk-sdd/ontology/traceability-validator.cjs +7 -4
- package/skywalk-sdd/reporting/change-report-markdown.cjs +137 -19
- package/skywalk-sdd/reporting/change-report-model.cjs +993 -14
- package/skywalk-sdd/reporting/change-report-renderer.cjs +106 -41
- package/skywalk-sdd/reporting/change-report-view-model.cjs +272 -43
- package/skywalk-sdd/reporting/core-metric-definitions.cjs +192 -0
- package/skywalk-sdd/spec-root.cjs +31 -0
- package/templates/hooks/codebuddy/hooks/hook-gate-core.cjs +327 -0
- package/templates/hooks/codebuddy/hooks/sdd-apply-test-gate.cjs +54 -9
- package/templates/hooks/codebuddy/hooks/sdd-mid-checkpoint.cjs +63 -6
- package/templates/hooks/codebuddy/hooks/sdd-tdd-rhythm-gate.cjs +113 -65
- package/templates/openspec/proposal.md +7 -3
- package/templates/openspec/spec.md +3 -3
- package/templates/skills/kld-sdd/opsx-apply/SKILL.md +8 -6
- package/templates/skills/kld-sdd/opsx-apply/checklist.md +2 -0
- package/templates/skills/kld-sdd/opsx-apply/reference.md +29 -7
- package/templates/skills/kld-sdd/opsx-archive/SKILL.md +6 -5
- package/templates/skills/kld-sdd/opsx-check/SKILL.md +48 -16
- package/templates/skills/kld-sdd/opsx-check/checklist.md +4 -2
- package/templates/skills/kld-sdd/opsx-design/SKILL.md +2 -2
- package/templates/skills/kld-sdd/opsx-explore/SKILL.md +2 -2
- package/templates/skills/kld-sdd/opsx-kb-config/SKILL.md +164 -0
- package/templates/skills/kld-sdd/opsx-kb-config/reference.md +116 -0
- package/templates/skills/kld-sdd/opsx-kb-ingest/SKILL.md +218 -53
- package/templates/skills/kld-sdd/opsx-kb-ingest/reference.md +51 -9
- package/templates/skills/kld-sdd/opsx-ontology-query/SKILL.md +12 -50
- package/templates/skills/kld-sdd/opsx-ontology-query/phase-3-postchange.md +2 -2
- package/templates/skills/kld-sdd/opsx-ontology-query/reference.md +1 -1
- package/templates/skills/kld-sdd/opsx-propose/SKILL.md +35 -23
- package/templates/skills/kld-sdd/opsx-propose/checklist.md +2 -0
- package/templates/skills/kld-sdd/opsx-propose/reference.md +22 -17
- package/templates/skills/kld-sdd/opsx-rules/SKILL.md +2 -2
- package/templates/skills/kld-sdd/opsx-spec/SKILL.md +19 -15
- package/templates/skills/kld-sdd/opsx-spec/checklist.md +2 -0
- package/templates/skills/kld-sdd/opsx-task/SKILL.md +2 -4
- package/templates/skills/kld-sdd/opsx-test/SKILL.md +2 -2
- package/templates/skills/kld-sdd/tdd-core/reference.md +1 -1
- package/templates/skills/kld-sdd/tdd-rules/rules/test-skeleton-telemetry.md +1 -1
- package/templates/skills/kld-sdd/opsx-kb-ingest/state.example.json +0 -7
- 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, '<')
|
|
14
|
+
.replace(/>/g, '>')
|
|
15
|
+
.replace(/"/g, '"')
|
|
16
|
+
.replace(/'/g, ''')
|
|
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.
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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.
|
|
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.
|
|
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 =
|
|
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(`-
|
|
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.
|
|
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
|
-
|
|
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
|
-
...(
|
|
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} -->`,
|