mirror of
https://git.openapi.site/https://github.com/desirecore/market.git
synced 2026-09-05 17:43:49 +08:00
feat: 市场支持团队条目类型并上架合同审查团队 (#110)
## 变更 / What
市场此前只有 `agents` 与 `skills` 两类条目。本 PR 加入**团队(teams)**条目类型,并上架第一条真实团队
listing。
The market supported only `agents` and `skills`. This PR adds a
**teams** entry type and lists the first real team.
## 一、支持团队条目类型
「支持一种新条目类型」实际涉及 4 组共 11 个文件,比表面看到的多:
**客户端契约快照**
- 新增 `schemas/market-team-entry.client.schema.json`,用 esbuild 打包客户端
`packages/schemas/src/market.ts` 后导出生成。用同样方法重新生成
`market-agent-entry.client.schema.json` 验证过管线——字节完全一致(含属性顺序),确认不是手工誊抄。
**Sidecar schema**
- `identity.kind` 枚举加 `team`;新增 `$defs.teamSpec`;接入 `spec.oneOf` 与
kind→spec 派发
**校验器(工作量主要在这里)**
- `scripts/catalog/validate_catalog_metadata.py`:`load_legacy`
原先硬编码只认两个根目录。抽出 `CATALOG_ROOTS` 常量同时驱动允许的父目录集合与错误文案;按 kind 分派客户端 schema
校验;`teams` 进 stats 与 `--require-complete` 覆盖统计;把**严格 provenance
比对**与「可安装 pointer 必须自带不可变 ref」两道门禁扩展到团队
- `scripts/i18n/validate-i18n.py`:**它独立重算计数并逐个校验 `entry.json`**,不接团队会漏校
- `.github/workflows/i18n-validate.yml`:变更检测的 grep 不含 `teams/`——**一个只改
teams 的 PR 会报「无 i18n 相关变更,跳过校验」然后零校验通过**
- 测试:`test_validate_catalog_metadata.py` 29→47,`test_validate_i18n.py`
9→17
**顺带修正一条本就不对的规则**:`icon` 此前被要求「每个 entry.json 都必须有非空内联 SVG」,但运行时 schema 里
`marketAgentSchema` 与 `marketTeamSchema` **都没有 `icon` 字段**(只有 skill
有)。也就是说这条规则对 Agent pointer 同样在强加死重量,只因本仓库暂无 agent pointer 条目而未暴露。改为
`ICON_RENDERED_KINDS = {"skill"}`,agent/team 声明 icon
时给**警告**而非错误,文案说明「下一个维护者会以为改它能改变卡片」。
## 二、上架合同审查团队
`teams/contract-review-team/`(`entry.json` + sidecar)。
**团队条目是 fork 指针卡,不分发正文**:市场只存展示元数据 + git-only `source`,真实定义(`team.json`
/ `members.json` / `shared/`)在 `source.repoUrl` 指向的仓库里。安装即
`forkTeam`,更新即 `git pull`——组合固定,因此**没有** `installPolicy` /
`updatePolicy`。
| 字段 | 值 | 依据 |
|---|---|---|
| `source.ref` | `73cd87a9901cc548871927e9d5dbec8e4cc6c2b1` | v0.1.1
的**完整 SHA**。tag 不是可复现 pin,validator 有测试专门拒绝 |
| `latestVersion` | `0.1.1` | 上游真实 tag,与 `release.version` 交叉校验 |
| `license` | `MIT` | 上游仓库真有 LICENSE,已在 pinned ref 的快照中复验 |
| `redistribution` | `source-pointer-only` |
市场从不打包团队正文,只给指针——这是交付形态,与许可证宽松与否无关 |
| `requiredClientVersion` | `10.0.137` | 六个成员都声明了 `FileDigest`
内置工具,它随该版本发布 |
| `memberCount` / `memberNames` | 6 / 5 名 | schema 规定前者**含**组长、后者**不含**
|
| `availability` | `listing-only` | 见下 |
**`availability` 为什么不是 `installable`**:四项证据满足两项(不可变 pin ✓、已知 license
✓),缺的 `reviewedAt` 与 `governance.compliance`
本质是**一次尚未发生的治理审查**——需要具名方在具体日期针对这个确切 ref 审过许可合规、第三方内容与商标使用。没发生的事不能写进目录。
补充一个事实:本仓库**零个 sidecar 有 `compliance` 块,29 个 pointer 条目全是
listing-only**,`installable` 路径从未在任何真实条目上走过。这不阻止安装——fork 由 `source` 驱动。
**`license.evidencePath` 的基准此前是未定义的**:schema 只说
`safeRelativePath`,没规定相对谁。仓库里仅有的两个先例(`guizang-ppt`、`presentation-forge`)都是
vendored 技能,LICENSE 物理上在条目目录里。按那个读法,pointer 条目写 `evidencePath`
断言的是市场目录下有该文件——对 pointer 永远不成立。新增 `license-evidence` 规则按条目形态分派:vendored
要求文件存在(error),pointer 要求条目已 pin(warning),两种读法写进 README。
## 校验 / Validation
```
test_validate_catalog_metadata.py 47 tests OK
test_validate_i18n.py 17 tests OK
test_collection_generator.py exit 0
validate_catalog_metadata.py --require-complete
0 error, 116 warning (agents=1, teams=1, publishableSkills=62, sidecars=64)
validate-i18n.py / --online 0 error, 116 warning
translate.py --check exit 0
gen-collection-children.py --check exit 0
```
116 warnings 即加入团队之前的基线——**本条 listing 贡献 0 个警告**。
真实条目上的反向控制(跑在 rsync 副本上,仓库保持干净):
```
source.kind=zip → team-entry-schema (error)
install/updatePolicy 出现 → team-entry-schema (error)
requiredClientVersion 漂移 → legacy-consistency (error)
memberCount 漂移 → legacy-consistency (error)
provenance ref 漂移 → legacy-consistency (error)
可安装但无不可变 ref → installable-evidence (error)
evidencePath 在未 pin 的 pointer → license-evidence (warning)
```
另用**客户端真实校验器**(`parseMarketTeamEntry`,不是快照)验证条目通过,且多写一个字段会被拒。
## 公开信息边界 / Public information boundary
全树扫描无新增命中。团队内容使用「某某科技(北京)有限公司」这类标准中文占位。
---------
Co-authored-by: yi-ge <mizan57533@gmail.com>
This commit is contained in:
106
README.md
106
README.md
@@ -1,6 +1,6 @@
|
||||
# DesireCore Market
|
||||
|
||||
DesireCore 官方市场仓库,存放官方维护的 Agent/Skill 定义,以及经过整理的第三方 Skill 入口。
|
||||
DesireCore 官方市场仓库,存放官方维护的 Agent/Team/Skill 定义,以及经过整理的第三方 Skill 入口。
|
||||
|
||||
## Repository Shape
|
||||
|
||||
@@ -12,6 +12,9 @@ DesireCore 官方市场仓库,存放官方维护的 Agent/Skill 定义,以
|
||||
├── agents/
|
||||
│ └── desirecore/
|
||||
│ └── agent.json
|
||||
├── teams/
|
||||
│ └── <team>/
|
||||
│ └── entry.json
|
||||
└── skills/
|
||||
├── <local-skill>/
|
||||
│ ├── SKILL.md
|
||||
@@ -23,6 +26,7 @@ DesireCore 官方市场仓库,存放官方维护的 Agent/Skill 定义,以
|
||||
The market currently contains:
|
||||
|
||||
- `1` Agent: `desirecore`
|
||||
- `1` Team: `contract-review-team`
|
||||
- `34` local built-in skills with `SKILL.md`
|
||||
- `28` external skill entries with `entry.json`
|
||||
- `62` publishable skills in total (`SKILL.md` + `entry.json`)
|
||||
@@ -128,6 +132,70 @@ External entries point to upstream packages or repositories. They are counted in
|
||||
}
|
||||
```
|
||||
|
||||
### Team Listing (`teams/<id>/entry.json`)
|
||||
|
||||
A Team is a group of Agents with a supervisor. It is published as a **fork pointer
|
||||
only**: the team body (`team.json`, `members.json`, `shared/`) always stays in the
|
||||
upstream team repository, and the catalog registers just "what it is and where to
|
||||
fork it from". Installation forks that repository and installs the declared members;
|
||||
updates are a `git pull` on the fork. Because both actions are Git actions,
|
||||
`source.kind` must be `git` and `source.repoUrl` is required — `zip` and `web` cannot
|
||||
express either one — and a Team deliberately has **no** `installPolicy` /
|
||||
`updatePolicy` pair: it is always market-initiated fork plus repository-driven update.
|
||||
|
||||
`teams/<id>/` therefore holds exactly `entry.json` plus the sidecar. There is no
|
||||
inline form; a `team.json` in the catalog is rejected.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "example-team",
|
||||
"name": "Example Team",
|
||||
"category": "development",
|
||||
"tags": ["example"],
|
||||
"latestVersion": "0.1.0",
|
||||
"maintainer": {
|
||||
"name": "Example",
|
||||
"verified": false,
|
||||
"account": "example",
|
||||
"url": "https://github.com/example"
|
||||
},
|
||||
"stewardship": "community",
|
||||
"license": "MIT",
|
||||
"redistribution": "source-pointer-only",
|
||||
"source": {
|
||||
"kind": "git",
|
||||
"repoUrl": "https://github.com/example/example-team.git",
|
||||
"repoBranch": "main",
|
||||
"ref": "0123456789abcdef0123456789abcdef01234567"
|
||||
},
|
||||
"requiredClientVersion": "10.0.0",
|
||||
"avatar": { "t": "示", "bg": "linear-gradient(135deg, #5856D6, #3634A3)" },
|
||||
"supervisorName": "Example Supervisor",
|
||||
"supervisorAgentId": "example-lead",
|
||||
"memberCount": 3,
|
||||
"memberNames": ["Example Member One", "Example Member Two"]
|
||||
}
|
||||
```
|
||||
|
||||
A Team card is rendered from `avatar`, not from `icon`. The client's runtime
|
||||
projection `marketTeamSchema` requires `avatar` and has no `icon` property at all —
|
||||
the same is true of `marketAgentSchema`, while only `marketSkillSchema` exposes
|
||||
`icon`. The entry contract inherits `icon` from the shared common properties, so it
|
||||
is *accepted*, but it can never reach a card. The validator therefore requires `icon`
|
||||
on Skill listings only, and warns when an Agent or Team listing declares one.
|
||||
|
||||
`redistribution` stays `source-pointer-only` for a Team even under a permissive
|
||||
license: the market never ships the team body, it only points at the repository the
|
||||
client forks. The license governs what a fork may do; `redistribution` describes how
|
||||
the content is delivered, and for teams that is always "fetch from upstream".
|
||||
|
||||
`supervisorName`, `supervisorAgentId`, `memberCount`, `memberNames` and
|
||||
`requiredSkills` are display metadata declared by the publisher. They may drift from
|
||||
the upstream repository, so installation, permissions and member resolution must read
|
||||
the forked `team.json` / `members.json` instead. Teams are counted in
|
||||
`manifest.stats.totalTeams`, which the client keeps optional: a catalog with no teams
|
||||
may omit it, and once the key is present it must be exact.
|
||||
|
||||
### Catalog metadata sidecar (`catalog-metadata.v1.json`)
|
||||
|
||||
The versioned catalog metadata contract is stored at one fixed path next to each
|
||||
@@ -135,6 +203,7 @@ legacy item:
|
||||
|
||||
```text
|
||||
agents/<id>/catalog-metadata.v1.json
|
||||
teams/<id>/catalog-metadata.v1.json
|
||||
skills/<id>/catalog-metadata.v1.json
|
||||
```
|
||||
|
||||
@@ -177,12 +246,45 @@ Pointer 的目录 slug、`entry.id`、sidecar `identity.id` 必须一致;上
|
||||
可安装指针自身必须固定 Git ref 或 Web/ZIP 摘要,不能只在 sidecar 宣称不可变版本。
|
||||
现有许可、治理审查、不可变来源和完整覆盖门禁继续有效,不适用内置 Skill 的宽松例外。
|
||||
|
||||
Team listings are pointer-only, so `teams/<slug>/` carries exactly `entry.json` plus
|
||||
the sidecar; an inline `team.json` is rejected. Team pointers first pass the complete
|
||||
raw client contract in
|
||||
[`schemas/market-team-entry.client.schema.json`](schemas/market-team-entry.client.schema.json),
|
||||
exported from `marketTeamEntrySchema` the same way as the Agent snapshot; its
|
||||
`$comment` records the source commit and blob. `entry.id`, the directory slug and
|
||||
sidecar `identity.id` must agree, `identity.kind` is `team`, and `latestVersion` maps
|
||||
to `release.version`. `supervisorName`, `supervisorAgentId`, `memberCount`,
|
||||
`memberNames`, `requiredSkills` and `requiredClientVersion` are compared symmetrically:
|
||||
the sidecar may neither drop a fact the pointer declares nor invent one it omits,
|
||||
because the client reads the pointer and a version gate that exists only in the
|
||||
sidecar would not gate anything. Pointer source fields must describe the same
|
||||
artifact as `provenance.content`, and an installable Team pointer must itself pin a
|
||||
full-SHA `source.ref` — a tag is not a reproducible pin, because a tag can be moved
|
||||
to a different commit after the listing is reviewed.
|
||||
|
||||
团队条目只有指针形态:`teams/<slug>/` 仅放 `entry.json` 与 sidecar,目录内出现 `team.json` 直接判非法。
|
||||
Pointer 原始 JSON 先通过由 `marketTeamEntrySchema` 导出的完整客户端 Schema;
|
||||
`source.kind` 恒为 `git` 且必须有 `repoUrl`,团队没有 `installPolicy` / `updatePolicy` 组合。
|
||||
目录 slug、`entry.id`、sidecar `identity.id` 必须一致,`identity.kind` 为 `team`。
|
||||
展示字段与最低客户端版本双向比对:sidecar 既不得丢弃指针声明的事实,也不得凭空补上指针没有的事实。
|
||||
可安装团队指针自身必须固定完整 SHA 的 `source.ref`,tag 或分支不算可复现锁定。
|
||||
|
||||
The sidecar records source-owned presentation, release, timestamp, content
|
||||
provenance, governance, compatibility, and type-specific facts. It deliberately
|
||||
cannot declare `catalogSourceId`, catalog commit/path/trust, effective official
|
||||
status, installation state, device state, health, URLs discovered at runtime, or
|
||||
`syncedAt`. DesireCore injects trusted catalog provenance and runtime facts.
|
||||
|
||||
`license.evidencePath`, `compliance.licenseEvidencePath` and `compliance.noticePath`
|
||||
resolve differently by item shape, because the schema constrains only the string
|
||||
form. Vendored content (built-in Skills, inline Agents) ships inside this repository,
|
||||
so the path is relative to the catalog item directory and the file must actually be
|
||||
there — a missing file is an error. A pointer distributes nothing, so its evidence
|
||||
can only be inside the upstream snapshot at the pinned revision; the validator cannot
|
||||
read that offline, so it warns when such a claim is made against an unpinned pointer.
|
||||
Pin `source.ref` to a full commit SHA and the claim becomes falsifiable by anyone who
|
||||
fetches it.
|
||||
|
||||
Time facts are explicit `known`/`unknown` values. A known day uses
|
||||
`YYYY-MM-DD` with `precision: "day"`; a known second uses an RFC 3339 UTC value
|
||||
ending in `Z` with `precision: "second"`. Never use the current date, clone time,
|
||||
@@ -235,7 +337,7 @@ evidence, collection identity, i18n completeness, and translation freshness.
|
||||
Human-locked translations (`translated_by: human`) must keep `source_hash`
|
||||
aligned after manual review. During a data migration,
|
||||
`scripts/catalog/validate_catalog_metadata.py --require-complete` additionally
|
||||
requires one sidecar for every top-level Agent and Skill.
|
||||
requires one sidecar for every top-level Agent, Team and Skill.
|
||||
|
||||
Detailed i18n guidance is in [docs/I18N.md](docs/I18N.md).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user