@autobest-ui/agent 1.0.6 → 1.0.7
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/bin/sync-assets.test.mjs +11 -0
- package/bin/traceability-validators.test.mjs +209 -0
- package/package.json +2 -2
- package/plugins/autobest-delivery/README.md +5 -1
- package/plugins/autobest-delivery/mcp-server/src/runner.mjs +48 -0
- package/plugins/autobest-delivery/mcp-server/tests/runner.test.mjs +98 -0
- package/plugins/autobest-delivery/skills/code-audit/SKILL.md +3 -0
- package/plugins/autobest-delivery/skills/code-craft/SKILL.md +3 -3
- package/plugins/autobest-delivery/skills/delivery-loop/SKILL.md +4 -4
- package/plugins/autobest-delivery/skills/delivery-loop/references/delivery-contract.md +16 -1
- package/plugins/autobest-delivery/skills/e2e-gen-spec/SKILL.md +4 -0
- package/plugins/autobest-delivery/skills/e2e-ui-checker/SKILL.md +2 -0
- package/plugins/autobest-delivery/skills/export-report/SKILL.md +3 -0
- package/skills/README.md +5 -0
- package/skills/common/code-pr-submit/SKILL.md +7 -4
- package/skills/common/make-spec/SKILL.md +37 -0
- package/skills/common/make-spec/agents/openai.yaml +4 -0
- package/skills/common/make-spec/references/spec-schema.md +82 -0
- package/skills/common/make-spec/scripts/validate-spec-traceability.mjs +130 -0
- package/skills/common/review-from-docs/SKILL.md +33 -0
- package/skills/common/review-from-docs/agents/openai.yaml +4 -0
- package/skills/common/review-from-docs/references/review-result-schema.md +42 -0
- package/skills/common/review-from-docs/scripts/validate-review-traceability.mjs +91 -0
- package/skills/common/ui-prd-scope/SKILL.md +6 -3
- package/skills/common/ui-prd-scope/references/requirement-traceability.md +82 -0
- package/skills/common/ui-prd-scope/references/scope-schema.md +28 -1
- package/skills/common/ui-prd-scope/scripts/validate-scope-bundle.mjs +104 -0
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
```json
|
|
25
25
|
{
|
|
26
26
|
"schemaVersion": 1,
|
|
27
|
+
"traceabilitySchemaVersion": 1,
|
|
27
28
|
"prId": "<Azure PR ID>",
|
|
28
29
|
"prUrl": "<完整 PR 链接>",
|
|
29
30
|
"requestedPath": "<PR path 过滤条件或 null>",
|
|
@@ -33,6 +34,7 @@
|
|
|
33
34
|
{
|
|
34
35
|
"directory": "01-page-family",
|
|
35
36
|
"pageFamily": "<页面族>",
|
|
37
|
+
"requirementPrefix": "PF",
|
|
36
38
|
"decision": "<用户分类或合并/拆分依据>",
|
|
37
39
|
"sourceFiles": ["/Frontend_APP/..."],
|
|
38
40
|
"ragCoverage": {
|
|
@@ -41,7 +43,24 @@
|
|
|
41
43
|
"emptyErrors": "no-hit",
|
|
42
44
|
"permissions": "no-hit",
|
|
43
45
|
"crossPage": "not-applicable"
|
|
44
|
-
}
|
|
46
|
+
},
|
|
47
|
+
"requirements": [
|
|
48
|
+
{
|
|
49
|
+
"id": "REQ-PF-001",
|
|
50
|
+
"statement": "<可独立确认、实现和验收的需求>",
|
|
51
|
+
"status": "active",
|
|
52
|
+
"sourceRefs": [
|
|
53
|
+
{
|
|
54
|
+
"type": "azure-prd",
|
|
55
|
+
"path": "/Frontend_APP/...",
|
|
56
|
+
"section": "<章节>"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"figmaRefs": ["mobile-default.png#<节点或状态>"],
|
|
60
|
+
"ragRefs": ["<doc_id>#<规则>"],
|
|
61
|
+
"statusReason": null
|
|
62
|
+
}
|
|
63
|
+
]
|
|
45
64
|
}
|
|
46
65
|
],
|
|
47
66
|
"unmappedSources": [],
|
|
@@ -57,6 +76,8 @@
|
|
|
57
76
|
}
|
|
58
77
|
```
|
|
59
78
|
|
|
79
|
+
`traceabilitySchemaVersion: 1` 表示该范围包启用需求追踪。`00-global` 可不声明 `requirementPrefix` 和 `requirements`;其他 scope 必须声明。编号、生命周期和刷新规则以 [requirement-traceability.md](requirement-traceability.md) 为准。旧范围包未声明 `traceabilitySchemaVersion` 时仍按旧契约读取,但进入 `review-from-docs` 前必须由本 Skill 刷新。
|
|
80
|
+
|
|
60
81
|
每条 Figma 溯源记录必须指向 manifest 中已有的 scope 和实际存在的目标目录。默认使用 `operation: "copy"`,并要求源文件继续存在。只有用户明确要求移动时才能使用 `operation: "move"`。`operation: "legacy-move"` 与 `sourceStatus: "not-present-after-move"` 只用于审计本技能采用默认复制策略之前已移动的历史资产。
|
|
61
82
|
|
|
62
83
|
## 页面 Scope 模板
|
|
@@ -94,6 +115,12 @@
|
|
|
94
115
|
|
|
95
116
|
- <PRD 变更边界>
|
|
96
117
|
|
|
118
|
+
## 需求清单
|
|
119
|
+
|
|
120
|
+
| 需求 ID | 状态 | 需求陈述 | PRD 来源 | Figma 证据 | RAG 证据 | 状态原因 |
|
|
121
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
122
|
+
| `REQ-PF-001` | `active` | <可独立确认、实现和验收的需求> | `<路径>#<章节>` | `<文件>#<节点/状态>` 或 `无` | `<doc_id>#<规则>` 或 `无` | - |
|
|
123
|
+
|
|
97
124
|
## 范围外
|
|
98
125
|
|
|
99
126
|
- <明确排除或暂缓的页面>
|
|
@@ -19,6 +19,8 @@ const coverageStatuses = new Set([
|
|
|
19
19
|
'not-applicable',
|
|
20
20
|
'deferred-by-user'
|
|
21
21
|
]);
|
|
22
|
+
const requirementIdPattern = /^REQ-([A-Z][A-Z0-9]{1,15})-\d{3}$/;
|
|
23
|
+
const requirementStatuses = new Set(['active', 'deferred', 'removed']);
|
|
22
24
|
|
|
23
25
|
const fail = message => errors.push(message);
|
|
24
26
|
|
|
@@ -43,6 +45,12 @@ if (fs.existsSync(manifestPath)) {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
if (manifest) {
|
|
48
|
+
if (
|
|
49
|
+
manifest.traceabilitySchemaVersion !== undefined &&
|
|
50
|
+
manifest.traceabilitySchemaVersion !== 1
|
|
51
|
+
) {
|
|
52
|
+
fail('Manifest traceabilitySchemaVersion 仅支持 1');
|
|
53
|
+
}
|
|
46
54
|
for (const field of [
|
|
47
55
|
'schemaVersion',
|
|
48
56
|
'prId',
|
|
@@ -92,6 +100,9 @@ const scopeDirs = fs
|
|
|
92
100
|
if (scopeDirs.length === 0) fail('没有找到包含 scope.md 的页面目录');
|
|
93
101
|
|
|
94
102
|
const manifestScopes = new Map();
|
|
103
|
+
const manifestRequirementIds = new Set();
|
|
104
|
+
const manifestRequirementPrefixes = new Set();
|
|
105
|
+
const traceabilityEnabled = manifest?.traceabilitySchemaVersion === 1;
|
|
95
106
|
if (manifest && Array.isArray(manifest.scopes)) {
|
|
96
107
|
for (const item of manifest.scopes) {
|
|
97
108
|
if (!item || typeof item.directory !== 'string') {
|
|
@@ -123,6 +134,55 @@ if (manifest && Array.isArray(manifest.scopes)) {
|
|
|
123
134
|
fail(`Manifest ${item.directory} 必须说明 RAG 暂缓原因`);
|
|
124
135
|
}
|
|
125
136
|
}
|
|
137
|
+
if (traceabilityEnabled && item.directory !== '00-global') {
|
|
138
|
+
if (!/^[A-Z][A-Z0-9]{1,15}$/.test(item.requirementPrefix || '')) {
|
|
139
|
+
fail(`Manifest ${item.directory} 的 requirementPrefix 格式无效`);
|
|
140
|
+
} else if (manifestRequirementPrefixes.has(item.requirementPrefix)) {
|
|
141
|
+
fail(`Manifest 包含重复 requirementPrefix:${item.requirementPrefix}`);
|
|
142
|
+
} else {
|
|
143
|
+
manifestRequirementPrefixes.add(item.requirementPrefix);
|
|
144
|
+
}
|
|
145
|
+
if (!Array.isArray(item.requirements) || item.requirements.length === 0) {
|
|
146
|
+
fail(`Manifest ${item.directory} 必须包含非空 requirements`);
|
|
147
|
+
} else {
|
|
148
|
+
for (const requirement of item.requirements) {
|
|
149
|
+
const id = requirement?.id;
|
|
150
|
+
const match = typeof id === 'string' ? id.match(requirementIdPattern) : null;
|
|
151
|
+
if (!match) {
|
|
152
|
+
fail(`Manifest ${item.directory} 包含无效需求 ID:${id}`);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (match[1] !== item.requirementPrefix) {
|
|
156
|
+
fail(`Manifest ${item.directory} 的 ${id} 与 requirementPrefix 不一致`);
|
|
157
|
+
}
|
|
158
|
+
if (manifestRequirementIds.has(id)) {
|
|
159
|
+
fail(`Manifest 包含重复需求 ID:${id}`);
|
|
160
|
+
}
|
|
161
|
+
manifestRequirementIds.add(id);
|
|
162
|
+
if (!requirement.statement || typeof requirement.statement !== 'string') {
|
|
163
|
+
fail(`Manifest ${item.directory} 的 ${id} 缺少 statement`);
|
|
164
|
+
}
|
|
165
|
+
if (!requirementStatuses.has(requirement.status)) {
|
|
166
|
+
fail(`Manifest ${item.directory} 的 ${id} 状态无效:${requirement.status}`);
|
|
167
|
+
}
|
|
168
|
+
if (!Array.isArray(requirement.sourceRefs) || requirement.sourceRefs.length === 0) {
|
|
169
|
+
fail(`Manifest ${item.directory} 的 ${id} 缺少 sourceRefs`);
|
|
170
|
+
} else if (requirement.sourceRefs.some(ref =>
|
|
171
|
+
!ref || ref.type !== 'azure-prd' || typeof ref.path !== 'string' || !ref.path
|
|
172
|
+
)) {
|
|
173
|
+
fail(`Manifest ${item.directory} 的 ${id} 包含无效 sourceRefs`);
|
|
174
|
+
}
|
|
175
|
+
for (const field of ['figmaRefs', 'ragRefs']) {
|
|
176
|
+
if (!Array.isArray(requirement[field])) {
|
|
177
|
+
fail(`Manifest ${item.directory} 的 ${id} 缺少数组字段 ${field}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (['deferred', 'removed'].includes(requirement.status) && !requirement.statusReason) {
|
|
181
|
+
fail(`Manifest ${item.directory} 的 ${id} 必须说明 statusReason`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
126
186
|
}
|
|
127
187
|
|
|
128
188
|
for (const dirName of scopeDirs) {
|
|
@@ -225,6 +285,50 @@ for (const dirName of scopeDirs) {
|
|
|
225
285
|
if (!content.includes('合并依据:')) {
|
|
226
286
|
fail(`${dirName}:缺少页面族合并依据`);
|
|
227
287
|
}
|
|
288
|
+
if (traceabilityEnabled && !/^## 需求清单$/m.test(content)) {
|
|
289
|
+
fail(`${dirName}:缺少“需求清单”`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (traceabilityEnabled && !isGlobal) {
|
|
294
|
+
const traceableScope = manifestScopes.get(dirName);
|
|
295
|
+
const expectedIds = new Set((traceableScope?.requirements || []).map(item => item.id));
|
|
296
|
+
const allFoundIds = [...content.matchAll(/\bREQ-[A-Z][A-Z0-9]{1,15}-\d{3}\b/g)].map(
|
|
297
|
+
match => match[0]
|
|
298
|
+
);
|
|
299
|
+
const foundIdSet = new Set(allFoundIds);
|
|
300
|
+
const requirementHeading = '## 需求清单';
|
|
301
|
+
const requirementStart = content.indexOf(requirementHeading);
|
|
302
|
+
const requirementEnd = content.indexOf(
|
|
303
|
+
'\n## ',
|
|
304
|
+
requirementStart + requirementHeading.length
|
|
305
|
+
);
|
|
306
|
+
const requirementSection = requirementStart === -1
|
|
307
|
+
? ''
|
|
308
|
+
: content.slice(
|
|
309
|
+
requirementStart + requirementHeading.length,
|
|
310
|
+
requirementEnd === -1 ? content.length : requirementEnd
|
|
311
|
+
);
|
|
312
|
+
const tableIds = [...requirementSection.matchAll(
|
|
313
|
+
/\bREQ-[A-Z][A-Z0-9]{1,15}-\d{3}\b/g
|
|
314
|
+
)].map(match => match[0]);
|
|
315
|
+
for (const id of expectedIds) {
|
|
316
|
+
if (!foundIdSet.has(id)) fail(`${dirName}:scope.md 缺少需求 ID ${id}`);
|
|
317
|
+
if (tableIds.filter(value => value === id).length !== 1) {
|
|
318
|
+
fail(`${dirName}:需求清单中的 ${id} 必须恰好出现一次`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
for (const id of foundIdSet) {
|
|
322
|
+
if (!expectedIds.has(id)) fail(`${dirName}:scope.md 包含 manifest 未声明的需求 ID ${id}`);
|
|
323
|
+
}
|
|
324
|
+
for (const requirement of traceableScope?.requirements || []) {
|
|
325
|
+
const row = requirementSection
|
|
326
|
+
.split('\n')
|
|
327
|
+
.find(line => line.includes(requirement.id));
|
|
328
|
+
if (row && !row.includes(`\`${requirement.status}\``)) {
|
|
329
|
+
fail(`${dirName}:需求清单中 ${requirement.id} 的状态与 manifest 不一致`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
228
332
|
}
|
|
229
333
|
|
|
230
334
|
for (const fields of [['Workspace', '工作区'], ['页面模块'], ['启动'], ['权限'], ['数据前置']]) {
|