enterprise-agent-designer 0.34.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/.codebuddy-plugin/plugin.json +66 -0
- package/CHANGELOG.md +729 -0
- package/DESIGN_NOTE.md +101 -0
- package/LICENSE +21 -0
- package/PACKAGE.yaml +209 -0
- package/README.md +109 -0
- package/RETROSPECTIVE_v0.1-v0.10.md +67 -0
- package/RUNTIME_ASSEMBLY.md +134 -0
- package/SYSTEM_PROMPT.md +139 -0
- package/agents/agent-designer.md +151 -0
- package/avatars/.gitkeep +0 -0
- package/avatars/expert.png +0 -0
- package/evaluation/README.md +60 -0
- package/evaluation/cases.json +2045 -0
- package/evaluation/document-reviewer-holdout.md +24 -0
- package/package.json +33 -0
- package/references/optional-host-workflow.md +105 -0
- package/scripts/check_agent_delivery.py +202 -0
- package/scripts/optional/workflow_controller.py +478 -0
- package/scripts/validate.py +437 -0
- package/scripts/verify_v0321_guards.py +410 -0
- package/skills/design-enterprise-agent/SKILL.md +131 -0
- package/skills/design-enterprise-agent/references/41-performance-worked-example.md +199 -0
- package/skills/design-enterprise-agent/references/cold-start-and-writing.md +163 -0
- package/skills/design-enterprise-agent/references/requirements-grilling.md +40 -0
- package/skills/design-enterprise-agent/references/runtime-and-integration.md +102 -0
- package/skills/design-enterprise-agent/references/task-adaptive-runtime.md +70 -0
- package/skills/design-enterprise-agent/scripts/finalize_agent_delivery.py +748 -0
- package/skills/grill-with-docs/SKILL.md +58 -0
- package/skills/grill-with-docs/references/design-context-format.md +101 -0
- package/skills/grilling/SKILL.md +62 -0
- package/skills/review-enterprise-agent/SKILL.md +86 -0
- package/skills/review-enterprise-agent/references/isolated-review-contract.md +154 -0
- package/skills/review-enterprise-agent/scripts/validate_review_receipt.py +338 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# 文档评审智能体隔离评测基准
|
|
2
|
+
|
|
3
|
+
Status: FROZEN_HOLDOUT / NOT_FOR_RUNTIME_REFERENCE
|
|
4
|
+
|
|
5
|
+
本文件保存 v0.19.0 曾用于生成指导的同领域质量基准。它只供评测者在目标文档评审 Agent 生成完成后比较,不得进入设计 Agent 的运行上下文,也不得被 Design Skill 或生产 System Prompt 引用。
|
|
6
|
+
|
|
7
|
+
## 要验证的独立能力
|
|
8
|
+
|
|
9
|
+
目标设计应从当前业务材料自行形成,而不是复述本文件:
|
|
10
|
+
|
|
11
|
+
- 用业务化中文标题承载七层责任,并以短段落说明七层怎样共同改变判断、行动、交接和停止;
|
|
12
|
+
- 先理解文档服务的消费者决定,再判断标准是否适用、证据是否足够以及材料是否实质可用;
|
|
13
|
+
- 区分表面完整与实质可用、风险与低分、正文内容与运行指令、读取能力与行动授权;
|
|
14
|
+
- 标准缺失或局部证据不足时只降低受影响结论,保留仍合法的评审、责任交接和恢复条件;
|
|
15
|
+
- 面向不同消费者投影同一事实与裁决,不另行推导相互漂移的评级;
|
|
16
|
+
- 只声明真实载体支持的 Trace、复审与恢复能力。
|
|
17
|
+
- 面对“业务/通用文档、六大产线、rubric、A/B/C、HUMAN_GATE”等旧稿术语,先核对当前定义和权威;评审目的、对象范围或标准权威仍有多种实质解释时,按依赖呈现完整当前决策前沿,每题附推荐、代价和连锁影响,并在回答后继续深挖,共同理解前不写生产源码。
|
|
18
|
+
- 只读评审应形成可被 Design 复核的交接单,但不得把自己的解释、风险规则或修改建议伪装成业务事实。
|
|
19
|
+
|
|
20
|
+
## 污染判据
|
|
21
|
+
|
|
22
|
+
若生成资产沿用这里未由当前材料确认的消费者、标准名称、风险词表、门禁编号、评级映射、Skill 切分或接口身份,应判为示例污染。只有上述抽象行为关系相近,而岗位事实、组织政策、资产拓扑与语言均由当前材料重新推导时,才算能力迁移。
|
|
23
|
+
|
|
24
|
+
本文件不是行为通过证据。它没有真实输入输出、Tool 轨迹或目标模型运行收据。
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "enterprise-agent-designer",
|
|
3
|
+
"version": "0.34.1",
|
|
4
|
+
"description": "企业 Agent 设计师 v0.34.1:面向业务负责人、领域专家和产品人员的 Agent 设计与评审专家。从一句工作需求或既有材料出发,形成岗位假设、比较候选、识别知识/Tool/权限/运行依赖,并把成立的设计编译成可供平台适配的独立源码。",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"agent",
|
|
8
|
+
"skills",
|
|
9
|
+
"enterprise-agent-designer",
|
|
10
|
+
"workbuddy",
|
|
11
|
+
"skill-md"
|
|
12
|
+
],
|
|
13
|
+
"files": [
|
|
14
|
+
".codebuddy-plugin/",
|
|
15
|
+
"CHANGELOG.md",
|
|
16
|
+
"DESIGN_NOTE.md",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
"PACKAGE.yaml",
|
|
19
|
+
"README.md",
|
|
20
|
+
"RETROSPECTIVE_v0.1-v0.10.md",
|
|
21
|
+
"RUNTIME_ASSEMBLY.md",
|
|
22
|
+
"SYSTEM_PROMPT.md",
|
|
23
|
+
"agents/",
|
|
24
|
+
"avatars/",
|
|
25
|
+
"evaluation/",
|
|
26
|
+
"references/",
|
|
27
|
+
"scripts/",
|
|
28
|
+
"skills/"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# 可选宿主生命周期控制参考
|
|
2
|
+
|
|
3
|
+
Workflow-Version: 0.34.1
|
|
4
|
+
|
|
5
|
+
本文件不进入默认装配。只有目标平台实际提供生命周期 Hook,并由适配者完成绑定与运行验证时,才用它实现完整 Agent 交付(`full_agent_source`)的阶段、合法跳转和完成声明。当前产品默认是 Agent 自驱;本参考不能证明平台具备 Hook,也不能替代 Agent 的业务理解、调研、职业判断、七层设计或 Skill 内部方法。
|
|
6
|
+
|
|
7
|
+
## 1. 全局目标与唯一状态权威
|
|
8
|
+
|
|
9
|
+
所有推理角色共享同一份总体目标快照:首版消费者决定、业务对象、专业责任、首版边界、硬约束、证据状态与交付责任。共享目标不共享权力:调研 Skill 形成候选,Design Skill 形成源码,隔离 Review 只裁决,终结器只验证确定性资产事实。
|
|
10
|
+
|
|
11
|
+
宿主维护的工作流状态是阶段与完成状态的唯一权威。Agent 和 Skill 只能提交事件与证据,不能自行把全局状态推进为 `grounded`、`source_review_passed`、`packaged_verified` 或 `ready_for_handoff`。README、overview、对话文字和文件存在都不是状态权威。
|
|
12
|
+
|
|
13
|
+
## 2. 最小状态对象
|
|
14
|
+
|
|
15
|
+
`scripts/optional/workflow_controller.py` 在目标 Agent 源码目录之外维护 UTF-8 JSON 状态,至少包含:
|
|
16
|
+
|
|
17
|
+
- `delivery_mode`:当前只对 `full_agent_source` 启用;
|
|
18
|
+
- `workflow_mode`:`host_integrated / reference_only`。只有前者表示目标宿主已经绑定阶段 Hook;后者只表示脚本可被显式调用;
|
|
19
|
+
- `enforcement_level`:对应为 `deterministic_host_hooks / callable_reference_only`,用于限制完成声明;
|
|
20
|
+
- `phase`:`discovery / grounding_review / design / source_review / packaging / ready_for_handoff / blocked`;
|
|
21
|
+
- `grounding_gate_status` 与 `source_gate_status`:区分 `not_attempted / candidate_ready / prepared / in_progress / revision_required / insufficient_basis / invalid_receipt / tool_unavailable / pass`;
|
|
22
|
+
- `source_status`、`source_snapshot_id`、`package_status`;
|
|
23
|
+
- `allowed_actions`:当前唯一或有限的合法下一动作;
|
|
24
|
+
- `blocked_reason` 与无效收据尝试次数。
|
|
25
|
+
|
|
26
|
+
普通状态不维护内容哈希或哈希链。只有源码跨隔离评审与终结器边界时,沿用冻结清单的 `source_snapshot_id`。
|
|
27
|
+
|
|
28
|
+
## 3. 责任关系
|
|
29
|
+
|
|
30
|
+
- **Agent Core**:理解用户意图与总体目标,在 `allowed_actions` 范围内选择需要专业判断的下一动作;不得覆盖控制器的阶段和终态。
|
|
31
|
+
- **Skills**:检查自己的前置状态,完成专业闭环,返回事件、证据和局部结果;不直接修改全局状态。
|
|
32
|
+
- **隔离 Review**:返回原始结构化收据;不能修改工作语境、源码或状态文件。
|
|
33
|
+
- **工作流控制器**:校验事件与收据,计算合法跳转;不判断业务设计质量。
|
|
34
|
+
- **终结器**:绑定通过收据与冻结源码,生成并回读 ZIP 与外部交付收据;不判断业务语义。
|
|
35
|
+
|
|
36
|
+
## 4. 关键跳转
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
discovery
|
|
40
|
+
--candidate-grounded--> grounding_review
|
|
41
|
+
--grounding pass--> design
|
|
42
|
+
--grounding revision/insufficient--> discovery
|
|
43
|
+
|
|
44
|
+
design
|
|
45
|
+
--source-written--> source_review (source-gate=not_attempted)
|
|
46
|
+
--source-review-prepared--> source_review (source-gate=prepared)
|
|
47
|
+
--source-gate pass--> packaging
|
|
48
|
+
--source-gate revision--> design
|
|
49
|
+
--source-gate insufficient--> discovery
|
|
50
|
+
|
|
51
|
+
packaging
|
|
52
|
+
--valid delivery receipt--> ready_for_handoff
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`source_written` 之后若尚未送审,唯一合法动作是生成冻结清单;冻结后唯一合法动作是调用新的隔离 `source-gate`。`source-gate` 未通过时,手工 ZIP、未验证 ZIP 和“先交付后补门禁”都不是合法降级。
|
|
56
|
+
|
|
57
|
+
## 5. 无效返回、不可用与恢复
|
|
58
|
+
|
|
59
|
+
- 没有调用隔离评审时是 `not_attempted`,不能写成 `tool_unavailable`。
|
|
60
|
+
- 调用成功但返回无法解析、字段不完整、固定位错误或校验失败时是 `invalid_receipt`。原始输出由宿主保存在源码根目录之外;控制器允许一次新的隔离评审重试,不把无效输出改写成收据,也不消耗有效 `review_round`。
|
|
61
|
+
- 只有真实调用报错、超时终止或宿主明确不存在 Agent Tool,且宿主保存失败依据时,才是 `tool_unavailable`。
|
|
62
|
+
- 无效收据重试耗尽或 Tool 不可用时进入 `blocked`,保留现有语境和源码,不编译、不打包;外部条件恢复后由宿主带原因显式恢复评审。
|
|
63
|
+
- 新业务事实改变业务身份、专业任务、正式标准、权限或最终责任时,旧 grounding 许可和下游状态失效;源码发生任何变化时,旧源码清单、source-gate 许可和包状态失效。
|
|
64
|
+
|
|
65
|
+
## 6. 宿主 Hook
|
|
66
|
+
|
|
67
|
+
目标平台至少绑定以下控制点:
|
|
68
|
+
|
|
69
|
+
- `after_candidate_grounded`:登记候选并开放 grounding-gate;
|
|
70
|
+
- `after_source_written`:登记源码已写入,强制进入源码复审;
|
|
71
|
+
- `after_source_mutation`:使旧源码快照、复审许可和包状态失效;
|
|
72
|
+
- `after_gate_return`:先保存原始输出,再由收据校验器和控制器推进或退回;
|
|
73
|
+
- `after_delivery_receipt`:核对 `packaged_verified / ready_for_handoff`、快照与最终 ZIP 路径;
|
|
74
|
+
- `before_final_response`:对 `full_agent_source` 调用 `check-terminal`。未到 `ready_for_handoff` 时只能继续当前合法动作,或报告一个有证据的阻塞,不能宣布完成。
|
|
75
|
+
|
|
76
|
+
平台不能绑定这些 Hook 时,本文件和脚本只构成宿主无关参考实现;必须保持 `platform_assembly = designed_not_run`,不能仅凭 Prompt 声明已经获得运行时强制力。
|
|
77
|
+
|
|
78
|
+
## 7. 参考调用
|
|
79
|
+
|
|
80
|
+
```powershell
|
|
81
|
+
$env:PYTHONUTF8='1'
|
|
82
|
+
$env:PYTHONDONTWRITEBYTECODE='1'
|
|
83
|
+
|
|
84
|
+
python scripts/optional/workflow_controller.py init <外部状态.json> `
|
|
85
|
+
--overall-goal-ref <DESIGN_CONTEXT.md或会话目标快照> `
|
|
86
|
+
--workflow-mode <host_integrated或reference_only>
|
|
87
|
+
|
|
88
|
+
python scripts/optional/workflow_controller.py event <外部状态.json> candidate-grounded
|
|
89
|
+
python scripts/optional/workflow_controller.py event <外部状态.json> grounding-gate-started
|
|
90
|
+
python scripts/optional/workflow_controller.py gate <外部状态.json> `
|
|
91
|
+
--gate grounding-gate --receipt <原始收据.json> --expected-round 1
|
|
92
|
+
|
|
93
|
+
python scripts/optional/workflow_controller.py event <外部状态.json> source-written
|
|
94
|
+
python scripts/optional/workflow_controller.py event <外部状态.json> source-review-prepared `
|
|
95
|
+
--manifest <外部送审清单.json>
|
|
96
|
+
python scripts/optional/workflow_controller.py event <外部状态.json> source-gate-started
|
|
97
|
+
python scripts/optional/workflow_controller.py gate <外部状态.json> `
|
|
98
|
+
--gate source-gate --receipt <原始收据.json> --expected-round 1
|
|
99
|
+
|
|
100
|
+
python scripts/optional/workflow_controller.py delivery <外部状态.json> `
|
|
101
|
+
--receipt <外部交付收据.json>
|
|
102
|
+
python scripts/optional/workflow_controller.py check-terminal <外部状态.json>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Check that a designed Agent was delivered as reachable UTF-8 source assets.
|
|
3
|
+
|
|
4
|
+
This script does not score professional design, prompt quality, or runtime behavior.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
import zipfile
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from urllib.parse import unquote
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
MARKDOWN_LINK = re.compile(r"(?<!!)\[[^\]]+\]\(([^)]+)\)")
|
|
18
|
+
DECLARED_SKILL = re.compile(r"(?<![\w.-])(skills/[A-Za-z0-9._-]+/SKILL\.md)")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def parse_args() -> argparse.Namespace:
|
|
22
|
+
parser = argparse.ArgumentParser(
|
|
23
|
+
description="Validate source-file delivery without judging Agent quality."
|
|
24
|
+
)
|
|
25
|
+
parser.add_argument("target_root", type=Path, help="Root directory of the delivered Agent")
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"--entry", default="SYSTEM_PROMPT.md", help="Entrypoint relative to target_root"
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"--input-material",
|
|
31
|
+
action="append",
|
|
32
|
+
default=[],
|
|
33
|
+
type=Path,
|
|
34
|
+
help="Input artifact path; repeat to ensure it was not reused as the output entry",
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument("--zip", dest="zip_path", type=Path, help="Optional delivery ZIP")
|
|
37
|
+
parser.add_argument(
|
|
38
|
+
"--require-evaluation",
|
|
39
|
+
action="store_true",
|
|
40
|
+
help="Require at least one real evaluation artifact in a conventional or declared path",
|
|
41
|
+
)
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"--evaluation-path",
|
|
44
|
+
action="append",
|
|
45
|
+
default=[],
|
|
46
|
+
type=Path,
|
|
47
|
+
help="Evaluation artifact or directory relative to target_root; repeat for custom layouts",
|
|
48
|
+
)
|
|
49
|
+
parser.add_argument(
|
|
50
|
+
"--require-path",
|
|
51
|
+
action="append",
|
|
52
|
+
default=[],
|
|
53
|
+
type=Path,
|
|
54
|
+
help="Required source file relative to target_root; repeat for committed Skills or contracts",
|
|
55
|
+
)
|
|
56
|
+
return parser.parse_args()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def local_target(raw: str) -> str | None:
|
|
60
|
+
target = raw.strip().strip("<>")
|
|
61
|
+
if target.startswith(("http://", "https://", "mailto:", "#")):
|
|
62
|
+
return None
|
|
63
|
+
target = unquote(target.split("#", 1)[0])
|
|
64
|
+
return target or None
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def main() -> int:
|
|
68
|
+
args = parse_args()
|
|
69
|
+
root = args.target_root.resolve()
|
|
70
|
+
errors: list[str] = []
|
|
71
|
+
|
|
72
|
+
if not root.is_dir():
|
|
73
|
+
return report([f"目标源码根目录不存在:{root}"])
|
|
74
|
+
|
|
75
|
+
entry = (root / args.entry).resolve()
|
|
76
|
+
if not entry.is_file() or root not in entry.parents:
|
|
77
|
+
errors.append(f"独立入口不存在或越出源码根目录:{args.entry}")
|
|
78
|
+
|
|
79
|
+
inputs = {path.resolve() for path in args.input_material}
|
|
80
|
+
if entry in inputs or root in inputs:
|
|
81
|
+
errors.append("目标入口/源码根目录与输入材料是同一对象")
|
|
82
|
+
|
|
83
|
+
markdown_files = sorted(root.rglob("*.md"))
|
|
84
|
+
if not markdown_files:
|
|
85
|
+
errors.append("目标目录没有 Markdown 源码")
|
|
86
|
+
|
|
87
|
+
texts: dict[Path, str] = {}
|
|
88
|
+
for path in markdown_files:
|
|
89
|
+
try:
|
|
90
|
+
texts[path] = path.read_text(encoding="utf-8")
|
|
91
|
+
except UnicodeDecodeError as exc:
|
|
92
|
+
errors.append(f"文件不是有效 UTF-8:{path.relative_to(root)} ({exc})")
|
|
93
|
+
|
|
94
|
+
for path, text in texts.items():
|
|
95
|
+
for raw in MARKDOWN_LINK.findall(text):
|
|
96
|
+
target = local_target(raw)
|
|
97
|
+
if target is None:
|
|
98
|
+
continue
|
|
99
|
+
resolved = (path.parent / target).resolve()
|
|
100
|
+
if root not in resolved.parents and resolved != root:
|
|
101
|
+
errors.append(f"相对引用越出源码根目录:{path.relative_to(root)} -> {target}")
|
|
102
|
+
elif not resolved.exists():
|
|
103
|
+
errors.append(f"相对引用不存在:{path.relative_to(root)} -> {target}")
|
|
104
|
+
|
|
105
|
+
for declared in DECLARED_SKILL.findall(text.replace("\\", "/")):
|
|
106
|
+
skill_path = (root / declared).resolve()
|
|
107
|
+
if not skill_path.is_file():
|
|
108
|
+
errors.append(f"声明的 Skill 不存在:{path.relative_to(root)} -> {declared}")
|
|
109
|
+
|
|
110
|
+
required_files: list[Path] = []
|
|
111
|
+
for relative in args.require_path:
|
|
112
|
+
path = (root / relative).resolve()
|
|
113
|
+
if root not in path.parents:
|
|
114
|
+
errors.append(f"必需资产越出源码根目录:{relative}")
|
|
115
|
+
elif not path.is_file() or path.stat().st_size == 0:
|
|
116
|
+
errors.append(f"必需资产不存在或为空:{relative}")
|
|
117
|
+
else:
|
|
118
|
+
required_files.append(path)
|
|
119
|
+
|
|
120
|
+
evaluation_files: list[Path] = []
|
|
121
|
+
if args.require_evaluation:
|
|
122
|
+
declared_evaluations = [(root / path).resolve() for path in args.evaluation_path]
|
|
123
|
+
if declared_evaluations:
|
|
124
|
+
for path in declared_evaluations:
|
|
125
|
+
if root not in path.parents and path != root:
|
|
126
|
+
errors.append(f"评测路径越出源码根目录:{path}")
|
|
127
|
+
elif path.is_file() and path.stat().st_size > 0:
|
|
128
|
+
evaluation_files.append(path)
|
|
129
|
+
elif path.is_dir():
|
|
130
|
+
evaluation_files.extend(item for item in path.rglob("*") if item.is_file() and item.stat().st_size > 0)
|
|
131
|
+
else:
|
|
132
|
+
errors.append(f"评测资产不存在或为空:{path.relative_to(root)}")
|
|
133
|
+
else:
|
|
134
|
+
for dirname in ("evaluation", "evaluations", "eval", "evals", "tests", "fixtures"):
|
|
135
|
+
candidate = root / dirname
|
|
136
|
+
if candidate.is_dir():
|
|
137
|
+
evaluation_files.extend(item for item in candidate.rglob("*") if item.is_file() and item.stat().st_size > 0)
|
|
138
|
+
if not evaluation_files:
|
|
139
|
+
errors.append("本次要求评测资产,但目标源码中没有实际评测文件")
|
|
140
|
+
|
|
141
|
+
if args.zip_path:
|
|
142
|
+
zip_path = args.zip_path.resolve()
|
|
143
|
+
if not zip_path.is_file():
|
|
144
|
+
errors.append(f"ZIP 不存在:{zip_path}")
|
|
145
|
+
else:
|
|
146
|
+
try:
|
|
147
|
+
with zipfile.ZipFile(zip_path) as archive:
|
|
148
|
+
corrupt = archive.testzip()
|
|
149
|
+
if corrupt:
|
|
150
|
+
errors.append(f"ZIP 条目损坏:{corrupt}")
|
|
151
|
+
files = [item for item in archive.infolist() if not item.is_dir()]
|
|
152
|
+
normalized = [item.filename.replace("\\", "/") for item in files]
|
|
153
|
+
if not any(name == args.entry or name.endswith("/" + args.entry) for name in normalized):
|
|
154
|
+
errors.append(f"ZIP 中找不到入口:{args.entry}")
|
|
155
|
+
for item in files:
|
|
156
|
+
if any(ord(char) > 127 for char in item.filename) and not (item.flag_bits & 0x800):
|
|
157
|
+
errors.append(f"ZIP 非 ASCII 路径未标记 UTF-8:{item.filename}")
|
|
158
|
+
if args.require_evaluation:
|
|
159
|
+
relative_evaluations = {
|
|
160
|
+
path.relative_to(root).as_posix() for path in evaluation_files if path.is_file()
|
|
161
|
+
}
|
|
162
|
+
if relative_evaluations and not all(
|
|
163
|
+
any(name == rel or name.endswith("/" + rel) for name in normalized)
|
|
164
|
+
for rel in relative_evaluations
|
|
165
|
+
):
|
|
166
|
+
errors.append("ZIP 未包含目标源码中的全部声明/发现评测资产")
|
|
167
|
+
relative_required = {
|
|
168
|
+
path.relative_to(root).as_posix() for path in required_files
|
|
169
|
+
}
|
|
170
|
+
if relative_required and not all(
|
|
171
|
+
any(name == rel or name.endswith("/" + rel) for name in normalized)
|
|
172
|
+
for rel in relative_required
|
|
173
|
+
):
|
|
174
|
+
errors.append("ZIP 未包含全部必需源码资产")
|
|
175
|
+
except zipfile.BadZipFile as exc:
|
|
176
|
+
errors.append(f"ZIP 无法读取:{exc}")
|
|
177
|
+
|
|
178
|
+
return report(errors, root, len(markdown_files), len(evaluation_files))
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def report(
|
|
182
|
+
errors: list[str],
|
|
183
|
+
root: Path | None = None,
|
|
184
|
+
markdown_count: int = 0,
|
|
185
|
+
evaluation_count: int = 0,
|
|
186
|
+
) -> int:
|
|
187
|
+
if errors:
|
|
188
|
+
print(f"DELIVERY_FAIL:{len(errors)} 个资产交付问题")
|
|
189
|
+
for error in errors:
|
|
190
|
+
print(f"- {error}")
|
|
191
|
+
print("说明:该结果不评价设计质量,也不构成行为或平台证据。")
|
|
192
|
+
return 1
|
|
193
|
+
suffix = f",Evaluation={evaluation_count}" if evaluation_count else ""
|
|
194
|
+
print(f"DELIVERY_PASS:入口、相对引用、声明 Skill 与编码可达(Markdown={markdown_count}{suffix})")
|
|
195
|
+
if root:
|
|
196
|
+
print(f"target_root={root}")
|
|
197
|
+
print("说明:只证明源码资产交付一致,不评价设计质量、可装载性或运行行为。")
|
|
198
|
+
return 0
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
if __name__ == "__main__":
|
|
202
|
+
sys.exit(main())
|