feat: 添加 Kimi WebBridge 受控目录条目 (#2)

This commit is contained in:
2026-08-30 13:49:44 -04:00
committed by GitHub
parent e06a0b74d0
commit 877a3b2424
11 changed files with 1565 additions and 23 deletions

27
.github/workflows/validate.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Validate Registry
on:
pull_request:
push:
branches:
- main
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Check out registry
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Validate registry
run: npm test

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules/
npm-debug.log*

View File

@@ -1,16 +1,22 @@
# DesireCore Registry # DesireCore Registry
DesireCore 官方注册表仓库,包含所有可安装的应用、MCP 服务HTTP API 服务。 DesireCore 官方注册表仓库包含可安装的应用、MCP 服务HTTP API 服务,以及只用于发现和合规披露的第三方外部集成
DesireCore 客户端启动时会克隆此仓库,并定期同步更新。用户在应用商店中看到的所有条目均来自此仓库。 DesireCore 客户端启动时会克隆此仓库,并定期同步更新。用户在应用商店中看到的所有条目均来自此仓库。
## 目录结构 ## 目录结构
``` ```text
. .
├── README.md # 本文件 ├── README.md # 本文件
├── SCHEMA_VERSION # 数据格式版本号(当前 3.0.0 ├── SCHEMA_VERSION # 数据格式版本号(当前 4.0.0
├── manifest.json # 仓库元数据(版本、统计、维护者) ├── manifest.json # 仓库元数据(版本、统计、维护者)
├── package.json # Registry 校验入口
├── schemas/
│ └── registry-entry.schema.json # Draft-07 严格判别 Schema
├── scripts/
│ ├── validate-registry.mjs # 仓库语义校验
│ └── validate-registry.test.mjs # 失败关闭回归测试
├── entries/ # 🔑 所有注册表条目(统一格式) ├── entries/ # 🔑 所有注册表条目(统一格式)
│ ├── n8n/ # 示例Docker 应用 │ ├── n8n/ # 示例Docker 应用
│ │ ├── manifest.json # 条目元数据(必需) │ │ ├── manifest.json # 条目元数据(必需)
@@ -20,9 +26,11 @@ DesireCore 客户端启动时会克隆此仓库,并定期同步更新。用户
│ │ ├── manifest.json │ │ ├── manifest.json
│ │ ├── install.md │ │ ├── install.md
│ │ └── usage.md │ │ └── usage.md
── baidu-map/ # 示例HTTP API无需安装 ── baidu-map/ # 示例HTTP API无需安装
├── manifest.json ├── manifest.json
└── usage.md └── usage.md
│ └── kimi-webbridge/ # external-integration只允许 manifest.json
│ └── manifest.json
├── models/ # 模型能力描述符与分类 ├── models/ # 模型能力描述符与分类
│ ├── descriptors.json │ ├── descriptors.json
│ └── categories.json │ └── categories.json
@@ -45,7 +53,7 @@ DesireCore 客户端启动时会克隆此仓库,并定期同步更新。用户
|------|------|------|------| |------|------|------|------|
| `id` | string | ✅ | 唯一标识,与目录名一致 | | `id` | string | ✅ | 唯一标识,与目录名一致 |
| `name` | string | ✅ | 显示名称 | | `name` | string | ✅ | 显示名称 |
| `type` | string | ✅ | 条目类型:`docker-app` / `mcp` / `http-api` | | `type` | string | ✅ | 条目类型:`docker-app` / `mcp` / `http-api` / `external-integration` |
| `version` | string | ✅ | 语义版本号 | | `version` | string | ✅ | 语义版本号 |
| `description` | string | ✅ | 一行功能摘要 | | `description` | string | ✅ | 一行功能摘要 |
| `author` | string | | 作者或组织 | | `author` | string | | 作者或组织 |
@@ -102,26 +110,46 @@ MCP `connection.transport` 取值:`stdio` / `streamable-http` / `sse`
| `sourceAppId` | string | 关联的应用 ID | | `sourceAppId` | string | 关联的应用 ID |
| `sourceAppName` | string | 关联的应用名称 | | `sourceAppName` | string | 关联的应用名称 |
**第三方外部集成专属字段(`type: "external-integration"`**
Schema v4 的 external integration 是严格、失败关闭的目录指针,不是 `StoreApp`、安装事实、连接或 Browser Provider。当前只准入经过审核的 `kimi-webbridge` ID并固定以下治理语义
- `stewardship: "pointer"`
- `availability: "listing-only"`
- `redistribution: "source-pointer-only"`
- `branding.relationship: "independent-listing"`
- `branding.nameUsage: "nominative"`
- `branding.logoStatus: "not-used"`
- `admission.status: "blocked"`
条目还必须结构化披露上游维护者、完整官方 URL、浏览器扩展 ID、物理组件、扩展权限、独立 Profile 建议、WebBridge 本地链路与 DesireCore 模型 Provider 的不同数据边界、阻塞准入原因,以及固定版本 daemon 的 SHA-256 审核记录。
external integration 目录必须恰好包含一个常规文件 `manifest.json`。额外文件、目录、符号链接、设备节点、FIFO、Socket 或二进制制品全部被拒绝;因此它没有可被 Agent 当成安装指令执行的自由文本面。`sourceId``hasInstall` 仅由客户端从可信来源和目录事实注入,禁止写入上游 manifest。
### install.md可选 ### install.md可选
自然语言安装说明,供 DesireCore Agent 读取并执行安装流程。 自然语言安装说明,供 DesireCore Agent 读取并执行安装流程。
内容应包含: 内容应包含:
- 环境要求Node.js 版本、Python 等) - 环境要求Node.js 版本、Python 等)
- 安装步骤(可直接执行的命令) - 安装步骤(可直接执行的命令)
- 验证方式 - 验证方式
**不需要 install.md 的情况**:纯 HTTP API 服务(无需在本地安装)、通过关联应用附带安装的服务(如 dify-mcp 随 Dify 一起可用)。 **不需要 install.md 的情况**:纯 HTTP API 服务(无需在本地安装)、通过关联应用附带安装的服务(如 dify-mcp 随 Dify 一起可用)。`external-integration` 明确禁止 `install.md`
### usage.md可选 ### usage.md可选
使用说明,描述安装后如何连接和使用此服务。 使用说明,描述安装后如何连接和使用此服务。
内容应包含: 内容应包含:
- 连接配置transport、command、URL 等) - 连接配置transport、command、URL 等)
- 配置示例JSON 格式,可直接使用) - 配置示例JSON 格式,可直接使用)
- 注意事项 - 注意事项
`external-integration` 不允许 `usage.md` 或其他附加文件;所有用户可见披露必须是经过 Schema 约束的 manifest 字段。
## 添加新条目 ## 添加新条目
### 添加 Docker 应用 ### 添加 Docker 应用
@@ -144,6 +172,7 @@ cat > entries/my-app/manifest.json << 'EOF'
"iconLetter": "M", "iconLetter": "M",
"platformSupport": ["macos", "windows", "linux"], "platformSupport": ["macos", "windows", "linux"],
"fullDesc": "详细描述...", "fullDesc": "详细描述...",
"shortDesc": "简短描述...",
"install": { "install": {
"method": "docker", "method": "docker",
"requirements": { "requirements": {
@@ -231,6 +260,7 @@ cat > entries/my-api/manifest.json << 'EOF'
"description": "一行功能描述", "description": "一行功能描述",
"tags": ["tag1"], "tags": ["tag1"],
"icon": "globe", "icon": "globe",
"platformSupport": ["macos", "windows", "linux"],
"endpoint": "https://api.example.com/v1", "endpoint": "https://api.example.com/v1",
"capabilities": ["capability_1"] "capabilities": ["capability_1"]
} }
@@ -239,17 +269,24 @@ EOF
HTTP API 通常不需要 install.md只需 usage.md 说明如何调用。 HTTP API 通常不需要 install.md只需 usage.md 说明如何调用。
### 添加第三方外部集成
external integration 不是开放的自助条目类型。新增 ID、URL、扩展 ID、组件或制品审核事实需要先修改严格 Schema、校验器与 DesireCore 客户端契约,并经过安全与合规 review未知 ID 会失败关闭。请以 [`entries/kimi-webbridge/manifest.json`](entries/kimi-webbridge/manifest.json) 为唯一当前示例。
## 修改现有条目 ## 修改现有条目
1. 编辑 `entries/<id>/manifest.json` 中的字段 1. 编辑 `entries/<id>/manifest.json` 中的字段
2. 如有安装/使用流程变更,同步更新 `install.md` / `usage.md` 2. 如有安装/使用流程变更,同步更新 `install.md` / `usage.md`external integration 不适用
3. **务必更新 `version` 字段**(客户端通过版本号判断是否有更新) 3. **务必更新 `version` 字段**(客户端通过版本号判断是否有更新)
4. 提交并创建 PR 4. 新增或删除条目时同步更新根 `manifest.json#stats`
5. 执行 `npm ci && npm test`
6. 提交并创建 PR
## 版本规范 ## 版本规范
- `SCHEMA_VERSION`:数据格式版本,格式不兼容时递增主版本号 - `SCHEMA_VERSION`:数据格式版本,格式不兼容时递增主版本号
- `manifest.json#version`:仓库元数据版本 - `manifest.json#version`:仓库元数据版本,必须等于 `SCHEMA_VERSION`
- `manifest.json#dataVersion`:仓库数据版本,必须等于 `SCHEMA_VERSION`
- `entries/<id>/manifest.json#version`:条目自身版本 - `entries/<id>/manifest.json#version`:条目自身版本
**Schema 版本历史:** **Schema 版本历史:**
@@ -258,7 +295,17 @@ HTTP API 通常不需要 install.md只需 usage.md 说明如何调用。
|------|------| |------|------|
| 1.0.0 | 初始格式 — 单文件 JSON 数组 | | 1.0.0 | 初始格式 — 单文件 JSON 数组 |
| 2.0.0 | 分散式目录 — apps/mcp/services 三目录,每个条目 `<id>/index.json` | | 2.0.0 | 分散式目录 — apps/mcp/services 三目录,每个条目 `<id>/index.json` |
| 3.0.0 | **当前** 统一 entries/ 目录manifest.json + install.md + usage.md | | 3.0.0 | 统一 entries/ 目录manifest.json + install.md + usage.md |
| 4.0.0 | **当前** — Draft-07 严格判别 Schema、仓库校验和 listing-only external integration |
## 校验
```bash
npm ci
npm test
```
校验包含 JSON Schema、目录与 ID、全局唯一性、根版本、统计、来源注入字段、external 单文件布局、固定 Kimi ID、完整官方 URL、扩展 ID、组件/权限/准入集合、真实日历日期和不可变供应链审核记录。
## 同步机制 ## 同步机制
@@ -269,16 +316,21 @@ DesireCore 客户端的同步流程:
3. 有新 commit 时 `git pull` 并重建本地索引 3. 有新 commit 时 `git pull` 并重建本地索引
4. 离线时使用本地缓存或内置 fallback 数据 4. 离线时使用本地缓存或内置 fallback 数据
客户端读取 `entries/` 目录下所有 `manifest.json`,按 `type` 字段分类为应用、MCP 服务HTTP 服务展示在商店中。`install.md``usage.md` 供 AI Agent 执行安装和配置时使用。 客户端读取 `entries/` 目录下所有 `manifest.json`,按 `type` 字段分类为应用、MCP 服务HTTP 服务和第三方外部集成展示在商店中。旧三类条目的 `install.md``usage.md` 供 AI Agent 执行安装和配置时使用external integration 只有结构化 manifest且 listing-only 条目不会被派生为 Docker 应用、installed-entry、ready 连接或 Browser Provider
主仓库的 `npm run sync-registry` 在打包前执行本 checkout 的 `scripts/validate-registry.mjs`。validator 缺失或失败时同步必须失败关闭,不能生成新的 `defaults/registry.zip`
## 贡献指南 ## 贡献指南
1. Fork 本仓库 1. Fork 本仓库
2.`entries/` 下创建以 ID 命名的子目录 2.`entries/` 下创建以 ID 命名的子目录
3. 按上述格式添加 `manifest.json`,按需添加 `install.md``usage.md` 3. 按上述格式添加 `manifest.json`旧三类按需添加 `install.md``usage.md`
4. 更新根目录 `manifest.json` 中的 `stats` 统计 4. 更新根目录 `manifest.json` 中的 `stats` 统计
5. 提交 PR 并描述变更内容 5. 执行 `npm ci && npm test`
6. 等待审核合并 6. 提交 PR 并描述变更内容、来源和验证结果
7. 等待审核合并
external integration 需要额外安全、供应链、商标和隐私 review不接受绕过严格 Schema 的未知 ID 或自由文本安装说明。
## 镜像 ## 镜像

View File

@@ -1 +1 @@
3.0.0 4.0.0

View File

@@ -0,0 +1,175 @@
{
"id": "kimi-webbridge",
"name": "Kimi WebBridge",
"type": "external-integration",
"version": "1.0.0",
"author": "Moonshot AI",
"description": "连接本机 Chrome 或 Edge 的第三方浏览器桥接集成目录入口",
"category": "tools",
"shortDesc": "第三方浏览器桥接集成,仅提供官方来源和合规披露",
"fullDesc": "Kimi WebBridge 由上游浏览器扩展和本地桥接服务组成,可让兼容的本地 Agent 使用现有 Chrome 或 Edge 会话执行导航、点击、填写、截图和内容提取。本条目由 DesireCore 独立收录,仅提供官方来源、权限和数据边界披露;当前不提供安装、连接或 DesireCore 原生执行能力。",
"tags": [
"browser",
"chrome",
"edge",
"webbridge"
],
"icon": "monitor",
"platformSupport": [
"macos",
"windows"
],
"requiredClientVersion": "10.0.132",
"stewardship": "pointer",
"availability": "listing-only",
"redistribution": "source-pointer-only",
"branding": {
"relationship": "independent-listing",
"nameUsage": "nominative",
"logoStatus": "not-used"
},
"listingMaintainer": {
"name": "DesireCore Registry",
"url": "https://github.com/desirecore/registry",
"verified": true
},
"upstreamMaintainer": {
"name": "Moonshot AI",
"url": "https://www.kimi.ai/",
"verified": true
},
"integration": {
"kind": "local-extension-bridge",
"adapterId": "kimi-webbridge",
"executionAvailability": "blocked",
"installMode": "upstream-guided"
},
"officialLinks": [
{
"kind": "product",
"label": "Kimi WebBridge 官方产品页",
"url": "https://www.kimi.ai/products/kimi-webbridge"
},
{
"kind": "documentation",
"label": "Kimi WebBridge 官方帮助",
"url": "https://www.kimi.ai/help/kimi-webbridge/kimi-webbridge-introduction"
},
{
"kind": "chrome-web-store",
"label": "Chrome Web Store 官方条目",
"extensionId": "fldmhceldgbpfpkbgopacenieobmligc",
"url": "https://chromewebstore.google.com/detail/kimi-webbridge/fldmhceldgbpfpkbgopacenieobmligc"
},
{
"kind": "edge-add-ons",
"label": "Microsoft Edge Add-ons 官方条目",
"extensionId": "bnlffdbcfnanfbknnlaflhlhkocccckg",
"url": "https://microsoftedge.microsoft.com/addons/detail/kimi-webbridge/bnlffdbcfnanfbknnlaflhlhkocccckg"
},
{
"kind": "privacy",
"label": "Kimi 隐私政策",
"url": "https://www.kimi.ai/user/agreement/userPrivacy?version=v2"
},
{
"kind": "terms",
"label": "Kimi 服务条款",
"url": "https://www.kimi.ai/user/agreement/modelUse?version=v2"
}
],
"components": [
{
"kind": "browser-extension",
"name": "Kimi WebBridge browser extension",
"description": "在 Chrome 或 Edge 中执行浏览器操作并与本地桥接服务通信的上游扩展",
"distribution": "official-upstream-only",
"browsers": [
"chrome",
"edge"
]
},
{
"kind": "local-daemon",
"name": "Kimi WebBridge local service",
"description": "在用户设备上接收 Agent 指令并协调浏览器扩展的上游本地服务",
"distribution": "official-upstream-only",
"platforms": [
"macos",
"windows"
]
}
],
"permissions": {
"browserExtension": {
"apiPermissions": [
"tabs",
"activeTab",
"debugger",
"storage",
"alarms",
"tabGroups",
"windows"
],
"hostPermissions": [
"<all_urls>"
],
"riskLevel": "high"
}
},
"profileRecommendation": "dedicated-browser-profile",
"dataBoundaries": {
"webBridgeLocalExecution": "上游声明 WebBridge 的桥接执行、登录状态和页面处理发生在用户设备本地;该声明仅描述 WebBridge 自身链路。",
"desireCoreModelContext": "当页面文本、截图或操作结果进入 DesireCore Agent 上下文时,内容仍可能按用户选择的模型与数据驻留配置发送给模型 Provider这不属于上游本地执行声明的覆盖范围。",
"modelProviderDisclosureRequired": true
},
"admission": {
"status": "blocked",
"code": "native-integration-not-admitted",
"reason": "DesireCore 尚未获得足以把该第三方桥接提升为受治理浏览器 Provider 的稳定协议、授权和确定性治理信号,因此当前仅展示目录信息。",
"missingPrerequisites": [
"stable-auditable-protocol",
"integration-authorization",
"deterministic-command-receipts",
"user-interaction-pause-signal"
]
},
"compliance": {
"reviewedAt": "2026-08-30",
"reviewedBy": "DesireCore Registry maintainers",
"upstreamEndorsed": false,
"relationshipDisclosure": "independent-listing-not-endorsed",
"artifactReviews": [
{
"component": "local-daemon",
"platform": "macos",
"architecture": "arm64",
"version": "1.11.6",
"url": "https://cdn.kimi.com/webbridge/v1.11.6/releases/kimi-webbridge-darwin-arm64",
"sha256": "46fe401eaa5669c6d9915b4d7ea734cd3fb968c877362644212234241d0c9930",
"reviewedAt": "2026-08-30",
"reviewedBy": "DesireCore Registry maintainers"
},
{
"component": "local-daemon",
"platform": "macos",
"architecture": "x64",
"version": "1.11.6",
"url": "https://cdn.kimi.com/webbridge/v1.11.6/releases/kimi-webbridge-darwin-amd64",
"sha256": "edd1b1265445410ef5e8684788955c7283f9c47d9121f53159fa7e5a4641ec54",
"reviewedAt": "2026-08-30",
"reviewedBy": "DesireCore Registry maintainers"
},
{
"component": "local-daemon",
"platform": "windows",
"architecture": "x64",
"version": "1.11.6",
"url": "https://cdn.kimi.com/webbridge/v1.11.6/releases/kimi-webbridge-windows-amd64.exe",
"sha256": "e085991e0127c3872d8cbf2ec11078a1efba3c534f6229e42af0dde45ce90520",
"reviewedAt": "2026-08-30",
"reviewedBy": "DesireCore Registry maintainers"
}
]
}
}

View File

@@ -1,17 +1,18 @@
{ {
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"id": "desirecore-registry-manifest", "id": "desirecore-registry-manifest",
"version": "3.0.0", "version": "4.0.0",
"name": "DesireCore Registry", "name": "DesireCore Registry",
"description": "DesireCore 官方注册表 — 应用、MCP 服务HTTP API 的统一仓库", "description": "DesireCore 官方注册表 — Docker 应用、MCP 服务HTTP API 和第三方外部集成的统一目录",
"maintainer": "DesireCore Team", "maintainer": "DesireCore Team",
"repository": "https://github.com/desirecore/registry", "repository": "https://github.com/desirecore/registry",
"lastUpdated": "2026-07-29", "lastUpdated": "2026-08-30",
"stats": { "stats": {
"totalEntries": 21, "totalEntries": 22,
"dockerApps": 8, "dockerApps": 8,
"mcpServices": 8, "mcpServices": 8,
"httpApis": 5 "httpApis": 5,
"externalIntegrations": 1
}, },
"dataVersion": "3.0.0" "dataVersion": "4.0.0"
} }

76
package-lock.json generated Normal file
View File

@@ -0,0 +1,76 @@
{
"name": "@desirecore/registry",
"version": "4.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@desirecore/registry",
"version": "4.0.0",
"devDependencies": {
"ajv": "8.20.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/ajv": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.6.tgz",
"integrity": "sha512-7Ical1vFEMr0onbVzEDIreM22I4khW+fzyQPwvAFWBp1iwdshSZRsL4jjRvPG9JP1uiqMHRto+YU6R2/CzDz5Q==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true,
"license": "MIT"
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
}
}
}

17
package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "@desirecore/registry",
"version": "4.0.0",
"private": true,
"description": "Validated catalog data for the DesireCore Registry",
"type": "module",
"scripts": {
"validate": "node scripts/validate-registry.mjs",
"test": "node --test scripts/validate-registry.test.mjs && npm run validate"
},
"devDependencies": {
"ajv": "8.20.0"
},
"engines": {
"node": ">=20"
}
}

View File

@@ -0,0 +1,552 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://github.com/desirecore/registry/schemas/registry-entry.schema.json",
"title": "DesireCore Registry Entry",
"description": "A strictly discriminated DesireCore Registry catalog entry. External integrations are discovery-only pointers and cannot carry installation or connection semantics.",
"oneOf": [
{ "$ref": "#/definitions/dockerApp" },
{ "$ref": "#/definitions/mcp" },
{ "$ref": "#/definitions/httpApi" },
{ "$ref": "#/definitions/externalIntegration" }
],
"definitions": {
"id": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"description": "Stable entry identifier; must equal the containing directory name."
},
"nonEmptyString": {
"type": "string",
"minLength": 1
},
"version": {
"type": "string",
"pattern": "^[0-9]+(?:\\.[0-9]+){1,3}(?:[-+][0-9A-Za-z.-]+)?$",
"description": "Entry or client version in dotted numeric form."
},
"httpsUrl": {
"type": "string",
"pattern": "^https://[^\\s]+$",
"description": "An HTTPS URL without embedded whitespace."
},
"platformSupport": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"enum": ["macos", "windows", "linux"]
},
"description": "Desktop platforms on which the entry is relevant."
},
"tags": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": { "$ref": "#/definitions/nonEmptyString" },
"description": "Human-readable discovery and search tags."
},
"capabilities": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"pattern": "^[a-z0-9]+(?:_[a-z0-9]+)*$"
}
},
"environment": {
"type": "object",
"additionalProperties": { "type": "string" }
},
"mcpInstall": {
"type": "object",
"required": ["method", "command", "args"],
"additionalProperties": false,
"properties": {
"method": { "$ref": "#/definitions/nonEmptyString" },
"packageName": { "$ref": "#/definitions/nonEmptyString" },
"command": { "$ref": "#/definitions/nonEmptyString" },
"args": {
"type": "array",
"items": { "type": "string" }
},
"postInstall": {
"type": "array",
"items": { "$ref": "#/definitions/nonEmptyString" }
},
"env": { "$ref": "#/definitions/environment" }
}
},
"connection": {
"type": "object",
"required": ["transport"],
"additionalProperties": false,
"properties": {
"transport": {
"type": "string",
"enum": ["stdio", "streamable-http", "sse"]
},
"command": { "$ref": "#/definitions/nonEmptyString" },
"args": {
"type": "array",
"items": { "type": "string" }
},
"url": { "$ref": "#/definitions/nonEmptyString" },
"env": { "$ref": "#/definitions/environment" }
}
},
"dockerApp": {
"type": "object",
"required": [
"id", "name", "type", "version", "author", "description", "tags", "icon",
"iconLetter", "platformSupport", "category", "fullDesc", "shortDesc", "install"
],
"additionalProperties": false,
"properties": {
"id": { "$ref": "#/definitions/id" },
"name": { "$ref": "#/definitions/nonEmptyString" },
"type": { "const": "docker-app" },
"version": { "$ref": "#/definitions/version" },
"author": { "$ref": "#/definitions/nonEmptyString" },
"description": { "$ref": "#/definitions/nonEmptyString" },
"tags": { "$ref": "#/definitions/tags" },
"icon": { "$ref": "#/definitions/nonEmptyString" },
"iconLetter": { "type": "string", "minLength": 1, "maxLength": 2 },
"platformSupport": { "$ref": "#/definitions/platformSupport" },
"category": {
"type": "string",
"enum": ["ai-platform", "chat", "workflow", "rag", "tools"]
},
"fullDesc": { "$ref": "#/definitions/nonEmptyString" },
"shortDesc": { "$ref": "#/definitions/nonEmptyString" },
"stars": { "type": "integer", "minimum": 0 },
"githubUrl": { "$ref": "#/definitions/httpsUrl" },
"install": {
"type": "object",
"required": ["method", "requirements", "configNeeded"],
"additionalProperties": false,
"properties": {
"method": { "type": "string", "enum": ["docker", "docker-compose"] },
"requirements": {
"type": "object",
"required": ["docker", "minMemory", "minDisk", "ports"],
"additionalProperties": false,
"properties": {
"docker": { "const": true },
"minMemory": { "$ref": "#/definitions/nonEmptyString" },
"minDisk": { "$ref": "#/definitions/nonEmptyString" },
"ports": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": { "type": "integer", "minimum": 1, "maximum": 65535 }
}
}
},
"configNeeded": {
"type": "array",
"items": { "$ref": "#/definitions/nonEmptyString" }
}
}
},
"exposes": {
"type": "array",
"items": {
"type": "object",
"required": ["type", "port", "path", "name"],
"additionalProperties": false,
"properties": {
"type": { "const": "http-api" },
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
"path": { "type": "string", "pattern": "^/" },
"name": { "$ref": "#/definitions/nonEmptyString" }
}
}
}
}
},
"mcp": {
"type": "object",
"required": [
"id", "name", "type", "version", "author", "description", "tags", "icon",
"platformSupport", "capabilities", "connection"
],
"additionalProperties": false,
"properties": {
"id": { "$ref": "#/definitions/id" },
"name": { "$ref": "#/definitions/nonEmptyString" },
"type": { "const": "mcp" },
"version": { "$ref": "#/definitions/version" },
"author": { "$ref": "#/definitions/nonEmptyString" },
"description": { "$ref": "#/definitions/nonEmptyString" },
"tags": { "$ref": "#/definitions/tags" },
"icon": { "$ref": "#/definitions/nonEmptyString" },
"platformSupport": { "$ref": "#/definitions/platformSupport" },
"capabilities": { "$ref": "#/definitions/capabilities" },
"toolCount": { "type": "integer", "minimum": 0 },
"install": { "$ref": "#/definitions/mcpInstall" },
"connection": { "$ref": "#/definitions/connection" },
"sourceAppId": { "$ref": "#/definitions/id" },
"sourceAppName": { "$ref": "#/definitions/nonEmptyString" }
}
},
"httpApi": {
"type": "object",
"required": [
"id", "name", "type", "version", "author", "description", "tags", "icon",
"platformSupport", "endpoint", "capabilities"
],
"additionalProperties": false,
"properties": {
"id": { "$ref": "#/definitions/id" },
"name": { "$ref": "#/definitions/nonEmptyString" },
"type": { "const": "http-api" },
"version": { "$ref": "#/definitions/version" },
"author": { "$ref": "#/definitions/nonEmptyString" },
"description": { "$ref": "#/definitions/nonEmptyString" },
"tags": { "$ref": "#/definitions/tags" },
"icon": { "$ref": "#/definitions/nonEmptyString" },
"platformSupport": { "$ref": "#/definitions/platformSupport" },
"endpoint": { "type": "string", "pattern": "^https?://[^\\s]+$" },
"capabilities": { "$ref": "#/definitions/capabilities" },
"sourceAppId": { "$ref": "#/definitions/id" },
"sourceAppName": { "$ref": "#/definitions/nonEmptyString" }
}
},
"maintainer": {
"type": "object",
"required": ["name", "url", "verified"],
"additionalProperties": false,
"properties": {
"name": {
"allOf": [{ "$ref": "#/definitions/nonEmptyString" }],
"description": "Human-readable maintainer identity."
},
"url": {
"allOf": [{ "$ref": "#/definitions/httpsUrl" }],
"description": "Public source used to verify the maintainer identity."
},
"verified": {
"const": true,
"description": "The Registry maintainer verified this identity against the public source."
}
}
},
"officialLink": {
"description": "A Kimi WebBridge upstream URL pinned by kind, hostname, path, and extension ID where applicable.",
"oneOf": [
{
"type": "object",
"required": ["kind", "label", "url"],
"additionalProperties": false,
"properties": {
"kind": { "const": "product" },
"label": { "$ref": "#/definitions/nonEmptyString" },
"url": { "const": "https://www.kimi.ai/products/kimi-webbridge" }
}
},
{
"type": "object",
"required": ["kind", "label", "url"],
"additionalProperties": false,
"properties": {
"kind": { "const": "documentation" },
"label": { "$ref": "#/definitions/nonEmptyString" },
"url": { "const": "https://www.kimi.ai/help/kimi-webbridge/kimi-webbridge-introduction" }
}
},
{
"type": "object",
"required": ["kind", "label", "extensionId", "url"],
"additionalProperties": false,
"properties": {
"kind": { "const": "chrome-web-store" },
"label": { "$ref": "#/definitions/nonEmptyString" },
"extensionId": {
"const": "fldmhceldgbpfpkbgopacenieobmligc",
"description": "The audited Chrome Web Store extension identifier."
},
"url": { "const": "https://chromewebstore.google.com/detail/kimi-webbridge/fldmhceldgbpfpkbgopacenieobmligc" }
}
},
{
"type": "object",
"required": ["kind", "label", "extensionId", "url"],
"additionalProperties": false,
"properties": {
"kind": { "const": "edge-add-ons" },
"label": { "$ref": "#/definitions/nonEmptyString" },
"extensionId": {
"const": "bnlffdbcfnanfbknnlaflhlhkocccckg",
"description": "The audited Microsoft Edge Add-ons extension identifier."
},
"url": { "const": "https://microsoftedge.microsoft.com/addons/detail/kimi-webbridge/bnlffdbcfnanfbknnlaflhlhkocccckg" }
}
},
{
"type": "object",
"required": ["kind", "label", "url"],
"additionalProperties": false,
"properties": {
"kind": { "const": "privacy" },
"label": { "$ref": "#/definitions/nonEmptyString" },
"url": { "const": "https://www.kimi.ai/user/agreement/userPrivacy?version=v2" }
}
},
{
"type": "object",
"required": ["kind", "label", "url"],
"additionalProperties": false,
"properties": {
"kind": { "const": "terms" },
"label": { "$ref": "#/definitions/nonEmptyString" },
"url": { "const": "https://www.kimi.ai/user/agreement/modelUse?version=v2" }
}
}
]
},
"browserExtensionComponent": {
"type": "object",
"required": ["kind", "name", "description", "distribution", "browsers"],
"additionalProperties": false,
"properties": {
"kind": { "const": "browser-extension" },
"name": { "$ref": "#/definitions/nonEmptyString" },
"description": { "$ref": "#/definitions/nonEmptyString" },
"distribution": {
"const": "official-upstream-only",
"description": "DesireCore does not mirror or repackage this third-party component."
},
"browsers": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"uniqueItems": true,
"items": { "type": "string", "enum": ["chrome", "edge"] },
"allOf": [{ "contains": { "const": "chrome" } }, { "contains": { "const": "edge" } }]
}
}
},
"localDaemonComponent": {
"type": "object",
"required": ["kind", "name", "description", "distribution", "platforms"],
"additionalProperties": false,
"properties": {
"kind": { "const": "local-daemon" },
"name": { "$ref": "#/definitions/nonEmptyString" },
"description": { "$ref": "#/definitions/nonEmptyString" },
"distribution": {
"const": "official-upstream-only",
"description": "DesireCore does not mirror or repackage this third-party component."
},
"platforms": {
"type": "array",
"minItems": 2,
"maxItems": 3,
"uniqueItems": true,
"items": { "type": "string", "enum": ["macos", "windows", "linux"] },
"allOf": [{ "contains": { "const": "macos" } }, { "contains": { "const": "windows" } }]
}
}
},
"externalComponent": {
"description": "One strictly discriminated Kimi WebBridge physical component.",
"oneOf": [
{ "$ref": "#/definitions/browserExtensionComponent" },
{ "$ref": "#/definitions/localDaemonComponent" }
]
},
"artifactReview": {
"type": "object",
"required": ["component", "platform", "architecture", "version", "url", "sha256", "reviewedAt", "reviewedBy"],
"additionalProperties": false,
"properties": {
"component": { "const": "local-daemon" },
"platform": { "type": "string", "enum": ["macos", "windows", "linux"] },
"architecture": { "type": "string", "enum": ["x64", "arm64"] },
"version": { "$ref": "#/definitions/version" },
"url": { "$ref": "#/definitions/httpsUrl" },
"sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"reviewedAt": { "type": "string", "format": "date" },
"reviewedBy": { "$ref": "#/definitions/nonEmptyString" }
}
},
"externalIntegration": {
"type": "object",
"required": [
"id", "name", "type", "version", "author", "description", "category", "shortDesc",
"fullDesc", "tags", "icon", "platformSupport", "requiredClientVersion", "stewardship",
"availability", "redistribution", "branding", "listingMaintainer", "upstreamMaintainer",
"integration", "officialLinks", "components", "permissions", "profileRecommendation",
"dataBoundaries", "admission", "compliance"
],
"additionalProperties": false,
"properties": {
"id": {
"const": "kimi-webbridge",
"description": "The only external-integration ID admitted by Registry Schema v4."
},
"name": { "$ref": "#/definitions/nonEmptyString" },
"type": { "const": "external-integration" },
"version": { "$ref": "#/definitions/version" },
"author": { "$ref": "#/definitions/nonEmptyString" },
"description": { "$ref": "#/definitions/nonEmptyString" },
"category": { "const": "tools" },
"shortDesc": { "$ref": "#/definitions/nonEmptyString" },
"fullDesc": { "$ref": "#/definitions/nonEmptyString" },
"tags": { "$ref": "#/definitions/tags" },
"icon": {
"type": "string",
"enum": ["monitor", "puzzle", "globe"],
"description": "A neutral DesireCore icon name; upstream logos are not permitted in this listing type."
},
"platformSupport": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"uniqueItems": true,
"items": { "type": "string", "enum": ["macos", "windows"] },
"allOf": [{ "contains": { "const": "macos" } }, { "contains": { "const": "windows" } }],
"description": "The reviewed listing must support both macOS and Windows."
},
"requiredClientVersion": {
"allOf": [{ "$ref": "#/definitions/version" }],
"description": "Minimum DesireCore version that understands this strict listing-only entry."
},
"stewardship": { "const": "pointer" },
"availability": { "const": "listing-only" },
"redistribution": { "const": "source-pointer-only" },
"branding": {
"type": "object",
"required": ["relationship", "nameUsage", "logoStatus"],
"additionalProperties": false,
"properties": {
"relationship": { "const": "independent-listing" },
"nameUsage": { "const": "nominative" },
"logoStatus": { "const": "not-used" }
}
},
"listingMaintainer": { "$ref": "#/definitions/maintainer" },
"upstreamMaintainer": { "$ref": "#/definitions/maintainer" },
"integration": {
"type": "object",
"required": ["kind", "adapterId", "executionAvailability", "installMode"],
"additionalProperties": false,
"properties": {
"kind": { "const": "local-extension-bridge" },
"adapterId": { "$ref": "#/definitions/id" },
"executionAvailability": { "const": "blocked" },
"installMode": { "const": "upstream-guided" }
}
},
"officialLinks": {
"type": "array",
"minItems": 6,
"maxItems": 6,
"uniqueItems": true,
"items": { "$ref": "#/definitions/officialLink" },
"description": "One reviewed official source for each required link kind."
},
"components": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"uniqueItems": true,
"items": { "$ref": "#/definitions/externalComponent" },
"description": "The upstream browser extension and local daemon, neither redistributed by DesireCore."
},
"permissions": {
"type": "object",
"required": ["browserExtension"],
"additionalProperties": false,
"properties": {
"browserExtension": {
"type": "object",
"required": ["apiPermissions", "hostPermissions", "riskLevel"],
"additionalProperties": false,
"properties": {
"apiPermissions": {
"type": "array",
"minItems": 7,
"maxItems": 7,
"uniqueItems": true,
"items": {
"type": "string",
"enum": ["tabs", "activeTab", "debugger", "storage", "alarms", "tabGroups", "windows"]
}
},
"hostPermissions": {
"type": "array",
"minItems": 1,
"maxItems": 1,
"items": { "const": "<all_urls>" }
},
"riskLevel": { "const": "high" }
}
}
}
},
"profileRecommendation": { "const": "dedicated-browser-profile" },
"dataBoundaries": {
"type": "object",
"required": ["webBridgeLocalExecution", "desireCoreModelContext", "modelProviderDisclosureRequired"],
"additionalProperties": false,
"properties": {
"webBridgeLocalExecution": {
"allOf": [{ "$ref": "#/definitions/nonEmptyString" }],
"description": "A scoped statement of the upstream claim about the local WebBridge execution path."
},
"desireCoreModelContext": {
"allOf": [{ "$ref": "#/definitions/nonEmptyString" }],
"description": "A separate disclosure that content entering DesireCore context may be sent to the selected model provider."
},
"modelProviderDisclosureRequired": { "const": true }
}
},
"admission": {
"type": "object",
"required": ["status", "code", "reason", "missingPrerequisites"],
"additionalProperties": false,
"properties": {
"status": { "const": "blocked" },
"code": { "const": "native-integration-not-admitted" },
"reason": { "$ref": "#/definitions/nonEmptyString" },
"missingPrerequisites": {
"type": "array",
"minItems": 4,
"maxItems": 4,
"uniqueItems": true,
"items": {
"type": "string",
"enum": [
"stable-auditable-protocol",
"integration-authorization",
"deterministic-command-receipts",
"user-interaction-pause-signal"
]
}
}
}
},
"compliance": {
"type": "object",
"required": ["reviewedAt", "reviewedBy", "upstreamEndorsed", "relationshipDisclosure", "artifactReviews"],
"additionalProperties": false,
"properties": {
"reviewedAt": { "type": "string", "format": "date" },
"reviewedBy": { "$ref": "#/definitions/nonEmptyString" },
"upstreamEndorsed": { "const": false },
"relationshipDisclosure": { "const": "independent-listing-not-endorsed" },
"artifactReviews": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#/definitions/artifactReview" },
"description": "Immutable upstream artifact audit facts; these records do not admit installation or redistribution."
}
}
}
}
}
}
}

View File

@@ -0,0 +1,381 @@
import { lstat, readFile, readdir } from 'node:fs/promises'
import { dirname, join, relative, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import Ajv from 'ajv'
const scriptDirectory = dirname(fileURLToPath(import.meta.url))
const rootArgumentIndex = process.argv.indexOf('--root')
if (rootArgumentIndex >= 0 && !process.argv[rootArgumentIndex + 1]) {
throw new Error('--root requires a directory path')
}
const repositoryRoot = rootArgumentIndex >= 0
? resolve(process.argv[rootArgumentIndex + 1])
: resolve(scriptDirectory, '..')
const entriesRoot = join(repositoryRoot, 'entries')
const errors = []
const addError = (message) => errors.push(message)
const readText = async (path) => {
try {
return await readFile(path, 'utf8')
} catch (error) {
addError(`${relative(repositoryRoot, path)}: unable to read (${error.message})`)
return null
}
}
const readJson = async (path) => {
const text = await readText(path)
if (text === null) return null
try {
return JSON.parse(text)
} catch (error) {
addError(`${relative(repositoryRoot, path)}: invalid JSON (${error.message})`)
return null
}
}
const formatAjvErrors = (validationErrors = []) =>
validationErrors
.map((error) => `${error.instancePath || '/'} ${error.message}`)
.join('; ')
const sorted = (values) => [...values].sort()
const sameSet = (actual, expected) =>
JSON.stringify(sorted(actual)) === JSON.stringify(sorted(expected))
const containsKey = (value, prohibitedKey) => {
if (Array.isArray(value)) return value.some((item) => containsKey(item, prohibitedKey))
if (!value || typeof value !== 'object') return false
if (Object.hasOwn(value, prohibitedKey)) return true
return Object.values(value).some((item) => containsKey(item, prohibitedKey))
}
const assertHttpsUrl = (rawUrl, context) => {
try {
const url = new URL(rawUrl)
if (url.protocol !== 'https:') addError(`${context}: URL must use HTTPS`)
if (url.username || url.password) addError(`${context}: URL must not contain credentials`)
return url
} catch {
addError(`${context}: invalid URL`)
return null
}
}
const requiredOfficialLinkKinds = [
'product',
'documentation',
'chrome-web-store',
'edge-add-ons',
'privacy',
'terms',
]
const admittedExternalIntegrationIds = new Set(['kimi-webbridge'])
const kimiOfficialLinkPolicy = {
product: {
url: 'https://www.kimi.ai/products/kimi-webbridge',
},
documentation: {
url: 'https://www.kimi.ai/help/kimi-webbridge/kimi-webbridge-introduction',
},
'chrome-web-store': {
url: 'https://chromewebstore.google.com/detail/kimi-webbridge/fldmhceldgbpfpkbgopacenieobmligc',
extensionId: 'fldmhceldgbpfpkbgopacenieobmligc',
},
'edge-add-ons': {
url: 'https://microsoftedge.microsoft.com/addons/detail/kimi-webbridge/bnlffdbcfnanfbknnlaflhlhkocccckg',
extensionId: 'bnlffdbcfnanfbknnlaflhlhkocccckg',
},
privacy: {
url: 'https://www.kimi.ai/user/agreement/userPrivacy?version=v2',
},
terms: {
url: 'https://www.kimi.ai/user/agreement/modelUse?version=v2',
},
}
const requiredKimiPermissions = [
'tabs',
'activeTab',
'debugger',
'storage',
'alarms',
'tabGroups',
'windows',
]
const requiredAdmissionPrerequisites = [
'stable-auditable-protocol',
'integration-authorization',
'deterministic-command-receipts',
'user-interaction-pause-signal',
]
const isValidCalendarDate = (value) => {
if (typeof value !== 'string') return false
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value)
if (!match) return false
const year = Number(match[1])
const month = Number(match[2])
const day = Number(match[3])
const date = new Date(Date.UTC(year, month - 1, day))
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day
}
const describeFilesystemEntry = (entry) => {
if (entry.isSymbolicLink()) return 'symbolic link'
if (entry.isDirectory()) return 'directory'
if (entry.isFile()) return 'file'
if (entry.isBlockDevice()) return 'block device'
if (entry.isCharacterDevice()) return 'character device'
if (entry.isFIFO()) return 'FIFO'
if (entry.isSocket()) return 'socket'
return 'unsupported filesystem entry'
}
const validateExternalDirectoryLayout = async (entryDirectory, manifestId) => {
const prefix = `entries/${manifestId}`
const directoryEntries = await readdir(entryDirectory, { withFileTypes: true })
for (const entry of directoryEntries) {
if (entry.name !== 'manifest.json') {
addError(`${prefix}: external-integration allows only manifest.json; found ${describeFilesystemEntry(entry)} ${entry.name}`)
continue
}
if (!entry.isFile() || entry.isSymbolicLink()) {
addError(`${prefix}/manifest.json: must be a regular file, not a ${describeFilesystemEntry(entry)}`)
}
}
if (directoryEntries.length !== 1 || directoryEntries[0]?.name !== 'manifest.json') {
addError(`${prefix}: external-integration directory must contain exactly one manifest.json regular file`)
}
}
const validateExternalIntegration = async (entryDirectory, manifest) => {
const prefix = `entries/${manifest.id}`
await validateExternalDirectoryLayout(entryDirectory, manifest.id)
if (!admittedExternalIntegrationIds.has(manifest.id)) {
addError(`${prefix}/manifest.json: unknown external-integration id ${manifest.id}`)
}
const forbiddenFields = [
'install',
'entrypoints',
'exposes',
'endpoint',
'connection',
'auth',
'operations',
'source',
]
for (const field of forbiddenFields) {
if (Object.hasOwn(manifest, field)) addError(`${prefix}/manifest.json: forbidden field "${field}"`)
}
const linkKinds = manifest.officialLinks?.map((link) => link.kind) ?? []
if (!sameSet(linkKinds, requiredOfficialLinkKinds)) {
addError(`${prefix}/manifest.json: officialLinks must contain each required kind exactly once`)
}
for (const link of manifest.officialLinks ?? []) {
const url = assertHttpsUrl(link.url, `${prefix}/manifest.json officialLinks.${link.kind}`)
const policy = kimiOfficialLinkPolicy[link.kind]
if (!policy || link.url !== policy.url) {
addError(`${prefix}/manifest.json officialLinks.${link.kind}: URL must exactly equal ${policy?.url ?? 'an admitted URL'}`)
}
if (policy?.extensionId) {
if (link.extensionId !== policy.extensionId) {
addError(`${prefix}/manifest.json officialLinks.${link.kind}: extensionId must equal ${policy.extensionId}`)
}
if (url && url.pathname.split('/').filter(Boolean).at(-1) !== link.extensionId) {
addError(`${prefix}/manifest.json officialLinks.${link.kind}: URL path must end with extensionId`)
}
} else if (Object.hasOwn(link, 'extensionId')) {
addError(`${prefix}/manifest.json officialLinks.${link.kind}: extensionId is allowed only for browser stores`)
}
}
if (manifest.id === 'kimi-webbridge') {
for (const [field, expectedHost] of [
['listingMaintainer', 'github.com'],
['upstreamMaintainer', 'www.kimi.ai'],
]) {
const url = assertHttpsUrl(manifest[field]?.url, `${prefix}/manifest.json ${field}.url`)
if (url && url.hostname !== expectedHost) {
addError(`${prefix}/manifest.json ${field}.url: hostname must be ${expectedHost}`)
}
}
}
if (manifest.listingMaintainer?.url !== 'https://github.com/desirecore/registry' || manifest.listingMaintainer?.verified !== true) {
addError(`${prefix}/manifest.json: listingMaintainer must be the verified DesireCore Registry URL`)
}
if (manifest.upstreamMaintainer?.url !== 'https://www.kimi.ai/' || manifest.upstreamMaintainer?.verified !== true) {
addError(`${prefix}/manifest.json: upstreamMaintainer must be the verified Kimi URL`)
}
const componentKinds = manifest.components?.map((component) => component.kind) ?? []
if (!sameSet(componentKinds, ['browser-extension', 'local-daemon'])) {
addError(`${prefix}/manifest.json: components must contain browser-extension and local-daemon exactly once`)
}
for (const component of manifest.components ?? []) {
if (component.kind === 'browser-extension') {
if (!sameSet(component.browsers ?? [], ['chrome', 'edge']) || Object.hasOwn(component, 'platforms')) {
addError(`${prefix}/manifest.json: browser-extension must declare only Chrome and Edge browsers`)
}
}
if (component.kind === 'local-daemon') {
if (!Array.isArray(component.platforms) ||
!component.platforms.includes('windows') ||
!component.platforms.includes('macos') ||
Object.hasOwn(component, 'browsers')) {
addError(`${prefix}/manifest.json: local-daemon must declare at least Windows and macOS and no browsers`)
}
}
}
const apiPermissions = manifest.permissions?.browserExtension?.apiPermissions ?? []
if (!sameSet(apiPermissions, requiredKimiPermissions)) {
addError(`${prefix}/manifest.json: browser extension API permissions must match the audited Kimi permission set`)
}
const hostPermissions = manifest.permissions?.browserExtension?.hostPermissions ?? []
if (!sameSet(hostPermissions, ['<all_urls>'])) {
addError(`${prefix}/manifest.json: browser extension must disclose <all_urls>`)
}
if (!sameSet(manifest.admission?.missingPrerequisites ?? [], requiredAdmissionPrerequisites)) {
addError(`${prefix}/manifest.json: blocked admission prerequisites are incomplete`)
}
const artifactIdentities = new Set()
if (!isValidCalendarDate(manifest.compliance?.reviewedAt)) {
addError(`${prefix}/manifest.json compliance.reviewedAt: expected a real YYYY-MM-DD calendar date`)
}
for (const artifact of manifest.compliance?.artifactReviews ?? []) {
const artifactContext = `${prefix}/manifest.json artifact ${artifact.platform}/${artifact.architecture}`
const url = assertHttpsUrl(artifact.url, artifactContext)
if (url && url.hostname !== 'cdn.kimi.com') {
addError(`${artifactContext}: hostname must be cdn.kimi.com`)
}
if (url && !url.pathname.includes(`/v${artifact.version}/releases/`)) {
addError(`${artifactContext}: URL must pin the reviewed version in its release path`)
}
if (url && (url.search || url.hash)) {
addError(`${artifactContext}: URL must not contain query or fragment components`)
}
if (!isValidCalendarDate(artifact.reviewedAt)) {
addError(`${artifactContext} reviewedAt: expected a real YYYY-MM-DD calendar date`)
}
const identity = `${artifact.platform}/${artifact.architecture}`
if (artifactIdentities.has(identity)) addError(`${artifactContext}: duplicate platform/architecture review`)
artifactIdentities.add(identity)
}
}
const schemaVersion = (await readText(join(repositoryRoot, 'SCHEMA_VERSION')))?.trim()
const rootManifest = await readJson(join(repositoryRoot, 'manifest.json'))
const entrySchema = await readJson(join(repositoryRoot, 'schemas', 'registry-entry.schema.json'))
if (!schemaVersion || !/^\d+\.\d+\.\d+$/.test(schemaVersion)) {
addError('SCHEMA_VERSION: expected a semantic version')
}
if (rootManifest) {
if (rootManifest.version !== schemaVersion) addError('manifest.json#version must equal SCHEMA_VERSION')
if (rootManifest.dataVersion !== schemaVersion) addError('manifest.json#dataVersion must equal SCHEMA_VERSION')
}
let validateEntry = null
if (entrySchema) {
try {
const ajv = new Ajv({ allErrors: true, strict: true, validateFormats: false })
validateEntry = ajv.compile(entrySchema)
} catch (error) {
addError(`schemas/registry-entry.schema.json: unable to compile (${error.message})`)
}
}
const manifests = []
const seenIds = new Set()
for (const directoryEntry of await readdir(entriesRoot, { withFileTypes: true })) {
if (!directoryEntry.isDirectory()) {
addError(`entries/${directoryEntry.name}: entries root may contain directories only`)
continue
}
const entryDirectory = join(entriesRoot, directoryEntry.name)
const manifestPath = join(entryDirectory, 'manifest.json')
let manifestStat
try {
manifestStat = await lstat(manifestPath)
} catch (error) {
if (error.code === 'ENOENT') {
addError(`entries/${directoryEntry.name}: missing manifest.json`)
continue
}
throw error
}
if (!manifestStat.isFile() || manifestStat.isSymbolicLink()) {
addError(`entries/${directoryEntry.name}/manifest.json: must be a regular file and not a symbolic link`)
continue
}
const manifest = await readJson(manifestPath)
if (!manifest) continue
manifests.push(manifest)
if (manifest.id !== directoryEntry.name) {
addError(`entries/${directoryEntry.name}/manifest.json: id must equal directory name`)
}
if (seenIds.has(manifest.id)) addError(`entries/${directoryEntry.name}/manifest.json: duplicate id ${manifest.id}`)
seenIds.add(manifest.id)
for (const injectedField of ['sourceId', 'hasInstall']) {
if (containsKey(manifest, injectedField)) {
addError(`entries/${directoryEntry.name}/manifest.json: ${injectedField} is client-injected and must not be authored`)
}
}
if (validateEntry && !validateEntry(manifest)) {
addError(`entries/${directoryEntry.name}/manifest.json: ${formatAjvErrors(validateEntry.errors)}`)
}
if (manifest.type === 'external-integration') {
await validateExternalIntegration(entryDirectory, manifest)
}
}
if (rootManifest) {
const expectedStats = {
totalEntries: manifests.length,
dockerApps: manifests.filter((entry) => entry.type === 'docker-app').length,
mcpServices: manifests.filter((entry) => entry.type === 'mcp').length,
httpApis: manifests.filter((entry) => entry.type === 'http-api').length,
externalIntegrations: manifests.filter((entry) => entry.type === 'external-integration').length,
}
for (const [field, expected] of Object.entries(expectedStats)) {
if (rootManifest.stats?.[field] !== expected) {
addError(`manifest.json#stats.${field}: expected ${expected}, received ${rootManifest.stats?.[field]}`)
}
}
const extraStats = Object.keys(rootManifest.stats ?? {}).filter((field) => !Object.hasOwn(expectedStats, field))
if (extraStats.length > 0) addError(`manifest.json#stats: unknown fields ${extraStats.join(', ')}`)
}
for (const manifest of manifests) {
if (manifest.sourceAppId && !seenIds.has(manifest.sourceAppId)) {
addError(`entries/${manifest.id}/manifest.json: sourceAppId ${manifest.sourceAppId} does not exist`)
}
}
if (errors.length > 0) {
console.error(`Registry validation failed with ${errors.length} error(s):`)
for (const error of errors) console.error(`- ${error}`)
process.exitCode = 1
} else {
const counts = rootManifest.stats
console.log(
`Registry validation passed: ${counts.totalEntries} entries ` +
`(${counts.dockerApps} Docker, ${counts.mcpServices} MCP, ` +
`${counts.httpApis} HTTP API, ${counts.externalIntegrations} external integration).`,
)
}

View File

@@ -0,0 +1,259 @@
import assert from 'node:assert/strict'
import { cp, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
import { spawnSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'
import test from 'node:test'
const scriptDirectory = dirname(fileURLToPath(import.meta.url))
const repositoryRoot = resolve(scriptDirectory, '..')
const validatorPath = join(scriptDirectory, 'validate-registry.mjs')
const createFixture = async () => {
const root = await mkdtemp(join(tmpdir(), 'desirecore-registry-test-'))
await Promise.all([
cp(join(repositoryRoot, 'entries'), join(root, 'entries'), { recursive: true }),
cp(join(repositoryRoot, 'schemas'), join(root, 'schemas'), { recursive: true }),
cp(join(repositoryRoot, 'SCHEMA_VERSION'), join(root, 'SCHEMA_VERSION')),
cp(join(repositoryRoot, 'manifest.json'), join(root, 'manifest.json')),
])
return root
}
const readJson = async (path) => JSON.parse(await readFile(path, 'utf8'))
const writeJson = async (path, value) => writeFile(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
const runValidator = (root) => spawnSync(
process.execPath,
[validatorPath, '--root', root],
{ cwd: repositoryRoot, encoding: 'utf8' },
)
const expectRejected = async (mutate, expectedMessage) => {
const root = await createFixture()
try {
await mutate(root)
const result = runValidator(root)
assert.equal(result.status, 1, `validator unexpectedly passed:\n${result.stdout}`)
assert.match(`${result.stdout}\n${result.stderr}`, expectedMessage)
} finally {
await rm(root, { recursive: true, force: true })
}
}
test('accepts the checked-in Registry fixture', async () => {
const root = await createFixture()
try {
const result = runValidator(root)
assert.equal(result.status, 0, result.stderr)
assert.match(result.stdout, /Registry validation passed: 22 entries/)
} finally {
await rm(root, { recursive: true, force: true })
}
})
test('rejects an entry whose directory and id differ', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.id = 'different-id'
await writeJson(path, manifest)
}, /id must equal directory name/)
})
test('rejects client-injected sourceId in an upstream manifest', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.sourceId = 'untrusted-source'
await writeJson(path, manifest)
}, /sourceId is client-injected/)
})
test('rejects stale root statistics', async () => {
await expectRejected(async (root) => {
const path = join(root, 'manifest.json')
const manifest = await readJson(path)
manifest.stats.externalIntegrations = 0
await writeJson(path, manifest)
}, /stats\.externalIntegrations: expected 1, received 0/)
})
test('rejects an unknown external-integration id', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.id = 'unreviewed-bridge'
await writeJson(path, manifest)
}, /unknown external-integration id unreviewed-bridge/)
})
for (const kind of ['product', 'documentation', 'chrome-web-store', 'edge-add-ons', 'privacy', 'terms']) {
test(`rejects a modified ${kind} official URL`, async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
const link = manifest.officialLinks.find((item) => item.kind === kind)
link.url = `${link.url}/tampered`
await writeJson(path, manifest)
}, /URL must exactly equal/)
})
}
test('rejects a browser-store extension id that does not match its URL path', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
const link = manifest.officialLinks.find((item) => item.kind === 'chrome-web-store')
link.url = 'https://chromewebstore.google.com/detail/kimi-webbridge/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
await writeJson(path, manifest)
}, /URL path must end with extensionId/)
})
test('rejects an incorrect structured extension id', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
const link = manifest.officialLinks.find((item) => item.kind === 'edge-addons')
?? manifest.officialLinks.find((item) => item.kind === 'edge-add-ons')
link.extensionId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
await writeJson(path, manifest)
}, /extensionId must equal bnlffdbcfnanfbknnlaflhlhkocccckg/)
})
test('rejects installation fields for listing-only integrations', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.install = { method: 'unsupported' }
await writeJson(path, manifest)
}, /forbidden field "install"/)
})
test('rejects an unverified or unexpected listing maintainer', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.listingMaintainer.url = 'https://github.com/example/registry'
manifest.listingMaintainer.verified = false
await writeJson(path, manifest)
}, /listingMaintainer must be the verified DesireCore Registry URL/)
})
test('rejects a non-tools external category', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.category = 'browser'
await writeJson(path, manifest)
}, /must be equal to constant/)
})
test('rejects an unapproved external icon', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.icon = 'kimi-logo'
await writeJson(path, manifest)
}, /must be equal to one of the allowed values/)
})
test('rejects extra text files in an external-integration directory', async () => {
await expectRejected(async (root) => {
await writeFile(join(root, 'entries', 'kimi-webbridge', 'usage.md'), '# not allowed\n', 'utf8')
}, /allows only manifest\.json; found file usage\.md/)
})
test('rejects extra directories in an external-integration directory', async () => {
await expectRejected(async (root) => {
await mkdir(join(root, 'entries', 'kimi-webbridge', 'assets'))
}, /allows only manifest\.json; found directory assets/)
})
test('rejects symbolic links in an external-integration directory', { skip: process.platform === 'win32' }, async () => {
await expectRejected(async (root) => {
await symlink('manifest.json', join(root, 'entries', 'kimi-webbridge', 'alias.json'))
}, /allows only manifest\.json; found symbolic link alias\.json/)
})
test('rejects a symbolic-link manifest', { skip: process.platform === 'win32' }, async () => {
await expectRejected(async (root) => {
const directory = join(root, 'entries', 'kimi-webbridge')
const manifestPath = join(directory, 'manifest.json')
const backupPath = join(directory, 'reviewed.json')
await cp(manifestPath, backupPath)
await rm(manifestPath)
await symlink('reviewed.json', manifestPath)
}, /manifest\.json: must be a regular file and not a symbolic link/)
})
test('rejects binary files in an external-integration directory', async () => {
await expectRejected(async (root) => {
await writeFile(join(root, 'entries', 'kimi-webbridge', 'payload.bin'), Buffer.from([0, 255, 1, 254]))
}, /allows only manifest\.json; found file payload\.bin/)
})
test('rejects special filesystem entries in an external-integration directory', { skip: process.platform === 'win32' }, async () => {
await expectRejected(async (root) => {
const fifoPath = join(root, 'entries', 'kimi-webbridge', 'control.fifo')
const result = spawnSync('mkfifo', [fifoPath], { encoding: 'utf8' })
assert.equal(result.status, 0, result.stderr)
}, /allows only manifest\.json; found FIFO control\.fifo/)
})
test('rejects an impossible compliance review date', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.reviewedAt = '2026-02-30'
await writeJson(path, manifest)
}, /compliance\.reviewedAt: expected a real YYYY-MM-DD calendar date/)
})
test('rejects an impossible artifact review date', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.artifactReviews[0].reviewedAt = '2026-13-01'
await writeJson(path, manifest)
}, /artifact macos\/arm64 reviewedAt: expected a real YYYY-MM-DD calendar date/)
})
test('rejects an artifact URL that is not pinned to its reviewed version', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.artifactReviews[0].url =
'https://cdn.kimi.com/webbridge/unpinned/releases/kimi-webbridge-darwin-arm64'
await writeJson(path, manifest)
}, /URL must pin the reviewed version in its release path/)
})
test('rejects query parameters on an immutable artifact URL', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.artifactReviews[0].url += '?redirect=1'
await writeJson(path, manifest)
}, /URL must not contain query or fragment components/)
})
test('rejects unsupported universal artifact architecture', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
manifest.compliance.artifactReviews[0].architecture = 'universal'
await writeJson(path, manifest)
}, /must be equal to one of the allowed values/)
})
test('rejects a local daemon that omits Windows', async () => {
await expectRejected(async (root) => {
const path = join(root, 'entries', 'kimi-webbridge', 'manifest.json')
const manifest = await readJson(path)
const daemon = manifest.components.find((item) => item.kind === 'local-daemon')
daemon.platforms = ['macos', 'linux']
await writeJson(path, manifest)
}, /local-daemon must declare at least Windows and macOS/)
})