kld-sdd 2.6.21 → 2.7.8-1
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/README.md +12 -5
- package/USABILITY.md +84 -0
- package/bin/kld-sdd-init.js +3 -9
- package/kld-sdd-guide.html +16 -4
- package/lib/hook-gate-core.js +327 -0
- package/lib/init.js +241 -94
- package/lib/scale-thresholds.json +19 -0
- package/lib/skills-bundle.js +2 -1
- package/package.json +5 -3
- package/skywalk-sdd/context-client.cjs +50 -30
- package/skywalk-sdd/index.cjs +49 -16
- package/skywalk-sdd/kb-sync-identity.cjs +99 -451
- package/skywalk-sdd/kb-upload.cjs +67 -44
- package/skywalk-sdd/lib/git-identity.cjs +270 -0
- package/skywalk-sdd/lib/usage-contract.cjs +13 -81
- package/skywalk-sdd/lib/usage-reporter.cjs +235 -104
- package/skywalk-sdd/lib/user-config.cjs +21 -46
- package/skywalk-sdd/metrics-v3.cjs +2 -2
- package/skywalk-sdd/ontology/active-changes.cjs +2 -1
- package/skywalk-sdd/ontology/archive-package.cjs +1 -1
- package/skywalk-sdd/ontology/artifact-parser.cjs +8 -6
- package/skywalk-sdd/ontology/id.cjs +5 -4
- package/skywalk-sdd/ontology/identity-index.cjs +9 -4
- package/skywalk-sdd/ontology/list-changes.cjs +1 -1
- package/skywalk-sdd/ontology/runtime.cjs +7 -3
- package/skywalk-sdd/ontology/schema.cjs +2 -0
- package/skywalk-sdd/ontology/traceability-validator.cjs +74 -4
- package/skywalk-sdd/ontology/workspace-layout.cjs +25 -5
- package/skywalk-sdd/reporting/change-report-model.cjs +4 -3
- package/templates/git-hooks/commit-msg +71 -27
- package/templates/git-hooks/consistency-check-core.cjs +1087 -0
- package/templates/git-hooks/hooks.config +38 -0
- package/templates/git-hooks/pre-commit +62 -27
- package/templates/git-hooks/pre-commit-consistency-check.cjs +29 -332
- package/templates/git-hooks/pre-commit-sdd-check.cjs +98 -0
- package/templates/git-hooks/pre-push +70 -27
- package/templates/git-hooks/pre-push-consistency-check.cjs +61 -299
- package/templates/hooks/codebuddy/hooks/sdd-tdd-rhythm-gate.cjs +1 -1
- package/templates/openspec/tasks.md +3 -3
- package/templates/skills/kld-sdd/opsx-apply/SKILL.md +43 -6
- package/templates/skills/kld-sdd/opsx-apply/checklist.md +1 -1
- package/templates/skills/kld-sdd/opsx-apply/reference.md +1 -1
- package/templates/skills/kld-sdd/opsx-archive/SKILL.md +9 -13
- package/templates/skills/kld-sdd/opsx-check/SKILL.md +54 -328
- package/templates/skills/kld-sdd/opsx-check/checklist.md +7 -4
- package/templates/skills/kld-sdd/opsx-check/reference.md +58 -0
- package/templates/skills/kld-sdd/opsx-check/result-template.json +52 -0
- package/templates/skills/kld-sdd/opsx-check/reviewer.md +100 -0
- package/templates/skills/kld-sdd/opsx-consistency-check/SKILL.md +82 -451
- package/templates/skills/kld-sdd/opsx-consistency-check/{reference.md → references/reference.md} +0 -1
- package/templates/skills/kld-sdd/opsx-consistency-check/scripts/scripts.cjs +517 -0
- package/templates/skills/kld-sdd/opsx-design/SKILL.md +10 -30
- package/templates/skills/kld-sdd/opsx-design/checklist.md +3 -4
- package/templates/skills/kld-sdd/opsx-design/reference.md +1 -1
- package/templates/skills/kld-sdd/opsx-kb-ingest/SKILL.md +12 -74
- package/templates/skills/kld-sdd/opsx-ontology-query/SKILL.md +7 -5
- package/templates/skills/kld-sdd/opsx-ontology-query/phase-1-prechange.md +2 -2
- package/templates/skills/kld-sdd/opsx-ontology-query/reference.md +1 -1
- package/templates/skills/kld-sdd/opsx-propose/SKILL.md +28 -73
- package/templates/skills/kld-sdd/opsx-propose/checklist.md +8 -8
- package/templates/skills/kld-sdd/opsx-propose/interaction-policy.md +28 -0
- package/templates/skills/kld-sdd/opsx-propose/reference.md +12 -46
- package/templates/skills/kld-sdd/opsx-spec/SKILL.md +14 -61
- package/templates/skills/kld-sdd/opsx-spec/checklist.md +3 -3
- package/templates/skills/kld-sdd/opsx-task/SKILL.md +38 -32
- package/templates/skills/kld-sdd/opsx-task/checklist.md +5 -6
- package/templates/skills/kld-sdd/opsx-test/SKILL.md +2 -0
- package/templates/skills/kld-sdd/tdd-rules/rules/tdd-strategy-selection.md +1 -1
- package/lib/device-auth-cli.js +0 -130
- package/lib/device-auth.js +0 -345
- package/lib/init-account-binding.js +0 -108
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
loadKbState,
|
|
13
13
|
resolveKbParams,
|
|
14
14
|
stripBom,
|
|
15
|
+
httpGetJson,
|
|
15
16
|
} = require('./lib/shared.cjs');
|
|
16
17
|
|
|
17
18
|
// Re-export requestJson for external callers (API compatibility)
|
|
@@ -105,6 +106,7 @@ function buildPayload(args, mode) {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
async function retrieveContext(args = parseArgs(process.argv), env = process.env) {
|
|
109
|
+
if (args.offline) return unavailableContext('engineering_kb_offline', '本次使用本地上下文,未验证远程基线');
|
|
108
110
|
// 优先从共享 state 文件读取配置(与 opsx-ontology-query / opsx-kb-ingest 共用)
|
|
109
111
|
let stateConfig = {};
|
|
110
112
|
const stateFile = args['state-file'] || env.SDD_KB_STATE_FILE;
|
|
@@ -131,12 +133,17 @@ async function retrieveContext(args = parseArgs(process.argv), env = process.env
|
|
|
131
133
|
|
|
132
134
|
const { apiBase: kbApiBase, token: kbToken, spaceId: kbSpaceId, kbId: kbKbId, targets: kbTargets } = resolveKbParams(stateConfig, env);
|
|
133
135
|
|
|
136
|
+
if (Boolean(args['space-id']) !== Boolean(args['kb-id'])) throw new Error('请同时指定 --space-id 和 --kb-id');
|
|
137
|
+
const explicitSpace = args['space-id'] || env.ENGINEERING_KB_SPACE_ID;
|
|
138
|
+
const explicitKb = args['kb-id'] || env.ENGINEERING_KB_KB_ID;
|
|
139
|
+
if (Boolean(explicitSpace) !== Boolean(explicitKb)) throw new Error('请同时配置目标 spaceId 和 kbId');
|
|
140
|
+
if (kbTargets.length > 1 && !explicitSpace) throw new Error('配置了多个 KB,请用 --space-id 和 --kb-id 明确本次查询目标');
|
|
134
141
|
const apiBase = args['api-base'] || kbApiBase;
|
|
135
142
|
const token = args.token || kbToken;
|
|
136
|
-
const spaceId =
|
|
137
|
-
const kbId =
|
|
143
|
+
const spaceId = explicitSpace || kbSpaceId;
|
|
144
|
+
const kbId = explicitKb || kbKbId;
|
|
138
145
|
|
|
139
|
-
// --check-only
|
|
146
|
+
// --check-only performs an authenticated check against the selected KB.
|
|
140
147
|
// 用于 SDD 各阶段(propose/spec/design/task/check)统一检测 KB 可用性,消除相对路径歧义
|
|
141
148
|
if (args['check-only']) {
|
|
142
149
|
const missing = [];
|
|
@@ -145,31 +152,27 @@ async function retrieveContext(args = parseArgs(process.argv), env = process.env
|
|
|
145
152
|
if (!kbId) missing.push('kbId');
|
|
146
153
|
if (missing.length > 0) {
|
|
147
154
|
return {
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
...unavailableContext('engineering_kb_not_configured', 'KB 尚未配置,本地工作可以继续'),
|
|
156
|
+
configured: false,
|
|
150
157
|
missing,
|
|
151
|
-
hint: 'Run /opsx-kb-config to configure kb-state.json (in spec root)',
|
|
152
158
|
};
|
|
153
159
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
const endpoint = `${String(apiBase).replace(/\/+$/, '')}/v1/spaces/${encodeURIComponent(spaceId)}`
|
|
161
|
+
+ `/knowledge-bases/${encodeURIComponent(kbId)}/context/readiness`;
|
|
162
|
+
const response = await httpGetJson(endpoint, token, contextTimeout(args, env, 3000));
|
|
163
|
+
if (response?.code != null && response.code !== 0) throw new Error(response.message || 'KB readiness failed');
|
|
164
|
+
const readiness = response?.data || response;
|
|
165
|
+
if (readiness?.available !== true || readiness?.authorized !== true) throw new Error('KB 未返回有效的权限与就绪状态');
|
|
166
|
+
return { ...readiness, configured: true, api: apiBase, spaceId, kbId };
|
|
167
|
+
|
|
159
168
|
}
|
|
160
169
|
|
|
161
|
-
if (!spaceId || !kbId) {
|
|
162
|
-
return {
|
|
163
|
-
available: false,
|
|
164
|
-
advisory: true,
|
|
165
|
-
degraded: true,
|
|
166
|
-
reason: 'engineering_kb_not_configured',
|
|
167
|
-
hint: 'set ENGINEERING_KB_SPACE_ID and ENGINEERING_KB_KB_ID; do not fall back to local archive/',
|
|
168
|
-
};
|
|
170
|
+
if (!spaceId || !kbId || !token) {
|
|
171
|
+
return { ...unavailableContext('engineering_kb_not_configured', 'KB 尚未配置,本地工作可以继续'), configured: false };
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
const mode = String(args.mode || 'match').trim().toLowerCase() === 'resolve' ? 'resolve' : 'match';
|
|
172
|
-
const timeoutMs =
|
|
175
|
+
const timeoutMs = contextTimeout(args, env, 5000);
|
|
173
176
|
const payload = buildPayload(args, mode);
|
|
174
177
|
const data = await requestJson(
|
|
175
178
|
buildEndpoint(apiBase, spaceId, kbId, mode),
|
|
@@ -184,21 +187,38 @@ async function retrieveContext(args = parseArgs(process.argv), env = process.env
|
|
|
184
187
|
};
|
|
185
188
|
}
|
|
186
189
|
|
|
190
|
+
function contextTimeout(args, env, fallback) {
|
|
191
|
+
const timeout = Number(args.timeout || env.ENGINEERING_KB_TIMEOUT_MS || fallback);
|
|
192
|
+
if (!Number.isFinite(timeout) || timeout <= 0) throw new Error('timeout 必须是大于 0 的毫秒数');
|
|
193
|
+
return timeout;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function unavailableContext(reason, message) {
|
|
197
|
+
return {
|
|
198
|
+
available: false,
|
|
199
|
+
advisory: true,
|
|
200
|
+
degraded: true,
|
|
201
|
+
localWorkAllowed: true,
|
|
202
|
+
baselineVerified: false,
|
|
203
|
+
inheritanceAllowed: false,
|
|
204
|
+
reason,
|
|
205
|
+
message,
|
|
206
|
+
hint: '继续本地编写、检查和测试;保留已有身份与真实基线。发布前重新在线校验,不把历史参考当作 KB current。',
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
187
210
|
async function main() {
|
|
188
211
|
const args = parseArgs(process.argv);
|
|
212
|
+
let result;
|
|
189
213
|
try {
|
|
190
|
-
|
|
214
|
+
result = await retrieveContext(args);
|
|
191
215
|
} catch (error) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
degraded: true,
|
|
196
|
-
reason: 'engineering_kb_unavailable',
|
|
197
|
-
message: error.message,
|
|
198
|
-
hint: 'KB unavailable: continue degraded; never scan local archive/ for inheritance UUIDs',
|
|
199
|
-
}, null, 2));
|
|
200
|
-
if (args.strict) process.exitCode = 1;
|
|
216
|
+
const reason = /\b(401|403|Unauthorized|Forbidden)\b/.test(error.message)
|
|
217
|
+
? 'engineering_kb_access_denied' : 'engineering_kb_unavailable';
|
|
218
|
+
result = unavailableContext(reason, error.message);
|
|
201
219
|
}
|
|
220
|
+
console.log(JSON.stringify(result, null, 2));
|
|
221
|
+
if (args.strict && result.available !== true) process.exitCode = 1;
|
|
202
222
|
}
|
|
203
223
|
|
|
204
224
|
if (require.main === module) {
|
package/skywalk-sdd/index.cjs
CHANGED
|
@@ -244,7 +244,7 @@ function findActiveStage(projectRoot, criteria) {
|
|
|
244
244
|
const matchingStarts = [];
|
|
245
245
|
for (const changeDir of changeDirs) {
|
|
246
246
|
const dir = path.join(eventsDir, changeDir);
|
|
247
|
-
const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort().reverse();
|
|
247
|
+
const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)).reverse();
|
|
248
248
|
for (const file of files) {
|
|
249
249
|
const lines = fs.readFileSync(path.join(dir, file), 'utf-8').split('\n').filter(Boolean);
|
|
250
250
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
@@ -357,7 +357,7 @@ function discoverTaskFiles(projectRoot, changeName) {
|
|
|
357
357
|
return walkFiles(changeDir, filePath => {
|
|
358
358
|
const fileName = path.basename(filePath).toLowerCase();
|
|
359
359
|
return fileName === 'tasks.md' || fileName === 'task.md';
|
|
360
|
-
}).sort();
|
|
360
|
+
}).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
function checklistEntriesOutsideCodeFences(lines) {
|
|
@@ -587,7 +587,7 @@ function scanTaskCompletionForArchiveDir(projectRoot, changeName, archiveDir) {
|
|
|
587
587
|
const taskFiles = walkFiles(archiveDir, filePath => {
|
|
588
588
|
const fileName = path.basename(filePath).toLowerCase();
|
|
589
589
|
return fileName === 'tasks.md' || fileName === 'task.md';
|
|
590
|
-
}).sort();
|
|
590
|
+
}).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
591
591
|
return scanTaskCompletionFromFiles(normalizedRoot, changeName, taskFiles);
|
|
592
592
|
}
|
|
593
593
|
|
|
@@ -796,7 +796,7 @@ function collectSpecFiles(changeRoot) {
|
|
|
796
796
|
if (!changeRoot || !fs.existsSync(changeRoot)) return [];
|
|
797
797
|
const specsDir = path.join(changeRoot, 'specs');
|
|
798
798
|
if (fs.existsSync(specsDir) && fs.statSync(specsDir).isDirectory()) {
|
|
799
|
-
return walkFiles(specsDir, filePath => path.basename(filePath).toLowerCase() === 'spec.md').sort();
|
|
799
|
+
return walkFiles(specsDir, filePath => path.basename(filePath).toLowerCase() === 'spec.md').sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
800
800
|
}
|
|
801
801
|
const rootSpec = path.join(changeRoot, 'spec.md');
|
|
802
802
|
if (fs.existsSync(rootSpec)) return [rootSpec];
|
|
@@ -1503,7 +1503,7 @@ function readEventsRaw(dataDir, changeName) {
|
|
|
1503
1503
|
if (!fs.existsSync(dir)) return [];
|
|
1504
1504
|
|
|
1505
1505
|
const events = [];
|
|
1506
|
-
const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort();
|
|
1506
|
+
const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
1507
1507
|
for (const file of files) {
|
|
1508
1508
|
const lines = fs.readFileSync(path.join(dir, file), 'utf-8').split('\n').filter(Boolean);
|
|
1509
1509
|
for (const line of lines) {
|
|
@@ -4859,7 +4859,7 @@ function buildReport(projectRoot, events, options = {}) {
|
|
|
4859
4859
|
const scopedReport = scopeEventsForChangeReport(events, options.change);
|
|
4860
4860
|
events = scopedReport.events;
|
|
4861
4861
|
const archiveEvent = latestByTimestamp(events.filter(e => {
|
|
4862
|
-
return e.command === 'archive' && e.type === 'stage_end';
|
|
4862
|
+
return e.command === 'archive' && e.type === 'stage_end' && e.details?.archive_result;
|
|
4863
4863
|
}));
|
|
4864
4864
|
const gitCommitTimeline = resolveGitCommitTimeline(
|
|
4865
4865
|
events,
|
|
@@ -5475,7 +5475,8 @@ function cmdEnd(args, options = {}) {
|
|
|
5475
5475
|
command: args.command,
|
|
5476
5476
|
agent_type: args.agent || args['agent-type'],
|
|
5477
5477
|
};
|
|
5478
|
-
|
|
5478
|
+
// let:下方占位 change 迁移逻辑需要重新赋值 startEvent(const 会在运行时抛 TypeError)
|
|
5479
|
+
let startEvent = eventId
|
|
5479
5480
|
? searchEventInDataDir(dataDir, eventId)
|
|
5480
5481
|
: findActiveStage(projectRoot, activeCriteria);
|
|
5481
5482
|
if (!eventId && startEvent) {
|
|
@@ -5858,6 +5859,19 @@ function cmdEnd(args, options = {}) {
|
|
|
5858
5859
|
if (!options.silent) {
|
|
5859
5860
|
console.log(JSON.stringify(output, null, 2));
|
|
5860
5861
|
}
|
|
5862
|
+
// kld-usage-flush: stage_end 落库后冲刷 pending 队列(fire-and-forget,不产生新事件)。
|
|
5863
|
+
// 覆盖"start 时网络故障/无身份,end 时已恢复"的同会话补报场景;失败不影响 output 与退出码。
|
|
5864
|
+
// promise 以不可枚举属性挂返回对象供测试 await,JSON.stringify 输出不变。
|
|
5865
|
+
try {
|
|
5866
|
+
const { flushPendingUsage } = require('./lib/usage-reporter.cjs');
|
|
5867
|
+
const usageFlush = flushPendingUsage({ projectRoot }).catch(() => null);
|
|
5868
|
+
Object.defineProperty(output, 'usageFlush', {
|
|
5869
|
+
value: usageFlush,
|
|
5870
|
+
enumerable: false,
|
|
5871
|
+
writable: false,
|
|
5872
|
+
configurable: true,
|
|
5873
|
+
});
|
|
5874
|
+
} catch { /* flush 不可用不阻塞 */ }
|
|
5861
5875
|
return output;
|
|
5862
5876
|
}
|
|
5863
5877
|
|
|
@@ -5947,7 +5961,7 @@ function normalizeRepositoryRelativeFiles(files, {
|
|
|
5947
5961
|
}
|
|
5948
5962
|
normalized.push(raw);
|
|
5949
5963
|
}
|
|
5950
|
-
return [...new Set(normalized)].sort();
|
|
5964
|
+
return [...new Set(normalized)].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
5951
5965
|
}
|
|
5952
5966
|
|
|
5953
5967
|
function normalizeStrictCheckResult(details, result) {
|
|
@@ -6399,13 +6413,13 @@ function normalizeStrictTestResult(args, details) {
|
|
|
6399
6413
|
|
|
6400
6414
|
const taskId = String(args['task-id'] || args.task_id || input.task_id || '').trim();
|
|
6401
6415
|
const verifiedTaskIds = Array.isArray(input.verified_task_ids)
|
|
6402
|
-
? [...new Set(input.verified_task_ids.map(value => String(value || '').trim()).filter(Boolean))].sort()
|
|
6416
|
+
? [...new Set(input.verified_task_ids.map(value => String(value || '').trim()).filter(Boolean))].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
6403
6417
|
: [];
|
|
6404
6418
|
if (!taskId && verifiedTaskIds.length === 0) {
|
|
6405
6419
|
fail('E_STRICT_FIELD_REQUIRED: strict test_result 必须提供 task_id 或 verified_task_ids');
|
|
6406
6420
|
}
|
|
6407
6421
|
if (taskId && !verifiedTaskIds.includes(taskId)) verifiedTaskIds.push(taskId);
|
|
6408
|
-
verifiedTaskIds.sort();
|
|
6422
|
+
verifiedTaskIds.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
6409
6423
|
|
|
6410
6424
|
const normalized = {
|
|
6411
6425
|
run_id: requireStrictString(args['run-id'] || args.run_id || input.run_id, 'EVENT_RUN_ID_REQUIRED', 'run_id'),
|
|
@@ -7846,7 +7860,7 @@ function searchEventInDataDir(dataDir, eventId) {
|
|
|
7846
7860
|
|
|
7847
7861
|
for (const changeDir of changeDirs) {
|
|
7848
7862
|
const dir = path.join(eventsDir, changeDir);
|
|
7849
|
-
const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort().reverse();
|
|
7863
|
+
const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)).reverse();
|
|
7850
7864
|
for (const file of files) {
|
|
7851
7865
|
const lines = fs.readFileSync(path.join(dir, file), 'utf-8').split('\n').filter(Boolean);
|
|
7852
7866
|
for (const line of lines) {
|
|
@@ -7872,7 +7886,7 @@ function readAllEventEndsById(dataDir, eventId, changeName) {
|
|
|
7872
7886
|
|
|
7873
7887
|
const scanDir = (dir) => {
|
|
7874
7888
|
if (!fs.existsSync(dir)) return;
|
|
7875
|
-
const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort().reverse();
|
|
7889
|
+
const files = fs.readdirSync(dir).filter(f => f.endsWith('.jsonl')).sort((a, b) => (a < b ? -1 : a > b ? 1 : 0)).reverse();
|
|
7876
7890
|
for (const file of files) {
|
|
7877
7891
|
const lines = fs.readFileSync(path.join(dir, file), 'utf-8').split('\n').filter(Boolean);
|
|
7878
7892
|
for (const line of lines) {
|
|
@@ -8161,18 +8175,37 @@ function cmdSemanticScan(args) {
|
|
|
8161
8175
|
|
|
8162
8176
|
function cmdSemanticReconcile(args, options = {}) {
|
|
8163
8177
|
const context = semanticCommandContext(args);
|
|
8178
|
+
const started = process.hrtime.bigint();
|
|
8164
8179
|
const result = require('./ontology/runtime.cjs').reconcileChange(
|
|
8165
8180
|
context.projectRoot,
|
|
8166
8181
|
context.changeName,
|
|
8167
8182
|
{ profile: context.profile, markPending: Boolean(options.markPending) },
|
|
8168
8183
|
);
|
|
8169
|
-
|
|
8184
|
+
const payload = semanticResultPayload(result);
|
|
8185
|
+
if (options.includeTasks) {
|
|
8186
|
+
const semanticFinished = process.hrtime.bigint();
|
|
8187
|
+
// A review packet avoids another CLI launch and a parent-agent document scan.
|
|
8188
|
+
// It is fresh input metadata, never a cached approval or a substitute for review.
|
|
8189
|
+
payload.task_completion = scanTaskCompletion(context.projectRoot, context.changeName);
|
|
8190
|
+
payload.review_inputs = {
|
|
8191
|
+
change_dir: path.join(context.projectRoot, 'openspec', 'changes', context.changeName),
|
|
8192
|
+
files: result.state.files,
|
|
8193
|
+
identity_history_hash: result.state.identity_history_hash,
|
|
8194
|
+
};
|
|
8195
|
+
const finished = process.hrtime.bigint();
|
|
8196
|
+
payload.timings_ms = {
|
|
8197
|
+
semantic: Number(semanticFinished - started) / 1e6,
|
|
8198
|
+
tasks: Number(finished - semanticFinished) / 1e6,
|
|
8199
|
+
total: Number(finished - started) / 1e6,
|
|
8200
|
+
};
|
|
8201
|
+
}
|
|
8202
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
8170
8203
|
if (!result.valid) process.exitCode = 1;
|
|
8171
8204
|
return result;
|
|
8172
8205
|
}
|
|
8173
8206
|
|
|
8174
8207
|
function cmdSemanticCheck(args) {
|
|
8175
|
-
return cmdSemanticReconcile(args, { markPending: true });
|
|
8208
|
+
return cmdSemanticReconcile(args, { markPending: true, includeTasks: Boolean(args['include-tasks']) });
|
|
8176
8209
|
}
|
|
8177
8210
|
|
|
8178
8211
|
function cmdSemanticStatus(args) {
|
|
@@ -8463,7 +8496,7 @@ SDD Telemetry CLI - 流程度量采集工具
|
|
|
8463
8496
|
node skywalk-sdd/log.cjs semantic-identity --delta-state=modified --entity-id=<uuid> --predecessor-version=<uuid>
|
|
8464
8497
|
node skywalk-sdd/log.cjs semantic-identity --delta-state=unchanged --entity-id=<uuid> --version-id=<uuid>
|
|
8465
8498
|
node skywalk-sdd/log.cjs semantic-reconcile --project=<path> --change=<name> [--profile=auto|simple|full|strict]
|
|
8466
|
-
node skywalk-sdd/log.cjs semantic-check --project=<path> --change=<name> [--profile=...]
|
|
8499
|
+
node skywalk-sdd/log.cjs semantic-check --project=<path> --change=<name> [--profile=...] [--include-tasks]
|
|
8467
8500
|
node skywalk-sdd/log.cjs semantic-status --project=<path> --change=<name>
|
|
8468
8501
|
node skywalk-sdd/log.cjs semantic-observe --project=<path> --change=<name> [--interval=1500]
|
|
8469
8502
|
|
|
@@ -8481,7 +8514,7 @@ SDD Telemetry CLI - 流程度量采集工具
|
|
|
8481
8514
|
semantic-identity 生成或复用实体/版本 ID(8 位十六进制);无需网络和中央 ID 服务
|
|
8482
8515
|
semantic-scan 只读解析并校验当前 Change
|
|
8483
8516
|
semantic-reconcile 全量对账文件与本地工作态本体实例
|
|
8484
|
-
semantic-check 全量对账并在通过时标记 pending
|
|
8517
|
+
semantic-check 全量对账并在通过时标记 pending;--include-tasks 同时返回任务状态、评审输入清单和程序耗时
|
|
8485
8518
|
semantic-status 读取当前工作态本体实例
|
|
8486
8519
|
semantic-observe 观察文件变化并同步;不提供 Hook 式控制,Check/Archive 仍会全量对账
|
|
8487
8520
|
|