skill-market-cli 1.1.0 → 1.1.1
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/package.json +1 -1
- package/src/api/client.js +10 -5
- package/src/auth/token-store.js +23 -1
- package/src/commands/delete.js +5 -3
- package/src/commands/logout.js +2 -1
- package/src/commands/token.js +55 -0
- package/src/commands/update.js +5 -3
- package/src/commands/upload.js +5 -3
- package/src/index.js +7 -0
- package/src/skills/skill-market-upload/.skill-examples.json +26 -0
- package/src/skills/skill-market-upload/SKILL.md +1 -0
package/package.json
CHANGED
package/src/api/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
2
|
const chalk = require('chalk');
|
|
3
|
-
const { getToken, isLoggedIn, getServerConfig } = require('../auth/token-store');
|
|
3
|
+
const { getToken, isLoggedIn, getServerConfig, getPersonalAccessToken } = require('../auth/token-store');
|
|
4
4
|
const { refreshAccessToken } = require('../auth/oauth');
|
|
5
5
|
|
|
6
6
|
class ApiClient {
|
|
@@ -23,12 +23,12 @@ class ApiClient {
|
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
// 请求拦截器 - 添加 Token
|
|
26
|
+
// 请求拦截器 - 添加 Token(优先 OAuth Token,其次 Personal Access Token)
|
|
27
27
|
this.client.interceptors.request.use(
|
|
28
28
|
async (config) => {
|
|
29
29
|
if (isLoggedIn()) {
|
|
30
30
|
const { accessToken, expiresAt } = getToken();
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
// 检查 Token 是否即将过期
|
|
33
33
|
if (expiresAt && Date.now() > expiresAt - 60000) {
|
|
34
34
|
// Token 即将过期,尝试刷新
|
|
@@ -42,6 +42,11 @@ class ApiClient {
|
|
|
42
42
|
} else {
|
|
43
43
|
config.headers['Authorization'] = `Bearer ${accessToken}`;
|
|
44
44
|
}
|
|
45
|
+
} else {
|
|
46
|
+
const pat = getPersonalAccessToken();
|
|
47
|
+
if (pat) {
|
|
48
|
+
config.headers['Authorization'] = `Bearer ${pat}`;
|
|
49
|
+
}
|
|
45
50
|
}
|
|
46
51
|
return config;
|
|
47
52
|
},
|
|
@@ -89,9 +94,9 @@ class ApiClient {
|
|
|
89
94
|
const response = await this.client.get('/skill/list', {
|
|
90
95
|
params: { page: 1, pageSize: 1000 }
|
|
91
96
|
});
|
|
92
|
-
|
|
97
|
+
|
|
93
98
|
const { user } = getToken();
|
|
94
|
-
if (response.data && response.data.data && response.data.data.list) {
|
|
99
|
+
if (user && response.data && response.data.data && response.data.data.list) {
|
|
95
100
|
response.data.data.list = response.data.data.list.filter(
|
|
96
101
|
skill => skill.creator === user.name
|
|
97
102
|
);
|
package/src/auth/token-store.js
CHANGED
|
@@ -60,9 +60,28 @@ function clearToken() {
|
|
|
60
60
|
saveConfig(config);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
//
|
|
63
|
+
// Personal Access Token (PAT) 管理
|
|
64
|
+
function savePersonalAccessToken(token) {
|
|
65
|
+
const config = getConfig();
|
|
66
|
+
config.personalAccessToken = token;
|
|
67
|
+
saveConfig(config);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function getPersonalAccessToken() {
|
|
71
|
+
const config = getConfig();
|
|
72
|
+
return config.personalAccessToken || null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function clearPersonalAccessToken() {
|
|
76
|
+
const config = getConfig();
|
|
77
|
+
delete config.personalAccessToken;
|
|
78
|
+
saveConfig(config);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 检查是否已登录(OAuth 或 Personal Access Token)
|
|
64
82
|
function isLoggedIn() {
|
|
65
83
|
const config = getConfig();
|
|
84
|
+
if (config.personalAccessToken) return true;
|
|
66
85
|
if (!config.accessToken) return false;
|
|
67
86
|
if (config.expiresAt && Date.now() > config.expiresAt) {
|
|
68
87
|
return false;
|
|
@@ -95,6 +114,9 @@ module.exports = {
|
|
|
95
114
|
isLoggedIn,
|
|
96
115
|
getServerConfig,
|
|
97
116
|
setServerConfig,
|
|
117
|
+
savePersonalAccessToken,
|
|
118
|
+
getPersonalAccessToken,
|
|
119
|
+
clearPersonalAccessToken,
|
|
98
120
|
CONFIG_DIR,
|
|
99
121
|
CONFIG_FILE
|
|
100
122
|
};
|
package/src/commands/delete.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const inquirer = require('inquirer');
|
|
3
|
-
const { isLoggedIn } = require('../auth/token-store');
|
|
3
|
+
const { isLoggedIn, getPersonalAccessToken } = require('../auth/token-store');
|
|
4
4
|
const apiClient = require('../api/client');
|
|
5
5
|
|
|
6
6
|
async function remove(skillId, options) {
|
|
7
|
-
if (!isLoggedIn()) {
|
|
8
|
-
console.error(chalk.red('❌ Please login first
|
|
7
|
+
if (!isLoggedIn() && !getPersonalAccessToken()) {
|
|
8
|
+
console.error(chalk.red('❌ Please login first or set an access token:'));
|
|
9
|
+
console.error(chalk.gray(' skill-market-cli login'));
|
|
10
|
+
console.error(chalk.gray(' skill-market-cli token set <your-access-token>\n'));
|
|
9
11
|
process.exit(1);
|
|
10
12
|
}
|
|
11
13
|
|
package/src/commands/logout.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
-
const { clearToken, isLoggedIn } = require('../auth/token-store');
|
|
2
|
+
const { clearToken, clearPersonalAccessToken, isLoggedIn } = require('../auth/token-store');
|
|
3
3
|
const apiClient = require('../api/client');
|
|
4
4
|
|
|
5
5
|
async function logout() {
|
|
@@ -16,6 +16,7 @@ async function logout() {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
clearToken();
|
|
19
|
+
clearPersonalAccessToken();
|
|
19
20
|
|
|
20
21
|
console.log(chalk.green('已登出本地凭证'));
|
|
21
22
|
console.log('');
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const { getPersonalAccessToken, savePersonalAccessToken, clearPersonalAccessToken } = require('../auth/token-store');
|
|
3
|
+
|
|
4
|
+
function showHelp() {
|
|
5
|
+
console.log(`
|
|
6
|
+
用法:skill-market-cli token <subcommand>
|
|
7
|
+
|
|
8
|
+
子命令:
|
|
9
|
+
set <token> 保存 Personal Access Token 到本地配置
|
|
10
|
+
get 查看当前保存的 Personal Access Token
|
|
11
|
+
remove 删除本地保存的 Personal Access Token
|
|
12
|
+
`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function token(subcommand, value) {
|
|
16
|
+
switch (subcommand) {
|
|
17
|
+
case 'set': {
|
|
18
|
+
if (!value) {
|
|
19
|
+
console.error(chalk.red('错误:请提供 token 值'));
|
|
20
|
+
console.log(chalk.gray('示例:skill-market-cli token set pat_xxxxxxxxxx'));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
savePersonalAccessToken(value);
|
|
24
|
+
console.log(chalk.green('✓ Personal Access Token 已保存'));
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
case 'get': {
|
|
28
|
+
const pat = getPersonalAccessToken();
|
|
29
|
+
if (pat) {
|
|
30
|
+
console.log(chalk.cyan('当前 Personal Access Token:'));
|
|
31
|
+
console.log(pat);
|
|
32
|
+
} else {
|
|
33
|
+
console.log(chalk.yellow('尚未保存 Personal Access Token'));
|
|
34
|
+
console.log(chalk.gray('可通过以下命令设置:'));
|
|
35
|
+
console.log(chalk.gray(' skill-market-cli token set <your-token>'));
|
|
36
|
+
}
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
case 'remove':
|
|
40
|
+
case 'rm': {
|
|
41
|
+
clearPersonalAccessToken();
|
|
42
|
+
console.log(chalk.green('✓ Personal Access Token 已删除'));
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
default: {
|
|
46
|
+
showHelp();
|
|
47
|
+
if (subcommand) {
|
|
48
|
+
console.error(chalk.red(`未知子命令:${subcommand}`));
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = token;
|
package/src/commands/update.js
CHANGED
|
@@ -3,12 +3,14 @@ const path = require('path');
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const inquirer = require('inquirer');
|
|
5
5
|
const YAML = require('yaml');
|
|
6
|
-
const { isLoggedIn } = require('../auth/token-store');
|
|
6
|
+
const { isLoggedIn, getPersonalAccessToken } = require('../auth/token-store');
|
|
7
7
|
const apiClient = require('../api/client');
|
|
8
8
|
|
|
9
9
|
async function update(skillId, options) {
|
|
10
|
-
if (!isLoggedIn()) {
|
|
11
|
-
console.error(chalk.red('❌ Please login first
|
|
10
|
+
if (!isLoggedIn() && !getPersonalAccessToken()) {
|
|
11
|
+
console.error(chalk.red('❌ Please login first or set an access token:'));
|
|
12
|
+
console.error(chalk.gray(' skill-market-cli login'));
|
|
13
|
+
console.error(chalk.gray(' skill-market-cli token set <your-access-token>\n'));
|
|
12
14
|
process.exit(1);
|
|
13
15
|
}
|
|
14
16
|
|
package/src/commands/upload.js
CHANGED
|
@@ -2,7 +2,7 @@ const fs = require('fs-extra');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const inquirer = require('inquirer');
|
|
5
|
-
const { isLoggedIn } = require('../auth/token-store');
|
|
5
|
+
const { isLoggedIn, getPersonalAccessToken } = require('../auth/token-store');
|
|
6
6
|
const apiClient = require('../api/client');
|
|
7
7
|
const { runExampleAndCollect } = require('../lib/run-example-collect');
|
|
8
8
|
const {
|
|
@@ -15,8 +15,10 @@ const {
|
|
|
15
15
|
* 交互补全:名称、描述、标签、模型、rootUrl、用户案例 + 可选运行采集轨迹
|
|
16
16
|
*/
|
|
17
17
|
async function upload(skillPath, options = {}) {
|
|
18
|
-
if (!isLoggedIn()) {
|
|
19
|
-
console.error(chalk.red('
|
|
18
|
+
if (!isLoggedIn() && !getPersonalAccessToken()) {
|
|
19
|
+
console.error(chalk.red('请先登录或设置 Access Token:'));
|
|
20
|
+
console.error(chalk.gray(' skill-market-cli login'));
|
|
21
|
+
console.error(chalk.gray(' skill-market-cli token set <your-access-token>\n'));
|
|
20
22
|
process.exit(1);
|
|
21
23
|
}
|
|
22
24
|
|
package/src/index.js
CHANGED
|
@@ -9,6 +9,7 @@ const upload = require('./commands/upload');
|
|
|
9
9
|
const update = require('./commands/update');
|
|
10
10
|
const remove = require('./commands/delete');
|
|
11
11
|
const runExample = require('./commands/run-example');
|
|
12
|
+
const token = require('./commands/token');
|
|
12
13
|
const { getConfig } = require('./auth/token-store');
|
|
13
14
|
const { applyServerMode, getServerModesHelp } = require('./config/server-modes');
|
|
14
15
|
const apiClient = require('./api/client');
|
|
@@ -67,6 +68,12 @@ program
|
|
|
67
68
|
.description('清除本地登录状态并尝试撤销服务端令牌')
|
|
68
69
|
.action(logout);
|
|
69
70
|
|
|
71
|
+
// Token command
|
|
72
|
+
program
|
|
73
|
+
.command('token [subcommand] [value]')
|
|
74
|
+
.description('管理 Personal Access Token(用于 CLI 免登录)')
|
|
75
|
+
.action(token);
|
|
76
|
+
|
|
70
77
|
// List command
|
|
71
78
|
program
|
|
72
79
|
.command('list')
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"model": "deepseek-chat",
|
|
3
|
+
"examples": [
|
|
4
|
+
{
|
|
5
|
+
"prompt": "请根据我仓库里的 SKILL.md 帮我执行上传,并告诉我你要确认哪些字段。",
|
|
6
|
+
"aiResponses": [
|
|
7
|
+
{
|
|
8
|
+
"type": "thinking",
|
|
9
|
+
"content": "用户要用 skill-market-cli 上传 SKILL。需先读 frontmatter,核对 name、描述、tags、model、rootUrl;至少一条用户案例与 thinking/toolcall/message 轨迹;再执行 upload 交互或脚本。"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"type": "toolcall",
|
|
13
|
+
"toolName": "read_file",
|
|
14
|
+
"toolInput": {
|
|
15
|
+
"path": "./SKILL.md"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"type": "message",
|
|
20
|
+
"content": "我会先读取 `SKILL.md` 的 frontmatter,列出缺失项;请你确认一条「最终用户会如何提问」的测试案例。然后运行 `skill-market-cli upload <skill 目录>`,在交互中补全字段并自动采集轨迹后提交到 Skill Market。"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"model": "deepseek-chat"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|