diff --git a/packages/ui-mac/electron-builder.config.ts b/packages/ui-mac/electron-builder.config.ts index e2798ae2c800..c3a6dca60796 100644 --- a/packages/ui-mac/electron-builder.config.ts +++ b/packages/ui-mac/electron-builder.config.ts @@ -97,12 +97,6 @@ const getBase = (appId: string): Configuration => ({ from: "resources/agents/", to: "agents/", }, - { - // REQ-023 T2:vendored 插件(自包含 plugin.js;installVendoredPlugin 复制入 ~/.alpha/plugins, - // plugin[] 写绝对路径 —— 安装零网络)。 - from: "resources/plugins/", - to: "plugins/", - }, { // MIT license/attribution shipped inside the app (B15). Also surfaced natively via // app.setAboutPanelOptions in src/main/index.ts. diff --git a/packages/ui-mac/resources/NOTICE.txt b/packages/ui-mac/resources/NOTICE.txt index 231ff904e09a..349284d8e076 100644 --- a/packages/ui-mac/resources/NOTICE.txt +++ b/packages/ui-mac/resources/NOTICE.txt @@ -39,14 +39,6 @@ Copyright Anthropic, licensed under the Apache License 2.0. Its full license text ships alongside it (resources/skills/skill-creator/LICENSE.txt). Source: Anthropic's official Claude plugins/skills. --------------------------------------------------------------------------------- -The "opencode-notify" plugin bundled under resources/plugins/opencode-notify -(plugin.js, vendored verbatim from npm opencode-notify@0.3.1 dist/index.js, -with its dependency detect-terminal inlined by the upstream build) is licensed -under the MIT License. The upstream OpenCodeNotifier.app helper binary is NOT -redistributed here; the plugin uses its built-in osascript fallback. - --------------------------------------------------------------------------------- Third-party components -------------------------------------------------------------------------------- Other bundled components (Electron, SolidJS, and the dependencies declared in the diff --git a/packages/ui-mac/resources/extension-seed/NOTICE.md b/packages/ui-mac/resources/extension-seed/NOTICE.md index 07b71cdf3838..e24e222cda6a 100644 --- a/packages/ui-mac/resources/extension-seed/NOTICE.md +++ b/packages/ui-mac/resources/extension-seed/NOTICE.md @@ -1,6 +1,6 @@ # Alpha extension seed — NOTICE / third-party attributions -Generated by `scripts/build-seed-lock.mjs` from stable catalog `2026-07-13.1` (payload sha256 `e1c148c66a107ddca8f71d626ed5af53b639e215b2a328ac502bc87574311b4a`). Do not hand-edit — regenerate instead. +Generated by `scripts/build-seed-lock.mjs` from stable catalog `2026-08-06.1` (payload sha256 `e37a4cf3142e12169fa5bd0a2b6907189499122f7ae578a22ffa5a731dc1e874`). Do not hand-edit — regenerate instead. Machine-readable inventory: [`seed.lock.json`](./seed.lock.json) (schema `alpha.extension-seed.lock.v1`; per-asset SPDX license identifiers). diff --git a/packages/ui-mac/resources/extension-seed/extension-seed.snapshot.json b/packages/ui-mac/resources/extension-seed/extension-seed.snapshot.json index a7b6124632ca..4bd0c149299a 100644 --- a/packages/ui-mac/resources/extension-seed/extension-seed.snapshot.json +++ b/packages/ui-mac/resources/extension-seed/extension-seed.snapshot.json @@ -1,8 +1,8 @@ { "v": 1, - "catalogVersion": "2026-07-13.1", - "lockSha256": "d13e1059ac2dba38f2f1082d1e269d0f258c5a89be7d0269b6417f37378bcf56", - "noticeSha256": "06e1f0a4483fb1ff23c18ead45f9c7458d0ae93e06673077c46b8d01decc4eb1", + "catalogVersion": "2026-08-06.1", + "lockSha256": "faad19deea09ab8debf93af45fc9bad92a0b52fbda0b6c71ef1b428bd4337af2", + "noticeSha256": "4c4e9d0e718e1e1076c8f4e6ac0eac04daa027247ce005e486aabcd2bea911ee", "blobCount": 98, "blobBytes": 5670465, "source": "alpha-web-checkout", diff --git a/packages/ui-mac/resources/extension-seed/seed.lock.json b/packages/ui-mac/resources/extension-seed/seed.lock.json index e583444c875e..76eae33cd30f 100644 --- a/packages/ui-mac/resources/extension-seed/seed.lock.json +++ b/packages/ui-mac/resources/extension-seed/seed.lock.json @@ -1,12 +1,12 @@ { "schema": "alpha.extension-seed.lock.v1", "channel": "stable", - "catalogVersion": "2026-07-13.1", + "catalogVersion": "2026-08-06.1", "catalog": { - "sha256": "fd5dbc78b3524333c8d90966d8ff48b0010b49c7d8d162562fe3059555fdf3d1", - "bytes": 59591, - "url": "https://alphacodeone.com/catalog/v1/releases/2026-07-13.1/catalog.json", - "sigUrl": "https://alphacodeone.com/catalog/v1/releases/2026-07-13.1/catalog.json.sig" + "sha256": "e37a4cf3142e12169fa5bd0a2b6907189499122f7ae578a22ffa5a731dc1e874", + "bytes": 81682, + "url": "https://alphacodeone.com/catalog/v1/releases/2026-08-06.1/catalog.json", + "sigUrl": "https://alphacodeone.com/catalog/v1/releases/2026-08-06.1/catalog.json.sig" }, "supportedPlatforms": [ "darwin-arm64", @@ -733,4 +733,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/packages/ui-mac/resources/plugins/opencode-notify/README.md b/packages/ui-mac/resources/plugins/opencode-notify/README.md deleted file mode 100644 index c6bbd3f01b71..000000000000 --- a/packages/ui-mac/resources/plugins/opencode-notify/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# vendored: opencode-notify@0.3.1(REQ-023 T2 离线资产通道) - -- 来源:npm `opencode-notify@0.3.1`(MIT,社区插件)—— 文件 = 包内 `dist/index.js` 原样(其构建已内联唯一依赖 `detect-terminal`,满足 ADR-006 自包含要求,零改动)。 -- **省略 `OpenCodeNotifier.app`**(224KB mach-o 原生通知器):未签名二进制进签名 Resources 会威胁公证;代码自带 osascript 回退,通知功能保留(样式降级为系统 AppleScript 通知)。 -- 安装:主进程复制本目录 → `/plugins/opencode-notify/` → 当前环境的 - `/alpha.jsonc` 中 `plugin[]` 写 **绝对路径** → 引擎直接加载,**零网络**。 - `ALPHA_GLOBAL_DIR` 只取桌面进程初始化后的 canonical 值,不得回退退休 home 根。npm@钉版仍是无 - vendored 资产条目的 fallback。 -- 升级:手动重新 `npm pack opencode-notify@` 替换本文件并 bump catalog 钉版。 -- 许可:MIT,见 resources/NOTICE.txt。 diff --git a/packages/ui-mac/src/main/ext-curation-policy.test.ts b/packages/ui-mac/src/main/ext-curation-policy.test.ts index 6bafe943b787..367947955cd4 100644 --- a/packages/ui-mac/src/main/ext-curation-policy.test.ts +++ b/packages/ui-mac/src/main/ext-curation-policy.test.ts @@ -54,14 +54,14 @@ describe("sessionGrantIdsFromEntries(纯判定,fail-closed 采信)", () => { }) describe("readSessionGrantIdsSync(同步读链,r1-4:不可判定 ≠ 空集)", () => { - test("无已验 LKG/v1 缓存 → ok:false(远端状态未知),partialIds = 随包可识别子集(当前随包无 curation → 空)", () => { + test("无已验 LKG/v1 缓存 → ok:false(远端状态未知),partialIds = 当前随包可识别子集", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "curation-oracle-")) try { const oracle = readSessionGrantIdsSync(dir, "stable") expect(oracle.ok).toBe(false) if (!oracle.ok) { expect(oracle.reason).toContain("no verified channel LKG") - expect(oracle.partialIds.size).toBe(0) + expect([...oracle.partialIds].sort()).toEqual(["mcp:chrome-devtools", "mcp:markitdown"]) } } finally { fs.rmSync(dir, { recursive: true, force: true }) diff --git a/packages/ui-mac/src/main/ext-fs-installer.test.ts b/packages/ui-mac/src/main/ext-fs-installer.test.ts index 21a560d04593..29a8eecee26a 100644 --- a/packages/ui-mac/src/main/ext-fs-installer.test.ts +++ b/packages/ui-mac/src/main/ext-fs-installer.test.ts @@ -321,19 +321,14 @@ describe("agentInstallPresent (REQ-100 #354)", () => { }) }) -describe("collectVendoredPluginPayload — #378 随包 plugin 载荷收集(只读;CAS 摄取源)", () => { - test("collects the real bundled plugin dir (byte-exact, POSIX rel paths, plugin.js present)", () => { - const r = collectVendoredPluginPayload("plugins/opencode-notify", "opencode-notify") - expect(r.ok).toBe(true) - if (!r.ok) return - const js = r.files.find((f) => f.path === "plugin.js") - expect(js).toBeDefined() - expect(js!.data.equals(fs.readFileSync(path.join(resourcesRoot(), "plugins", "opencode-notify", "plugin.js")))).toBe(true) - // 零副作用:资产原样(只读收集) - expect(fs.existsSync(path.join(resourcesRoot(), "plugins", "opencode-notify", "plugin.js"))).toBe(true) +describe("collectVendoredPluginPayload — ADR-040 后无随包 plugin 资产", () => { + test("the retired bundled asset is absent and cannot be collected", () => { + const retired = collectVendoredPluginPayload("plugins/opencode-notify", "opencode-notify") + expect(retired.ok).toBe(false) + if (!retired.ok) expect(retired.reason).toContain("未随此版本打包") }) - test("missing asset / unsafe key / unsafe name refused", () => { + test("missing asset and unsafe key/name are refused", () => { const ghost = collectVendoredPluginPayload("plugins/ghost-plugin", "ghost-plugin") expect(ghost.ok).toBe(false) if (!ghost.ok) expect(ghost.reason).toContain("未随此版本打包") @@ -347,25 +342,10 @@ describe("collectVendoredPluginPayload — #378 随包 plugin 载荷收集(只 if (!drift.ok) expect(drift.reason).toContain("content identity drift") }) - test("r16:stageVendoredPluginVersioned 走同一收集合同 —— 落盘与收集器逐字节一致、零额外条目;收集器拒即 staging 拒", () => { - const c = collectVendoredPluginPayload("plugins/opencode-notify", "opencode-notify") - expect(c.ok).toBe(true) - if (!c.ok) return - const s = stageVendoredPluginVersioned("plugins/opencode-notify", "opencode-notify") - expect(s.ok).toBe(true) - if (!s.ok) return - expect(path.dirname(s.dir)).toBe(path.join(alphaDir, "plugins")) - const walked: string[] = [] - const walk = (rel: string) => { - for (const n of fs.readdirSync(rel === "" ? s.dir : path.join(s.dir, rel))) { - const childRel = rel === "" ? n : `${rel}/${n}` - if (fs.lstatSync(path.join(s.dir, childRel)).isDirectory()) walk(childRel) - else walked.push(childRel) - } - } - walk("") - expect(walked.sort()).toEqual(c.files.map((f) => f.path).sort()) - for (const f of c.files) expect(fs.readFileSync(path.join(s.dir, f.path)).equals(f.data)).toBe(true) + test("staging cannot revive an absent packaged plugin", () => { + const retired = stageVendoredPluginVersioned("plugins/opencode-notify", "opencode-notify") + expect(retired.ok).toBe(false) + if (!retired.ok) expect(retired.reason).toContain("未随此版本打包") const ghost = stageVendoredPluginVersioned("plugins/ghost-plugin", "ghost-plugin") expect(ghost.ok).toBe(false) if (!ghost.ok) expect(ghost.reason).toContain("未随此版本打包") diff --git a/packages/ui-mac/src/preload/types.ts b/packages/ui-mac/src/preload/types.ts index 5830013c4ce2..10b7aed178d9 100644 --- a/packages/ui-mac/src/preload/types.ts +++ b/packages/ui-mac/src/preload/types.ts @@ -233,7 +233,7 @@ export type InstallReceipt = { origin: InstallReceiptOrigin /** absolute paths owned by this install (fs types + bridge symlinks) */ files?: string[] - /** config ownership, e.g. "mcp.markitdown" / "plugin:opencode-notify@0.3.1" */ + /** config ownership, e.g. "mcp.markitdown" / "plugin:example@1.0.0" */ configKey?: string } export type InstallLedgerView = { global: InstallReceipt[]; project: InstallReceipt[]; warnings: string[] } diff --git a/packages/ui-mac/src/renderer/extensions/alpha-catalog.json b/packages/ui-mac/src/renderer/extensions/alpha-catalog.json index 84e7f5a53d39..c8a91162ddd8 100644 --- a/packages/ui-mac/src/renderer/extensions/alpha-catalog.json +++ b/packages/ui-mac/src/renderer/extensions/alpha-catalog.json @@ -1,5 +1,5 @@ { - "version": "2026-07-13.1", + "version": "2026-08-06.1", "_note": "alpha-code 扩展目录 —— 远程分发真源(REQ-032:alphacodeone.com/catalog/v1,ed25519 签名,ETag 缓存;A 侧回退链 远端→缓存→内置)。schema 同 A 侧 alpha-catalog.json + 条目级 version + remoteAsset(下载清单,sha256 钉死)。编辑本文件后跑 scripts/build-catalog.mjs 再 git commit + deploy。", "_disclaimers": [ "标 _verify 的条目:包名/协议/可用性需落地前手工核实,不得当作已确认事实。", @@ -8,7 +8,7 @@ "MCP command/version 全部钉精确版本(A2/T1.5):npx `@pkg@x.y.z` / uvx `pkg@x.y.z`,消除每启动在线解析风暴。钉的值 = 更新当日各包 latest,行为与不钉一致、仅冻结确定性。升级 = 手动 bump(见 npm/pypi)。存量用户配置的一键钉版本迁移(T1.5 第二半)仍待做。", "内置 skill 资产(builtinAssetKey → resources/skills/):alpha-upstream-sync / safe-refactor(MIT,自写)+ skill-creator(Apache-2.0,Anthropic 官方,S12 T7 已打包,见 NOTICE)。mcp-builder / canvas-design / brand-guidelines 及空壳 bundle:design 已撤(REQ-044:资产从未打包 → 安装恒失败;S21 真机实锤)——资产就绪后经远程 catalog(REQ-032)上架,零发版,不再内置无资产条目。", "tools[]/hooks[] 是精选元数据(详情页展示用),非全集;引擎无 tools 查询路由,实时探测为 flag 内 V2(REQ-019 T8)。标 _verify 条目的 tools[] 同属待核实。", - "agent 类条目 = vendored md 资产(resources/agents/),安装经 writeAgent 同管线(桥+账本);plugin 条目带 vendoredAssetKey 时安装零网络(REQ-023)。", + "agent 类条目 = vendored md 资产(resources/agents/),安装经 writeAgent 同管线(桥+账本);legacy catalog 的 plugin entry type 只保留为货架词汇,ADR-040 后当前目录不再发布会写入引擎 plugin[] 的条目。", "REQ-105(2026-07-13,alpha-web#21):REQ-080 上架的 Word/PPT 社区连接器上游已于 2026-03-03 归档(不再维护)→ 从 stable catalog 下架。处置 = 条目移除而非 tombstone/archived 标记(A 侧 schema 无此字段,且其快照守卫禁归档包名逐字出现);已装用户由 A 侧随包 advisory 静态表 + receipts 如实警示,不静默删除。Excel 连接器审计钉版 0.1.8、仅 local stdio(详见条目 _provenance);回流/漂移由 tests/catalog-guard.test.mjs 拦截。" ], "entries": [ @@ -40,7 +40,60 @@ "name": "convert_to_markdown", "description": "把文件 / URL(PDF/Word/PPT/Excel/图片/HTML)转成 Markdown" } - ] + ], + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "labs", + "activationPolicy": "session-grant", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [], + "networkDomains": [ + "127.0.0.1", + "github.com", + "img.shields.io", + "modelcontextprotocol.io", + "pdm.fming.dev", + "pypi.org", + "python-poetry.org", + "www.microsoft.com" + ], + "requiredSecrets": [], + "runtimeDependencies": [ + "python" + ], + "download": { + "bytes": null, + "basis": "unknown" + } + }, + "refs": { + "sbom": { + "sha256": "448b40a09ce894a6cc1b93b14e85b6f4c892f57ba6782974fc3c77a7126a1d23", + "bytes": 258, + "url": "https://alphacodeone.com/catalog/assets/mcp.markitdown/1.0.0/alpha-curation/sbom/448b40a09ce894a6cc1b93b14e85b6f4c892f57ba6782974fc3c77a7126a1d23.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "752d7ab8d17ebd5712a82606a5785bad384da312b63b98b2b5266cc1fa1bb3b9", + "bytes": 465, + "url": "https://alphacodeone.com/catalog/assets/mcp.markitdown/1.0.0/alpha-curation/intake-provenance/752d7ab8d17ebd5712a82606a5785bad384da312b63b98b2b5266cc1fa1bb3b9.json", + "format": "alpha.intake-provenance.v1+json" + } + } + } }, { "id": "mcp:excel", @@ -142,7 +195,61 @@ "name": "search_files", "description": "按名称递归检索文件" } - ] + ], + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "precache", + "activationPolicy": "default-disabled", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [ + "fs:read", + "fs:write" + ], + "networkDomains": [ + "anthropic.com", + "code.visualstudio.com", + "github.com", + "img.shields.io", + "insiders.vscode.dev", + "modelcontextprotocol.io" + ], + "requiredSecrets": [], + "runtimeDependencies": [ + "node" + ], + "download": { + "bytes": null, + "basis": "unknown" + } + }, + "refs": { + "sbom": { + "sha256": "440af2f3847a719355731bcb94269baf9511242e711eb1f6288502e4036621ae", + "bytes": 258, + "url": "https://alphacodeone.com/catalog/assets/mcp.filesystem/1.0.0/alpha-curation/sbom/440af2f3847a719355731bcb94269baf9511242e711eb1f6288502e4036621ae.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "3d882c868067dcf43bf5b898b871026ad3da94f81d76948572e1d5b03498e1a4", + "bytes": 514, + "url": "https://alphacodeone.com/catalog/assets/mcp.filesystem/1.0.0/alpha-curation/intake-provenance/3d882c868067dcf43bf5b898b871026ad3da94f81d76948572e1d5b03498e1a4.json", + "format": "alpha.intake-provenance.v1+json" + } + } + } }, { "id": "mcp:fetch", @@ -172,7 +279,72 @@ "name": "fetch", "description": "抓取 URL 并转 Markdown(可分段续读)" } - ] + ], + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "precache", + "activationPolicy": "default-disabled", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [ + "net:http" + ], + "networkDomains": [ + "api.example.com", + "bower.io", + "docs.astral.sh", + "example.com", + "files.pythonhosted.org", + "github.com", + "gruntjs.com", + "img.shields.io", + "insiders.vscode.dev", + "nextjs.org", + "nodejs.org", + "parceljs.org", + "pdm.fming.dev", + "proxy.example.com", + "pypi.org", + "python-poetry.org", + "snowpack.dev" + ], + "requiredSecrets": [], + "runtimeDependencies": [ + "python", + "uv" + ], + "download": { + "bytes": null, + "basis": "unknown" + } + }, + "refs": { + "sbom": { + "sha256": "74413850a99f90697df0a24f292eff7b5533f22c1de2942286cb7e70ed9110f3", + "bytes": 248, + "url": "https://alphacodeone.com/catalog/assets/mcp.fetch/1.0.0/alpha-curation/sbom/74413850a99f90697df0a24f292eff7b5533f22c1de2942286cb7e70ed9110f3.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "3260c296249bb49dfc7e0ff894250f57b4436d00c74ca0a28a9f62d6a57bd5b3", + "bytes": 709, + "url": "https://alphacodeone.com/catalog/assets/mcp.fetch/1.0.0/alpha-curation/intake-provenance/3260c296249bb49dfc7e0ff894250f57b4436d00c74ca0a28a9f62d6a57bd5b3.json", + "format": "alpha.intake-provenance.v1+json" + } + } + } }, { "id": "mcp:playwright", @@ -197,7 +369,7 @@ "runtimeDep": [ "node" ], - "_verify": "实测结论(证据:docs/verification/2026-07-22-d5-playwright-kernel/verify.md):默认使用系统 Chrome,首次打开网页下载 0 字节;选择 Chromium 浏览器内核时,首次打开网页从 cdn.playwright.dev 下载约 268 MB。系统无 Chrome、下载或启动失败(含受限网络/中国区网络问题)都会直接报错,不会静默回退或伪装成功。默认安装配置已确认无需改变。中国区弱网格(需 sudo pfctl)与无 Chrome 设备的真机确认仍由用户后续补测。" + "_verify": "首次浏览时 Playwright 需浏览器内核:默认下载 Chromium(~150MB,中国区 egress 慢),或在 command 末尾加 \"--browser\",\"chrome\" 复用系统已装 Chrome(免下载但需已装)。runtimeDep 只能 which 到 node,内核下载发生在运行时而非安装时 → A6 必须桌面实测首个 navigate 能否真起浏览器。" }, "tools": [ { @@ -224,7 +396,75 @@ "name": "browser_evaluate", "description": "在页面内执行 JS" } - ] + ], + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "precache", + "activationPolicy": "default-disabled", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [ + "net:http" + ], + "networkDomains": [ + "block.github.io", + "code.visualstudio.com", + "cursor.com", + "docs.cline.bot", + "docs.factory.ai", + "docs.github.com", + "docs.qodo.ai", + "docs.warp.dev", + "docs.windsurf.com", + "example.com", + "files.lmstudio.ai", + "github.com", + "img.shields.io", + "insiders.vscode.dev", + "junie.jetbrains.com", + "kiro.dev", + "lmstudio.ai", + "modelcontextprotocol.io", + "opencode.ai", + "playwright.dev", + "www.apache.org" + ], + "requiredSecrets": [], + "runtimeDependencies": [ + "node" + ], + "download": { + "bytes": null, + "basis": "unknown" + } + }, + "refs": { + "sbom": { + "sha256": "c7bdeb162de72c19f00be720d2363be86d2580ddde0595a87eb0a5f1c98eb93a", + "bytes": 258, + "url": "https://alphacodeone.com/catalog/assets/mcp.playwright/1.0.0/alpha-curation/sbom/c7bdeb162de72c19f00be720d2363be86d2580ddde0595a87eb0a5f1c98eb93a.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "f76c0de46dbe623eba0822936e96082c5f53217535e54384c44693db1c141a30", + "bytes": 610, + "url": "https://alphacodeone.com/catalog/assets/mcp.playwright/1.0.0/alpha-curation/intake-provenance/f76c0de46dbe623eba0822936e96082c5f53217535e54384c44693db1c141a30.json", + "format": "alpha.intake-provenance.v1+json" + } + } + } }, { "id": "mcp:git", @@ -273,7 +513,64 @@ "name": "git_commit", "description": "提交" } - ] + ], + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "precache", + "activationPolicy": "default-disabled", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [ + "fs:read", + "fs:write" + ], + "networkDomains": [ + "code.visualstudio.com", + "docs.astral.sh", + "files.pythonhosted.org", + "github.com", + "img.shields.io", + "insiders.vscode.dev", + "pypi.org", + "zencoder.ai" + ], + "requiredSecrets": [], + "runtimeDependencies": [ + "python", + "uv" + ], + "download": { + "bytes": null, + "basis": "unknown" + } + }, + "refs": { + "sbom": { + "sha256": "8c33653a19e1c19b3a804bf7200cc1fa2600f2a2cc2a908e1002d28938f7d5a6", + "bytes": 244, + "url": "https://alphacodeone.com/catalog/assets/mcp.git/1.0.0/alpha-curation/sbom/8c33653a19e1c19b3a804bf7200cc1fa2600f2a2cc2a908e1002d28938f7d5a6.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "f00ec33f400fbe5a09480ff150c3235176b3ad19eb1f072a9c615a11fc5165e4", + "bytes": 706, + "url": "https://alphacodeone.com/catalog/assets/mcp.git/1.0.0/alpha-curation/intake-provenance/f00ec33f400fbe5a09480ff150c3235176b3ad19eb1f072a9c615a11fc5165e4.json", + "format": "alpha.intake-provenance.v1+json" + } + } + } }, { "id": "mcp:github", @@ -323,7 +620,65 @@ "name": "list_issues", "description": "列出 issue" } - ] + ], + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "connector", + "activationPolicy": "default-disabled", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "archived", + "supportTier": "none", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [ + "env:read", + "net:http" + ], + "networkDomains": [ + "anthropic.com", + "api.github.com", + "docs.github.com", + "github.com", + "modelcontextprotocol.io" + ], + "requiredSecrets": [ + { + "name": "GITHUB_PERSONAL_ACCESS_TOKEN", + "source": "environment" + } + ], + "runtimeDependencies": [ + "node" + ], + "download": { + "bytes": null, + "basis": "unknown" + } + }, + "refs": { + "sbom": { + "sha256": "89f798c7bb6d233f0370e3a4b535ac1804f109255c4dd3bf1bf90511c5f65108", + "bytes": 250, + "url": "https://alphacodeone.com/catalog/assets/mcp.github/1.0.0/alpha-curation/sbom/89f798c7bb6d233f0370e3a4b535ac1804f109255c4dd3bf1bf90511c5f65108.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "221ffa173da98063a20ec6028b60a399c27a6d05742962fcd856b36b60bf1bb2", + "bytes": 505, + "url": "https://alphacodeone.com/catalog/assets/mcp.github/1.0.0/alpha-curation/intake-provenance/221ffa173da98063a20ec6028b60a399c27a6d05742962fcd856b36b60bf1bb2.json", + "format": "alpha.intake-provenance.v1+json" + } + } + } }, { "id": "mcp:dbhub", @@ -356,8 +711,7 @@ "mirrorCommand": [ "npx", "-y", - "--registry", - "https://registry.npmmirror.com", + "--registry=https://registry.npmmirror.com", "@bytebase/dbhub@0.12.0", "--transport", "stdio", @@ -370,7 +724,244 @@ "name": "execute_sql", "description": "执行 SQL(--readonly 档:仅查询类语句)" } - ] + ], + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "connector", + "activationPolicy": "default-disabled", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [ + "env:read", + "fs:read", + "net:http" + ], + "networkDomains": [ + "api.star-history.com", + "contrib.rocks", + "creativecommons.org", + "database.windows.net", + "dbhub.ai", + "github.com", + "raw.githubusercontent.com", + "reactjs.org", + "reactrouter.com", + "www.bytebase.com", + "www.cs.aau.dk", + "www.w3.org" + ], + "requiredSecrets": [ + { + "name": "DB_PASSWORD", + "source": "environment" + }, + { + "name": "SSH_KEY", + "source": "environment" + }, + { + "name": "SSH_PASSWORD", + "source": "environment" + } + ], + "runtimeDependencies": [ + "node" + ], + "download": { + "bytes": null, + "basis": "unknown" + } + }, + "refs": { + "sbom": { + "sha256": "afcc8fb456cbd0e7163744b23d3f7f2cb2f922e390782b67ed98dd084c5d2dc9", + "bytes": 248, + "url": "https://alphacodeone.com/catalog/assets/mcp.dbhub/1.0.0/alpha-curation/sbom/afcc8fb456cbd0e7163744b23d3f7f2cb2f922e390782b67ed98dd084c5d2dc9.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "3ddee2b1f538a5d834ba9b8fd9b9199b44451cdff8ad778d49006c28dce30d1c", + "bytes": 605, + "url": "https://alphacodeone.com/catalog/assets/mcp.dbhub/1.0.0/alpha-curation/intake-provenance/3ddee2b1f538a5d834ba9b8fd9b9199b44451cdff8ad778d49006c28dce30d1c.json", + "format": "alpha.intake-provenance.v1+json" + } + } + } + }, + { + "id": "mcp:chrome-devtools", + "type": "mcp", + "name": "chrome-devtools", + "displayName": "网页性能与调试(Chrome DevTools)", + "description": "让 agent 用 Chrome 开发者工具排查网页:录制性能追踪、读控制台报错、查网络请求、截图与执行调试脚本。Google 官方 MCP,需本机已装 Chrome。", + "source": "official", + "category": "dev", + "license": "Apache-2.0", + "redistributable": true, + "version": "1.0.0", + "installSpec": { + "kind": "mcp", + "mcpType": "local", + "command": [ + "npx", + "-y", + "chrome-devtools-mcp@1.6.0" + ], + "requiredEnvVars": [], + "runtimeDep": [ + "node" + ], + "_verify": "运行时需系统已装 Chrome(不自带内核下载,免 Chromium egress);能力面含进程派生与文件写(截图/trace 落盘),故首批以逐会话授权层上架;冒烟 = stdio 握手 initialize+tools/list。" + }, + "tools": [ + { + "name": "performance_start_trace", + "description": "录制页面性能追踪(找加载慢的原因)" + }, + { + "name": "navigate_page", + "description": "打开网页" + }, + { + "name": "list_console_messages", + "description": "读浏览器控制台报错" + }, + { + "name": "list_network_requests", + "description": "查网络请求" + }, + { + "name": "take_screenshot", + "description": "截图" + }, + { + "name": "evaluate_script", + "description": "在页面内执行调试脚本" + } + ], + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "labs", + "activationPolicy": "session-grant", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [ + "env:read", + "fs:read", + "fs:write", + "net:http", + "proc:spawn" + ], + "networkDomains": [ + "127.0.0.1", + "ajv.js.org", + "ampcode.com", + "antigravity.google", + "chromeuxreport.googleapis.com", + "chromiumdash.appspot.com", + "cloud.google.com", + "code.claude.com", + "code.visualstudio.com", + "commandcode.ai", + "core-js.io", + "creativecommons.org", + "csp-evaluator.withgoogle.com", + "cursor.com", + "daringfireball.net", + "developer.chrome.com", + "developers.chrome.com", + "developers.openai.com", + "docs.cline.bot", + "docs.factory.ai", + "docs.katalon.com", + "docs.qoder.com", + "docs.warp.dev", + "docs.windsurf.com", + "docs.x.ai", + "example.com", + "facebook.github.io", + "ffmpeg.org", + "geminicli.com", + "github.com", + "img.shields.io", + "insiders.vscode.dev", + "lodash.com", + "mathiasbynens.be", + "modelcontextprotocol.io", + "mozilla.org", + "mths.be", + "nodejs.org", + "npmjs.org", + "opencode.ai", + "openjsf.org", + "play.googleapis.com", + "policies.google.com", + "registry.npmjs.org", + "sindresorhus.com", + "source.chromium.org", + "underscorejs.org", + "urlpattern.spec.whatwg.org", + "vs-open.link", + "vscode.dev", + "web.dev", + "www.apache.org", + "www.chromium.org", + "www.deque.com", + "www.ffmpeg.org", + "www.google.com", + "www.npmjs.com", + "www.typescriptlang.org", + "yargs.js.org", + "zod.dev" + ], + "requiredSecrets": [], + "runtimeDependencies": [ + "node" + ], + "download": { + "bytes": null, + "basis": "unknown" + } + }, + "refs": { + "sbom": { + "sha256": "97bde39092f92142ebbf69bebabf8c2dec86084dc0c479c5f9bbec71c45f4ddc", + "bytes": 268, + "url": "https://alphacodeone.com/catalog/assets/mcp.chrome-devtools/1.0.0/alpha-curation/sbom/97bde39092f92142ebbf69bebabf8c2dec86084dc0c479c5f9bbec71c45f4ddc.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "f3ade0db437f121aafc49a2159ce35b2960d045209e9157e3ec060a0ec704fb8", + "bytes": 619, + "url": "https://alphacodeone.com/catalog/assets/mcp.chrome-devtools/1.0.0/alpha-curation/intake-provenance/f3ade0db437f121aafc49a2159ce35b2960d045209e9157e3ec060a0ec704fb8.json", + "format": "alpha.intake-provenance.v1+json" + } + } + } }, { "id": "skill:skill-creator", @@ -1039,6 +1630,53 @@ "url": "https://alphacodeone.com/catalog/assets/skill.canvas-design/1.0.0/canvas-fonts/YoungSerif-Regular.ttf" } ] + }, + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "precache", + "activationPolicy": "default-disabled", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [], + "networkDomains": [ + "github.com", + "openfontlicense.org", + "www.apache.org", + "www.github.com" + ], + "requiredSecrets": [], + "runtimeDependencies": [], + "download": { + "bytes": 5554573, + "basis": "catalog-assets" + } + }, + "refs": { + "sbom": { + "sha256": "2e6200c3962f6bfc0f426ef83c16bfad4d3ef9c01c69aae63d37d0bfd7609edd", + "bytes": 268, + "url": "https://alphacodeone.com/catalog/assets/skill.canvas-design/1.0.0/alpha-curation/sbom/2e6200c3962f6bfc0f426ef83c16bfad4d3ef9c01c69aae63d37d0bfd7609edd.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "ba8a727ed80960c81f8369284a72c73c874cd39c8b501b31d7d93ea85b8db0a8", + "bytes": 4531, + "url": "https://alphacodeone.com/catalog/assets/skill.canvas-design/1.0.0/alpha-curation/intake-provenance/ba8a727ed80960c81f8369284a72c73c874cd39c8b501b31d7d93ea85b8db0a8.json", + "format": "alpha.intake-provenance.v1+json" + } + } } }, { @@ -1079,6 +1717,50 @@ "url": "https://alphacodeone.com/catalog/assets/skill.brand-guidelines/1.0.0/SKILL.md" } ] + }, + "curation": { + "schema": "alpha.catalog.curation.v1", + "tier": "precache", + "activationPolicy": "default-disabled", + "deliveryMode": "installable", + "review": { + "reviewedAt": "2026-07-18T00:00:00Z", + "reviewedBy": "jinjunnn", + "upstreamStatus": "active", + "supportTier": "community", + "reviewBefore": "2027-01-18T00:00:00Z" + }, + "applicability": { + "frameworks": [ + "*" + ] + }, + "summaries": { + "capabilities": [], + "networkDomains": [ + "www.apache.org" + ], + "requiredSecrets": [], + "runtimeDependencies": [], + "download": { + "bytes": 13987, + "basis": "catalog-assets" + } + }, + "refs": { + "sbom": { + "sha256": "2375a7875da7ddfd36fb24d6ee6ac82ea646429c4d929603caac455b2a5850b4", + "bytes": 274, + "url": "https://alphacodeone.com/catalog/assets/skill.brand-guidelines/1.0.0/alpha-curation/sbom/2375a7875da7ddfd36fb24d6ee6ac82ea646429c4d929603caac455b2a5850b4.cdx.json", + "format": "cyclonedx-1.6+json" + }, + "intakeProvenance": { + "sha256": "5f782d0c67d77f1af3d79e1eeb361e760e0e6f44a423bcc803218850cd78d887", + "bytes": 621, + "url": "https://alphacodeone.com/catalog/assets/skill.brand-guidelines/1.0.0/alpha-curation/intake-provenance/5f782d0c67d77f1af3d79e1eeb361e760e0e6f44a423bcc803218850cd78d887.json", + "format": "alpha.intake-provenance.v1+json" + } + } } }, { @@ -1126,32 +1808,6 @@ "builtinAssetKey": "agents/code-reviewer.md" } }, - { - "id": "plugin:opencode-notify", - "type": "plugin", - "name": "opencode-notify", - "displayName": "完成通知", - "description": "任务/会话完成时弹系统通知的 opencode 插件(社区)。", - "source": "community", - "category": "dev", - "license": "MIT", - "redistributable": true, - "version": "1.0.0", - "installSpec": { - "kind": "plugin", - "package": "opencode-notify", - "version": "0.3.1", - "mirrorRegistry": "https://registry.npmmirror.com", - "_verify": "社区插件:vendored 自 npm 0.3.1(dist 自包含);OpenCodeNotifier.app 未再分发(公证风险),通知走 osascript 回退 —— 真机核实回退通知实际弹出。", - "vendoredAssetKey": "plugins/opencode-notify" - }, - "hooks": [ - { - "name": "event(session.idle)", - "description": "会话空闲 / 任务完成时发 macOS 系统通知" - } - ] - }, { "id": "bundle:office", "type": "bundle", @@ -1406,4 +2062,4 @@ } } ] -} +} \ No newline at end of file diff --git a/packages/ui-mac/src/renderer/extensions/alpha-catalog.snapshot.json b/packages/ui-mac/src/renderer/extensions/alpha-catalog.snapshot.json index 3f32ce9c7fee..14ab5ae236a2 100644 --- a/packages/ui-mac/src/renderer/extensions/alpha-catalog.snapshot.json +++ b/packages/ui-mac/src/renderer/extensions/alpha-catalog.snapshot.json @@ -1,9 +1,9 @@ { "v": 1, - "version": "2026-07-13.1", + "version": "2026-08-06.1", "entries": 25, - "sha256": "fd5dbc78b3524333c8d90966d8ff48b0010b49c7d8d162562fe3059555fdf3d1", - "source": "https://alphacodeone.com/catalog/v1/catalog.json", - "fetchedAt": "2026-07-13T03:15:55.289Z", + "sha256": "e37a4cf3142e12169fa5bd0a2b6907189499122f7ae578a22ffa5a731dc1e874", + "source": "file:/private/tmp/issue143-web/public/catalog/v1/catalog.json", + "fetchedAt": "2026-08-06T07:27:53.997Z", "_note": "由 scripts/sync-catalog-snapshot.mjs 生成;alpha-catalog.json 禁手编(REQ-046),上架/撤架唯一动作在 alpha-web catalog-src。" } diff --git a/packages/ui-mac/src/renderer/extensions/catalog-source.retirement.test.ts b/packages/ui-mac/src/renderer/extensions/catalog-source.retirement.test.ts new file mode 100644 index 000000000000..fac3411647e1 --- /dev/null +++ b/packages/ui-mac/src/renderer/extensions/catalog-source.retirement.test.ts @@ -0,0 +1,17 @@ +import { expect, mock, test } from "bun:test" + +mock.module("./ext-ipc", () => ({ + extIpc: { + remoteCatalog: async () => ({ source: "none", error: "offline test" }), + }, +})) + +const { catalog, catalogSource, refreshCatalog } = await import("./catalog-source") + +test("ADR-040:remote unavailable keeps the real bundled catalog without opencode-notify", async () => { + await refreshCatalog() + expect(catalogSource()).toBe("builtin") + expect(catalog().entries.length).toBeGreaterThan(0) + expect(catalog().entries.some((entry) => entry.id === "plugin:opencode-notify")).toBe(false) + expect(JSON.stringify(catalog())).not.toContain("opencode-notify") +}) diff --git a/packages/ui-mac/src/renderer/extensions/ext-presentation.tsx b/packages/ui-mac/src/renderer/extensions/ext-presentation.tsx index 756d7b6ceb7d..f8353dd20f13 100644 --- a/packages/ui-mac/src/renderer/extensions/ext-presentation.tsx +++ b/packages/ui-mac/src/renderer/extensions/ext-presentation.tsx @@ -22,7 +22,6 @@ const ICON_COLOR: Record = { "mcp:playwright": "#7c3aed", "mcp:github": "#24292f", "mcp:yuque": "#1f7a4d", - "plugin:opencode-notify": "#d97706", } const ICON_GLYPH: Record = { "mcp:markitdown": "文", @@ -36,7 +35,6 @@ const ICON_GLYPH: Record = { "skill:skill-creator": "技", "skill:alpha-upstream-sync": "同", "skill:safe-refactor": "重", - "plugin:opencode-notify": "通", "bundle:office": "办", "bundle:research": "研", "bundle:dev": "开", @@ -74,7 +72,6 @@ export function sourceLabel(source: CatalogSource): string { export function catalogDescription(entry: CatalogEntry): string { if (entry.id === "skill:alpha-upstream-sync") return t("alpha.ext.upstreamSyncDescription") - if (entry.id === "plugin:opencode-notify") return t("alpha.ext.notifyPluginDescription") return entry.description } diff --git a/packages/ui-mac/src/renderer/i18n/locale-regression.test.ts b/packages/ui-mac/src/renderer/i18n/locale-regression.test.ts index 46d4244fd737..858714b5a581 100644 --- a/packages/ui-mac/src/renderer/i18n/locale-regression.test.ts +++ b/packages/ui-mac/src/renderer/i18n/locale-regression.test.ts @@ -146,10 +146,7 @@ describe("locale regression gate", () => { ) ).flatMap((item) => item.tokens.map((token) => ({ file: item.file, token }))) - expect(occurrences).toEqual([ - // Historical verification names the real third-party macOS bundle that is no longer redistributed. - { file: "extensions/alpha-catalog.json", token: "OpenCodeNotifier.app" }, - ]) + expect(occurrences).toEqual([]) }) }) diff --git a/packages/ui-mac/test-component/ext-install-catalog-result.cases.ts b/packages/ui-mac/test-component/ext-install-catalog-result.cases.ts index 5ff4c9cb5ba2..fee6c5ef49b6 100644 --- a/packages/ui-mac/test-component/ext-install-catalog-result.cases.ts +++ b/packages/ui-mac/test-component/ext-install-catalog-result.cases.ts @@ -20,13 +20,14 @@ const canary = "REQ128_IPC_CANARY_02c9f86a" // 是不够的 —— shipped catalog 的 8 条 MCP 全是 official/community,`source:"alpha"` 一条都没有, // 所以每一次真实首装走的都是 installedDisabled 那条提前返回。往那条分支塞明文, // 只测另一条时整包 3269 全绿。 -const entry = structuredClone(bundledCatalog.entries.find((item) => item.id === "mcp:github")!) +const entry = structuredClone(bundledCatalog.entries.find((item) => item.id === "mcp:dbhub")!) entry.source = "alpha" +delete entry.curation // 未改 source:保持 catalog 里的真实形状(official)⇒ 落 installedDisabled 提前返回那条。 -const disabledEntry = structuredClone(bundledCatalog.entries.find((item) => item.id === "mcp:github")!) -disabledEntry.id = "mcp:github-default-off" -disabledEntry.name = "github-default-off" +const disabledEntry = structuredClone(bundledCatalog.entries.find((item) => item.id === "mcp:dbhub")!) +disabledEntry.id = "mcp:dbhub-default-off" +disabledEntry.name = "dbhub-default-off" mock.module("electron", () => ({ BrowserWindow: class { @@ -127,7 +128,7 @@ test("真实 ext-install-catalog 返回值只含公开状态且不回显 canary" catalogId: entry.id, scope: { scope: "global" }, grants: { - secrets: { GITHUB_PERSONAL_ACCESS_TOKEN: canary }, + secrets: { DSN: canary }, }, } const first = await install({ sender: { id: 1 } }, intent) @@ -214,7 +215,7 @@ test("默认关的真实 catalog MCP:提前返回分支同样只含公开状态 catalogId: disabledEntry.id, scope: { scope: "global" }, grants: { - secrets: { GITHUB_PERSONAL_ACCESS_TOKEN: canary }, + secrets: { DSN: canary }, }, } const first = await install({ sender: { id: 1 } }, intent) diff --git a/packages/ui-mac/test-component/ext-package-detail-wiring.cases.ts b/packages/ui-mac/test-component/ext-package-detail-wiring.cases.ts index c2383d83d215..12c0835cddc7 100644 --- a/packages/ui-mac/test-component/ext-package-detail-wiring.cases.ts +++ b/packages/ui-mac/test-component/ext-package-detail-wiring.cases.ts @@ -1387,11 +1387,11 @@ describe("package detail production renderer path", () => { await mountHarness() setHubSection("connectors") await waitFor(() => - expect(document.querySelector(".alpha-ext-card-name b[title='github']")).toBeInstanceOf( + expect(document.querySelector(".alpha-ext-card-name b[title='dbhub']")).toBeInstanceOf( HTMLElement, ), ) - const card = document.querySelector(".alpha-ext-card-name b[title='github']")!.closest(".alpha-ext-card")! + const card = document.querySelector(".alpha-ext-card-name b[title='dbhub']")!.closest(".alpha-ext-card")! click(card.querySelector(".alpha-ext-add")) const keys = document.querySelector(".alpha-ext-confirm-keys") expect(keys).toBeInstanceOf(HTMLElement) diff --git a/packages/ui-mac/resources/plugins/opencode-notify/plugin.js b/packages/ui-mac/test-component/fixtures/retired-plugin.js similarity index 100% rename from packages/ui-mac/resources/plugins/opencode-notify/plugin.js rename to packages/ui-mac/test-component/fixtures/retired-plugin.js diff --git a/packages/ui-mac/test-component/package-plugin.fixture.ts b/packages/ui-mac/test-component/package-plugin.fixture.ts index c08171a0c94c..e8efd46dde44 100644 --- a/packages/ui-mac/test-component/package-plugin.fixture.ts +++ b/packages/ui-mac/test-component/package-plugin.fixture.ts @@ -6,7 +6,7 @@ // 生产分派仍是 `else → mcp` 的实现完全满足它。放齐五个,一次真安装的计划里就同时出现四个 // builder 各自的**特征 item**,路由是被跑出来的,不是被断言出来的。 // -// **第三方字节是真的**:plugin 组件的资产就是仓内 vendored 的 `opencode-notify/plugin.js` +// **第三方字节是真的**:plugin 组件的资产是仓内只供拒绝闸使用的历史语料 // (34,093 B)。夹具不重造它 —— D3 的 canary 断言(`server()` 返回键恰为 `event` + // `permission.ask`、两个值都是 function)必须打在**会被真的装进去的那份字节**上, // 拿一份自己写的小 stub 去断言等于给一个不存在的成员造反例。 @@ -29,8 +29,8 @@ export const LEAF_MCP_REMOTE_ID = "mcp:plugin-kit-remote" export const LEAF_PLUGIN_ID = "plugin:opencode-notify" export const PLUGIN_NAME = "opencode-notify" -/** 仓内 vendored 的第三方字节。**唯一**来源,夹具与 wrapper ABI 闸共用同一份。 */ -export const CANDIDATE_PLUGIN_JS = resolve(import.meta.dir, "../resources/plugins/opencode-notify/plugin.js") +/** 历史第三方字节只留在 test-component,绝不进入 app 的 resources/out 打包面。 */ +export const CANDIDATE_PLUGIN_JS = resolve(import.meta.dir, "fixtures/retired-plugin.js") const sha = (bytes: Uint8Array) => createHash("sha256").update(bytes).digest("hex") const canonicalBytes = (value: unknown) => new TextEncoder().encode(`${JSON.stringify(value, null, 2)}\n`) diff --git a/scripts/assert-seed-assets.sh b/scripts/assert-seed-assets.sh index 0ed499f8620c..8eae60d81caa 100755 --- a/scripts/assert-seed-assets.sh +++ b/scripts/assert-seed-assets.sh @@ -3,7 +3,7 @@ # # electron-builder.config.ts ships these via `extraResources`; a silent deletion (a refactor, an # upstream sync, a bad merge) would otherwise produce a package that is broken at runtime (missing -# vendored agent/plugin, no builtin skills) or LICENSE-NON-COMPLIANT (missing NOTICE.txt, B15) — +# vendored agent, no builtin skills) or LICENSE-NON-COMPLIANT (missing NOTICE.txt, B15) — # and neither typecheck nor unit tests catch it. This guard fails loud instead. # # Source-tracked assets ONLY. Build outputs (packages/ext/dist → alpha-ext/) are produced by the @@ -31,7 +31,6 @@ for fs in agent-creator customize-alpha integrate-project alpha-workspace cloud- need_file "$res/factory-skills/$fs/SKILL.md" done need_file "$res/agents/code-reviewer.md" # REQ-023 vendored agent (zero-network install) -need_dir "$res/plugins/opencode-notify" # REQ-023 vendored plugin (self-contained JS) need_file "$res/NOTICE.txt" # B15 MIT / third-party attribution — license compliance need_file "$res/entitlements.plist" # mac signing entitlements need_file "$res/icons/icon.icns" # mac app icon @@ -46,6 +45,19 @@ advisories_ts="$root/packages/ui-mac/src/shared/office-advisories.ts" need_file "$seed_catalog" need_file "$advisories_ts" +# ADR-040 / #841:engine plugin 已从线上货架与离线快照成对退休。随包字节和 catalog id +# 任一回流都会让离线路径重新展示一个只能被 planner 拒绝的条目。 +if [ -e "$res/plugins/opencode-notify" ]; then + echo "::error::ADR-040: retired opencode-notify bytes reappeared in packaged resources" + fail=1 +fi +for banned in '"plugin:opencode-notify"' 'opencode-notify'; do + if grep -qF -- "$banned" "$seed_catalog"; then + echo "::error::ADR-040: retired engine plugin reappeared in the offline catalog: $banned" + fail=1 + fi +done + for banned in office-word-mcp-server office-powerpoint-mcp-server '"mcp:word"' '"mcp:powerpoint"'; do if grep -qF -- "$banned" "$seed_catalog"; then echo "::error::REQ-105: archived office connector reappeared in the offline seed catalog: $banned"