diff --git a/.github/workflows/release-dsh-plugin.yml b/.github/workflows/release-dsh-plugin.yml index da5de22e0..5c0442063 100644 --- a/.github/workflows/release-dsh-plugin.yml +++ b/.github/workflows/release-dsh-plugin.yml @@ -99,16 +99,16 @@ jobs: PACKAGE_NAME: ${{ needs.validate.outputs.package_name }} VERSION: ${{ needs.validate.outputs.version }} run: | - # Public metadata may briefly return 404 after a successful upload. + # Public metadata can remain cached for up to five minutes after upload. # Retry only the read; never repeat npm publish after an uncertain response. - for attempt in 1 2 3 4 5 6; do - if npm view "$PACKAGE_NAME@$VERSION" dist.integrity --json --fetch-retries=0 --fetch-timeout=10000 > published-integrity.json; then + for attempt in {1..12}; do + if npm view "$PACKAGE_NAME@$VERSION" dist.integrity --json --prefer-online --fetch-retries=0 --fetch-timeout=10000 > published-integrity.json; then break fi - if [ "$attempt" -eq 6 ]; then + if [ "$attempt" -eq 12 ]; then exit 1 fi - sleep 5 + sleep 30 done node --input-type=module <<'NODE' import { readFileSync, readdirSync } from 'node:fs'; diff --git a/openspec/changes/add-dsh-native-plugin/release-guide.md b/openspec/changes/add-dsh-native-plugin/release-guide.md index 306de0352..33b02a9bd 100644 --- a/openspec/changes/add-dsh-native-plugin/release-guide.md +++ b/openspec/changes/add-dsh-native-plugin/release-guide.md @@ -110,7 +110,7 @@ node scripts/smoke-native-host.mjs --artifact /absolute/path/to/candidate.tgz -- Linux、macOS、Windows 分别记录 DSH 发行版、插件版本、Registry 契约版本及结果。未覆盖组合标为“未验证”,不列入支持列表。 -当前已有 Linux Host、真实浏览器交互及 Windows 浏览器访问 Host 的验收,界面已完成人工 review。Windows 浏览器验收不等于 Windows 原生 Host 全部文件事务验收。macOS 真实 Host/客户端仍待验证;其他 DSH 发行版及 SaaS 不列为已验证。CI 配置、已有版本的历史报告和当前候选人工验收分别记录,不能互相替代。 +当前已有 Linux Host、真实浏览器交互及 Windows 浏览器访问 Host 的验收,界面已完成人工 review。Windows 浏览器验收不等于 Windows 原生 Host 全部文件事务验收。`0.1.1` 发布标签的 Linux/macOS/Windows 原生 Host CI 六组均通过;个人电脑桌面客户端人工验收、其他 DSH 发行版及 SaaS 不列为本轮已验证。CI 配置、已有版本的历史报告和当前候选人工验收分别记录,不能互相替代。 ### 2.4 配置与人工验收 @@ -172,7 +172,7 @@ SaaS 使用其现有流水线部署;公共接口契约、测试数据规则与 1. 审核包名及正式版本,将可发布 manifest 显式设为 `private: false`,完成候选版本验收并创建对应 tag。 2. 核验仓库现有 `NPM_TOKEN` 对目标包和 tag 的发布权限,可以复用 CLI 使用的仓库 secret,无需重复配置。工作流引用的 `dsh-npm` Environment 不存在时 GitHub 会自动创建,但不自动配置审批规则;如设置了保护规则,发布还须满足这些规则。 3. 从同一 tag 手动运行工作流并选择 `publish=true`。版本身份校验后复用 `check-dsh-plugin.yml` 的完整矩阵,所有组合成功才进入发布环境。发布负责人须下载本次运行的 `skillhub-dsh-release-candidate`,核对 tarball 与 SHA512SUMS,并关联该候选包的隔离 DSH 验收记录及本次明确授权;配置了审批规则时由审批者核对后批准。缺少验收结果时不继续发布。`publish=false` 和后续 `publish=true` 是两次独立构建,不能仅凭 tag 相同认定包字节相同;如果复用前次验收,须先确认 SHA-512 一致,否则重新验收本次候选包。 -4. 发布固定的 Linux/Node 24.2.0 检查产物,不在发布阶段重新构建。候选归档前读取 tarball 内的 `package/package.json`,重新验证包名、版本与 private 条件;不只信任源码 manifest。上传前校验 SHA-512,npm 返回成功后比较 Registry 的 `dist.integrity` 与候选 tarball。新版本刚上传后,公开读取可能短暂返回 404;应在有限时间内重新读取并校验,不重复执行 `npm publish`。上传成功与公开包验证成功分别记录,超过验证期限仍须报告未完成。 +4. 发布固定的 Linux/Node 24.2.0 检查产物,不在发布阶段重新构建。候选归档前读取 tarball 内的 `package/package.json`,重新验证包名、版本与 private 条件;不只信任源码 manifest。上传前校验 SHA-512,npm 返回成功后比较 Registry 的 `dist.integrity` 与候选 tarball。新版本刚上传后,公开读取可能短暂返回 404;使用 `--prefer-online` 读取,最多读取 12 次、失败后间隔 30 秒,单次 fetch 超时为 10 秒,以覆盖观察到的五分钟公开元数据缓存;不重复执行 `npm publish`。这些是读取重试参数,不是 npm 进程的严格墙钟时限。上传成功与公开包验证成功分别记录,超过验证期限仍须报告未完成。 预发行版本使用 npm `next`,正式版本使用 `latest`。版本已经存在或发布失败时工作流失败,不把错误当成成功;排查后按实际 Registry 状态处理,不覆盖已发布版本。该工作流不创建 GitHub Release、不部署服务端;发布后仍须按下节在干净 DSH 环境安装验收,完整性相同不能替代功能验收。 diff --git a/openspec/changes/add-dsh-native-plugin/release-notes.md b/openspec/changes/add-dsh-native-plugin/release-notes.md index e3282e535..1b80646ba 100644 --- a/openspec/changes/add-dsh-native-plugin/release-notes.md +++ b/openspec/changes/add-dsh-native-plugin/release-notes.md @@ -2,9 +2,9 @@ ## 版本与交付状态 -本次交付版本为 `@astron-team/skillhub-dsh@0.1.1`,对应独立标签 `dsh-v0.1.1`。版本包含已合并的兼容性与历史安装回执修复;发布前完成候选验收,发布后下载公开包复核完整性和实际安装。npm 交付状态以公开包完整性和安装验收结果为准。`0.1.0` 已发布的内容保持不变。 +本次交付版本为 `@astron-team/skillhub-dsh@0.1.1`,对应独立标签 `dsh-v0.1.1`。该版本已发布,`latest` 指向 `0.1.1`;版本包含已合并的兼容性与历史安装回执修复,公开包完整性、干净安装及 15 项页面和重启验收通过。`0.1.0` 已发布的内容保持不变。 -`0.1.0` 的原环境固定 DSH `0.2.0-rc.2`、Cordis `4.0.4`、Node `>=24.2.0 <25`。当前已验证 Linux Host、真实浏览器页面与交互,以及 Windows 浏览器访问 Host;界面已完成人工 review。Windows 浏览器通过不代表 Windows 原生 Host 全部文件事务通过;macOS 真实 Host/客户端、其他 DSH 发行版和 SaaS 实例仍需独立验收。 +`0.1.0` 的原环境固定 DSH `0.2.0-rc.2`、Cordis `4.0.4`、Node `>=24.2.0 <25`。当前已验证 Linux Host、真实浏览器页面与交互,以及 Windows 浏览器访问 Host;界面已完成人工 review。Windows 浏览器通过不代表 Windows 原生 Host 全部文件事务通过;`0.1.1` 发布标签的 Linux/macOS/Windows 原生 Host CI 六组通过;个人电脑桌面客户端、其他 DSH 发行版和 SaaS 实例仍需独立验收。 ## 0.1.1 修复内容 @@ -39,7 +39,7 @@ ## 安装、更新与维护 -正式发布后可通过 `dsh plugin --profile skillhub-test add @astron-team/skillhub-dsh@0.1.1 --ignore-scripts` 安装到已有 Web Profile。发布前从源码执行 `bun run check` 后生成 `.tgz`,使用固定版本 DSH 的 `plugin ... add` 安装。具体准备、命令、配置和测试流程见 [中文指南](../../../plugins/dsh/README.md)、[英文指南](../../../plugins/dsh/README.en.md) 及 [发布指南](release-guide.md)。 +可通过 `dsh plugin --profile skillhub-test add @astron-team/skillhub-dsh@0.1.1 --ignore-scripts` 安装到已有 Web Profile。发布前从源码执行 `bun run check` 后生成 `.tgz`,使用固定版本 DSH 的 `plugin ... add` 安装。具体准备、命令、配置和测试流程见 [中文指南](../../../plugins/dsh/README.md)、[英文指南](../../../plugins/dsh/README.en.md) 及 [发布指南](release-guide.md)。 更新或回退前保留原包和校验值、停止新操作并处理待恢复事务,然后停止 Host、安装兼容包并重新启动。浏览器旧资源可强制刷新;这不能代替 Host 依赖重载。禁用或移除包不会卸载技能,不应删除技能目录、inventory 或操作日志。 @@ -52,7 +52,7 @@ 1. 当前 UI 为中文,英文指南不代表英文 UI。 2. 真实模型行为取决于模型和会话;安装成功、DSH 发现和模型执行分别验证。资源路径成功个例不保证所有技能的相对路径解析。 3. 官方 RC.2 在同端口 Host 重启后可能使原标签页空白,不能承诺无缝重连;使用有效入口重新进入并查询原操作。 -4. 开发候选之间的替换与回退验证,不等于跨正式版本日志迁移兼容。未知格式不能通过删除日志绕过。 +4. 本轮覆盖正式 `0.1.0`→`0.1.1` 升级后原记录和技能保留、历史回执核验及导航,不承诺其他版本迁移或全部回退组合。未知格式不能通过删除日志绕过。 5. 注册、页面或工具共存测试不证明其他插件全部业务及模型选工具行为均兼容。 兼容范围以 [兼容设计](compatibility-design.md) 为准,行为门禁以 [验收标准](acceptance.md) 为准。 diff --git a/openspec/changes/add-dsh-native-plugin/tasks.md b/openspec/changes/add-dsh-native-plugin/tasks.md index 9a2dc189e..53d96a046 100644 --- a/openspec/changes/add-dsh-native-plugin/tasks.md +++ b/openspec/changes/add-dsh-native-plugin/tasks.md @@ -194,9 +194,9 @@ ## 25. 0.1.0合并与独立npm发布 - [x] 25.1 确定0.1.0候选、可发布manifest、空默认来源及正式npm安装文档,保留平台限制。 -- [ ] 25.2 提交清理与修复,最终PR提交CI通过后合并并记录main提交。 -- [ ] 25.3 从确定的合并提交构建候选,完成干净DSH验收、包校验与发布权限核验。 -- [ ] 25.4 确认精确发布候选后创建独立tag,经审批发布npm,校验公开包并执行干净安装回归。 +- [x] 25.2 提交清理与修复,最终PR提交CI通过后合并并记录main提交。 +- [x] 25.3 从确定的合并提交构建候选,完成干净DSH验收、包校验与发布权限核验。 +- [x] 25.4 确认精确发布候选后创建独立tag,经审批发布npm,校验公开包并执行干净安装回归。 ## 26. 正式包验收后的兼容性与历史回执修复 @@ -211,7 +211,7 @@ - [x] 27.1 固定 `0.1.1` manifest 与安装文档,更新发布说明和兼容范围,保留 `0.1.0` 已知问题与验收边界。 - [x] 27.2 从最终提交以冻结锁安装依赖,完成插件完整检查、OpenSpec 严格校验、72 文件包审查及私人路径扫描,记录候选校验值。 -- [ ] 27.3 在最终提交 CI 通过并核对发布候选后,按已授权范围创建 `dsh-v0.1.1` 并执行专用 npm 发布工作流;不发布 CLI、镜像或 Chart。 -- [ ] 27.4 下载 npm `0.1.1` 公开包并核对 `latest`、manifest、完整性与全部交付文件;公开读取传播延迟单独记录,不重复上传。 -- [ ] 27.5 将公开包安装到隔离 DSH Profile,复核浏览安装、指定版本、升级卸载、官方工具与 Host 重启后历史回执;不调用模型、不以本地模拟市场代表生产或 SaaS。 -- [ ] 27.6 回写最终提交、CI 与公开包验收结果,保留原技能、清单、操作日志和可恢复安装包;未验证平台明确列出。 +- [x] 27.3 最终提交六组 CI 通过,按授权创建 `dsh-v0.1.1` 并执行专用 npm 发布;上传成功,工作流后续公开读取超时已记录并完成事后校验,未重复发布;未发布 CLI、镜像或 Chart。 +- [x] 27.4 下载 npm `0.1.1` 公开包并核对 `latest`、manifest、完整性与全部交付文件;公开读取传播延迟单独记录,不重复上传。 +- [x] 27.5 公开包干净安装、15 项页面/重启用例、直接选择第二项安装及正式 0.1.0→0.1.1 升级通过;旧回执核验和导航通过;不调用模型、不以本地模拟市场代表生产或 SaaS。 +- [x] 27.6 回写最终提交、CI 与公开包验收结果,保留原技能、清单、操作日志和可恢复安装包;未验证平台明确列出。 diff --git a/openspec/changes/add-dsh-native-plugin/verification.md b/openspec/changes/add-dsh-native-plugin/verification.md index b737c62d9..dbce623fc 100644 --- a/openspec/changes/add-dsh-native-plugin/verification.md +++ b/openspec/changes/add-dsh-native-plugin/verification.md @@ -2,17 +2,31 @@ ## 1. 当前结论 -`@astron-team/skillhub-dsh@0.1.0` 已正式发布到 npm。发布后本地验收使用正式包、独立 DSH RC.2 Profile 和本地契约模拟市场;固定完整依赖基线时,14 项页面及安装管理用例通过,Host 重启后的历史卡片当前库存核验与导航失败。普通新装另复现了 Cordis 传递依赖漂移造成的写入禁用。实际文件、清单、会话、原操作及 DSH 发现保留正常,不能把卡片失败表述为数据丢失。 +`@astron-team/skillhub-dsh@0.1.1` 已发布到 [npm](https://www.npmjs.com/package/@astron-team/skillhub-dsh),`latest` 指向 `0.1.1`。版本修复普通新装的 Cordis 依赖组合识别,以及 Host 重启后历史安装回执的当前库存核验和导航;默认 Registry 仍为空,DSH 主基线仍为 `0.2.0-rc.2`。 -`0.1.1` 交付上述两个问题的修复,不改变 npm `0.1.0` 的既有内容;本次发布和公开包复验完成前不声明新版本已发布。修复后验收与 CI 结果在本文件单独记录;下表保留首版候选的历史验证范围。默认 Registry 仍为空,DSH 主基线仍为 `0.2.0-rc.2`,完整 Cordis 组合以 [兼容性设计](compatibility-design.md) 为准。本轮按用户决定不调用模型,也不代表真实 Java 服务端、SaaS 或其他操作系统已重新验收。 +公开包已在全新、未设置 Cordis overrides 的隔离 Profile 中安装,并通过 15 项页面及重启验收。测试连接本地契约模拟市场,不调用模型;该结果不代表真实 Java 服务端、SaaS、其他 DSH 版本或个人电脑桌面客户端验收。三平台原生 Host CI 与 Linux 浏览器验收分别记录。 + +`0.1.0` 的历史验收曾复现新依赖组合写入被禁用、重启后历史回执无法核验和导航的问题;当时文件、清单、会话、原操作及 DSH 发现保留正常,不属于数据丢失。已发布的旧包没有被修改。 ## 2. 验证范围 ### 2.0 0.1.1 发布验收 -`0.1.1` 使用最终发布提交重新执行冻结锁安装、完整插件检查和 OpenSpec 严格校验。交付包审查包含 manifest、72 个文件、私人路径扫描及校验值;发布后从公开 npm 下载并逐文件对比,再以该公开包运行隔离 DSH 验收。`0.1.1` 版本准备检查已完成:CLI 和插件冻结锁安装成功,`bun run check` 的构建、类型检查、lint、272 项测试及 7057 次断言通过,OpenSpec 严格校验通过。候选包包含 72 个文件,私人路径扫描通过;与已验收修复包相比,仅版本 manifest 与中英文安装指南变化,运行代码产物一致。最终发布提交的 CI、npm 上传和公开包复验结果另行回填。 +发布源为 [PR #971](https://github.com/iflytek/skillhub/pull/971) 的合并提交 `2b181f7f94af05c2e1dd1c7cef25b701785d7e26`,标签 `dsh-v0.1.1`。修复来源为 [PR #967](https://github.com/iflytek/skillhub/pull/967)。 -公开包复验覆盖浏览、详情和指定版本、用户/项目安装、升级卸载、官方工具以及 Host 重启后的历史回执。测试使用本地契约模拟市场,不调用模型;公开包下载和实际文件核验与页面截图分别记录。 +| 检查 | 结果 | +| --- | --- | +| 发布前检查 | CLI 和插件冻结锁安装、构建、类型检查、lint、272 项测试、7057 次断言及 OpenSpec 严格校验通过 | +| 发布 CI | [专用工作流](https://github.com/iflytek/skillhub/actions/runs/39209878942) 的 Linux、macOS、Windows × Node 24.2.0/24 六组全部通过,包含隔离原生 Host 冒烟;Linux 24.2.0 另验证完整旧依赖组合 | +| npm 上传 | 上传步骤成功,仅执行一次 `npm publish`;公开元数据缓存导致其后完整性读取步骤在约 30 秒内六次返回 404,工作流整体失败,未重复发布 | +| 公开包核对 | 后续公开查询确认版本及 `latest=0.1.1`;公开 tarball 与本次 CI 发布包逐字节相同,安装后的 72 个交付文件也全部相同;包中无测试过程材料或私人路径 | +| 干净安装 | 普通 DSH RC.2 新装,无 Cordis overrides;实际解析 Cordis / Loader / Include / Timer `4.0.5 / 1.0.6 / 1.0.10 / 1.1.7`;Host/Client 加载及技能写入正常 | +| 页面与文件 | 14 项页面用例通过:浏览、分页、接口标签、搜索排序、延迟骨架、Markdown、四个版本、评论分页、指定版本安装、升级、双范围管理、离线卸载、对话结果和抽屉、主题窄屏及可选 Tab;安装文件、资源及元数据指纹核对通过 | +| 官方工具 | 真实执行搜索后选择第二项直接安装,不先查看详情;原操作 completed,资源和 DSH 发现通过,不调用模型 | +| 同版本 Host 重启 | 停止原进程、以同一 Profile 启动新进程;原会话及原操作可读,技能和发现保留,历史回执自动及手动核验、已安装导航通过,无新增安装或 executePlan 请求 | +| 正式旧版升级 | 从公开 npm 0.1.0 的隔离副本正常升级到公开 0.1.1,保留旧完整依赖组合;原会话、操作和库存副本字节保留,原项目技能文件及发现正常;旧回执自动/手动核验和已安装导航通过,零新增技能操作、零模型调用 | + +公开 tarball 的 SHA-256 为 `4bcfd437ad66309c7535e76382d8a3c7000c53b5d1f2d7c6192b8fa462568136`;以该校验值关联实际交付包,不能用同版本号的本地构建代替。发布后读取校验窗口已调整为最多 12 次、间隔 30 秒,并使用 `--prefer-online`;延迟可见、窗口耗尽及完整性不匹配检查通过,上传不在重试循环内。该调整用于后续发布,不改写本次已发布的包或标签。 连接探测的截止回归将夹具空闲超时设为 30 秒,独立校验客户端约 10 秒的总截止及精确降级请求次数,避免夹具先断开导致传输重试干扰。 ### 2.1 本轮发布后修复 @@ -27,7 +41,7 @@ | Host 重启 | 停止旧进程并启动同一持久 Profile 的新进程;原会话、原操作、文件和 DSH 发现保留 | 不是页面刷新;使用认证入口访问真实 Host | | 历史回执 | 自动及手动核验均通过,跳转已安装成功;安装和 executePlan 新请求均为 0 | 来源、会话、cwd、Host 不匹配及取消/晚响应由定向回归验证 | | 保留依赖组合 | 原 `4.0.4 / 1.0.5 / 1.0.9 / 1.1.6` 完整组合的独立 Host 基线及插件生命周期均通过 | 实际解析版本逐项核对;Client 禁用阻断写入、恢复后重新允许及插件重载通过 | -| 远端 CI | PR 对应提交的多平台结果另行核对 | 未完成前不声明 macOS/Windows 原生验收通过 | +| 远端 CI | 修复 PR 与 0.1.1 发布标签的六组矩阵均通过 | 原生 Host CI 不等同于个人电脑桌面客户端人工验收 | 模型调用、真实 Java 服务端、SaaS 和其他 DSH 版本未纳入本轮重新验收。浏览器历史由真实工具结果回放构造,不能视为模型回合。原开发预览与新候选预览独立保留,未迁移或清理用户对话。 @@ -50,12 +64,12 @@ | 环境 | 状态 | | --- | --- | -| Linux/WSL Host + DSH RC.2 Web | 当前功能候选已运行与验证 | +| Linux/WSL Host + DSH RC.2 Web | npm 0.1.1 公开包 15 项页面及重启验收通过 | | Windows 浏览器访问上述Host | 已人工确认并验证预览;不等同于Windows原生Host验收 | -| Windows原生Host | 历史开发产物有验证,最终候选须按发布范围复核 | +| Windows原生Host | npm 发布标签的两组 Node CI 原生 Host 冒烟通过;个人电脑人工验收未重做 | | 独立远程Linux Host | 历史候选双范围安装及文件核对通过,发布前根据最终变更复核 | -| macOS真实宿主 | 按既定安排后续验证,本轮不声明通过 | -| CI多平台矩阵 | 工作流覆盖Linux/macOS/Windows;历史提交矩阵通过不替代本轮最终提交 | +| macOS原生Host/桌面客户端 | 发布标签两组 Node CI Host 冒烟通过;个人电脑桌面客户端人工验收待执行 | +| CI多平台矩阵 | 发布标签 Linux/macOS/Windows × 两组 Node 全部通过,旧完整依赖组合独立通过 | | 开源Registry | 历史真实测试实例有匿名契约、资源下载与安装证据;当前服务端部署需目标环境验收 | | SaaS Registry | 契约同步及目标实例验收待执行 | diff --git a/plugins/dsh/test/registry-connection.test.ts b/plugins/dsh/test/registry-connection.test.ts index 148ef7c40..70d8211fa 100644 --- a/plugins/dsh/test/registry-connection.test.ts +++ b/plugins/dsh/test/registry-connection.test.ts @@ -77,7 +77,8 @@ test('connection probe cancellation stops an in-flight read', async () => { test('the ten-second total deadline includes the legacy fallback request', async () => { const paths: string[] = []; const release = Promise.withResolvers(); - const server = Bun.serve({ hostname: '127.0.0.1', port: 0, async fetch(request) { + // Keep the fixture socket alive beyond the probe deadline; an idle disconnect can retry GET. + const server = Bun.serve({ hostname: '127.0.0.1', port: 0, idleTimeout: 30, async fetch(request) { const path = new URL(request.url).pathname; paths.push(path); if (path === '/api/web/skills') { @@ -91,7 +92,9 @@ test('the ten-second total deadline includes the legacy fallback request', async const started = performance.now(); const result = await f.api.testRegistryConnection(server.url.href, new AbortController().signal).catch(error => error); expect(result).toMatchObject({ code: 'skillhub/registry-error', details: { reason: 'NETWORK_ERROR', retryable: true } }); - expect(performance.now() - started).toBeLessThan(10_900); + const elapsed = performance.now() - started; + expect(elapsed).toBeGreaterThanOrEqual(9_900); + expect(elapsed).toBeLessThan(10_900); expect(paths).toEqual(['/api/web/skills', '/api/cli/v1/skills/search']); } finally { release.resolve(new Response('')); await f.close(); await server.stop(true); } }, 15_000);