@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.
Files changed (27) hide show
  1. package/bin/sync-assets.test.mjs +11 -0
  2. package/bin/traceability-validators.test.mjs +209 -0
  3. package/package.json +2 -2
  4. package/plugins/autobest-delivery/README.md +5 -1
  5. package/plugins/autobest-delivery/mcp-server/src/runner.mjs +48 -0
  6. package/plugins/autobest-delivery/mcp-server/tests/runner.test.mjs +98 -0
  7. package/plugins/autobest-delivery/skills/code-audit/SKILL.md +3 -0
  8. package/plugins/autobest-delivery/skills/code-craft/SKILL.md +3 -3
  9. package/plugins/autobest-delivery/skills/delivery-loop/SKILL.md +4 -4
  10. package/plugins/autobest-delivery/skills/delivery-loop/references/delivery-contract.md +16 -1
  11. package/plugins/autobest-delivery/skills/e2e-gen-spec/SKILL.md +4 -0
  12. package/plugins/autobest-delivery/skills/e2e-ui-checker/SKILL.md +2 -0
  13. package/plugins/autobest-delivery/skills/export-report/SKILL.md +3 -0
  14. package/skills/README.md +5 -0
  15. package/skills/common/code-pr-submit/SKILL.md +7 -4
  16. package/skills/common/make-spec/SKILL.md +37 -0
  17. package/skills/common/make-spec/agents/openai.yaml +4 -0
  18. package/skills/common/make-spec/references/spec-schema.md +82 -0
  19. package/skills/common/make-spec/scripts/validate-spec-traceability.mjs +130 -0
  20. package/skills/common/review-from-docs/SKILL.md +33 -0
  21. package/skills/common/review-from-docs/agents/openai.yaml +4 -0
  22. package/skills/common/review-from-docs/references/review-result-schema.md +42 -0
  23. package/skills/common/review-from-docs/scripts/validate-review-traceability.mjs +91 -0
  24. package/skills/common/ui-prd-scope/SKILL.md +6 -3
  25. package/skills/common/ui-prd-scope/references/requirement-traceability.md +82 -0
  26. package/skills/common/ui-prd-scope/references/scope-schema.md +28 -1
  27. 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', '工作区'], ['页面模块'], ['启动'], ['权限'], ['数据前置']]) {