skill-market-cli 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/examples/test-skill.yaml +78 -0
- package/package.json +5 -5
- package/src/api/client.js +6 -2
- package/src/auth/oauth.js +161 -113
- package/src/auth/token-store.js +1 -1
- package/src/commands/login.js +4 -5
- package/src/commands/logout.js +5 -5
- package/src/commands/run-example.js +1 -56
- package/src/commands/update.js +36 -7
- package/src/commands/upload.js +229 -105
- package/src/config/server-modes.js +43 -0
- package/src/index.js +42 -13
- package/src/lib/run-example-collect.js +44 -0
- package/src/lib/skill-upload-helpers.js +77 -0
- package/src/skills/skill-market-upload/SKILL.md +53 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const YAML = require('yaml');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 解析 SKILL.md:frontmatter + ## Usage Examples 下简单分块(仅 prompt 文本)
|
|
7
|
+
*/
|
|
8
|
+
function parseSkillMarkdown(content) {
|
|
9
|
+
let frontmatter = null;
|
|
10
|
+
let examples = [];
|
|
11
|
+
|
|
12
|
+
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*(?:\n|$)/);
|
|
13
|
+
if (frontmatterMatch) {
|
|
14
|
+
try {
|
|
15
|
+
frontmatter = YAML.parse(frontmatterMatch[1]);
|
|
16
|
+
} catch {
|
|
17
|
+
// ignore
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const examplesMatch = content.match(/## Usage Examples?\s*\n([\s\S]*?)(?=##|$)/i);
|
|
22
|
+
if (examplesMatch) {
|
|
23
|
+
const exampleText = examplesMatch[1];
|
|
24
|
+
const exampleBlocks = exampleText.split(/\n\n+/).filter((b) => b.trim());
|
|
25
|
+
examples = exampleBlocks.map((block) => {
|
|
26
|
+
const lines = block.split('\n').filter((l) => l.trim());
|
|
27
|
+
return { prompt: lines.join('\n') };
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { frontmatter, examples };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 读取 run-example 生成的 .skill-examples.json,转为接口所需 usageExamples
|
|
36
|
+
*/
|
|
37
|
+
function loadDotSkillExamples(skillDir) {
|
|
38
|
+
const filePath = path.join(skillDir, '.skill-examples.json');
|
|
39
|
+
if (!fs.existsSync(filePath)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const data = fs.readJsonSync(filePath);
|
|
44
|
+
if (!data || !Array.isArray(data.examples)) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return data.examples.map((ex) => ({
|
|
48
|
+
prompt: ex.prompt,
|
|
49
|
+
aiResponses: ex.aiResponses || [],
|
|
50
|
+
model: ex.model || data.model || ''
|
|
51
|
+
}));
|
|
52
|
+
} catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 将仅有 prompt 的条目补全为完整 UsageExample(可选采集轨迹)
|
|
59
|
+
*/
|
|
60
|
+
function promptOnlyExamples(examples) {
|
|
61
|
+
if (!examples || !examples.length) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
return examples
|
|
65
|
+
.map((ex) => ({
|
|
66
|
+
prompt: (ex.prompt || '').trim(),
|
|
67
|
+
aiResponses: ex.aiResponses,
|
|
68
|
+
model: ex.model
|
|
69
|
+
}))
|
|
70
|
+
.filter((ex) => ex.prompt);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = {
|
|
74
|
+
parseSkillMarkdown,
|
|
75
|
+
loadDotSkillExamples,
|
|
76
|
+
promptOnlyExamples
|
|
77
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-market-upload
|
|
3
|
+
purpose: 指导 AI Agent 使用 skill-market-cli 将本地 SKILL 上传至 Skill Market,含用户案例与轨迹采集要求
|
|
4
|
+
tags:
|
|
5
|
+
- skill-market
|
|
6
|
+
- cli
|
|
7
|
+
- upload
|
|
8
|
+
model: deepseek-chat
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Skill Market 上传助手(给 AI Agent 用)
|
|
12
|
+
|
|
13
|
+
本说明面向 **代表用户操作终端的 AI Agent**。目标:在已登录 `skill-market-cli` 的前提下,通过 **`skill-market-cli upload`** 完成上传,并满足服务端对 **AI 渠道** 的必填规则。
|
|
14
|
+
|
|
15
|
+
## 你必须知道的约束
|
|
16
|
+
|
|
17
|
+
1. **登录**:用户须先执行 `skill-market-cli login`(可用 `--mode development` 指向本地)。凭证在 `~/.skill-market-cli/config.json`。
|
|
18
|
+
2. **上传走 AI 渠道**:CLI 使用 `POST /api/skill/ai/upload`,要求 **全部字段非空**,且 **`tags`、`usageExamples` 不得为空数组**。
|
|
19
|
+
3. **用户案例(必填)**:`usageExamples` 中每一项必须包含:
|
|
20
|
+
- **`prompt`**:终端用户会如何向该 Skill 提问(由用户或你根据上下文代写,但必须经用户确认)。
|
|
21
|
+
- **`aiResponses`**:一次「示例运行」采集到的轨迹(thinking / toolcall / message)。上传命令会在本地 **自动调用采集逻辑** 生成(当前为可替换的模拟实现,结构需与后端一致)。
|
|
22
|
+
- **`model`**:推荐模型名(如 `deepseek-chat`)。
|
|
23
|
+
4. **无法仅从文件推断的字段**:若 SKILL.md 未写全,上传流程会 **交互询问**:名称、描述、标签、`rootUrl`、推荐模型等。Agent 应结合仓库上下文、README、用户口述 **帮用户预填**,并在询问环节确认。
|
|
24
|
+
|
|
25
|
+
## 推荐工作流(Agent)
|
|
26
|
+
|
|
27
|
+
1. 确认仓库中存在 **`SKILL.md`**(目录则路径指向该目录)。
|
|
28
|
+
2. 读取 frontmatter,整理候选:`name`、`purpose`/`description`、`tags`、`model`、`rootUrl`。
|
|
29
|
+
3. 与用户确认 **至少一条「用户会如何提问」的测试案例**(可多轮补充)。案例文本即 `prompt`。
|
|
30
|
+
4. 在终端执行上传(勿省略路径):
|
|
31
|
+
```bash
|
|
32
|
+
skill-market-cli upload <path-to-skill-dir-or-SKILL.md>
|
|
33
|
+
```
|
|
34
|
+
5. 按 CLI 提示补全缺失字段;当提示采集轨迹时,**允许命令自动运行**(会调用内置采集器写入 `aiResponses`)。
|
|
35
|
+
6. 上传成功后,CLI 会在技能目录写入 **`.skill-examples.json`**,便于复查与再次上传。
|
|
36
|
+
|
|
37
|
+
## 与 `run-example` 的关系
|
|
38
|
+
|
|
39
|
+
- 可先运行 `skill-market-cli run-example <path>` 预采集,生成 `.skill-examples.json`;再执行 `upload` 时会 **自动合并** 该文件。
|
|
40
|
+
- 若未预先运行,`upload` 会引导用户 **逐条输入案例并自动采集轨迹**,无需用户手动拼 JSON。
|
|
41
|
+
|
|
42
|
+
## 禁止事项
|
|
43
|
+
|
|
44
|
+
- 不要编造不存在的 Git 仓库 URL;`rootUrl` 可用 `file:///...` 指向本地 `SKILL.md` 的绝对路径(CLI 默认值),或用户提供的 raw URL。
|
|
45
|
+
- 不要跳过「用户案例」;没有案例与轨迹,AI 渠道上传会失败。
|
|
46
|
+
|
|
47
|
+
## Usage Examples
|
|
48
|
+
|
|
49
|
+
### Example 1
|
|
50
|
+
|
|
51
|
+
**User:** 请根据我仓库里的 SKILL.md 帮我执行上传,并告诉我你要确认哪些字段。
|
|
52
|
+
|
|
53
|
+
**AI:** 我会先读取 `SKILL.md` 的 frontmatter,列出缺失的 name、描述、标签、模型与 rootUrl;请你至少提供一条「最终用户会对该 Skill 说的话」作为测试案例。然后我在终端运行 `skill-market-cli upload .`,在交互中替你填入并确认,自动完成轨迹采集后提交。
|