把版本推到 kashic 分发服务,或从契约里读取最新版。本文同时是人类说明书与 AI 代理执行规格。
三层结构,一切分发都落在这三层的组合上:
项目 project(slug) → 版本 release(version, channel) → 资产 asset(文件名, size, sha256)
| 用途 | 请求 |
|---|---|
| 作品列表(含最新版本与下载地址) | GET /works.json |
| 某项目最新版契约 | GET /<slug>/latest.json |
| 下载资产(支持子路径) | GET /<slug>/files/<文件名> |
契约与 GitHub releases 同形,客户端逐项校验:
{
"tag_name": "v1.14.85",
"body": "更新说明",
"draft": false,
"prerelease": false,
"assets": [
{
"name": "loli_v1.14.85.amr",
"size": 5524002,
"digest": "sha256:8fa34b07…(64 位十六进制)",
"browser_download_url": "https://sq.kashic.cn/loliapp/files/loli_v1.14.85.amr"
}
]
}
digest 缺失即拒绝该资产;size 必填;契约响应 no-store,可放心轮询。客户端只需一个 slug,就能自行完成「查版本 → 选资产 → 下载 → 校验」全流程。按下面顺序做即可:
GET https://sq.kashic.cn/<slug>/latest.json # 稳定版
got https://sq.kashic.cn/<slug>/latest.json?channel=prerelease # 预发布通道
建议时机:启动时拉一次 + 用户手动「检查更新」,或每 24 小时一次。契约带 no-store,不会拿到陈旧数据,高频拉取也不会踩缓存。
tag_name 去掉前导 v/V 后用四段数字比(如 0.2.0.0 > 0.1.1.5);缺失段按 0 补draft 或 prerelease 为 true 时,非预发布客户端直接跳过name == "DSHL-update.zip")<分量>_v<版本>.amr,逐分量比对本地版本、只拉需要升级的那几个size?不符丢弃重试sha256 == digest 后半段(不区分大小写)?不符丢弃重试import json, re, hashlib, urllib.request, pathlib
BASE, SLUG, ASSET = "https://sq.kashic.cn", "dshl", "DSHL-update.zip"
LOCAL = "0.1.1.5" # 本地当前版本
def ver(v):
p = [int(x) if str(x).isdigit() else 0 for x in str(v).lstrip("vV").split(".")]
return tuple((p + [0, 0, 0, 0])[:4])
rel = json.load(urllib.request.urlopen(f"{BASE}/{SLUG}/latest.json", timeout=20))
if rel.get("draft") or rel.get("prerelease"):
raise SystemExit("跳过非稳定版")
if ver(rel["tag_name"]) <= ver(LOCAL):
raise SystemExit("已是最新")
asset = next((a for a in rel["assets"] if a["name"] == ASSET), None)
assert asset, f"新版本缺少资产 {ASSET}"
assert re.fullmatch(r"sha256:[a-fA-F0-9]{64}", asset["digest"]), "digest 格式非法"
data = urllib.request.urlopen(asset["browser_download_url"], timeout=600).read()
assert len(data) == asset["size"], "字节数不符"
assert hashlib.sha256(data).hexdigest() == asset["digest"].split(":")[1].lower(), "哈希不符"
pathlib.Path("/tmp/" + ASSET).write_bytes(data) # 校验通过后才落盘/替换
print("已下载", ASSET, len(data), "B")
<分量>_v<版本> 里解出,或让服务方提供一个分量清单接口。kh_…Authorization: Bearer kh_…脚本:/usr/local/bin/kashic-push(纯标准库 python3,拷走即用)。
# 配置 key(二选一)
export KASHIC_HUB_KEY=kh_xxxxxxxx
# 或:mkdir -p ~/.config/kashic-hub && echo kh_xxxxxxxx > ~/.config/kashic-hub/key
kashic-push whoami # 校验 key,打印身份与绑定项目
kashic-push projects # 可见项目
kashic-push latest <slug> # 打印公网契约
kashic-push release <slug> <文件> \
--version 1.2.3 --notes "本次更新…" --channel stable
# 发布一个完整版本(单资产)
curl -X POST https://sq.kashic.cn/api/projects/<slug>/releases \
-H "Authorization: Bearer $KASHIC_HUB_KEY" \
-F "version=0.3.0" -F "notes=本次更新…" -F "channel=stable" \
-F "file=@./DSHL-update.zip"
# 推送/更新一个分量(多资产项目)
curl -X POST https://sq.kashic.cn/api/projects/<slug>/components \
-H "Authorization: Bearer $KASHIC_HUB_KEY" \
-F "name=cvi" -F "version=1.14.86" -F "file=@./cvi_v1.14.86.amr"
管理接口需 cookie(auth.kashic.cn 登录且 power==1)或请求头 X-Admin-Token。
| 码 | 含义 | 处理 |
|---|---|---|
| 401 | 未带凭据 / key 无效或已撤销 | 检查 Bearer 与 key 状态;不要重试 |
| 403 | key 绑定的是别的项目 | 换该项目专用 key |
| 404 | 项目不存在或未发布过 | 先让管理员建项目 / 发布一次 |
| 413 | 超过上传上限(4 GB) | 拆分或压缩 |
| 502/504 | 大文件上传超时 | 可安全重试 |
/api/projects/<slug>/releases 与 /<slug>/latest.json(整站就是分发服务,直接拼域名根路径即可)。