yingmi-skill-cli 0.0.2 → 0.0.7
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/README.md +71 -55
- package/bin/index.js +453 -157
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# `yingmi-cli`
|
|
1
|
+
# `yingmi-skill-cli`
|
|
2
2
|
|
|
3
3
|
一个面向 Agent 的 CLI,用来统一盈米 MCP 能力发现、初始化配置、远端 skill 管理和版本升级。
|
|
4
4
|
|
|
@@ -17,44 +17,52 @@
|
|
|
17
17
|
CLI 聚焦 5 个核心模块:
|
|
18
18
|
|
|
19
19
|
- `init`:让 CLI 首次可用,负责配置写入、环境检查和连通性验证
|
|
20
|
-
- `mcp
|
|
21
|
-
- `remote-skill
|
|
20
|
+
- `mcp`:浏览原子金融能力摘要、查看某个工具的完整 OpenAPI 定义,并发起工具调用
|
|
21
|
+
- `remote-skill`:列出可用金融场景 skill,进入某个 skill 上下文,先阅读 skill 说明,再执行约定脚本
|
|
22
22
|
- `help`:提供显式帮助入口,并保持与 `--help` 同源
|
|
23
23
|
- `upgrade`:检查版本并升级 CLI
|
|
24
24
|
|
|
25
25
|
这套划分的核心原则是:先初始化,再发现能力,再查看定义,再执行调用或远端脚本,让命令树围绕统一心智模型组织。
|
|
26
26
|
|
|
27
|
+
`mcp` 和 `remote-skill` 的边界不是按“复杂度高低”区分,而是按“能力层级”区分:
|
|
28
|
+
|
|
29
|
+
- `mcp` 是原子能力层,适合已知要调用哪个工具、并且能明确构造 JSON 输入的场景
|
|
30
|
+
- `remote-skill` 是金融场景编排层,适合基金分析、组合诊断、财富规划、市场简报等完整任务
|
|
31
|
+
- `remote-skill` 内部可以按需调用一个或多个 `mcp`
|
|
32
|
+
|
|
27
33
|
## 安装
|
|
28
34
|
|
|
29
35
|
```bash
|
|
30
|
-
npm install -g yingmi-cli
|
|
36
|
+
npm install -g yingmi-skill-cli
|
|
31
37
|
```
|
|
32
38
|
|
|
33
|
-
安装后可通过 `yingmi-cli` 命令使用。
|
|
39
|
+
安装后可通过 `yingmi-skill-cli` 命令使用。
|
|
34
40
|
|
|
35
41
|
## 命令树
|
|
36
42
|
|
|
37
43
|
```bash
|
|
38
|
-
yingmi-cli init setup
|
|
39
|
-
yingmi-cli init setup --api-key <value>
|
|
40
|
-
yingmi-cli init setup --phone <value>
|
|
41
|
-
yingmi-cli init setup --verify-code <value>
|
|
42
|
-
yingmi-cli init status
|
|
43
|
-
yingmi-cli init doctor
|
|
44
|
-
|
|
45
|
-
yingmi-cli mcp list
|
|
46
|
-
yingmi-cli mcp schema <toolName>
|
|
47
|
-
yingmi-cli mcp call <toolName> --input <json>
|
|
48
|
-
|
|
49
|
-
yingmi-cli remote-skill
|
|
50
|
-
yingmi-cli remote-skill
|
|
51
|
-
yingmi-cli remote-skill
|
|
52
|
-
yingmi-cli remote-skill
|
|
53
|
-
|
|
54
|
-
yingmi-cli
|
|
55
|
-
|
|
56
|
-
yingmi-cli
|
|
57
|
-
|
|
44
|
+
yingmi-skill-cli init setup
|
|
45
|
+
yingmi-skill-cli init setup --api-key <value>
|
|
46
|
+
yingmi-skill-cli init setup --phone <value>
|
|
47
|
+
yingmi-skill-cli init setup --verify-code <value>
|
|
48
|
+
yingmi-skill-cli init status
|
|
49
|
+
yingmi-skill-cli init doctor
|
|
50
|
+
|
|
51
|
+
yingmi-skill-cli mcp list
|
|
52
|
+
yingmi-skill-cli mcp schema <toolName>
|
|
53
|
+
yingmi-skill-cli mcp call <toolName> --input <json>
|
|
54
|
+
|
|
55
|
+
yingmi-skill-cli remote-skill scope set --skills <skill1,skill2,...>
|
|
56
|
+
yingmi-skill-cli remote-skill scope clear
|
|
57
|
+
yingmi-skill-cli remote-skill list
|
|
58
|
+
yingmi-skill-cli remote-skill enter <skillName>
|
|
59
|
+
yingmi-skill-cli remote-skill exec --script <script>
|
|
60
|
+
yingmi-skill-cli remote-skill exec --script-file <path>
|
|
61
|
+
|
|
62
|
+
yingmi-skill-cli help [command]
|
|
63
|
+
|
|
64
|
+
yingmi-skill-cli upgrade
|
|
65
|
+
yingmi-skill-cli upgrade --check-only
|
|
58
66
|
```
|
|
59
67
|
|
|
60
68
|
## 模块说明
|
|
@@ -66,11 +74,11 @@ yingmi-cli upgrade --check-only
|
|
|
66
74
|
常用命令:
|
|
67
75
|
|
|
68
76
|
```bash
|
|
69
|
-
yingmi-cli init setup --api-key <value>
|
|
70
|
-
yingmi-cli init setup --phone <手机号>
|
|
71
|
-
yingmi-cli init setup --verify-code <验证码>
|
|
72
|
-
yingmi-cli init status
|
|
73
|
-
yingmi-cli init doctor
|
|
77
|
+
yingmi-skill-cli init setup --api-key <value>
|
|
78
|
+
yingmi-skill-cli init setup --phone <手机号>
|
|
79
|
+
yingmi-skill-cli init setup --verify-code <验证码>
|
|
80
|
+
yingmi-skill-cli init status
|
|
81
|
+
yingmi-skill-cli init doctor
|
|
74
82
|
```
|
|
75
83
|
|
|
76
84
|
行为约束:
|
|
@@ -82,14 +90,14 @@ yingmi-cli init doctor
|
|
|
82
90
|
|
|
83
91
|
### `mcp`
|
|
84
92
|
|
|
85
|
-
`mcp`
|
|
93
|
+
`mcp` 负责“发现原子能力、理解能力定义、执行单次调用”三个阶段。
|
|
86
94
|
|
|
87
95
|
常用命令:
|
|
88
96
|
|
|
89
97
|
```bash
|
|
90
|
-
yingmi-cli mcp list
|
|
91
|
-
yingmi-cli mcp schema getFundCampisiIndicator
|
|
92
|
-
yingmi-cli mcp call getFundCampisiIndicator --input '{"fundCode":"000001","timePeriod":"LAST_YEAR"}'
|
|
98
|
+
yingmi-skill-cli mcp list
|
|
99
|
+
yingmi-skill-cli mcp schema getFundCampisiIndicator
|
|
100
|
+
yingmi-skill-cli mcp call getFundCampisiIndicator --input '{"fundCode":"000001","timePeriod":"LAST_YEAR"}'
|
|
93
101
|
```
|
|
94
102
|
|
|
95
103
|
行为约束:
|
|
@@ -97,44 +105,53 @@ yingmi-cli mcp call getFundCampisiIndicator --input '{"fundCode":"000001","timeP
|
|
|
97
105
|
- `mcp list`:展示工具摘要,默认优先结构化结果
|
|
98
106
|
- `mcp schema <toolName>`:展示某个工具的完整 OpenAPI 定义
|
|
99
107
|
- `mcp call <toolName>`:调用目标工具,支持 `--input` 和 `--input-file`
|
|
108
|
+
- `mcp` 适合直接取数、单次计算、单个分析接口调用,不适合直接承载完整金融场景工作流
|
|
100
109
|
- 输出协议必须稳定,stdout 只承载结果,stderr 承载提示与错误
|
|
101
110
|
|
|
102
111
|
### `remote-skill`
|
|
103
112
|
|
|
104
|
-
`remote-skill` 面向远端 skill 运行服务,核心是“发现 skill
|
|
113
|
+
`remote-skill` 面向远端 skill 运行服务,核心是“发现 skill、进入 skill 上下文,并按 skill 协议完成金融场景任务”。
|
|
105
114
|
|
|
106
115
|
常用命令:
|
|
107
116
|
|
|
108
117
|
```bash
|
|
109
|
-
yingmi-cli remote-skill
|
|
110
|
-
yingmi-cli remote-skill
|
|
111
|
-
yingmi-cli remote-skill
|
|
112
|
-
yingmi-cli remote-skill
|
|
118
|
+
yingmi-skill-cli remote-skill scope set --skills fund-analyzer,market-brief
|
|
119
|
+
yingmi-skill-cli remote-skill scope clear
|
|
120
|
+
yingmi-skill-cli remote-skill list
|
|
121
|
+
yingmi-skill-cli remote-skill enter fund-analyzer
|
|
122
|
+
yingmi-skill-cli remote-skill exec --script 'cat SKILL.md'
|
|
123
|
+
yingmi-skill-cli remote-skill exec --script 'python main.py'
|
|
124
|
+
yingmi-skill-cli remote-skill exec --script-file ./scripts/run.sh
|
|
113
125
|
```
|
|
114
126
|
|
|
115
127
|
行为约束:
|
|
116
128
|
|
|
129
|
+
- `scope set --skills <a,b,c>`:设置本地 scope 白名单,限制 `remote-skill` 默认可见的 skill 范围
|
|
130
|
+
- `scope clear`:清除本地 scope,恢复默认行为
|
|
117
131
|
- `list`:调用远端 `/api/get-skills` 接口,使用本地 `apiKey` 作为请求头
|
|
118
|
-
- `
|
|
119
|
-
- `
|
|
120
|
-
-
|
|
132
|
+
- `list` 在配置了 scope 且与远端列表存在交集时,只返回交集;如果 scope 未配置或交集为空,则返回远端全量,避免返回空数组
|
|
133
|
+
- `enter <skillName>`:会先基于当前可见 skill 列表做校验;通过后再调用远端 `/api/get-skill-by-name` 获取压缩包地址,下载并解压到 `~/.yingmi-skill-cli/skills/<skillName>` 后输出目录树,并把当前 skill 上下文写入本地配置
|
|
134
|
+
- `exec --script/--script-file`:只能在最近一次成功 `enter` 后使用,建议先执行 `cat SKILL.md` 理解 skill 约定,再在当前 skill 目录执行入口脚本;执行结果输出状态、退出码、stdout 和 stderr,不额外回传本地工作目录路径
|
|
135
|
+
- `remote-skill` 适合基金分析、组合诊断、财富规划、市场简报等场景任务;skill 内部可以继续调用多个 `mcp`
|
|
136
|
+
- 远端服务地址默认读取 `https://stargate-staging.yingmi-inc.com/`,也可在 `~/.yingmi-skill-cli/config.json` 里手工设置 `stargateBaseUrl`
|
|
121
137
|
|
|
122
138
|
### `help`
|
|
123
139
|
|
|
124
|
-
`help` 是显式帮助入口,用来补足 `--help`
|
|
140
|
+
`help` 是显式帮助入口,用来补足 `--help` 之外的可发现性,并承担按任务导航的职责。
|
|
125
141
|
|
|
126
142
|
常用命令:
|
|
127
143
|
|
|
128
144
|
```bash
|
|
129
|
-
yingmi-cli help
|
|
130
|
-
yingmi-cli help mcp
|
|
131
|
-
yingmi-cli mcp --help
|
|
145
|
+
yingmi-skill-cli help
|
|
146
|
+
yingmi-skill-cli help mcp
|
|
147
|
+
yingmi-skill-cli mcp --help
|
|
132
148
|
```
|
|
133
149
|
|
|
134
150
|
约束:
|
|
135
151
|
|
|
136
152
|
- `help` 和 `--help` 必须共用同一套命令元数据
|
|
137
|
-
-
|
|
153
|
+
- 根帮助优先回答“该去哪个模块”,模块帮助优先说明推荐顺序,叶子命令帮助优先说明输入规则和常见示例
|
|
154
|
+
- `remote-skill` 默认示例应体现“先读 `SKILL.md`,再执行入口脚本”,不把目录探测命令作为推荐路径
|
|
138
155
|
|
|
139
156
|
### `upgrade`
|
|
140
157
|
|
|
@@ -143,8 +160,8 @@ yingmi-cli mcp --help
|
|
|
143
160
|
常用命令:
|
|
144
161
|
|
|
145
162
|
```bash
|
|
146
|
-
yingmi-cli upgrade
|
|
147
|
-
yingmi-cli upgrade --check-only
|
|
163
|
+
yingmi-skill-cli upgrade
|
|
164
|
+
yingmi-skill-cli upgrade --check-only
|
|
148
165
|
```
|
|
149
166
|
|
|
150
167
|
约束:
|
|
@@ -167,12 +184,11 @@ yingmi-cli upgrade --check-only
|
|
|
167
184
|
|
|
168
185
|
推荐使用方式如下:
|
|
169
186
|
|
|
170
|
-
1. 先执行 `yingmi-cli init setup`,让 CLI 进入可用状态。
|
|
171
|
-
2.
|
|
172
|
-
3.
|
|
173
|
-
4.
|
|
174
|
-
5.
|
|
175
|
-
6. 需要查看帮助或升级时,分别使用 `help` 和 `upgrade`。
|
|
187
|
+
1. 先执行 `yingmi-skill-cli init setup`,让 CLI 进入可用状态。
|
|
188
|
+
2. 如果要直接调用单个原子能力,先用 `yingmi-skill-cli mcp list` 浏览可用工具。
|
|
189
|
+
3. 对于 `mcp`,继续用 `yingmi-skill-cli mcp schema <toolName>` 查看完整定义,再用 `yingmi-skill-cli mcp call <toolName>` 发起调用。
|
|
190
|
+
4. 如果要完成基金分析、组合诊断、财富规划等场景任务,可先用 `yingmi-skill-cli remote-skill scope set --skills <a,b,c>` 收敛默认 skill 范围,再用 `yingmi-skill-cli remote-skill list` 发现 skill,随后执行 `yingmi-skill-cli remote-skill enter <skillName>` 进入上下文,优先执行 `yingmi-skill-cli remote-skill exec --script 'cat SKILL.md'` 阅读说明,再按 skill 约定执行脚本。
|
|
191
|
+
5. 需要查看帮助或升级时,分别使用 `help` 和 `upgrade`。
|
|
176
192
|
|
|
177
193
|
## 当前代码组织
|
|
178
194
|
|
package/bin/index.js
CHANGED
|
@@ -7,12 +7,11 @@ var fs = require('fs');
|
|
|
7
7
|
var os = require('os');
|
|
8
8
|
var path = require('path');
|
|
9
9
|
var axios = require('axios');
|
|
10
|
-
var puppeteer = require('puppeteer');
|
|
11
10
|
var crypto = require('crypto');
|
|
12
11
|
var child_process = require('child_process');
|
|
13
12
|
|
|
14
13
|
var name = "yingmi-skill-cli";
|
|
15
|
-
var version = "0.0.
|
|
14
|
+
var version = "0.0.7";
|
|
16
15
|
|
|
17
16
|
function fail(message) {
|
|
18
17
|
console.error(message);
|
|
@@ -21,30 +20,72 @@ function fail(message) {
|
|
|
21
20
|
|
|
22
21
|
function resolveCommand(root, pathSegments) {
|
|
23
22
|
let current = root;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
const matchedPath = [];
|
|
24
|
+
for (const segment of pathSegments) {
|
|
25
|
+
const nextCommand = current?.commands.find(
|
|
26
|
+
(command) => command.name() === segment
|
|
27
|
+
);
|
|
28
|
+
if (!nextCommand) {
|
|
29
|
+
return {
|
|
30
|
+
command: current ?? root,
|
|
31
|
+
matchedPath,
|
|
32
|
+
invalidSegment: segment
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
current = nextCommand;
|
|
36
|
+
matchedPath.push(segment);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
command: current ?? root,
|
|
40
|
+
matchedPath
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function formatAvailableCommands(command) {
|
|
44
|
+
const availableCommands = command.commands.map((item) => item.name());
|
|
45
|
+
return availableCommands.length > 0 ? availableCommands.join(", ") : "(\u65E0\u53EF\u7528\u5B50\u547D\u4EE4)";
|
|
28
46
|
}
|
|
29
47
|
function registerHelpCommand(program) {
|
|
30
|
-
program.command("help").description("\u663E\u793A CLI \u6216\u6307\u5B9A\u5B50\u547D\u4EE4\u7684\u5E2E\u52A9\u4FE1\u606F").argument("[commandPath...]", "\u547D\u4EE4\u8DEF\u5F84\uFF0C\u4F8B\u5982: mcp call").
|
|
48
|
+
program.command("help").description("\u663E\u793A CLI \u6216\u6307\u5B9A\u5B50\u547D\u4EE4\u7684\u5E2E\u52A9\u4FE1\u606F").argument("[commandPath...]", "\u547D\u4EE4\u8DEF\u5F84\uFF0C\u4F8B\u5982: mcp call").addHelpText(
|
|
49
|
+
"after",
|
|
50
|
+
`
|
|
51
|
+
\u7528\u9014:
|
|
52
|
+
\u67E5\u770B\u6839\u547D\u4EE4\u3001\u6A21\u5757\u547D\u4EE4\u6216\u6307\u5B9A\u5B50\u547D\u4EE4\u7684\u5E2E\u52A9\u4FE1\u606F\u3002
|
|
53
|
+
|
|
54
|
+
\u793A\u4F8B:
|
|
55
|
+
yingmi-skill-cli help
|
|
56
|
+
yingmi-skill-cli help init
|
|
57
|
+
yingmi-skill-cli help mcp
|
|
58
|
+
yingmi-skill-cli help mcp call
|
|
59
|
+
yingmi-skill-cli help remote-skill exec
|
|
60
|
+
|
|
61
|
+
\u8BF4\u660E:
|
|
62
|
+
- help \u548C --help \u5171\u4EAB\u540C\u4E00\u5957\u547D\u4EE4\u5143\u6570\u636E
|
|
63
|
+
- \u4E0D\u786E\u5B9A\u8BE5\u770B\u54EA\u4E2A\u6A21\u5757\u65F6\uFF0C\u5148\u6267\u884C yingmi-skill-cli help
|
|
64
|
+
- \u4E0D\u786E\u5B9A\u8BE5\u7528 mcp \u8FD8\u662F remote-skill \u65F6\uFF0C\u5148\u770B\u5B83\u662F\u5728\u8C03\u7528\u5355\u4E2A\u80FD\u529B\uFF0C\u8FD8\u662F\u5728\u5B8C\u6210\u91D1\u878D\u573A\u666F\u4EFB\u52A1
|
|
65
|
+
- \u5DF2\u77E5\u76EE\u6807\u6A21\u5757\u65F6\uFF0C\u4F18\u5148\u67E5\u770B\u66F4\u5177\u4F53\u7684\u5B50\u547D\u4EE4\u5E2E\u52A9
|
|
66
|
+
`
|
|
67
|
+
).action((commandPath) => {
|
|
31
68
|
if (!commandPath || commandPath.length === 0) {
|
|
32
69
|
program.outputHelp();
|
|
33
70
|
return;
|
|
34
71
|
}
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
37
|
-
|
|
72
|
+
const resolvedCommand = resolveCommand(program, commandPath);
|
|
73
|
+
if (resolvedCommand.invalidSegment) {
|
|
74
|
+
const availableCommands = formatAvailableCommands(resolvedCommand.command);
|
|
75
|
+
const prefix = resolvedCommand.matchedPath.length > 0 ? `\u5DF2\u8BC6\u522B\u524D\u7F00: ${resolvedCommand.matchedPath.join(" ")}` : "\u5DF2\u8BC6\u522B\u524D\u7F00: \u9876\u5C42\u547D\u4EE4";
|
|
76
|
+
fail(`\u672A\u627E\u5230\u547D\u4EE4: ${commandPath.join(" ")}
|
|
77
|
+
${prefix}
|
|
78
|
+
\u53EF\u7528\u5B50\u547D\u4EE4: ${availableCommands}`);
|
|
38
79
|
}
|
|
39
|
-
|
|
80
|
+
resolvedCommand.command.outputHelp();
|
|
40
81
|
});
|
|
41
82
|
}
|
|
42
83
|
|
|
43
|
-
const CONFIG_DIR = path.join(os.homedir(), ".yingmi-cli");
|
|
84
|
+
const CONFIG_DIR = path.join(os.homedir(), ".yingmi-skill-cli");
|
|
44
85
|
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
45
86
|
const SKILLS_DIR = path.join(CONFIG_DIR, "skills");
|
|
46
87
|
const DEFAULT_QIEMAN_BASE_URL = "https://qieman.com";
|
|
47
|
-
const
|
|
88
|
+
const DEFAULT_STARGATE_BASE_URL = "https://stargate-staging.yingmi-inc.com/";
|
|
48
89
|
function ensureConfigDir() {
|
|
49
90
|
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
50
91
|
}
|
|
@@ -59,7 +100,7 @@ function readConfig() {
|
|
|
59
100
|
}
|
|
60
101
|
const parsed = JSON.parse(content);
|
|
61
102
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
62
|
-
throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u975E\u6CD5\uFF0C\u8BF7\u68C0\u67E5 ~/.yingmi-cli/config.json");
|
|
103
|
+
throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u975E\u6CD5\uFF0C\u8BF7\u68C0\u67E5 ~/.yingmi-skill-cli/config.json");
|
|
63
104
|
}
|
|
64
105
|
return parsed;
|
|
65
106
|
}
|
|
@@ -102,6 +143,23 @@ function setCurrentRemoteSkillSession(session) {
|
|
|
102
143
|
};
|
|
103
144
|
writeConfig(nextConfig);
|
|
104
145
|
}
|
|
146
|
+
function getRemoteSkillScope() {
|
|
147
|
+
return readConfig().remoteSkillScope;
|
|
148
|
+
}
|
|
149
|
+
function setRemoteSkillScope(scope) {
|
|
150
|
+
const nextConfig = {
|
|
151
|
+
...readConfig(),
|
|
152
|
+
remoteSkillScope: scope
|
|
153
|
+
};
|
|
154
|
+
writeConfig(nextConfig);
|
|
155
|
+
}
|
|
156
|
+
function clearRemoteSkillScope() {
|
|
157
|
+
const nextConfig = {
|
|
158
|
+
...readConfig()
|
|
159
|
+
};
|
|
160
|
+
delete nextConfig.remoteSkillScope;
|
|
161
|
+
writeConfig(nextConfig);
|
|
162
|
+
}
|
|
105
163
|
function maskSecret(value) {
|
|
106
164
|
if (!value) {
|
|
107
165
|
return "(\u672A\u8BBE\u7F6E)";
|
|
@@ -119,9 +177,9 @@ function getSkillsDirPath() {
|
|
|
119
177
|
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
120
178
|
return SKILLS_DIR;
|
|
121
179
|
}
|
|
122
|
-
function
|
|
123
|
-
const configuredBaseUrl = readConfig().
|
|
124
|
-
return configuredBaseUrl ||
|
|
180
|
+
function getStargateBaseUrl() {
|
|
181
|
+
const configuredBaseUrl = readConfig().stargateBaseUrl?.trim();
|
|
182
|
+
return configuredBaseUrl || DEFAULT_STARGATE_BASE_URL;
|
|
125
183
|
}
|
|
126
184
|
function getQiemanBaseUrl() {
|
|
127
185
|
const configuredBaseUrl = readConfig().qiemanBaseUrl?.trim();
|
|
@@ -206,7 +264,7 @@ function runInitDoctorChecks() {
|
|
|
206
264
|
name: "api-key",
|
|
207
265
|
status: "warning",
|
|
208
266
|
message: "\u5C1A\u672A\u914D\u7F6E apiKey",
|
|
209
|
-
nextStep: "\u6267\u884C yingmi-cli init setup --api-key <your-api-key> \u6216\u9A8C\u8BC1\u7801\u521D\u59CB\u5316\u6D41\u7A0B"
|
|
267
|
+
nextStep: "\u6267\u884C yingmi-skill-cli init setup --api-key <your-api-key> \u6216\u9A8C\u8BC1\u7801\u521D\u59CB\u5316\u6D41\u7A0B"
|
|
210
268
|
}
|
|
211
269
|
);
|
|
212
270
|
if (status.hasPendingSession && status.pendingPhone) {
|
|
@@ -214,7 +272,7 @@ function runInitDoctorChecks() {
|
|
|
214
272
|
name: "pending-session",
|
|
215
273
|
status: "warning",
|
|
216
274
|
message: `\u5B58\u5728\u5F85\u5B8C\u6210\u7684\u9A8C\u8BC1\u7801\u767B\u5F55\u4E0A\u4E0B\u6587: ${status.pendingPhone}`,
|
|
217
|
-
nextStep: "\u6267\u884C yingmi-cli init setup --verify-code <\u9A8C\u8BC1\u7801> \u5B8C\u6210\u521D\u59CB\u5316"
|
|
275
|
+
nextStep: "\u6267\u884C yingmi-skill-cli init setup --verify-code <\u9A8C\u8BC1\u7801> \u5B8C\u6210\u521D\u59CB\u5316"
|
|
218
276
|
});
|
|
219
277
|
} else {
|
|
220
278
|
checks.push({
|
|
@@ -228,7 +286,7 @@ function runInitDoctorChecks() {
|
|
|
228
286
|
name: "config-read",
|
|
229
287
|
status: "warning",
|
|
230
288
|
message: `\u8BFB\u53D6\u914D\u7F6E\u5931\u8D25: ${getErrorMessage(error)}`,
|
|
231
|
-
nextStep: "\u68C0\u67E5 ~/.yingmi-cli/config.json \u683C\u5F0F\uFF0C\u5FC5\u8981\u65F6\u4FEE\u590D\u540E\u91CD\u8BD5"
|
|
289
|
+
nextStep: "\u68C0\u67E5 ~/.yingmi-skill-cli/config.json \u683C\u5F0F\uFF0C\u5FC5\u8981\u65F6\u4FEE\u590D\u540E\u91CD\u8BD5"
|
|
232
290
|
});
|
|
233
291
|
}
|
|
234
292
|
return {
|
|
@@ -246,118 +304,35 @@ function getPendingSetupResult() {
|
|
|
246
304
|
configFile: getConfigFilePath(),
|
|
247
305
|
availableActions: ["--api-key <value>", "--phone <value>", "--verify-code <value>"],
|
|
248
306
|
nextSteps: [
|
|
249
|
-
"yingmi-cli init setup --api-key <your-api-key>",
|
|
250
|
-
"yingmi-cli init setup --phone <your-phone>",
|
|
251
|
-
"yingmi-cli init setup --verify-code <\u9A8C\u8BC1\u7801>"
|
|
307
|
+
"yingmi-skill-cli init setup --api-key <your-api-key>",
|
|
308
|
+
"yingmi-skill-cli init setup --phone <your-phone>",
|
|
309
|
+
"yingmi-skill-cli init setup --verify-code <\u9A8C\u8BC1\u7801>"
|
|
252
310
|
]
|
|
253
311
|
};
|
|
254
312
|
}
|
|
255
313
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
);
|
|
261
|
-
return matchedEntry?.[1];
|
|
262
|
-
}
|
|
263
|
-
function waitForFirstFetchRequest(page, timeoutMs) {
|
|
264
|
-
return new Promise((resolve, reject) => {
|
|
265
|
-
let settled = false;
|
|
266
|
-
const cleanup = () => {
|
|
267
|
-
clearTimeout(timer);
|
|
268
|
-
page.off("request", handleRequest);
|
|
269
|
-
};
|
|
270
|
-
const settle = (callback) => {
|
|
271
|
-
if (settled) {
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
settled = true;
|
|
275
|
-
cleanup();
|
|
276
|
-
callback();
|
|
277
|
-
};
|
|
278
|
-
const handleRequest = (request) => {
|
|
279
|
-
if (request.resourceType() !== "fetch") {
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
settle(() => resolve(request));
|
|
283
|
-
};
|
|
284
|
-
const timer = setTimeout(() => {
|
|
285
|
-
settle(() => reject(new Error(`\u5728 ${timeoutMs}ms \u5185\u672A\u6355\u83B7\u5230 fetch \u8BF7\u6C42`)));
|
|
286
|
-
}, timeoutMs);
|
|
287
|
-
page.on("request", handleRequest);
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function getCandidateExecutablePaths() {
|
|
292
|
-
const homeDirectory = os.homedir();
|
|
293
|
-
switch (process.platform) {
|
|
294
|
-
case "darwin":
|
|
295
|
-
return [
|
|
296
|
-
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
297
|
-
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
298
|
-
"/Applications/Chromium.app/Contents/MacOS/Chromium"
|
|
299
|
-
];
|
|
300
|
-
case "win32":
|
|
301
|
-
return [
|
|
302
|
-
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
303
|
-
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
304
|
-
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
305
|
-
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe"
|
|
306
|
-
];
|
|
307
|
-
default:
|
|
308
|
-
return [
|
|
309
|
-
"/usr/bin/google-chrome",
|
|
310
|
-
"/usr/bin/google-chrome-stable",
|
|
311
|
-
"/usr/bin/chromium",
|
|
312
|
-
"/usr/bin/chromium-browser",
|
|
313
|
-
`${homeDirectory}/.cache/puppeteer/chrome/linux-*/chrome-linux64/chrome`
|
|
314
|
-
];
|
|
315
|
-
}
|
|
314
|
+
const DEFAULT_TIMEOUT_MS = 2e4;
|
|
315
|
+
const SKILL_ACCESS_CONFIG_PATH = "/api/skill-access-config";
|
|
316
|
+
function trimTrailingSlash$1(value) {
|
|
317
|
+
return value.replace(/\/+$/, "");
|
|
316
318
|
}
|
|
317
|
-
function
|
|
318
|
-
|
|
319
|
-
if (customExecutablePath) {
|
|
320
|
-
if (!fs.existsSync(customExecutablePath)) {
|
|
321
|
-
throw new Error(`\u6D4F\u89C8\u5668\u4E0D\u5B58\u5728: ${customExecutablePath}`);
|
|
322
|
-
}
|
|
323
|
-
return customExecutablePath;
|
|
324
|
-
}
|
|
325
|
-
const matchedPath = getCandidateExecutablePaths().find(
|
|
326
|
-
(candidatePath) => fs.existsSync(candidatePath)
|
|
327
|
-
);
|
|
328
|
-
if (!matchedPath) {
|
|
329
|
-
throw new Error(
|
|
330
|
-
"\u672A\u627E\u5230\u53EF\u7528\u7684 Chrome/Chromium\uFF0C\u53EF\u901A\u8FC7 --executable-path \u6216 PUPPETEER_EXECUTABLE_PATH \u6307\u5B9A\u6D4F\u89C8\u5668\u8DEF\u5F84"
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
return matchedPath;
|
|
319
|
+
function buildSkillAccessConfigUrl(baseUrl) {
|
|
320
|
+
return `${trimTrailingSlash$1(baseUrl)}${SKILL_ACCESS_CONFIG_PATH}`;
|
|
334
321
|
}
|
|
335
|
-
|
|
336
|
-
const DEFAULT_TIMEOUT_MS = 2e4;
|
|
337
322
|
async function getXSign(options = {}) {
|
|
338
323
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
324
|
+
const url = options.url?.trim() || buildSkillAccessConfigUrl(getStargateBaseUrl());
|
|
325
|
+
const response = await axios.get(url, {
|
|
326
|
+
headers: {
|
|
327
|
+
accept: "application/json"
|
|
328
|
+
},
|
|
329
|
+
timeout: timeoutMs
|
|
343
330
|
});
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const url = options.url ?? getQiemanBaseUrl();
|
|
348
|
-
await page.goto(url, {
|
|
349
|
-
waitUntil: "domcontentloaded",
|
|
350
|
-
timeout: timeoutMs
|
|
351
|
-
});
|
|
352
|
-
const firstFetchRequest = await firstFetchRequestPromise;
|
|
353
|
-
const xSign = getHeaderValue(firstFetchRequest.headers(), "x-sign")?.trim();
|
|
354
|
-
if (!xSign) {
|
|
355
|
-
throw new Error(`\u9996\u4E2A fetch \u8BF7\u6C42\u672A\u643A\u5E26 x-sign: ${firstFetchRequest.url()}`);
|
|
356
|
-
}
|
|
357
|
-
return xSign;
|
|
358
|
-
} finally {
|
|
359
|
-
await browser.close();
|
|
331
|
+
const xSign = response.data.sign?.trim();
|
|
332
|
+
if (!xSign) {
|
|
333
|
+
throw new Error(`\u83B7\u53D6 x-sign \u5931\u8D25\uFF0C\u54CD\u5E94\u4E2D\u7F3A\u5C11 sign: ${url}`);
|
|
360
334
|
}
|
|
335
|
+
return xSign;
|
|
361
336
|
}
|
|
362
337
|
|
|
363
338
|
function trimTrailingSlash(value) {
|
|
@@ -381,7 +356,7 @@ const API_KEY_APPLICATION_PAYLOAD = {
|
|
|
381
356
|
function createRequestId() {
|
|
382
357
|
const hexTimestamp = Date.now().toString(16).toUpperCase();
|
|
383
358
|
const randomSuffix = crypto.randomBytes(8).toString("hex").toUpperCase();
|
|
384
|
-
return `yingmi-cli.${hexTimestamp}${randomSuffix}`;
|
|
359
|
+
return `yingmi-skill-cli.${hexTimestamp}${randomSuffix}`;
|
|
385
360
|
}
|
|
386
361
|
function getHeaders(xSign, accessToken) {
|
|
387
362
|
return {
|
|
@@ -421,7 +396,7 @@ async function prepareSmsSetup(phone) {
|
|
|
421
396
|
configFile: getConfigFilePath(),
|
|
422
397
|
pendingPhone: maskPhone(phone),
|
|
423
398
|
cooldownSeconds: response.data.nextInSec ?? null,
|
|
424
|
-
nextStep: "yingmi-cli init setup --verify-code <\u9A8C\u8BC1\u7801>"
|
|
399
|
+
nextStep: "yingmi-skill-cli init setup --verify-code <\u9A8C\u8BC1\u7801>"
|
|
425
400
|
};
|
|
426
401
|
}
|
|
427
402
|
|
|
@@ -451,10 +426,14 @@ async function confirmSmsSetup(verifyCode) {
|
|
|
451
426
|
validateVerifyCode(verifyCode);
|
|
452
427
|
const session = getApiKeyApplySession();
|
|
453
428
|
if (!session) {
|
|
454
|
-
throw new Error(
|
|
429
|
+
throw new Error(
|
|
430
|
+
"\u672A\u627E\u5230\u9A8C\u8BC1\u7801\u767B\u5F55\u4E0A\u4E0B\u6587\uFF0C\u8BF7\u5148\u6267\u884C: yingmi-skill-cli init setup --phone <\u624B\u673A\u53F7>"
|
|
431
|
+
);
|
|
455
432
|
}
|
|
456
433
|
if (!session.accessToken && !session.prepareToken) {
|
|
457
|
-
throw new Error(
|
|
434
|
+
throw new Error(
|
|
435
|
+
"\u7533\u8BF7\u4E0A\u4E0B\u6587\u7F3A\u5C11\u767B\u5F55 token\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C: yingmi-skill-cli init setup --phone <\u624B\u673A\u53F7>"
|
|
436
|
+
);
|
|
458
437
|
}
|
|
459
438
|
try {
|
|
460
439
|
const qiemanPmdjBaseUrl = getQiemanPmdjBaseUrl();
|
|
@@ -525,7 +504,7 @@ async function confirmSmsSetup(verifyCode) {
|
|
|
525
504
|
await refreshSessionXSignOnInvalidVerifyCode(session);
|
|
526
505
|
} catch (refreshError) {
|
|
527
506
|
throw new Error(
|
|
528
|
-
`\u9A8C\u8BC1\u7801\u6821\u9A8C\u5931\u8D25\uFF0C\u5237\u65B0 x-sign \u4E5F\u5931\u8D25\u4E86: ${getErrorMessage(refreshError)}\u3002\u8BF7\u91CD\u65B0\u6267\u884C: yingmi-cli init setup --phone <\u624B\u673A\u53F7>`
|
|
507
|
+
`\u9A8C\u8BC1\u7801\u6821\u9A8C\u5931\u8D25\uFF0C\u5237\u65B0 x-sign \u4E5F\u5931\u8D25\u4E86: ${getErrorMessage(refreshError)}\u3002\u8BF7\u91CD\u65B0\u6267\u884C: yingmi-skill-cli init setup --phone <\u624B\u673A\u53F7>`
|
|
529
508
|
);
|
|
530
509
|
}
|
|
531
510
|
}
|
|
@@ -537,14 +516,14 @@ function countSetupModes(options) {
|
|
|
537
516
|
return [options.apiKey, options.phone, options.verifyCode].filter(Boolean).length;
|
|
538
517
|
}
|
|
539
518
|
function persistHiddenConfigOptions(options) {
|
|
540
|
-
const
|
|
519
|
+
const stargateBaseUrl = options.stargateBaseUrl?.trim();
|
|
541
520
|
const qiemanBaseUrl = options.qiemanBaseUrl?.trim();
|
|
542
|
-
if (!
|
|
521
|
+
if (!stargateBaseUrl && !qiemanBaseUrl) {
|
|
543
522
|
return;
|
|
544
523
|
}
|
|
545
524
|
writeConfig({
|
|
546
525
|
...readConfig(),
|
|
547
|
-
...
|
|
526
|
+
...stargateBaseUrl ? { stargateBaseUrl } : {},
|
|
548
527
|
...qiemanBaseUrl ? { qiemanBaseUrl } : {}
|
|
549
528
|
});
|
|
550
529
|
}
|
|
@@ -552,14 +531,16 @@ async function runInitSetup(options) {
|
|
|
552
531
|
const apiKey = options.apiKey?.trim();
|
|
553
532
|
const phone = options.phone?.trim();
|
|
554
533
|
const qiemanBaseUrl = options.qiemanBaseUrl?.trim();
|
|
555
|
-
const remoteSkillServerBaseUrl = options.
|
|
534
|
+
const remoteSkillServerBaseUrl = options.stargateBaseUrl?.trim();
|
|
556
535
|
const verifyCode = options.verifyCode?.trim();
|
|
557
536
|
persistHiddenConfigOptions({
|
|
558
|
-
remoteSkillServerBaseUrl,
|
|
537
|
+
stargateBaseUrl: remoteSkillServerBaseUrl,
|
|
559
538
|
qiemanBaseUrl
|
|
560
539
|
});
|
|
561
540
|
if (countSetupModes({ apiKey, phone, verifyCode }) > 1) {
|
|
562
|
-
throw new Error(
|
|
541
|
+
throw new Error(
|
|
542
|
+
"`--api-key`\u3001`--phone`\u3001`--verify-code` \u4E00\u6B21\u53EA\u80FD\u4F7F\u7528\u4E00\u79CD\uFF0C\u8BF7\u6309\u521D\u59CB\u5316\u9636\u6BB5\u5206\u522B\u6267\u884C"
|
|
543
|
+
);
|
|
563
544
|
}
|
|
564
545
|
if (apiKey) {
|
|
565
546
|
return setupWithApiKey(apiKey);
|
|
@@ -574,15 +555,40 @@ async function runInitSetup(options) {
|
|
|
574
555
|
}
|
|
575
556
|
|
|
576
557
|
function registerDoctorCommand(initCommand) {
|
|
577
|
-
initCommand.command("doctor").description("\u68C0\u67E5\u672C\u5730\u914D\u7F6E\u4E0E\u8FD0\u884C\u73AF\u5883").
|
|
558
|
+
initCommand.command("doctor").description("\u68C0\u67E5\u672C\u5730\u914D\u7F6E\u4E0E\u8FD0\u884C\u73AF\u5883").addHelpText(
|
|
559
|
+
"after",
|
|
560
|
+
`
|
|
561
|
+
\u7528\u9014:
|
|
562
|
+
\u8BCA\u65AD\u672C\u5730\u914D\u7F6E\u3001\u8FD0\u884C\u73AF\u5883\u548C\u521D\u59CB\u5316\u72B6\u6001\uFF0C\u5E2E\u52A9\u5B9A\u4F4D\u4E0D\u53EF\u7528\u539F\u56E0\u3002
|
|
563
|
+
|
|
564
|
+
\u793A\u4F8B:
|
|
565
|
+
yingmi-skill-cli init doctor
|
|
566
|
+
|
|
567
|
+
\u8BF4\u660E:
|
|
568
|
+
- \u9002\u5408\u5728 init status \u8F93\u51FA\u5F02\u5E38\u65F6\u4F7F\u7528
|
|
569
|
+
- \u9519\u8BEF\u4FE1\u606F\u5E94\u540C\u65F6\u8BF4\u660E\u539F\u56E0\u548C\u4E0B\u4E00\u6B65\u4FEE\u590D\u5EFA\u8BAE
|
|
570
|
+
`
|
|
571
|
+
).action(() => {
|
|
578
572
|
console.log(JSON.stringify(runInitDoctorChecks(), null, 2));
|
|
579
573
|
});
|
|
580
574
|
}
|
|
581
575
|
|
|
582
576
|
function registerSetupCommand(initCommand) {
|
|
583
|
-
initCommand.command("setup").description("\u6267\u884C\u9996\u6B21\u521D\u59CB\u5316\uFF0C\u652F\u6301\u76F4\u63A5\u5199\u5165 API Key \u6216\u9A8C\u8BC1\u7801\u7533\u8BF7 API Key").option("--api-key <value>", "\u76F4\u63A5\u5199\u5165 StarGate API Key").option("--phone <value>", "\u901A\u8FC7\u624B\u673A\u53F7\u53D1\u8D77\u9A8C\u8BC1\u7801\u521D\u59CB\u5316").option("--verify-code <value>", "\u786E\u8BA4\u77ED\u4FE1\u9A8C\u8BC1\u7801\u5E76\u5B8C\u6210 API Key \u521D\u59CB\u5316").addOption(
|
|
584
|
-
|
|
585
|
-
|
|
577
|
+
initCommand.command("setup").description("\u6267\u884C\u9996\u6B21\u521D\u59CB\u5316\uFF0C\u652F\u6301\u76F4\u63A5\u5199\u5165 API Key \u6216\u9A8C\u8BC1\u7801\u7533\u8BF7 API Key").option("--api-key <value>", "\u76F4\u63A5\u5199\u5165 StarGate API Key").option("--phone <value>", "\u901A\u8FC7\u624B\u673A\u53F7\u53D1\u8D77\u9A8C\u8BC1\u7801\u521D\u59CB\u5316").option("--verify-code <value>", "\u786E\u8BA4\u77ED\u4FE1\u9A8C\u8BC1\u7801\u5E76\u5B8C\u6210 API Key \u521D\u59CB\u5316").addOption(new commander.Option("--stargate-base-url <value>", "\u8986\u76D6 Stargate \u670D\u52A1\u57FA\u5730\u5740").hideHelp()).addOption(new commander.Option("--qieman-base-url <value>", "\u8986\u76D6\u4E14\u6162\u670D\u52A1\u57FA\u5730\u5740").hideHelp()).addHelpText(
|
|
578
|
+
"after",
|
|
579
|
+
`
|
|
580
|
+
\u8F93\u5165\u89C4\u5219:
|
|
581
|
+
1. --api-key\u3001--phone\u3001--verify-code \u4E09\u79CD\u6A21\u5F0F\u4E92\u65A5
|
|
582
|
+
2. \u4E0D\u5E26\u53C2\u6570\u6267\u884C\u65F6\uFF0C\u8FD4\u56DE\u4E0B\u4E00\u6B65\u521D\u59CB\u5316\u5F15\u5BFC
|
|
583
|
+
3. \u5EFA\u8BAE\u4F18\u5148\u4F7F\u7528\u957F\u53C2\u6570\u540D\uFF0C\u4FBF\u4E8E\u811A\u672C\u548C Agent \u8C03\u7528
|
|
584
|
+
|
|
585
|
+
\u793A\u4F8B:
|
|
586
|
+
yingmi-skill-cli init setup
|
|
587
|
+
yingmi-skill-cli init setup --api-key <value>
|
|
588
|
+
yingmi-skill-cli init setup --phone <\u624B\u673A\u53F7>
|
|
589
|
+
yingmi-skill-cli init setup --verify-code <\u9A8C\u8BC1\u7801>
|
|
590
|
+
`
|
|
591
|
+
).action(async (options) => {
|
|
586
592
|
try {
|
|
587
593
|
const result = await runInitSetup(options);
|
|
588
594
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -593,13 +599,43 @@ function registerSetupCommand(initCommand) {
|
|
|
593
599
|
}
|
|
594
600
|
|
|
595
601
|
function registerStatusCommand(initCommand) {
|
|
596
|
-
initCommand.command("status").description("\u67E5\u770B\u521D\u59CB\u5316\u72B6\u6001\u548C\u914D\u7F6E\u6458\u8981").
|
|
602
|
+
initCommand.command("status").description("\u67E5\u770B\u521D\u59CB\u5316\u72B6\u6001\u548C\u914D\u7F6E\u6458\u8981").addHelpText(
|
|
603
|
+
"after",
|
|
604
|
+
`
|
|
605
|
+
\u7528\u9014:
|
|
606
|
+
\u8F93\u51FA\u5F53\u524D\u521D\u59CB\u5316\u72B6\u6001\u6458\u8981\uFF0C\u4FBF\u4E8E\u786E\u8BA4 CLI \u662F\u5426\u5DF2\u53EF\u7528\u3002
|
|
607
|
+
|
|
608
|
+
\u793A\u4F8B:
|
|
609
|
+
yingmi-skill-cli init status
|
|
610
|
+
|
|
611
|
+
\u4E0B\u4E00\u6B65:
|
|
612
|
+
1. \u5982\u679C\u5C1A\u672A\u5B8C\u6210\u521D\u59CB\u5316\uFF0C\u6267\u884C yingmi-skill-cli init setup
|
|
613
|
+
2. \u5982\u679C\u72B6\u6001\u5F02\u5E38\uFF0C\u6267\u884C yingmi-skill-cli init doctor
|
|
614
|
+
`
|
|
615
|
+
).action(() => {
|
|
597
616
|
console.log(JSON.stringify(getInitStatusSummary(), null, 2));
|
|
598
617
|
});
|
|
599
618
|
}
|
|
600
619
|
|
|
601
620
|
function registerInitCommand(program) {
|
|
602
|
-
const initCommand = program.command("init").description("\u521D\u59CB\u5316 CLI \u5E76\u67E5\u770B\u5F53\u524D\u72B6\u6001")
|
|
621
|
+
const initCommand = program.command("init").description("\u521D\u59CB\u5316 CLI \u5E76\u67E5\u770B\u5F53\u524D\u72B6\u6001").addHelpText(
|
|
622
|
+
"after",
|
|
623
|
+
`
|
|
624
|
+
\u7528\u9014:
|
|
625
|
+
\u8BA9 CLI \u8FDB\u5165\u53EF\u7528\u72B6\u6001\uFF0C\u5E76\u68C0\u67E5\u5F53\u524D\u672C\u5730\u914D\u7F6E\u548C\u8FD0\u884C\u73AF\u5883\u3002
|
|
626
|
+
|
|
627
|
+
\u63A8\u8350\u987A\u5E8F:
|
|
628
|
+
1. yingmi-skill-cli init setup
|
|
629
|
+
2. yingmi-skill-cli init status
|
|
630
|
+
3. \u9047\u5230\u95EE\u9898\u65F6\u6267\u884C yingmi-skill-cli init doctor
|
|
631
|
+
|
|
632
|
+
\u8BF4\u660E:
|
|
633
|
+
- setup \u7528\u4E8E\u9996\u6B21\u521D\u59CB\u5316\u6216\u8865\u5168 API Key
|
|
634
|
+
- status \u7528\u4E8E\u67E5\u770B\u5F53\u524D\u72B6\u6001\u6458\u8981
|
|
635
|
+
- doctor \u7528\u4E8E\u6392\u67E5\u914D\u7F6E\u6216\u73AF\u5883\u95EE\u9898
|
|
636
|
+
- \u521D\u59CB\u5316\u5B8C\u6210\u540E\uFF0C\u8C03\u7528\u5355\u4E2A\u80FD\u529B\u4F18\u5148\u4F7F\u7528 mcp\uFF0C\u5B8C\u6210\u91D1\u878D\u573A\u666F\u4EFB\u52A1\u4F18\u5148\u4F7F\u7528 remote-skill
|
|
637
|
+
`
|
|
638
|
+
);
|
|
603
639
|
registerSetupCommand(initCommand);
|
|
604
640
|
registerStatusCommand(initCommand);
|
|
605
641
|
registerDoctorCommand(initCommand);
|
|
@@ -638,7 +674,7 @@ function requireApiKey() {
|
|
|
638
674
|
const { apiKey } = readConfig();
|
|
639
675
|
if (!apiKey) {
|
|
640
676
|
fail(
|
|
641
|
-
"\u672A\
|
|
677
|
+
"\u672A\u5B8C\u6210\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u6267\u884C: yingmi-skill-cli init setup --phone <\u624B\u673A\u53F7> \u5B8C\u6210\u624B\u673A\u53F7\u9A8C\u8BC1\u7801\u521D\u59CB\u5316"
|
|
642
678
|
);
|
|
643
679
|
}
|
|
644
680
|
return apiKey;
|
|
@@ -821,6 +857,7 @@ function validateParameters(parameters, values, locationLabel) {
|
|
|
821
857
|
|
|
822
858
|
const DOCS_URL = "https://stargate.yingmi.com/api/docs.json";
|
|
823
859
|
const HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options"];
|
|
860
|
+
const HIDDEN_OPERATION_NAMES = /* @__PURE__ */ new Set(["getSkillByName"]);
|
|
824
861
|
async function fetchOpenApiDocument(apiKey) {
|
|
825
862
|
const response = await axios.get(DOCS_URL, {
|
|
826
863
|
params: {
|
|
@@ -856,6 +893,9 @@ function listOperations(document) {
|
|
|
856
893
|
});
|
|
857
894
|
return operations.sort((left, right) => left.name.localeCompare(right.name));
|
|
858
895
|
}
|
|
896
|
+
function listVisibleOperations(document) {
|
|
897
|
+
return listOperations(document).filter((operation) => !HIDDEN_OPERATION_NAMES.has(operation.name));
|
|
898
|
+
}
|
|
859
899
|
function getOperationByName(document, toolName) {
|
|
860
900
|
return listOperations(document).find((operation) => operation.name === toolName);
|
|
861
901
|
}
|
|
@@ -881,7 +921,21 @@ function getPrimaryRequestContentType(operation) {
|
|
|
881
921
|
}
|
|
882
922
|
|
|
883
923
|
function registerCallCommand(mcpCommand) {
|
|
884
|
-
mcpCommand.command("call").description("\u8C03\u7528\u6307\u5B9A MCP \u5DE5\u5177").argument("<toolName>", "\u5DE5\u5177\u540D").option("--input <json>", "\u76F4\u63A5\u4F20\u5165 JSON \u5B57\u7B26\u4E32").option("--input-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 JSON \u8F93\u5165").
|
|
924
|
+
mcpCommand.command("call").description("\u8C03\u7528\u6307\u5B9A MCP \u5DE5\u5177").argument("<toolName>", "\u5DE5\u5177\u540D").option("--input <json>", "\u76F4\u63A5\u4F20\u5165 JSON \u5B57\u7B26\u4E32").option("--input-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6 JSON \u8F93\u5165").addHelpText(
|
|
925
|
+
"after",
|
|
926
|
+
`
|
|
927
|
+
\u8F93\u5165\u89C4\u5219:
|
|
928
|
+
1. \u5148\u6267\u884C yingmi-skill-cli mcp schema <toolName> \u786E\u8BA4\u5B57\u6BB5\u540D\u548C requestBody
|
|
929
|
+
2. path/query/header \u53C2\u6570\u53EF\u76F4\u63A5\u653E\u5728 JSON \u9876\u5C42\uFF0C\u4E5F\u53EF\u5206\u522B\u653E\u8FDB path/query/header
|
|
930
|
+
3. body \u53EF\u663E\u5F0F\u653E\u5728 body \u5B57\u6BB5\uFF1B\u5982\u679C\u5DE5\u5177\u53EA\u6709 requestBody \u4E14\u6CA1\u6709\u5176\u5B83\u53C2\u6570\uFF0C\u4E5F\u53EF\u76F4\u63A5\u4F20 body \u5BF9\u8C61
|
|
931
|
+
4. mcp call \u9002\u5408\u5355\u6B21\u539F\u5B50\u80FD\u529B\u8C03\u7528\uFF0C\u4E0D\u9002\u5408\u76F4\u63A5\u627F\u8F7D\u5B8C\u6574\u91D1\u878D\u573A\u666F\u5DE5\u4F5C\u6D41
|
|
932
|
+
|
|
933
|
+
\u793A\u4F8B:
|
|
934
|
+
yingmi-skill-cli mcp call GetCurrentTime
|
|
935
|
+
yingmi-skill-cli mcp call GuessFundCode --input '{"fundNameOrCode":"\u6613\u65B9\u8FBE\u84DD\u7B79\u7CBE\u9009"}'
|
|
936
|
+
yingmi-skill-cli mcp call <toolName> --input '{"query":{"pageNum":1},"body":{"keyword":"\u65B0\u80FD\u6E90"}}'
|
|
937
|
+
`
|
|
938
|
+
).action(async (toolName, options) => {
|
|
885
939
|
const apiKey = requireApiKey();
|
|
886
940
|
const document = await fetchOpenApiDocument(apiKey);
|
|
887
941
|
const operation = getOperationByName(document, toolName);
|
|
@@ -933,10 +987,21 @@ function registerCallCommand(mcpCommand) {
|
|
|
933
987
|
}
|
|
934
988
|
|
|
935
989
|
function registerListCommand(mcpCommand) {
|
|
936
|
-
mcpCommand.command("list").description("\u5217\u51FA\u6240\u6709 MCP \u5DE5\u5177\u6458\u8981").
|
|
990
|
+
mcpCommand.command("list").description("\u5217\u51FA\u6240\u6709 MCP \u5DE5\u5177\u6458\u8981").addHelpText(
|
|
991
|
+
"after",
|
|
992
|
+
`
|
|
993
|
+
\u7528\u9014:
|
|
994
|
+
\u6D4F\u89C8\u53EF\u76F4\u63A5\u8C03\u7528\u7684\u539F\u5B50\u80FD\u529B\u5217\u8868\uFF0C\u5224\u65AD\u662F\u5426\u5DF2\u7ECF\u5B58\u5728\u5408\u9002\u7684 tool\u3002
|
|
995
|
+
|
|
996
|
+
\u4E0B\u4E00\u6B65:
|
|
997
|
+
1. \u4ECE\u8F93\u51FA\u91CC\u6311\u4E00\u4E2A toolName
|
|
998
|
+
2. \u6267\u884C yingmi-skill-cli mcp schema <toolName> \u67E5\u770B\u53C2\u6570\u548C\u54CD\u5E94\u7ED3\u6784
|
|
999
|
+
3. \u5982\u679C\u76EE\u6807\u5176\u5B9E\u662F\u57FA\u91D1\u5206\u6790\u3001\u7EC4\u5408\u8BCA\u65AD\u6216\u8D22\u5BCC\u89C4\u5212\u7B49\u5B8C\u6574\u573A\u666F\uFF0C\u6539\u770B yingmi-skill-cli remote-skill list
|
|
1000
|
+
`
|
|
1001
|
+
).action(async () => {
|
|
937
1002
|
const apiKey = requireApiKey();
|
|
938
1003
|
const document = await fetchOpenApiDocument(apiKey);
|
|
939
|
-
const operations =
|
|
1004
|
+
const operations = listVisibleOperations(document);
|
|
940
1005
|
console.log(
|
|
941
1006
|
JSON.stringify(
|
|
942
1007
|
operations.map((operation) => ({
|
|
@@ -954,7 +1019,20 @@ function registerListCommand(mcpCommand) {
|
|
|
954
1019
|
}
|
|
955
1020
|
|
|
956
1021
|
function registerSchemaCommand(mcpCommand) {
|
|
957
|
-
mcpCommand.command("schema").description("\u67E5\u770B\u67D0\u4E2A MCP \u5DE5\u5177\u7684\u5B8C\u6574 Schema").argument("<toolName>", "\u5DE5\u5177\u540D").
|
|
1022
|
+
mcpCommand.command("schema").description("\u67E5\u770B\u67D0\u4E2A MCP \u5DE5\u5177\u7684\u5B8C\u6574 Schema").argument("<toolName>", "\u5DE5\u5177\u540D").addHelpText(
|
|
1023
|
+
"after",
|
|
1024
|
+
`
|
|
1025
|
+
\u5EFA\u8BAE:
|
|
1026
|
+
0. schema \u9002\u5408\u5728\u4F60\u5DF2\u7ECF\u786E\u5B9A\u8981\u8C03\u7528\u67D0\u4E2A\u539F\u5B50\u80FD\u529B\u65F6\u4F7F\u7528
|
|
1027
|
+
1. \u5148\u770B parameters\uFF0C\u786E\u8BA4 path/query/header \u7684\u5B57\u6BB5\u540D
|
|
1028
|
+
2. \u518D\u770B requestBody\uFF0C\u786E\u8BA4 body \u662F\u5426\u5FC5\u586B
|
|
1029
|
+
3. \u6700\u540E\u6267\u884C yingmi-skill-cli mcp call <toolName> --input '<json>'
|
|
1030
|
+
|
|
1031
|
+
\u793A\u4F8B:
|
|
1032
|
+
yingmi-skill-cli mcp schema GetCurrentTime
|
|
1033
|
+
yingmi-skill-cli mcp schema GuessFundCode
|
|
1034
|
+
`
|
|
1035
|
+
).action(async (toolName) => {
|
|
958
1036
|
const apiKey = requireApiKey();
|
|
959
1037
|
const document = await fetchOpenApiDocument(apiKey);
|
|
960
1038
|
const operation = getOperationByName(document, toolName);
|
|
@@ -981,7 +1059,28 @@ function registerSchemaCommand(mcpCommand) {
|
|
|
981
1059
|
}
|
|
982
1060
|
|
|
983
1061
|
function registerMcpCommand(program) {
|
|
984
|
-
const mcpCommand = program.command("mcp").description("\u6D4F\u89C8
|
|
1062
|
+
const mcpCommand = program.command("mcp").description("\u6D4F\u89C8\u539F\u5B50\u80FD\u529B\u6458\u8981\u3001\u67E5\u770B Schema \u5E76\u76F4\u63A5\u8C03\u7528\u5DE5\u5177").addHelpText(
|
|
1063
|
+
"after",
|
|
1064
|
+
`
|
|
1065
|
+
\u7528\u9014:
|
|
1066
|
+
\u6D4F\u89C8 MCP \u5DE5\u5177\u6458\u8981\uFF0C\u67E5\u770B\u5DE5\u5177 schema\uFF0C\u5E76\u53D1\u8D77\u5355\u6B21\u539F\u5B50\u80FD\u529B\u8C03\u7528\u3002
|
|
1067
|
+
|
|
1068
|
+
\u63A8\u8350\u987A\u5E8F:
|
|
1069
|
+
1. yingmi-skill-cli mcp list
|
|
1070
|
+
2. yingmi-skill-cli mcp schema <toolName>
|
|
1071
|
+
3. yingmi-skill-cli mcp call <toolName> --input '<json>'
|
|
1072
|
+
|
|
1073
|
+
\u8BF4\u660E:
|
|
1074
|
+
- mcp \u9002\u5408\u5DF2\u77E5\u8981\u8C03\u7528\u54EA\u4E2A\u80FD\u529B\u3001\u5E76\u4E14\u80FD\u660E\u786E\u6784\u9020 JSON \u8F93\u5165\u7684\u573A\u666F
|
|
1075
|
+
- schema \u7528\u4E8E\u786E\u8BA4\u5B57\u6BB5\u540D\u3001\u53C2\u6570\u4F4D\u7F6E\u548C requestBody
|
|
1076
|
+
- call \u7684\u8F93\u5165\u662F JSON \u534F\u8BAE\uFF0C\u4E0D\u662F\u81EA\u7136\u8BED\u8A00 prompt
|
|
1077
|
+
- \u5982\u679C\u76EE\u6807\u662F\u5B8C\u6210\u57FA\u91D1\u5206\u6790\u3001\u7EC4\u5408\u8BCA\u65AD\u6216\u8D22\u5BCC\u89C4\u5212\u7B49\u573A\u666F\u4EFB\u52A1\uFF0C\u4F18\u5148\u67E5\u770B remote-skill
|
|
1078
|
+
|
|
1079
|
+
\u6700\u5C0F\u6210\u529F\u793A\u4F8B:
|
|
1080
|
+
yingmi-skill-cli mcp schema GetCurrentTime
|
|
1081
|
+
yingmi-skill-cli mcp call GetCurrentTime
|
|
1082
|
+
`
|
|
1083
|
+
);
|
|
985
1084
|
registerListCommand(mcpCommand);
|
|
986
1085
|
registerSchemaCommand(mcpCommand);
|
|
987
1086
|
registerCallCommand(mcpCommand);
|
|
@@ -1083,7 +1182,7 @@ function validateRemoteSkillName(skillName) {
|
|
|
1083
1182
|
return normalizedName;
|
|
1084
1183
|
}
|
|
1085
1184
|
async function fetchRemoteSkillSummaries(apiKey) {
|
|
1086
|
-
const serverBaseUrl = normalizeServerBaseUrl(
|
|
1185
|
+
const serverBaseUrl = normalizeServerBaseUrl(getStargateBaseUrl());
|
|
1087
1186
|
const response = await axios.get(`${serverBaseUrl}/api/get-skills`, {
|
|
1088
1187
|
headers: buildRequestHeaders(apiKey),
|
|
1089
1188
|
timeout: REQUEST_TIMEOUT
|
|
@@ -1092,7 +1191,7 @@ async function fetchRemoteSkillSummaries(apiKey) {
|
|
|
1092
1191
|
}
|
|
1093
1192
|
async function prepareRemoteSkillContext(skillName, apiKey) {
|
|
1094
1193
|
const normalizedSkillName = validateRemoteSkillName(skillName);
|
|
1095
|
-
const serverBaseUrl = normalizeServerBaseUrl(
|
|
1194
|
+
const serverBaseUrl = normalizeServerBaseUrl(getStargateBaseUrl());
|
|
1096
1195
|
const detailResponse = await axios.get(
|
|
1097
1196
|
`${serverBaseUrl}/api/get-skill-by-name`,
|
|
1098
1197
|
{
|
|
@@ -1128,6 +1227,29 @@ async function prepareRemoteSkillContext(skillName, apiKey) {
|
|
|
1128
1227
|
};
|
|
1129
1228
|
}
|
|
1130
1229
|
|
|
1230
|
+
function parseRemoteSkillScopeInput(input) {
|
|
1231
|
+
const normalizedSkills = (input ?? "").split(",").map((skillName) => skillName.trim()).filter(Boolean);
|
|
1232
|
+
const deduplicatedSkills = Array.from(new Set(normalizedSkills));
|
|
1233
|
+
deduplicatedSkills.forEach((skillName) => {
|
|
1234
|
+
validateRemoteSkillName(skillName);
|
|
1235
|
+
});
|
|
1236
|
+
if (deduplicatedSkills.length === 0) {
|
|
1237
|
+
throw new Error(
|
|
1238
|
+
"--skills \u53C2\u6570\u975E\u6CD5\uFF0C\u8BF7\u63D0\u4F9B\u9017\u53F7\u5206\u9694\u7684 skill \u540D\u79F0\uFF0C\u4F8B\u5982 --skills fund-analyzer,market-brief"
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
return deduplicatedSkills;
|
|
1242
|
+
}
|
|
1243
|
+
function applyRemoteSkillScope(remoteSkills, configuredScope) {
|
|
1244
|
+
const scopeSkills = configuredScope?.skills ?? [];
|
|
1245
|
+
if (scopeSkills.length === 0) {
|
|
1246
|
+
return remoteSkills;
|
|
1247
|
+
}
|
|
1248
|
+
const visibleSkillNames = new Set(scopeSkills);
|
|
1249
|
+
const filteredSkills = remoteSkills.filter((skill) => visibleSkillNames.has(skill.name));
|
|
1250
|
+
return filteredSkills.length > 0 ? filteredSkills : remoteSkills;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1131
1253
|
function formatWorkingDirectoryTree(rootDir) {
|
|
1132
1254
|
const lines = ["."];
|
|
1133
1255
|
const walk = (currentDir, prefix) => {
|
|
@@ -1168,23 +1290,144 @@ function readScriptInput(options) {
|
|
|
1168
1290
|
throw new Error("\u8BFB\u53D6\u811A\u672C\u6587\u4EF6\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u8DEF\u5F84\u662F\u5426\u5B58\u5728\u4E14\u5F53\u524D\u7528\u6237\u6709\u8BFB\u53D6\u6743\u9650");
|
|
1169
1291
|
}
|
|
1170
1292
|
}
|
|
1293
|
+
async function resolveVisibleRemoteSkills(apiKey) {
|
|
1294
|
+
const remoteSkills = await fetchRemoteSkillSummaries(apiKey);
|
|
1295
|
+
return applyRemoteSkillScope(remoteSkills, getRemoteSkillScope());
|
|
1296
|
+
}
|
|
1171
1297
|
function registerRemoteSkillCommand(program) {
|
|
1172
|
-
const remoteSkillCommand = program.command("remote-skill").description("\u67E5\u770B skill
|
|
1173
|
-
|
|
1298
|
+
const remoteSkillCommand = program.command("remote-skill").description("\u67E5\u770B\u91D1\u878D\u573A\u666F skill\u3001\u8FDB\u5165\u4E0A\u4E0B\u6587\uFF0C\u5E76\u5728\u8BE5\u76EE\u5F55\u6267\u884C\u7EA6\u5B9A\u811A\u672C").addHelpText(
|
|
1299
|
+
"after",
|
|
1300
|
+
`
|
|
1301
|
+
\u7528\u9014:
|
|
1302
|
+
\u53D1\u73B0\u8FDC\u7AEF\u91D1\u878D\u573A\u666F skill\uFF0C\u8FDB\u5165\u67D0\u4E2A skill \u7684\u5DE5\u4F5C\u4E0A\u4E0B\u6587\uFF0C\u5E76\u6309 skill \u7EA6\u5B9A\u6267\u884C\u811A\u672C\u3002
|
|
1303
|
+
|
|
1304
|
+
\u63A8\u8350\u987A\u5E8F:
|
|
1305
|
+
1. \u5982\u53EA\u60F3\u56F4\u7ED5\u56FA\u5B9A skill \u5DE5\u4F5C\uFF0C\u5148\u6267\u884C yingmi-skill-cli remote-skill scope set --skills <a,b,c>
|
|
1306
|
+
2. yingmi-skill-cli remote-skill list
|
|
1307
|
+
3. yingmi-skill-cli remote-skill enter <skillName>
|
|
1308
|
+
4. yingmi-skill-cli remote-skill exec --script 'cat SKILL.md'
|
|
1309
|
+
5. \u6309 skill \u8BF4\u660E\u6267\u884C\u5B9E\u9645\u811A\u672C\uFF0C\u4F8B\u5982:
|
|
1310
|
+
yingmi-skill-cli remote-skill exec --script 'python main.py'
|
|
1311
|
+
|
|
1312
|
+
\u6CE8\u610F:
|
|
1313
|
+
- remote-skill \u7528\u4E8E\u5B8C\u6210\u57FA\u91D1\u5206\u6790\u3001\u7EC4\u5408\u8BCA\u65AD\u3001\u8D22\u5BCC\u89C4\u5212\u3001\u5E02\u573A\u7B80\u62A5\u7B49\u573A\u666F\u4EFB\u52A1
|
|
1314
|
+
- \u4E00\u4E2A skill \u5185\u90E8\u53EF\u4EE5\u6309\u9700\u8C03\u7528\u4E00\u4E2A\u6216\u591A\u4E2A mcp
|
|
1315
|
+
- remote-skill exec \u6267\u884C\u7684\u662F shell \u811A\u672C\uFF0C\u4E0D\u662F\u81EA\u7136\u8BED\u8A00\u4EFB\u52A1
|
|
1316
|
+
- \u5EFA\u8BAE\u4F18\u5148\u9605\u8BFB skill \u5185\u7684 SKILL.md\uFF0C\u518D\u6267\u884C\u7EA6\u5B9A\u5165\u53E3
|
|
1317
|
+
`
|
|
1318
|
+
);
|
|
1319
|
+
const scopeCommand = remoteSkillCommand.command("scope").description("\u8BBE\u7F6E\u6216\u6E05\u9664\u5F53\u524D remote-skill \u7684\u672C\u5730\u53EF\u89C1\u8303\u56F4").addHelpText(
|
|
1320
|
+
"after",
|
|
1321
|
+
`
|
|
1322
|
+
\u7528\u9014:
|
|
1323
|
+
\u901A\u8FC7\u672C\u5730 scope \u9650\u5236 remote-skill \u9ED8\u8BA4\u53EF\u89C1\u7684 skill \u8303\u56F4\u3002
|
|
1324
|
+
|
|
1325
|
+
\u793A\u4F8B:
|
|
1326
|
+
yingmi-skill-cli remote-skill scope set --skills fund-analyzer,market-brief
|
|
1327
|
+
yingmi-skill-cli remote-skill scope clear
|
|
1328
|
+
`
|
|
1329
|
+
);
|
|
1330
|
+
scopeCommand.command("set").description("\u8BBE\u7F6E\u5F53\u524D remote-skill \u7684\u672C\u5730 scope \u767D\u540D\u5355").requiredOption("--skills <skillNames>", "\u9017\u53F7\u5206\u9694\u7684 skill \u540D\u79F0\u5217\u8868").addHelpText(
|
|
1331
|
+
"after",
|
|
1332
|
+
`
|
|
1333
|
+
\u8BF4\u660E:
|
|
1334
|
+
- --skills \u4F7F\u7528\u9017\u53F7\u5206\u9694\u591A\u4E2A skill \u540D\u79F0
|
|
1335
|
+
- \u4F1A\u81EA\u52A8\u53BB\u91CD\u5E76\u6821\u9A8C skill \u540D\u79F0\u683C\u5F0F
|
|
1336
|
+
- scope \u4E0E\u8FDC\u7AEF\u5217\u8868\u65E0\u4EA4\u96C6\u65F6\uFF0Clist \u548C enter \u4F1A\u81EA\u52A8\u56DE\u9000\u5230\u8FDC\u7AEF\u5168\u91CF
|
|
1337
|
+
|
|
1338
|
+
\u793A\u4F8B:
|
|
1339
|
+
yingmi-skill-cli remote-skill scope set --skills fund-analyzer,market-brief
|
|
1340
|
+
`
|
|
1341
|
+
).action((options) => {
|
|
1342
|
+
try {
|
|
1343
|
+
const skills = parseRemoteSkillScopeInput(options.skills);
|
|
1344
|
+
setRemoteSkillScope({
|
|
1345
|
+
skills,
|
|
1346
|
+
updatedAt: Date.now()
|
|
1347
|
+
});
|
|
1348
|
+
console.log(
|
|
1349
|
+
JSON.stringify(
|
|
1350
|
+
{
|
|
1351
|
+
enabled: true,
|
|
1352
|
+
skills
|
|
1353
|
+
},
|
|
1354
|
+
null,
|
|
1355
|
+
2
|
|
1356
|
+
)
|
|
1357
|
+
);
|
|
1358
|
+
} catch (error) {
|
|
1359
|
+
fail(error.message);
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
1362
|
+
scopeCommand.command("clear").description("\u6E05\u9664\u5F53\u524D remote-skill \u7684\u672C\u5730 scope").addHelpText(
|
|
1363
|
+
"after",
|
|
1364
|
+
`
|
|
1365
|
+
\u8BF4\u660E:
|
|
1366
|
+
\u6E05\u9664\u540E\uFF0Cremote-skill list \u548C remote-skill enter \u4F1A\u6062\u590D\u4E3A\u9ED8\u8BA4\u884C\u4E3A\u3002
|
|
1367
|
+
`
|
|
1368
|
+
).action(() => {
|
|
1369
|
+
try {
|
|
1370
|
+
clearRemoteSkillScope();
|
|
1371
|
+
console.log(
|
|
1372
|
+
JSON.stringify(
|
|
1373
|
+
{
|
|
1374
|
+
enabled: false
|
|
1375
|
+
},
|
|
1376
|
+
null,
|
|
1377
|
+
2
|
|
1378
|
+
)
|
|
1379
|
+
);
|
|
1380
|
+
} catch (error) {
|
|
1381
|
+
fail(error.message);
|
|
1382
|
+
}
|
|
1383
|
+
});
|
|
1384
|
+
remoteSkillCommand.command("list").description("\u5C55\u793A\u5F53\u524D\u53EF\u7528\u7684\u91D1\u878D\u573A\u666F skill \u6458\u8981").addHelpText(
|
|
1385
|
+
"after",
|
|
1386
|
+
`
|
|
1387
|
+
\u8BF4\u660E:
|
|
1388
|
+
\u5982\u679C\u5DF2\u8BBE\u7F6E remote-skill scope\uFF0C\u4F18\u5148\u8FD4\u56DE scope \u5185\u4ECD\u7136\u53EF\u7528\u7684 skill\uFF1B
|
|
1389
|
+
\u5F53 scope \u4E0E\u8FDC\u7AEF\u5217\u8868\u6CA1\u6709\u4EA4\u96C6\u65F6\uFF0C\u4F1A\u81EA\u52A8\u56DE\u9000\u4E3A\u8FDC\u7AEF\u5168\u91CF\uFF0C\u907F\u514D\u8FD4\u56DE\u7A7A\u6570\u7EC4\u3002
|
|
1390
|
+
|
|
1391
|
+
\u4E0B\u4E00\u6B65:
|
|
1392
|
+
1. \u4ECE\u8F93\u51FA\u91CC\u6311\u4E00\u4E2A\u6700\u8D34\u8FD1\u5F53\u524D\u91D1\u878D\u573A\u666F\u4EFB\u52A1\u7684 skillName
|
|
1393
|
+
2. \u6267\u884C yingmi-skill-cli remote-skill enter <skillName>
|
|
1394
|
+
3. \u518D\u6267\u884C yingmi-skill-cli remote-skill exec --script 'cat SKILL.md'
|
|
1395
|
+
`
|
|
1396
|
+
).action(async () => {
|
|
1174
1397
|
try {
|
|
1175
1398
|
const apiKey = requireApiKey();
|
|
1176
|
-
const skills = await
|
|
1399
|
+
const skills = await resolveVisibleRemoteSkills(apiKey);
|
|
1177
1400
|
console.log(JSON.stringify(skills, null, 2));
|
|
1178
1401
|
} catch (error) {
|
|
1179
1402
|
fail(error.message);
|
|
1180
1403
|
}
|
|
1181
1404
|
});
|
|
1182
|
-
remoteSkillCommand.command("enter").description("\u8FDB\u5165\u67D0\u4E2A skill \u4E0A\u4E0B\u6587\uFF0C\u5E76\u5C55\u793A\u76EE\u5F55\
|
|
1405
|
+
remoteSkillCommand.command("enter").description("\u8FDB\u5165\u67D0\u4E2A\u573A\u666F skill \u4E0A\u4E0B\u6587\uFF0C\u4FDD\u5B58\u5F53\u524D\u4F1A\u8BDD\uFF0C\u5E76\u5C55\u793A\u76EE\u5F55\u6811").argument("<skillName>", "skill \u540D\u79F0").addHelpText(
|
|
1406
|
+
"after",
|
|
1407
|
+
`
|
|
1408
|
+
\u8BF4\u660E:
|
|
1409
|
+
enter \u6210\u529F\u540E\u4F1A\u8BB0\u5F55\u6700\u8FD1\u4E00\u6B21 skill \u4F1A\u8BDD\uFF0C\u540E\u7EED exec \u9ED8\u8BA4\u590D\u7528\u8FD9\u4E2A\u4E0A\u4E0B\u6587\u3002
|
|
1410
|
+
\u8FDB\u5165 skill \u9002\u5408\u4F60\u5DF2\u7ECF\u786E\u5B9A\u8981\u5B8C\u6210\u67D0\u4E2A\u91D1\u878D\u573A\u666F\u4EFB\u52A1\uFF0C\u800C\u4E0D\u662F\u53EA\u8C03\u7528\u5355\u4E2A mcp\u3002
|
|
1411
|
+
|
|
1412
|
+
\u793A\u4F8B:
|
|
1413
|
+
yingmi-skill-cli remote-skill enter fund-analyst
|
|
1414
|
+
|
|
1415
|
+
\u4E0B\u4E00\u6B65:
|
|
1416
|
+
1. yingmi-skill-cli remote-skill exec --script 'cat SKILL.md'
|
|
1417
|
+
2. \u6309 skill \u6587\u6863\u8BF4\u660E\u6267\u884C\u5165\u53E3\u811A\u672C
|
|
1418
|
+
`
|
|
1419
|
+
).action(async (skillName) => {
|
|
1183
1420
|
try {
|
|
1184
1421
|
const apiKey = requireApiKey();
|
|
1185
|
-
const
|
|
1422
|
+
const normalizedSkillName = validateRemoteSkillName(skillName);
|
|
1423
|
+
const visibleSkills = await resolveVisibleRemoteSkills(apiKey);
|
|
1424
|
+
if (!visibleSkills.some((skill) => skill.name === normalizedSkillName)) {
|
|
1425
|
+
fail(`\u672A\u627E\u5230 skill: ${normalizedSkillName}
|
|
1426
|
+
\u8BF7\u5148\u6267\u884C remote-skill list \u67E5\u770B\u5F53\u524D\u53EF\u7528 skill`);
|
|
1427
|
+
}
|
|
1428
|
+
const context = await prepareRemoteSkillContext(normalizedSkillName, apiKey);
|
|
1186
1429
|
setCurrentRemoteSkillSession({
|
|
1187
|
-
skillName,
|
|
1430
|
+
skillName: normalizedSkillName,
|
|
1188
1431
|
workingDirectory: context.workingDirectory
|
|
1189
1432
|
});
|
|
1190
1433
|
console.log(formatWorkingDirectoryTree(context.workingDirectory));
|
|
@@ -1192,7 +1435,21 @@ function registerRemoteSkillCommand(program) {
|
|
|
1192
1435
|
fail(error.message);
|
|
1193
1436
|
}
|
|
1194
1437
|
});
|
|
1195
|
-
remoteSkillCommand.command("exec").description("\u5728\u6700\u8FD1\u4E00\u6B21\u8FDB\u5165\u7684 skill \u4E0A\u4E0B\u6587\u4E2D\u6267\u884C\u811A\u672C").option("--script <content>", "\u5728\u5F53\u524D skill \u4E0A\u4E0B\u6587\u4E2D\u6267\u884C\u811A\u672C").option("--script-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6\u811A\u672C\u5185\u5BB9\u540E\u6267\u884C").
|
|
1438
|
+
remoteSkillCommand.command("exec").description("\u5728\u6700\u8FD1\u4E00\u6B21\u8FDB\u5165\u7684 skill \u4E0A\u4E0B\u6587\u4E2D\u6267\u884C\u7EA6\u5B9A\u811A\u672C").option("--script <content>", "\u5728\u5F53\u524D skill \u4E0A\u4E0B\u6587\u4E2D\u6267\u884C shell \u811A\u672C\u5185\u5BB9").option("--script-file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6\u811A\u672C\u5185\u5BB9\u540E\u6267\u884C").addHelpText(
|
|
1439
|
+
"after",
|
|
1440
|
+
`
|
|
1441
|
+
\u6CE8\u610F:
|
|
1442
|
+
1. \u8FD9\u91CC\u6267\u884C\u7684\u662F shell \u811A\u672C\uFF0C\u4E0D\u662F\u81EA\u7136\u8BED\u8A00 prompt
|
|
1443
|
+
2. \u5EFA\u8BAE\u4F18\u5148\u9605\u8BFB skill \u5185\u7684 SKILL.md\uFF0C\u6309 skill \u7EA6\u5B9A\u6267\u884C\u811A\u672C
|
|
1444
|
+
3. skill \u5728\u6267\u884C\u8FC7\u7A0B\u4E2D\u53EF\u80FD\u4F1A\u7EE7\u7EED\u8C03\u7528\u4E00\u4E2A\u6216\u591A\u4E2A mcp
|
|
1445
|
+
4. \u5BF9\u4E8E Python skill\uFF0C\u4F18\u5148\u4F7F\u7528 python \u547D\u4EE4\u6267\u884C\u5165\u53E3\u811A\u672C
|
|
1446
|
+
|
|
1447
|
+
\u793A\u4F8B:
|
|
1448
|
+
yingmi-skill-cli remote-skill exec --script 'cat SKILL.md'
|
|
1449
|
+
yingmi-skill-cli remote-skill exec --script 'python main.py'
|
|
1450
|
+
yingmi-skill-cli remote-skill exec --script-file ./scripts/run.sh
|
|
1451
|
+
`
|
|
1452
|
+
).action(async (options) => {
|
|
1196
1453
|
try {
|
|
1197
1454
|
if (options.script && options.scriptFile) {
|
|
1198
1455
|
fail("--script \u548C --script-file \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
@@ -1215,7 +1472,6 @@ function registerRemoteSkillCommand(program) {
|
|
|
1215
1472
|
JSON.stringify(
|
|
1216
1473
|
{
|
|
1217
1474
|
skillName: currentSession.skillName,
|
|
1218
|
-
workingDirectory: currentSession.workingDirectory,
|
|
1219
1475
|
execution
|
|
1220
1476
|
},
|
|
1221
1477
|
null,
|
|
@@ -1319,7 +1575,22 @@ async function checkAndUpdate(checkOnly = false) {
|
|
|
1319
1575
|
}
|
|
1320
1576
|
|
|
1321
1577
|
function registerUpgradeCommand(program) {
|
|
1322
|
-
program.command("upgrade").description("\u68C0\u67E5 CLI \u66F4\u65B0\uFF0C\u5E76\u5728\u6709\u65B0\u7248\u672C\u65F6\u6267\u884C\u5347\u7EA7").option("--check-only", "\u4EC5\u68C0\u67E5\u6700\u65B0\u7248\u672C\uFF0C\u4E0D\u6267\u884C\u5B89\u88C5").
|
|
1578
|
+
program.command("upgrade").description("\u68C0\u67E5 CLI \u66F4\u65B0\uFF0C\u5E76\u5728\u6709\u65B0\u7248\u672C\u65F6\u6267\u884C\u5347\u7EA7").option("--check-only", "\u4EC5\u68C0\u67E5\u6700\u65B0\u7248\u672C\uFF0C\u4E0D\u6267\u884C\u5B89\u88C5").addHelpText(
|
|
1579
|
+
"after",
|
|
1580
|
+
`
|
|
1581
|
+
\u7528\u9014:
|
|
1582
|
+
\u68C0\u67E5 CLI \u662F\u5426\u6709\u65B0\u7248\u672C\uFF0C\u5E76\u5728\u9700\u8981\u65F6\u6267\u884C\u5347\u7EA7\u3002
|
|
1583
|
+
|
|
1584
|
+
\u793A\u4F8B:
|
|
1585
|
+
yingmi-skill-cli upgrade --check-only
|
|
1586
|
+
yingmi-skill-cli upgrade
|
|
1587
|
+
|
|
1588
|
+
\u8BF4\u660E:
|
|
1589
|
+
- --check-only \u53EA\u68C0\u67E5\u7248\u672C\uFF0C\u4E0D\u6267\u884C\u5B89\u88C5
|
|
1590
|
+
- \u771F\u6B63\u5347\u7EA7\u524D\u5E94\u660E\u786E\u4E86\u89E3\u526F\u4F5C\u7528
|
|
1591
|
+
- \u975E\u4EA4\u4E92\u73AF\u5883\u4E0B\u4E0D\u5E94\u4F9D\u8D56\u786E\u8BA4\u8F93\u5165
|
|
1592
|
+
`
|
|
1593
|
+
).action(async (options) => {
|
|
1323
1594
|
try {
|
|
1324
1595
|
await checkAndUpdate(Boolean(options.checkOnly));
|
|
1325
1596
|
} catch (error) {
|
|
@@ -1333,13 +1604,38 @@ function registerUpgradeCommand(program) {
|
|
|
1333
1604
|
|
|
1334
1605
|
function createProgram() {
|
|
1335
1606
|
const program = new commander.Command();
|
|
1336
|
-
program.name("yingmi-cli").version(version);
|
|
1607
|
+
program.name("yingmi-skill-cli").version(version);
|
|
1337
1608
|
registerInitCommand(program);
|
|
1338
1609
|
registerMcpCommand(program);
|
|
1339
1610
|
registerRemoteSkillCommand(program);
|
|
1340
1611
|
registerHelpCommand(program);
|
|
1341
1612
|
registerUpgradeCommand(program);
|
|
1342
1613
|
program.showHelpAfterError("(\u4F7F\u7528 --help \u67E5\u770B\u547D\u4EE4\u5E2E\u52A9)");
|
|
1614
|
+
program.addHelpText(
|
|
1615
|
+
"after",
|
|
1616
|
+
`
|
|
1617
|
+
\u5E38\u89C1\u4EFB\u52A1:
|
|
1618
|
+
\u9996\u6B21\u914D\u7F6E CLI yingmi-skill-cli help init
|
|
1619
|
+
\u76F4\u63A5\u8C03\u7528\u539F\u5B50\u91D1\u878D\u80FD\u529B yingmi-skill-cli help mcp
|
|
1620
|
+
\u5B8C\u6210\u57FA\u91D1\u6216\u8D22\u5BCC\u573A\u666F\u4EFB\u52A1 yingmi-skill-cli help remote-skill
|
|
1621
|
+
\u67E5\u770B\u67D0\u4E2A\u547D\u4EE4\u7684\u8BE6\u7EC6\u5E2E\u52A9 yingmi-skill-cli help <command...>
|
|
1622
|
+
\u68C0\u67E5\u6216\u5347\u7EA7\u7248\u672C yingmi-skill-cli help upgrade
|
|
1623
|
+
|
|
1624
|
+
\u5FEB\u901F\u5F00\u59CB:
|
|
1625
|
+
1. yingmi-skill-cli init setup
|
|
1626
|
+
2. \u5982\u679C\u8981\u76F4\u63A5\u8C03\u7528\u5355\u4E2A\u80FD\u529B\uFF0C\u6267\u884C yingmi-skill-cli mcp list
|
|
1627
|
+
3. \u5982\u679C\u8981\u5B8C\u6210\u91D1\u878D\u573A\u666F\u4EFB\u52A1\uFF0C\u6267\u884C yingmi-skill-cli remote-skill list
|
|
1628
|
+
4. \u5BF9\u4E8E mcp\uFF0C\u7EE7\u7EED\u6267\u884C yingmi-skill-cli mcp schema <toolName>
|
|
1629
|
+
5. \u5BF9\u4E8E mcp\uFF0C\u6267\u884C yingmi-skill-cli mcp call <toolName> --input '<json>'
|
|
1630
|
+
|
|
1631
|
+
\u534F\u8BAE\u63D0\u793A:
|
|
1632
|
+
- \u7ED3\u6784\u5316\u7ED3\u679C\u8F93\u51FA\u5230 stdout
|
|
1633
|
+
- \u63D0\u793A\u3001\u544A\u8B66\u548C\u9519\u8BEF\u8F93\u51FA\u5230 stderr
|
|
1634
|
+
- \u4F18\u5148\u4F7F\u7528\u975E\u4EA4\u4E92\u53C2\u6570\uFF0C\u4FBF\u4E8E\u811A\u672C\u548C Agent \u8C03\u7528
|
|
1635
|
+
- mcp \u7528\u4E8E\u539F\u5B50\u80FD\u529B\u8C03\u7528\uFF0Cremote-skill \u7528\u4E8E\u91D1\u878D\u573A\u666F\u7F16\u6392
|
|
1636
|
+
- \u8C03\u7528 mcp \u524D\u5EFA\u8BAE\u5148\u67E5\u770B schema \u786E\u8BA4\u8F93\u5165\u5B57\u6BB5
|
|
1637
|
+
`
|
|
1638
|
+
);
|
|
1343
1639
|
return program;
|
|
1344
1640
|
}
|
|
1345
1641
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yingmi-skill-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"author": "yingmi",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"files": [
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"scripts": {
|
|
14
14
|
"dev": "rollup -c -w",
|
|
15
15
|
"build": "rollup -c",
|
|
16
|
+
"release": "bash ./publish.sh",
|
|
16
17
|
"test": "jest --passWithNoTests",
|
|
17
18
|
"test:watch": "jest --watch",
|
|
18
19
|
"test:coverage": "jest --coverage --passWithNoTests"
|
|
@@ -33,7 +34,6 @@
|
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"axios": "^1",
|
|
35
36
|
"chalk": "^4",
|
|
36
|
-
"commander": "*"
|
|
37
|
-
"puppeteer": "^24.39.1"
|
|
37
|
+
"commander": "*"
|
|
38
38
|
}
|
|
39
39
|
}
|