跳到主要内容

灵栈发布助手

收藏0

把技能文件夹脱敏、打包、发布到灵栈(含隐私检查、上传、轮询全流程)

让 AI 安装

lrt最新版本 0.1.0更新于 2026-11-08下载 0 次

SKILL.md

5.3 KB查看排版效果
1---
2name: lingzhan-publish
3description: 把一个技能文件夹脱敏、打包并发布到灵栈(lingzhanskill.com)。用户说「把这个技能发到灵栈」「更新 XX 技能」「发布技能」时使用;涵盖隐私检查、打包、上传、等待审核全流程。
4---
5
6# 发技能到灵栈
7
8能做什么:把一个本地技能文件夹检查指纹、脱敏打包、通过灵栈的 Agent 接口发布,并把公开链接回报给用户。
9带脚本:不单独带,正文里有可直接复制的 Python / curl 片段。
10联不联网:要,全程访问 https://lingzhanskill.com 。
11写文件:会写临时 ZIP 和脱敏副本(放在临时目录),不修改作者原始技能文件夹。
12
13官方说明(每次先读一遍,可能更新):https://lingzhanskill.com/publish.md
14
15## 前置
16
17- 发布密钥在 `~/.lingzhan/agent-token`(`lzk_` 开头)。已有就直接用,不要重复走设备授权。
18- 校验密钥:`curl -s -H "Authorization: Bearer $(cat ~/.lingzhan/agent-token)" https://lingzhanskill.com/api/v1/agent/me`,返回 `owner` 说明可用。
19- 没有密钥时才走设备授权:`POST /api/v1/agent/authorize` → 让作者在 `verification_url` 核对确认码并点允许 → 轮询 `/api/v1/agent/token` → 把 token 存到 `~/.lingzhan/agent-token`(权限只给当前用户)。
20
21## 七步
22
231. **隐私扫描**(必做,发布后公开且收不回)
24 在待发文件里找:绝对路径与用户名(`C:\Users\<名字>\`、`/home/<名字>/`)、内网地址(`10.`、`192.168.`、`172.16~31`、`.internal`/`.corp`/`.local`)、密钥凭据(`sk-`、`ghp_`、`AKIA`、`BEGIN PRIVATE`、`password=`、`.env`)、手机号邮箱等个人信息。
25 把「文件:行号 + 该行内容(密钥只显示前 4 位)」列给作者,由作者决定。
262. **脱敏打包**(推荐,绝不改原文件夹)
27 复制到临时目录再替换:本机绝对路径 → `~/.dsh-workspace` 之类占位符;解释器绝对路径 → `python`;本地服务端口 → `127.0.0.1:<端口>`。
28 在 SKILL.md 开头补一句「依赖本地 XX,路径按自己环境替换」。
29 ZIP 要求:条目路径用 `/`、不能有 `./`、`..`、绝对路径;最多 500 文件、≤20MB、解压≤100MB;ZIP 不要放进技能文件夹。
303. **确认**:slug(3~32 位小写字母数字连字符,**发布后不可改**)、显示名、一句话描述——念给作者,明确同意再发。
314. **建版本**:`POST /api/v1/agent/releases`,body `{"slug","size","name","summary","category","changes"}`;返回 `put_url`(15 分钟临时凭据,不保存不外传)、`complete_url`、`version`。
325. **上传**:`PUT put_url`,`Content-Type: application/zip`,body 为 ZIP 字节。
336. **完成**:`POST complete_url`(空 body),返回 `stage: checking`。
347. **轮询**:`GET /api/v1/agent/releases/<slug>/<version>`,每 5 秒、最多 3 分钟。`published` → 把 `url` 给作者;`blocked`/`returned` → 按 `problems` 改完重发;`in_review`/`closed` → 让作者看 `manage_url`。
35
36## 坑
37
38- **Cloudflare 1010**:Python urllib 默认 UA 会被 403。所有请求都要带
39 `User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0 Safari/537.36`
40 和 `Accept: application/json`。
41- 中文请求体必须 UTF-8 字节:`json.dumps(obj, ensure_ascii=False).encode('utf-8')`,Content-Type 带 `charset=utf-8`。
42- slug 发布后不能改;名称、简介可以改。
43- 已公开的版本不能修改,要改就发新版本号(不填 `version` 会自动 +1)。
44- 用户没看过内容、没同意之前不要发布;不要把 token、`put_url` 贴进聊天或写进技能包。
45- 失败重试是安全的(PUT 同一个 zip、complete 同一版本不会重复发布)。
46
47## Python 片段
48
49```python
50import json, os, time, urllib.request
51T = open(os.path.expanduser('~/.lingzhan/agent-token')).read().strip()
52UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0 Safari/537.36'
53H = {'Authorization': 'Bearer ' + T, 'User-Agent': UA, 'Accept': 'application/json',
54 'Content-Type': 'application/json; charset=utf-8'}
55
56zip_path = 'skill.zip'
57body = json.dumps({"slug": "my-skill", "size": os.path.getsize(zip_path),
58 "name": "技能名", "summary": "一句话说明", "changes": ["首个版本"]},
59 ensure_ascii=False).encode()
60r = json.loads(urllib.request.urlopen(urllib.request.Request(
61 'https://lingzhanskill.com/api/v1/agent/releases', data=body, headers=H, method='POST')).read())
62
63up = urllib.request.Request(r['put_url'], data=open(zip_path, 'rb').read(),
64 headers={**(r.get('headers') or {}), 'Content-Type': 'application/zip'},
65 method='PUT')
66urllib.request.urlopen(up, timeout=120)
67
68urllib.request.urlopen(urllib.request.Request(
69 r['complete_url'], data=b'', headers={'Authorization': 'Bearer ' + T, 'User-Agent': UA}, method='POST'))
70
71for _ in range(36):
72 d = json.loads(urllib.request.urlopen(urllib.request.Request(
73 f"https://lingzhanskill.com/api/v1/agent/releases/{r['slug']}/{r['version']}",
74 headers={'Authorization': 'Bearer ' + T, 'User-Agent': UA})).read())
75 if d['stage'] in ('published', 'blocked', 'returned', 'closed', 'in_review'):
76 break
77 time.sleep(5)
78print(d)
79```

文件内容是平台检查时读出的文本,只供查看。平台不会运行包里的任何脚本或程序。