feat(slark-dsh-cicd): 新增 DSH/Slark 发布实战技能(REQ-20261007-0003)
- 新建 skills-dev/slark-dsh-cicd-plugin:plugin.json + skills/SKILL.md + skills/references/fork-release-and-post-checks.md - 覆盖两条发布线(DSH 插件 pack 双资产 / Slark 宿主重打包+签名)、权限与身份三连 (push:true 才可写,ls-remote 通 ≠ 能 push)、无上游写权限的 fork 发布且原仓库零改动、 干净单提交 + git diff --stat <OURS> 树一致性 gate、改指向后必须重新 pack、 draft→publish 与「更新检查看不到新版」的因果、GitHub HTTPS/fetch 卡死/无 macOS timeout 的判死处置、发布后 SHA 逐项核对(verify-remote 仅 Windows)、app.asar 完整性约束、 ai-proj staging→released 与 /req done 证据要求及文档接口故障绕过 - 与 slark-cicd 明确分工并交叉引用,不重复 staging/生产/Desktop 细节 - update-plugin-meta.py PLUGIN_MAP 增加 slark-dsh-cicd-plugin (skill/dev) - generate-marketplace.py devops 分类补充 slark-dsh-cicd;marketplace.json 仅新增该条目 - 校验:claude plugin validate . 通过(警告为该仓库既有 install_name 字段提示)、git diff --check 干净
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
---
|
||||
name: slark-dsh-cicd
|
||||
description: DSH 插件包与 Slark 宿主补丁的发布 runbook。覆盖 npm run pack 双 tgz 双资产、无上游写权限时的 fork 发布、干净单提交与树一致性 gate、改指向后必须重新打包、draft→publish 节奏、GitHub HTTPS/SSH 与 fetch 卡死处置、发布后 SHA 核对、app.asar 完整性约束、ai-proj 发布状态对齐。当用户要发布或升级 DSH 插件(dsh-worktable 等)、发布/更新 Slark 宿主补丁、push 或下载 GitHub 失败、插件「检查更新」看不到新版本、需要 fork 发布、或排查 asar 完整性/签名问题时使用。
|
||||
---
|
||||
|
||||
# DSH 插件与 Slark 宿主发布 runbook (slark-dsh-cicd)
|
||||
|
||||
面向「把插件包/宿主补丁真正发出去」的可执行清单。默认在**发布机**执行;命令按阶段照做,
|
||||
每阶段结束先核验再进入下一阶段。
|
||||
|
||||
## 适用与分工
|
||||
|
||||
两条发布线,**互不依赖**,不要串流程:
|
||||
|
||||
| 发布线 | 产物 | 入口 | 权威源 |
|
||||
| --- | --- | --- | --- |
|
||||
| A · DSH 插件 | `dist/v<ver>/dsh-worktable.tgz` + `dsh-worktable-<ver>.tgz`(同一验收包) | `<pkg>/npm run pack` | GitHub Release(tag = `v<包内版本>`) |
|
||||
| B · Slark 宿主补丁 | 重打包 + 签名的 Slark.app(含内嵌 DSH runtime) | 宿主自身打包/签名链 | 宿主发布链,不经 GitHub Release |
|
||||
|
||||
与同市场技能的分工,避免重复:
|
||||
|
||||
- **本技能**:DSH 插件包发布、宿主补丁打包侧的完整性约束、发布链本身(权限、tag、Release、SHA 核对)。
|
||||
- `slark-cicd`:Slark 仓库 staging 验收、生产发布、Desktop 安装包上传 OSS、PR/CI 门禁——服务器与包分发细节以它为准。
|
||||
- `dev-cicd`:通用流水线设计与排查(Gitea Actions/缓存/并发)。
|
||||
- `ai-proj-cicd-release`:AI-Proj 服务自身的门禁与回滚。
|
||||
|
||||
## 铁律(先记死)
|
||||
|
||||
1. **打包只走唯一入口**:`npm run pack`(或仓库自带的等价脚本)。手写 `tar`/`npm pack` 会绕过结构断言与安装导入验证。
|
||||
脚本自己会做:版本一致性 → 兼容回归 → 构建 → 语法检查 → 结构断言(精确文件清单、无 `src/`、无 `.map`)→
|
||||
独立临时目录真实安装 + `import()` 断言 → 客户端/宿主门禁 → 双资产同源 → SHA-256。
|
||||
2. **`package.json` 与 `dsh.plugin.json` 的版本必须相等**,否则构建与打包脚本 fail-closed。发版只升这一处对,不要只改一边。
|
||||
3. **产物出了包就不再改**:任何源码/常量/文档改动都可能改变 bundle → 旧 `.tgz` 立即作废、sha 必变。**改完必须重新 pack 并重新记录 sha**。
|
||||
4. **对上游仓库零改动是硬指标**(尤其是没有写权限的外部作者仓库):不 push、不打 tag、不建 Release/PR,一次都不做。
|
||||
5. **公开发布必须是 draft 起步**,对外动作经用户过目后再 `--draft=false`。
|
||||
6. **force push 只允许发生在自己 fork 的分支/tag 上**;绝不对上游使用 `-f`。
|
||||
7. **发布用的分支必须是干净单提交**,不要为了省事把本地历史推上去(本地历史可能含个人路径、凭据、临时调试 commit)。
|
||||
8. **"下载通了" ≠ "hash 对了"**:发布完成的判据是「远端资产 sha == 本地验收 sha」,不是页面能打开。
|
||||
|
||||
## 阶段 0:身份与权限三连(先判定能力,再决定链路)
|
||||
|
||||
```bash
|
||||
gh auth status # 登录账号是否符合预期
|
||||
ssh -T git@github.com 2>&1 | head -3 # SSH 身份(回显 Hi <user>! 即通)
|
||||
gh api repos/<owner>/<repo> --jq '.permissions' # 关键:{"pull":true,"push":<bool>}
|
||||
```
|
||||
|
||||
- **只有 `push:true` 才能走「上游直发」**;`push:false` 时不要硬撞,直接走阶段 2 的 fork 发布。
|
||||
- **`git ls-remote` 通 ≠ 能 push**:读权限随时可通,写权限被拒要到 push 才暴露。不要用 ls-remote 成功推断可写。
|
||||
- 同时确认远端协议:`git remote -v`。HTTPS 到 GitHub 可能整体不通(见「网络与链路故障处置」),
|
||||
必要时改用 SSH:`git remote set-url origin git@github.com:<owner>/<repo>.git`。
|
||||
|
||||
## 阶段 1:发布线 A — DSH 插件(有上游写权限)
|
||||
|
||||
```bash
|
||||
export HOME="/Users/johnq"
|
||||
export PATH="/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin:/opt/homebrew/bin:$PATH"
|
||||
cd <repo>/<pkg>
|
||||
npm run check && npm run test:gate && npm run pack
|
||||
shasum -a 256 dist/v<ver>/*.tgz # 两个文件必须同 sha
|
||||
tar -xzf dist/v<ver>/dsh-worktable.tgz -C "$(mktemp -d)" && grep -rn "<旧仓库名>" <解包目录> # 期望无输出
|
||||
git add -A && git commit -m "release: <name> v<ver>(REQ-…)…"
|
||||
git tag -f v<ver> && git push origin HEAD v<ver>
|
||||
gh release create v<ver> dist/v<ver>/dsh-worktable.tgz dist/v<ver>/dsh-worktable-<ver>.tgz \
|
||||
--draft --title "<name> v<ver>" --notes-file <notes.md>
|
||||
```
|
||||
|
||||
- tag **必须等于包内版本**(`v` + `package.json#version`),否则下游按 tag 拼版本化资产名会 404。
|
||||
- Release 附**双资产**:固定名(供 `releases/latest/download/<fixed>.tgz` 长期入口)+ 版本化名(可追责)。
|
||||
|
||||
## 阶段 2:发布线 B — 无上游写权限 → fork 发布
|
||||
|
||||
```bash
|
||||
gh repo fork <upstream-owner>/<repo> --clone=false # 已存在则复用
|
||||
git remote add fork git@github.com:<me>/<repo>.git # 已存在则 git remote set-url fork …
|
||||
git fetch --no-tags origin main
|
||||
```
|
||||
|
||||
### 2.1 干净单提交 + 树一致性 gate(必做,不可省)
|
||||
|
||||
```bash
|
||||
OURS=$(git rev-parse <本地完成发布内容的 HEAD>)
|
||||
git checkout -B release/v<ver> origin/main
|
||||
git rm -rq --cached .
|
||||
git checkout "$OURS" -- .
|
||||
git add -A
|
||||
git commit -m "release: <name> v<ver>(REQ-…)…"
|
||||
git diff --stat "$OURS" # 必须是空输出
|
||||
```
|
||||
|
||||
- `git diff --stat "$OURS"` **非空即 abort**:切回原分支、删掉该发布分支、报告差异,不要「差一点也推」。
|
||||
- 该 gate 的真实作用是:让公开发布分支的**树**等于本地验收树,同时**不携带本地历史提交**(个人路径、调试、凭据)。
|
||||
- `git rm -rq --cached .` 只清索引,随后 `git checkout "$OURS" -- .` 覆盖工作树;若上游 `main` 存在本地树里**已删除**的
|
||||
文件,残留文件会被 `git add -A` 重新加回导致 gate 失败——先确认 `git diff --name-status origin/main <OURS>` 无 `D`/`R`。
|
||||
- 提交前可顺手确认没有敏感路径混入:`git log -S'<本机绝对路径前缀>' --oneline`。
|
||||
|
||||
### 2.2 推分支 + tag + 附双资产的 draft Release
|
||||
|
||||
```bash
|
||||
git push -u fork release/v<ver>
|
||||
git tag -f v<ver> && git push -f fork v<ver> # -f 只作用于 fork 的 tag
|
||||
gh release create v<ver> dist/v<ver>/dsh-worktable.tgz dist/v<ver>/dsh-worktable-<ver>.tgz \
|
||||
--repo <me>/<repo> --draft --title "<name> v<ver>" --notes-file <notes.md>
|
||||
```
|
||||
|
||||
- 推完复核「原仓库零改动」:`git ls-remote <origin-url>`(应无新分支/tag)+ `gh release list --repo <upstream>`(列表应与之前一致)。
|
||||
- Release notes 至少写:新增 / 修复 / 清理 / 验证(实际跑过的测试与数字)/ 安装命令(指向 fork)/ 包 SHA-256 / 已知边界。
|
||||
|
||||
## 阶段 3:改指向(换仓库、换发布方时)
|
||||
|
||||
只要「发布方」变了,插件里所有指向旧仓库的常量都要一次改全,否则**更新检查读的还是旧仓库 → 永远发现不了新版**:
|
||||
|
||||
- 更新检查仓库常量(如 `UPDATE_REPO`,可能有多份:入口 + 独立模块 + 设置面板各自实现);
|
||||
- 升级命令/提示词里的安装 URL(可能拼在字符串里);
|
||||
- `package.json#repository.url`;
|
||||
- 发布后核对脚本里硬编码的 REPO;
|
||||
- README/AGENTS/安装说明里的一行命令、`git clone` 地址、文档链接;
|
||||
- 任何 `grep -rn "<旧 owner>"` 的残留。
|
||||
|
||||
规则:
|
||||
|
||||
- **只改指向,不改版本号与逻辑**;逐处 `git diff` 复核。
|
||||
- 「相关项目/其它仓库」的外链如果指向**另一位开发者的独立仓库**,不要顺手改指(目标仓库不存在会变成死链)——保留并在交付里说明。
|
||||
- **改完必须重新 pack**(铁律 3),解包 `grep` 确认产物内无旧仓库名,sha 与 Release 全部按新值重来。
|
||||
|
||||
## 阶段 4:draft → publish
|
||||
|
||||
```bash
|
||||
gh release edit v<ver> --repo <me>/<repo> --draft=false
|
||||
```
|
||||
|
||||
- **draft 期间 `releases/latest` 仍指向上一个已发布版本** → 插件内「检查更新」看不到新版本;
|
||||
draft 资产的 tag 路径也不公开可下(需鉴权)。这是「更新检查不生效」最常见的**非 bug 原因**,先查 Release 是否还是 draft。
|
||||
- 发布前用用户过目确认;发布后再跑阶段 5。
|
||||
|
||||
## 阶段 5:发布后核对
|
||||
|
||||
优先用仓库自带的核对脚本,但**平台适配要先判定**:`verify-remote.mjs` 之类脚本若用
|
||||
`powershell Invoke-WebRequest` 下载,则**只在 Windows 可用**,在 macOS 会以 `FAIL: download fixed-name asset` 收场
|
||||
(它的 GET URL 仍能证明改指生效,不代表脚本思路错)。
|
||||
|
||||
macOS/无 PowerShell 时的等价核对(全部要过):
|
||||
|
||||
```bash
|
||||
gh release view v<ver> --repo <me>/<repo> --json assets # 两个资产的 digest 必须都等于本地 sha
|
||||
gh release download v<ver> --repo <me>/<repo> --dir "$TMP" # draft 也可下载(已鉴权)
|
||||
shasum -a 256 "$TMP"/*.tgz # 与本地验收 sha 逐字一致
|
||||
cmp "$TMP/dsh-worktable.tgz" dist/v<ver>/dsh-worktable.tgz # byte-identical
|
||||
tar -xzf "$TMP/dsh-worktable.tgz" -C "$TMP/ext" && grep -rn "<旧仓库名>" "$TMP/ext" # 无输出
|
||||
curl -sL -o /dev/null -w '%{http_code}\n' <版本化资产 URL> # 发布后 200/302;draft 阶段 404 属预期
|
||||
```
|
||||
|
||||
结论口径:**文件名 + 结构(精确文件清单)+ 包内版本 + 双资产同源 + 远端=本地验收 SHA + 真实安装导入** 全过才算发布验收。
|
||||
draft 阶段只能做「远端资产 = 本地验收包」的比对,匿名可下载性要等 publish 后再验。
|
||||
|
||||
## 阶段 6:Slark 宿主补丁(宿主侧特有)
|
||||
|
||||
- **改 `app.asar` 无效**:Electron 用 `ElectronAsarIntegrity` 记录 asar 头哈希并有 fuse 完整性校验,直接热改会让
|
||||
哈希失配,破坏签名,应用拒绝启动或行为异常。**必须重打包 + 重新安装**,不要在安装目录里就地改文件。
|
||||
- 宿主补丁落在 fork/分支上时:rebase 到发布基线后**必须重跑全量测试**(类型检查 + 全量单测),
|
||||
例如 `pnpm -r typecheck` 与 `node --import tsx --test "src/**/*.test.ts"`;rebase 不产生冲突**不代表语义没变**。
|
||||
- 宿主发布与插件发布解耦:宿主要用新插件版本,通常靠宿主内嵌 runtime 的升级,而不是「插件先发、宿主自动跟进」。
|
||||
|
||||
## 网络与链路故障处置
|
||||
|
||||
| 现象 | 判定 | 处置 |
|
||||
| --- | --- | --- |
|
||||
| `curl` 访问 GitHub 返回 HTTP `000`(HTTPS 整体不通) | 出口到 github.com:443 被掐断,与凭据无关 | 改走 SSH:`git remote set-url origin git@github.com:<owner>/<repo>.git`,并确认 SSH 身份 |
|
||||
| `git fetch` 长时间无输出/0 字节、卡十几分钟 | 链路假死,不是"慢" | 判死并清理后重试(见下方循环模板),不要原地等 |
|
||||
| 30 秒内报 `fatal: early EOF` | 链路被中途掐断(代理/MTU/网络策略) | 记录原文与时间点;换协议/换网络重试;不要反复 force |
|
||||
| macOS 没有 `timeout` 命令 | BSD 无 GNU timeout | 用后台 + 轮询模板 |
|
||||
| `git push` 报无权限但 ls-remote 正常 | 只读凭据 | 直接走 fork 发布(阶段 2),不要重试上游 |
|
||||
|
||||
macOS 无 `timeout` 时的判死模板:
|
||||
|
||||
```bash
|
||||
( git fetch --no-tags origin main ) & PID=$!
|
||||
for i in $(seq 1 30); do sleep 1; kill -0 "$PID" 2>/dev/null || break; done
|
||||
if kill -0 "$PID" 2>/dev/null; then kill -9 "$PID"; pkill -9 -f git-upload-pack; echo "TIMEOUT(30s) — 链路假死"; fi
|
||||
```
|
||||
|
||||
- 认证/网络失败时**不做破坏性重试**(尤其不要为了"绕过"而 force 到上游);把失败原文、已完成的步骤、当前指针状态写清楚上报。
|
||||
- 推送成功但平台上看不到:查 `git config --get-regexp '^url\.'` 是否有 `pushInsteadOf` 静默改写了目标。
|
||||
|
||||
## ai-proj 对齐
|
||||
|
||||
- 需求阶段:动手前立项(`create_requirement`,写清需求描述 / 预期结果 / 验收标准三段式 + AC),commit/PR 引用 `REQ-…`。
|
||||
纯文档/工具/只读排查可例外。
|
||||
- 交付阶段:**真实发布之后**才推进 `staging → released`;只有计划、没有发布产物或验收证据时不要推进。
|
||||
- 归档阶段:`/req done` 归档前要**逐条 AC 证据**(命令、输出、资产 sha、URL),不能只写"已完成"。
|
||||
- **文档接口故障绕过**:若 `append-document-content` / `create-and-attach` 持续报
|
||||
`document_versions_document_id_version_number_key` 唯一约束错误(同一 `(document_id, version_number)` 冲突),
|
||||
改用 `PUT /api/v1/requirements/{id}` 把说明写进**需求描述**——`requirements` 表不经过 `document_versions`,可绕开该约束;
|
||||
不要伪造版本号或删除已有文档版本。
|
||||
|
||||
## 故障分流
|
||||
|
||||
| 现象 | 处置 |
|
||||
| --- | --- |
|
||||
| 插件「检查更新」永远看不到新版 | 依次查:Release 是否还是 draft;`releases/latest` 指向;插件内 `UPDATE_REPO` 是否仍指旧仓库;`latest` 资产名是否与代码拼的一致 |
|
||||
| pack 报结构断言失败 | 包内混入了 `src/`、`.map` 或多余文件;检查 `files` 字段与构建产物位置,不要手改 tgz |
|
||||
| 两个 tgz 的 sha 不一致 | 打包脚本的"同源复制"被绕过(手工 pack/改名);重新走唯一入口 |
|
||||
| `git diff --stat <OURS>` 非空 | 上游 `main` 有本地已删除/重命名文件残留 → 先 `git rm --cached` 清理并确认无 `D`/`R`,gate 不过不上推 |
|
||||
| 发布分支含个人路径/凭据 commit | 不要 push 该历史;改用干净单提交分支(阶段 2.1) |
|
||||
| `gh release create` 报 tag 不存在/被占用 | tag 必须已存在或由 `create` 指定;draft 会以 `untagged-…` 预览 URL 呈现,属正常,publish 后即 `.../tags/v<ver>` |
|
||||
| draft 资产匿名下载 404 | 预期行为(draft 需鉴权);发布后用 `curl -sL -o /dev/null -w '%{http_code}'` 复验 |
|
||||
| 宿主改完不生效 | 是否只改了 `app.asar`(被完整性校验挡住);必须重打包重装;再查是否加载了另一份 runtime |
|
||||
|
||||
## 参考
|
||||
|
||||
- `references/fork-release-and-post-checks.md` —— fork 发布可复制命令序列、Release notes 模板、发布后核对矩阵。
|
||||
- 同市场:`slark-cicd`(Slark staging/生产/Desktop)、`dev-cicd`(流水线设计)、`ai-proj-cicd-release`(AI-Proj 发布链)。
|
||||
- 权威流程以目标仓库自带的发布脚本与文档为准;本技能是清单,不替代仓库脚本的断言。
|
||||
@@ -0,0 +1,134 @@
|
||||
# Fork 发布与发布后核对
|
||||
|
||||
本文件是 `slark-dsh-cicd` 的操作附件:需要**无上游写权限发布**,或需要**逐项核对远端资产**时读取。
|
||||
把它当模板:替换 `<...>` 占位符,按阶段执行,每阶段的核验不通过就停下,不要"带病"推进。
|
||||
|
||||
## 0. 变量与前置
|
||||
|
||||
```bash
|
||||
export HOME="/Users/johnq"
|
||||
export PATH="/Users/johnq/.local/node-v22.22.3-darwin-arm64/bin:/opt/homebrew/bin:$PATH"
|
||||
|
||||
UP=<upstream-owner>/<repo> # 例如 Aisland-SJL/dsh-worktable(外部作者,无写权限)
|
||||
ME=<your-account> # 例如 qiudl
|
||||
PKG=<repo>/01_content # 打包脚本所在目录
|
||||
VER=0.4.1 # = package.json#version
|
||||
```
|
||||
|
||||
```bash
|
||||
gh auth status
|
||||
ssh -T git@github.com 2>&1 | head -3
|
||||
gh api "repos/$UP" --jq '.permissions' # push:false → 必须走 fork 发布
|
||||
git remote -v
|
||||
```
|
||||
|
||||
## 1. 改指向 → 重新打包(顺序不可颠倒)
|
||||
|
||||
```bash
|
||||
cd "$PKG"
|
||||
grep -rn "<upstream-owner>" .. --include='*.json' --include='*.ts' --include='*.tsx' --include='*.md' --include='*.mjs'
|
||||
# 逐处改完只后再打包:
|
||||
npm run check && npm run test:gate && npm run pack
|
||||
shasum -a 256 dist/v$VER/*.tgz
|
||||
TMP=$(mktemp -d) && tar -xzf dist/v$VER/dsh-worktable.tgz -C "$TMP"
|
||||
grep -rn "<upstream-owner>" "$TMP" ; echo "grep exit=$? (1 = 无残留,正确)"
|
||||
```
|
||||
|
||||
判据:`check`/`test:gate`/`pack` 全部 exit 0;两个 tgz 同 sha;解包无旧仓库名。
|
||||
|
||||
## 2. fork 与干净发布分支
|
||||
|
||||
```bash
|
||||
cd <repo-root>
|
||||
gh repo fork "$UP" --clone=false # 已存在会提示 already exists,可复用
|
||||
git remote add fork "git@github.com:$ME/<repo>.git" # 已存在:git remote set-url fork …
|
||||
git fetch --no-tags origin main
|
||||
|
||||
OURS=$(git rev-parse HEAD) # 本地"发布内容已就绪"的 HEAD
|
||||
git diff --name-status origin/main "$OURS" | awk '$1 ~ /^[DR]/' # 期望空;有 D/R 先处理再用 gate
|
||||
|
||||
git checkout -B release/v$VER origin/main
|
||||
git rm -rq --cached .
|
||||
git checkout "$OURS" -- .
|
||||
git add -A
|
||||
git commit -m "release: <name> v$VER(REQ-…)<一句话说明>"
|
||||
|
||||
DIFFOUT="$(git diff --stat "$OURS")"
|
||||
if [ -n "$DIFFOUT" ]; then
|
||||
echo "GATE FAILED:"; echo "$DIFFOUT"
|
||||
git checkout <原分支> && git branch -D release/v$VER # abort:不留半成品分支
|
||||
exit 1
|
||||
fi
|
||||
echo "GATE PASSED: release tree == OURS tree"
|
||||
```
|
||||
|
||||
## 3. 推送(只对 fork)与 draft Release
|
||||
|
||||
```bash
|
||||
git push -u fork release/v$VER
|
||||
git tag -f v$VER && git push -f fork v$VER # -f 仅限自己 fork 的 tag
|
||||
|
||||
gh release create v$VER \
|
||||
dist/v$VER/dsh-worktable.tgz dist/v$VER/dsh-worktable-$VER.tgz \
|
||||
--repo "$ME/<repo>" --draft --title "<name> v$VER" --notes-file /tmp/rel-notes.md
|
||||
```
|
||||
|
||||
原仓库零改动复核:
|
||||
|
||||
```bash
|
||||
git ls-remote "git@github.com:$UP.git" # 无 release/v… 分支、无新 tag
|
||||
gh release list --repo "$UP" # 与发布前一致
|
||||
```
|
||||
|
||||
### Release notes 模板(draft 阶段就写全新值)
|
||||
|
||||
```markdown
|
||||
# <name> v<ver>
|
||||
> 发布方:fork <ME>/<repo>(原仓库 <UP> 为上游来源)。插件内更新检查已指向本 fork。
|
||||
|
||||
## 新增 / 修复 / 清理
|
||||
## 验证
|
||||
- check / gate / pack 实际输出(测试条数、断言项)
|
||||
- 双资产同 SHA:<sha256>
|
||||
- 解包 grep 无旧仓库名
|
||||
- 发布分支为干净单提交(父提交 = 上游 main),`git diff --stat <OURS>` 为空
|
||||
## 安装
|
||||
网页端 / 桌面端一行命令(指向 fork)
|
||||
## 已知边界
|
||||
- draft 期间 releases/latest 仍指旧版 → 更新检查看不到新版
|
||||
- 保留的第三方外链、平台未验证范围
|
||||
```
|
||||
|
||||
## 4. publish 与发布后核对矩阵
|
||||
|
||||
```bash
|
||||
gh release edit v$VER --repo "$ME/<repo>" --draft=false
|
||||
```
|
||||
|
||||
| 核对项 | 命令 | 通过判据 |
|
||||
| --- | --- | --- |
|
||||
| 资产列表与 digest | `gh release view v$VER --repo $ME/<repo> --json assets` | 两个资产 `digest` = 本地 sha |
|
||||
| 下载后 sha | `gh release download v$VER --repo $ME/<repo> --dir "$D"` + `shasum -a 256 "$D"/*.tgz` | 与本地逐字一致 |
|
||||
| 与本地验收件一致 | `cmp "$D/dsh-worktable.tgz" dist/v$VER/dsh-worktable.tgz` | 无差异(byte-identical) |
|
||||
| 包内无旧仓库名 | 解包后 `grep -rn "<upstream-owner>"` | 无输出(exit 1) |
|
||||
| 包内版本 = tag | 解包读 `package.json#version` | `v$VER` |
|
||||
| 匿名可下载 | `curl -sL -o /dev/null -w '%{http_code}\n' <资产 URL>` | publish 后 200/302;draft 期 404 属预期 |
|
||||
| 安装可用 | 临时目录 `npm install <tgz>` + `import()` 断言 | 导出/版本断言通过 |
|
||||
|
||||
- **`verify-remote.mjs` 的平台限制**:其下载走 `powershell Invoke-WebRequest`,只在 Windows 可用;
|
||||
在 macOS 会 `FAIL: download fixed-name asset`。此时用上表的 `gh release view/download` + `shasum` + `cmp` 等价替代,
|
||||
并说明该脚本的 GET URL 已证明改指生效。
|
||||
- **"检查更新"看不到新版**的排查顺序:Release 是否 draft → `releases/latest` 指向 → 插件内 `UPDATE_REPO` 指向 →
|
||||
`latest` 资产名与代码拼法一致。
|
||||
|
||||
## 5. 链路判死模板(macOS 无 `timeout`)
|
||||
|
||||
```bash
|
||||
( git fetch --no-tags origin main ) & PID=$!
|
||||
for i in $(seq 1 30); do sleep 1; kill -0 "$PID" 2>/dev/null || break; done
|
||||
if kill -0 "$PID" 2>/dev/null; then kill -9 "$PID"; pkill -9 -f git-upload-pack; echo "TIMEOUT(30s)"; fi
|
||||
```
|
||||
|
||||
- HTTPS 到 GitHub `curl` 返回 `000` → 整体不通,改 SSH(`git remote set-url`)。
|
||||
- 30 秒内 `fatal: early EOF` → 链路被掐断;记录原文与时间,换网络/协议重试。
|
||||
- 认证或网络失败时不做破坏性重试,也不要把 force 用到上游;保留本地提交并上报失败原文。
|
||||
Reference in New Issue
Block a user