yingmi-skill-cli 0.0.2 → 0.0.6
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 +64 -55
- package/bin/index.js +313 -143
- package/package.json +4 -4
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,50 @@
|
|
|
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 list
|
|
50
|
-
yingmi-cli remote-skill enter <skillName>
|
|
51
|
-
yingmi-cli remote-skill exec --script <script>
|
|
52
|
-
yingmi-cli remote-skill exec --script-file <path>
|
|
53
|
-
|
|
54
|
-
yingmi-cli help [command]
|
|
55
|
-
|
|
56
|
-
yingmi-cli upgrade
|
|
57
|
-
yingmi-cli upgrade --check-only
|
|
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 list
|
|
56
|
+
yingmi-skill-cli remote-skill enter <skillName>
|
|
57
|
+
yingmi-skill-cli remote-skill exec --script <script>
|
|
58
|
+
yingmi-skill-cli remote-skill exec --script-file <path>
|
|
59
|
+
|
|
60
|
+
yingmi-skill-cli help [command]
|
|
61
|
+
|
|
62
|
+
yingmi-skill-cli upgrade
|
|
63
|
+
yingmi-skill-cli upgrade --check-only
|
|
58
64
|
```
|
|
59
65
|
|
|
60
66
|
## 模块说明
|
|
@@ -66,11 +72,11 @@ yingmi-cli upgrade --check-only
|
|
|
66
72
|
常用命令:
|
|
67
73
|
|
|
68
74
|
```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
|
|
75
|
+
yingmi-skill-cli init setup --api-key <value>
|
|
76
|
+
yingmi-skill-cli init setup --phone <手机号>
|
|
77
|
+
yingmi-skill-cli init setup --verify-code <验证码>
|
|
78
|
+
yingmi-skill-cli init status
|
|
79
|
+
yingmi-skill-cli init doctor
|
|
74
80
|
```
|
|
75
81
|
|
|
76
82
|
行为约束:
|
|
@@ -82,14 +88,14 @@ yingmi-cli init doctor
|
|
|
82
88
|
|
|
83
89
|
### `mcp`
|
|
84
90
|
|
|
85
|
-
`mcp`
|
|
91
|
+
`mcp` 负责“发现原子能力、理解能力定义、执行单次调用”三个阶段。
|
|
86
92
|
|
|
87
93
|
常用命令:
|
|
88
94
|
|
|
89
95
|
```bash
|
|
90
|
-
yingmi-cli mcp list
|
|
91
|
-
yingmi-cli mcp schema getFundCampisiIndicator
|
|
92
|
-
yingmi-cli mcp call getFundCampisiIndicator --input '{"fundCode":"000001","timePeriod":"LAST_YEAR"}'
|
|
96
|
+
yingmi-skill-cli mcp list
|
|
97
|
+
yingmi-skill-cli mcp schema getFundCampisiIndicator
|
|
98
|
+
yingmi-skill-cli mcp call getFundCampisiIndicator --input '{"fundCode":"000001","timePeriod":"LAST_YEAR"}'
|
|
93
99
|
```
|
|
94
100
|
|
|
95
101
|
行为约束:
|
|
@@ -97,44 +103,48 @@ yingmi-cli mcp call getFundCampisiIndicator --input '{"fundCode":"000001","timeP
|
|
|
97
103
|
- `mcp list`:展示工具摘要,默认优先结构化结果
|
|
98
104
|
- `mcp schema <toolName>`:展示某个工具的完整 OpenAPI 定义
|
|
99
105
|
- `mcp call <toolName>`:调用目标工具,支持 `--input` 和 `--input-file`
|
|
106
|
+
- `mcp` 适合直接取数、单次计算、单个分析接口调用,不适合直接承载完整金融场景工作流
|
|
100
107
|
- 输出协议必须稳定,stdout 只承载结果,stderr 承载提示与错误
|
|
101
108
|
|
|
102
109
|
### `remote-skill`
|
|
103
110
|
|
|
104
|
-
`remote-skill` 面向远端 skill 运行服务,核心是“发现 skill
|
|
111
|
+
`remote-skill` 面向远端 skill 运行服务,核心是“发现 skill、进入 skill 上下文,并按 skill 协议完成金融场景任务”。
|
|
105
112
|
|
|
106
113
|
常用命令:
|
|
107
114
|
|
|
108
115
|
```bash
|
|
109
|
-
yingmi-cli remote-skill list
|
|
110
|
-
yingmi-cli remote-skill enter fund-analyzer
|
|
111
|
-
yingmi-cli remote-skill exec --script '
|
|
112
|
-
yingmi-cli remote-skill exec --script
|
|
116
|
+
yingmi-skill-cli remote-skill list
|
|
117
|
+
yingmi-skill-cli remote-skill enter fund-analyzer
|
|
118
|
+
yingmi-skill-cli remote-skill exec --script 'cat SKILL.md'
|
|
119
|
+
yingmi-skill-cli remote-skill exec --script 'python main.py'
|
|
120
|
+
yingmi-skill-cli remote-skill exec --script-file ./scripts/run.sh
|
|
113
121
|
```
|
|
114
122
|
|
|
115
123
|
行为约束:
|
|
116
124
|
|
|
117
125
|
- `list`:调用远端 `/api/get-skills` 接口,使用本地 `apiKey` 作为请求头
|
|
118
|
-
- `enter <skillName>`:每次都会重新调用远端 `/api/get-skill-by-name` 获取压缩包地址,下载并解压到 `~/.yingmi-cli/skills/<skillName>`
|
|
119
|
-
- `exec --script/--script-file`:只能在最近一次成功 `enter`
|
|
120
|
-
-
|
|
126
|
+
- `enter <skillName>`:每次都会重新调用远端 `/api/get-skill-by-name` 获取压缩包地址,下载并解压到 `~/.yingmi-skill-cli/skills/<skillName>` 后输出目录树,并把当前 skill 上下文写入本地配置
|
|
127
|
+
- `exec --script/--script-file`:只能在最近一次成功 `enter` 后使用,建议先执行 `cat SKILL.md` 理解 skill 约定,再在当前 skill 目录执行入口脚本;执行结果输出状态、退出码、stdout 和 stderr,不额外回传本地工作目录路径
|
|
128
|
+
- `remote-skill` 适合基金分析、组合诊断、财富规划、市场简报等场景任务;skill 内部可以继续调用多个 `mcp`
|
|
129
|
+
- 远端服务地址默认读取 `https://stargate-staging.yingmi-inc.com/`,也可在 `~/.yingmi-skill-cli/config.json` 里手工设置 `remoteSkillServerBaseUrl`
|
|
121
130
|
|
|
122
131
|
### `help`
|
|
123
132
|
|
|
124
|
-
`help` 是显式帮助入口,用来补足 `--help`
|
|
133
|
+
`help` 是显式帮助入口,用来补足 `--help` 之外的可发现性,并承担按任务导航的职责。
|
|
125
134
|
|
|
126
135
|
常用命令:
|
|
127
136
|
|
|
128
137
|
```bash
|
|
129
|
-
yingmi-cli help
|
|
130
|
-
yingmi-cli help mcp
|
|
131
|
-
yingmi-cli mcp --help
|
|
138
|
+
yingmi-skill-cli help
|
|
139
|
+
yingmi-skill-cli help mcp
|
|
140
|
+
yingmi-skill-cli mcp --help
|
|
132
141
|
```
|
|
133
142
|
|
|
134
143
|
约束:
|
|
135
144
|
|
|
136
145
|
- `help` 和 `--help` 必须共用同一套命令元数据
|
|
137
|
-
-
|
|
146
|
+
- 根帮助优先回答“该去哪个模块”,模块帮助优先说明推荐顺序,叶子命令帮助优先说明输入规则和常见示例
|
|
147
|
+
- `remote-skill` 默认示例应体现“先读 `SKILL.md`,再执行入口脚本”,不把目录探测命令作为推荐路径
|
|
138
148
|
|
|
139
149
|
### `upgrade`
|
|
140
150
|
|
|
@@ -143,8 +153,8 @@ yingmi-cli mcp --help
|
|
|
143
153
|
常用命令:
|
|
144
154
|
|
|
145
155
|
```bash
|
|
146
|
-
yingmi-cli upgrade
|
|
147
|
-
yingmi-cli upgrade --check-only
|
|
156
|
+
yingmi-skill-cli upgrade
|
|
157
|
+
yingmi-skill-cli upgrade --check-only
|
|
148
158
|
```
|
|
149
159
|
|
|
150
160
|
约束:
|
|
@@ -167,12 +177,11 @@ yingmi-cli upgrade --check-only
|
|
|
167
177
|
|
|
168
178
|
推荐使用方式如下:
|
|
169
179
|
|
|
170
|
-
1. 先执行 `yingmi-cli init setup`,让 CLI 进入可用状态。
|
|
171
|
-
2.
|
|
172
|
-
3.
|
|
173
|
-
4.
|
|
174
|
-
5.
|
|
175
|
-
6. 需要查看帮助或升级时,分别使用 `help` 和 `upgrade`。
|
|
180
|
+
1. 先执行 `yingmi-skill-cli init setup`,让 CLI 进入可用状态。
|
|
181
|
+
2. 如果要直接调用单个原子能力,先用 `yingmi-skill-cli mcp list` 浏览可用工具。
|
|
182
|
+
3. 对于 `mcp`,继续用 `yingmi-skill-cli mcp schema <toolName>` 查看完整定义,再用 `yingmi-skill-cli mcp call <toolName>` 发起调用。
|
|
183
|
+
4. 如果要完成基金分析、组合诊断、财富规划等场景任务,先用 `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 约定执行脚本。
|
|
184
|
+
5. 需要查看帮助或升级时,分别使用 `help` 和 `upgrade`。
|
|
176
185
|
|
|
177
186
|
## 当前代码组织
|
|
178
187
|
|
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
|
-
var name = "yingmi-
|
|
15
|
-
var version = "0.0.
|
|
13
|
+
var name = "yingmi-cli";
|
|
14
|
+
var version = "0.0.6";
|
|
16
15
|
|
|
17
16
|
function fail(message) {
|
|
18
17
|
console.error(message);
|
|
@@ -21,22 +20,64 @@ 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-cli help
|
|
56
|
+
yingmi-cli help init
|
|
57
|
+
yingmi-cli help mcp
|
|
58
|
+
yingmi-cli help mcp call
|
|
59
|
+
yingmi-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-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
|
|
|
@@ -44,7 +85,7 @@ const CONFIG_DIR = path.join(os.homedir(), ".yingmi-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
|
}
|
|
@@ -119,9 +160,9 @@ function getSkillsDirPath() {
|
|
|
119
160
|
fs.mkdirSync(SKILLS_DIR, { recursive: true });
|
|
120
161
|
return SKILLS_DIR;
|
|
121
162
|
}
|
|
122
|
-
function
|
|
123
|
-
const configuredBaseUrl = readConfig().
|
|
124
|
-
return configuredBaseUrl ||
|
|
163
|
+
function getStargateBaseUrl() {
|
|
164
|
+
const configuredBaseUrl = readConfig().stargateBaseUrl?.trim();
|
|
165
|
+
return configuredBaseUrl || DEFAULT_STARGATE_BASE_URL;
|
|
125
166
|
}
|
|
126
167
|
function getQiemanBaseUrl() {
|
|
127
168
|
const configuredBaseUrl = readConfig().qiemanBaseUrl?.trim();
|
|
@@ -253,111 +294,28 @@ function getPendingSetupResult() {
|
|
|
253
294
|
};
|
|
254
295
|
}
|
|
255
296
|
|
|
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
|
-
});
|
|
297
|
+
const DEFAULT_TIMEOUT_MS = 2e4;
|
|
298
|
+
const SKILL_ACCESS_CONFIG_PATH = "/api/skill-access-config";
|
|
299
|
+
function trimTrailingSlash$1(value) {
|
|
300
|
+
return value.replace(/\/+$/, "");
|
|
289
301
|
}
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
}
|
|
302
|
+
function buildSkillAccessConfigUrl(baseUrl) {
|
|
303
|
+
return `${trimTrailingSlash$1(baseUrl)}${SKILL_ACCESS_CONFIG_PATH}`;
|
|
316
304
|
}
|
|
317
|
-
function resolveExecutablePath(executablePath) {
|
|
318
|
-
const customExecutablePath = executablePath?.trim() || process.env.PUPPETEER_EXECUTABLE_PATH?.trim();
|
|
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;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const DEFAULT_TIMEOUT_MS = 2e4;
|
|
337
305
|
async function getXSign(options = {}) {
|
|
338
306
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
307
|
+
const url = options.url?.trim() || buildSkillAccessConfigUrl(getStargateBaseUrl());
|
|
308
|
+
const response = await axios.get(url, {
|
|
309
|
+
headers: {
|
|
310
|
+
accept: "application/json"
|
|
311
|
+
},
|
|
312
|
+
timeout: timeoutMs
|
|
343
313
|
});
|
|
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();
|
|
314
|
+
const xSign = response.data.sign?.trim();
|
|
315
|
+
if (!xSign) {
|
|
316
|
+
throw new Error(`\u83B7\u53D6 x-sign \u5931\u8D25\uFF0C\u54CD\u5E94\u4E2D\u7F3A\u5C11 sign: ${url}`);
|
|
360
317
|
}
|
|
318
|
+
return xSign;
|
|
361
319
|
}
|
|
362
320
|
|
|
363
321
|
function trimTrailingSlash(value) {
|
|
@@ -537,14 +495,14 @@ function countSetupModes(options) {
|
|
|
537
495
|
return [options.apiKey, options.phone, options.verifyCode].filter(Boolean).length;
|
|
538
496
|
}
|
|
539
497
|
function persistHiddenConfigOptions(options) {
|
|
540
|
-
const
|
|
498
|
+
const stargateBaseUrl = options.stargateBaseUrl?.trim();
|
|
541
499
|
const qiemanBaseUrl = options.qiemanBaseUrl?.trim();
|
|
542
|
-
if (!
|
|
500
|
+
if (!stargateBaseUrl && !qiemanBaseUrl) {
|
|
543
501
|
return;
|
|
544
502
|
}
|
|
545
503
|
writeConfig({
|
|
546
504
|
...readConfig(),
|
|
547
|
-
...
|
|
505
|
+
...stargateBaseUrl ? { stargateBaseUrl } : {},
|
|
548
506
|
...qiemanBaseUrl ? { qiemanBaseUrl } : {}
|
|
549
507
|
});
|
|
550
508
|
}
|
|
@@ -552,14 +510,16 @@ async function runInitSetup(options) {
|
|
|
552
510
|
const apiKey = options.apiKey?.trim();
|
|
553
511
|
const phone = options.phone?.trim();
|
|
554
512
|
const qiemanBaseUrl = options.qiemanBaseUrl?.trim();
|
|
555
|
-
const remoteSkillServerBaseUrl = options.
|
|
513
|
+
const remoteSkillServerBaseUrl = options.stargateBaseUrl?.trim();
|
|
556
514
|
const verifyCode = options.verifyCode?.trim();
|
|
557
515
|
persistHiddenConfigOptions({
|
|
558
|
-
remoteSkillServerBaseUrl,
|
|
516
|
+
stargateBaseUrl: remoteSkillServerBaseUrl,
|
|
559
517
|
qiemanBaseUrl
|
|
560
518
|
});
|
|
561
519
|
if (countSetupModes({ apiKey, phone, verifyCode }) > 1) {
|
|
562
|
-
throw new Error(
|
|
520
|
+
throw new Error(
|
|
521
|
+
"`--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"
|
|
522
|
+
);
|
|
563
523
|
}
|
|
564
524
|
if (apiKey) {
|
|
565
525
|
return setupWithApiKey(apiKey);
|
|
@@ -574,15 +534,40 @@ async function runInitSetup(options) {
|
|
|
574
534
|
}
|
|
575
535
|
|
|
576
536
|
function registerDoctorCommand(initCommand) {
|
|
577
|
-
initCommand.command("doctor").description("\u68C0\u67E5\u672C\u5730\u914D\u7F6E\u4E0E\u8FD0\u884C\u73AF\u5883").
|
|
537
|
+
initCommand.command("doctor").description("\u68C0\u67E5\u672C\u5730\u914D\u7F6E\u4E0E\u8FD0\u884C\u73AF\u5883").addHelpText(
|
|
538
|
+
"after",
|
|
539
|
+
`
|
|
540
|
+
\u7528\u9014:
|
|
541
|
+
\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
|
|
542
|
+
|
|
543
|
+
\u793A\u4F8B:
|
|
544
|
+
yingmi-cli init doctor
|
|
545
|
+
|
|
546
|
+
\u8BF4\u660E:
|
|
547
|
+
- \u9002\u5408\u5728 init status \u8F93\u51FA\u5F02\u5E38\u65F6\u4F7F\u7528
|
|
548
|
+
- \u9519\u8BEF\u4FE1\u606F\u5E94\u540C\u65F6\u8BF4\u660E\u539F\u56E0\u548C\u4E0B\u4E00\u6B65\u4FEE\u590D\u5EFA\u8BAE
|
|
549
|
+
`
|
|
550
|
+
).action(() => {
|
|
578
551
|
console.log(JSON.stringify(runInitDoctorChecks(), null, 2));
|
|
579
552
|
});
|
|
580
553
|
}
|
|
581
554
|
|
|
582
555
|
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
|
-
|
|
556
|
+
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(
|
|
557
|
+
"after",
|
|
558
|
+
`
|
|
559
|
+
\u8F93\u5165\u89C4\u5219:
|
|
560
|
+
1. --api-key\u3001--phone\u3001--verify-code \u4E09\u79CD\u6A21\u5F0F\u4E92\u65A5
|
|
561
|
+
2. \u4E0D\u5E26\u53C2\u6570\u6267\u884C\u65F6\uFF0C\u8FD4\u56DE\u4E0B\u4E00\u6B65\u521D\u59CB\u5316\u5F15\u5BFC
|
|
562
|
+
3. \u5EFA\u8BAE\u4F18\u5148\u4F7F\u7528\u957F\u53C2\u6570\u540D\uFF0C\u4FBF\u4E8E\u811A\u672C\u548C Agent \u8C03\u7528
|
|
563
|
+
|
|
564
|
+
\u793A\u4F8B:
|
|
565
|
+
yingmi-cli init setup
|
|
566
|
+
yingmi-cli init setup --api-key <value>
|
|
567
|
+
yingmi-cli init setup --phone <\u624B\u673A\u53F7>
|
|
568
|
+
yingmi-cli init setup --verify-code <\u9A8C\u8BC1\u7801>
|
|
569
|
+
`
|
|
570
|
+
).action(async (options) => {
|
|
586
571
|
try {
|
|
587
572
|
const result = await runInitSetup(options);
|
|
588
573
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -593,13 +578,43 @@ function registerSetupCommand(initCommand) {
|
|
|
593
578
|
}
|
|
594
579
|
|
|
595
580
|
function registerStatusCommand(initCommand) {
|
|
596
|
-
initCommand.command("status").description("\u67E5\u770B\u521D\u59CB\u5316\u72B6\u6001\u548C\u914D\u7F6E\u6458\u8981").
|
|
581
|
+
initCommand.command("status").description("\u67E5\u770B\u521D\u59CB\u5316\u72B6\u6001\u548C\u914D\u7F6E\u6458\u8981").addHelpText(
|
|
582
|
+
"after",
|
|
583
|
+
`
|
|
584
|
+
\u7528\u9014:
|
|
585
|
+
\u8F93\u51FA\u5F53\u524D\u521D\u59CB\u5316\u72B6\u6001\u6458\u8981\uFF0C\u4FBF\u4E8E\u786E\u8BA4 CLI \u662F\u5426\u5DF2\u53EF\u7528\u3002
|
|
586
|
+
|
|
587
|
+
\u793A\u4F8B:
|
|
588
|
+
yingmi-cli init status
|
|
589
|
+
|
|
590
|
+
\u4E0B\u4E00\u6B65:
|
|
591
|
+
1. \u5982\u679C\u5C1A\u672A\u5B8C\u6210\u521D\u59CB\u5316\uFF0C\u6267\u884C yingmi-cli init setup
|
|
592
|
+
2. \u5982\u679C\u72B6\u6001\u5F02\u5E38\uFF0C\u6267\u884C yingmi-cli init doctor
|
|
593
|
+
`
|
|
594
|
+
).action(() => {
|
|
597
595
|
console.log(JSON.stringify(getInitStatusSummary(), null, 2));
|
|
598
596
|
});
|
|
599
597
|
}
|
|
600
598
|
|
|
601
599
|
function registerInitCommand(program) {
|
|
602
|
-
const initCommand = program.command("init").description("\u521D\u59CB\u5316 CLI \u5E76\u67E5\u770B\u5F53\u524D\u72B6\u6001")
|
|
600
|
+
const initCommand = program.command("init").description("\u521D\u59CB\u5316 CLI \u5E76\u67E5\u770B\u5F53\u524D\u72B6\u6001").addHelpText(
|
|
601
|
+
"after",
|
|
602
|
+
`
|
|
603
|
+
\u7528\u9014:
|
|
604
|
+
\u8BA9 CLI \u8FDB\u5165\u53EF\u7528\u72B6\u6001\uFF0C\u5E76\u68C0\u67E5\u5F53\u524D\u672C\u5730\u914D\u7F6E\u548C\u8FD0\u884C\u73AF\u5883\u3002
|
|
605
|
+
|
|
606
|
+
\u63A8\u8350\u987A\u5E8F:
|
|
607
|
+
1. yingmi-cli init setup
|
|
608
|
+
2. yingmi-cli init status
|
|
609
|
+
3. \u9047\u5230\u95EE\u9898\u65F6\u6267\u884C yingmi-cli init doctor
|
|
610
|
+
|
|
611
|
+
\u8BF4\u660E:
|
|
612
|
+
- setup \u7528\u4E8E\u9996\u6B21\u521D\u59CB\u5316\u6216\u8865\u5168 API Key
|
|
613
|
+
- status \u7528\u4E8E\u67E5\u770B\u5F53\u524D\u72B6\u6001\u6458\u8981
|
|
614
|
+
- doctor \u7528\u4E8E\u6392\u67E5\u914D\u7F6E\u6216\u73AF\u5883\u95EE\u9898
|
|
615
|
+
- \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
|
|
616
|
+
`
|
|
617
|
+
);
|
|
603
618
|
registerSetupCommand(initCommand);
|
|
604
619
|
registerStatusCommand(initCommand);
|
|
605
620
|
registerDoctorCommand(initCommand);
|
|
@@ -637,9 +652,7 @@ function readJsonInput(input, inputFile) {
|
|
|
637
652
|
function requireApiKey() {
|
|
638
653
|
const { apiKey } = readConfig();
|
|
639
654
|
if (!apiKey) {
|
|
640
|
-
fail(
|
|
641
|
-
"\u672A\u914D\u7F6E apiKey\uFF0C\u8BF7\u5148\u6267\u884C: yingmi-cli init setup --api-key <your-api-key>\uFF0C\u6216\u5148\u7528 yingmi-cli init setup --phone <\u624B\u673A\u53F7> \u5B8C\u6210\u9A8C\u8BC1\u7801\u521D\u59CB\u5316"
|
|
642
|
-
);
|
|
655
|
+
fail("\u672A\u5B8C\u6210\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u6267\u884C: yingmi-cli init setup --phone <\u624B\u673A\u53F7> \u5B8C\u6210\u624B\u673A\u53F7\u9A8C\u8BC1\u7801\u521D\u59CB\u5316");
|
|
643
656
|
}
|
|
644
657
|
return apiKey;
|
|
645
658
|
}
|
|
@@ -821,6 +834,7 @@ function validateParameters(parameters, values, locationLabel) {
|
|
|
821
834
|
|
|
822
835
|
const DOCS_URL = "https://stargate.yingmi.com/api/docs.json";
|
|
823
836
|
const HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options"];
|
|
837
|
+
const HIDDEN_OPERATION_NAMES = /* @__PURE__ */ new Set(["getSkillByName"]);
|
|
824
838
|
async function fetchOpenApiDocument(apiKey) {
|
|
825
839
|
const response = await axios.get(DOCS_URL, {
|
|
826
840
|
params: {
|
|
@@ -856,6 +870,9 @@ function listOperations(document) {
|
|
|
856
870
|
});
|
|
857
871
|
return operations.sort((left, right) => left.name.localeCompare(right.name));
|
|
858
872
|
}
|
|
873
|
+
function listVisibleOperations(document) {
|
|
874
|
+
return listOperations(document).filter((operation) => !HIDDEN_OPERATION_NAMES.has(operation.name));
|
|
875
|
+
}
|
|
859
876
|
function getOperationByName(document, toolName) {
|
|
860
877
|
return listOperations(document).find((operation) => operation.name === toolName);
|
|
861
878
|
}
|
|
@@ -881,7 +898,21 @@ function getPrimaryRequestContentType(operation) {
|
|
|
881
898
|
}
|
|
882
899
|
|
|
883
900
|
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").
|
|
901
|
+
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(
|
|
902
|
+
"after",
|
|
903
|
+
`
|
|
904
|
+
\u8F93\u5165\u89C4\u5219:
|
|
905
|
+
1. \u5148\u6267\u884C yingmi-cli mcp schema <toolName> \u786E\u8BA4\u5B57\u6BB5\u540D\u548C requestBody
|
|
906
|
+
2. path/query/header \u53C2\u6570\u53EF\u76F4\u63A5\u653E\u5728 JSON \u9876\u5C42\uFF0C\u4E5F\u53EF\u5206\u522B\u653E\u8FDB path/query/header
|
|
907
|
+
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
|
|
908
|
+
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
|
|
909
|
+
|
|
910
|
+
\u793A\u4F8B:
|
|
911
|
+
yingmi-cli mcp call GetCurrentTime
|
|
912
|
+
yingmi-cli mcp call GuessFundCode --input '{"fundNameOrCode":"\u6613\u65B9\u8FBE\u84DD\u7B79\u7CBE\u9009"}'
|
|
913
|
+
yingmi-cli mcp call <toolName> --input '{"query":{"pageNum":1},"body":{"keyword":"\u65B0\u80FD\u6E90"}}'
|
|
914
|
+
`
|
|
915
|
+
).action(async (toolName, options) => {
|
|
885
916
|
const apiKey = requireApiKey();
|
|
886
917
|
const document = await fetchOpenApiDocument(apiKey);
|
|
887
918
|
const operation = getOperationByName(document, toolName);
|
|
@@ -933,10 +964,21 @@ function registerCallCommand(mcpCommand) {
|
|
|
933
964
|
}
|
|
934
965
|
|
|
935
966
|
function registerListCommand(mcpCommand) {
|
|
936
|
-
mcpCommand.command("list").description("\u5217\u51FA\u6240\u6709 MCP \u5DE5\u5177\u6458\u8981").
|
|
967
|
+
mcpCommand.command("list").description("\u5217\u51FA\u6240\u6709 MCP \u5DE5\u5177\u6458\u8981").addHelpText(
|
|
968
|
+
"after",
|
|
969
|
+
`
|
|
970
|
+
\u7528\u9014:
|
|
971
|
+
\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
|
|
972
|
+
|
|
973
|
+
\u4E0B\u4E00\u6B65:
|
|
974
|
+
1. \u4ECE\u8F93\u51FA\u91CC\u6311\u4E00\u4E2A toolName
|
|
975
|
+
2. \u6267\u884C yingmi-cli mcp schema <toolName> \u67E5\u770B\u53C2\u6570\u548C\u54CD\u5E94\u7ED3\u6784
|
|
976
|
+
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-cli remote-skill list
|
|
977
|
+
`
|
|
978
|
+
).action(async () => {
|
|
937
979
|
const apiKey = requireApiKey();
|
|
938
980
|
const document = await fetchOpenApiDocument(apiKey);
|
|
939
|
-
const operations =
|
|
981
|
+
const operations = listVisibleOperations(document);
|
|
940
982
|
console.log(
|
|
941
983
|
JSON.stringify(
|
|
942
984
|
operations.map((operation) => ({
|
|
@@ -954,7 +996,20 @@ function registerListCommand(mcpCommand) {
|
|
|
954
996
|
}
|
|
955
997
|
|
|
956
998
|
function registerSchemaCommand(mcpCommand) {
|
|
957
|
-
mcpCommand.command("schema").description("\u67E5\u770B\u67D0\u4E2A MCP \u5DE5\u5177\u7684\u5B8C\u6574 Schema").argument("<toolName>", "\u5DE5\u5177\u540D").
|
|
999
|
+
mcpCommand.command("schema").description("\u67E5\u770B\u67D0\u4E2A MCP \u5DE5\u5177\u7684\u5B8C\u6574 Schema").argument("<toolName>", "\u5DE5\u5177\u540D").addHelpText(
|
|
1000
|
+
"after",
|
|
1001
|
+
`
|
|
1002
|
+
\u5EFA\u8BAE:
|
|
1003
|
+
0. schema \u9002\u5408\u5728\u4F60\u5DF2\u7ECF\u786E\u5B9A\u8981\u8C03\u7528\u67D0\u4E2A\u539F\u5B50\u80FD\u529B\u65F6\u4F7F\u7528
|
|
1004
|
+
1. \u5148\u770B parameters\uFF0C\u786E\u8BA4 path/query/header \u7684\u5B57\u6BB5\u540D
|
|
1005
|
+
2. \u518D\u770B requestBody\uFF0C\u786E\u8BA4 body \u662F\u5426\u5FC5\u586B
|
|
1006
|
+
3. \u6700\u540E\u6267\u884C yingmi-cli mcp call <toolName> --input '<json>'
|
|
1007
|
+
|
|
1008
|
+
\u793A\u4F8B:
|
|
1009
|
+
yingmi-cli mcp schema GetCurrentTime
|
|
1010
|
+
yingmi-cli mcp schema GuessFundCode
|
|
1011
|
+
`
|
|
1012
|
+
).action(async (toolName) => {
|
|
958
1013
|
const apiKey = requireApiKey();
|
|
959
1014
|
const document = await fetchOpenApiDocument(apiKey);
|
|
960
1015
|
const operation = getOperationByName(document, toolName);
|
|
@@ -981,7 +1036,28 @@ function registerSchemaCommand(mcpCommand) {
|
|
|
981
1036
|
}
|
|
982
1037
|
|
|
983
1038
|
function registerMcpCommand(program) {
|
|
984
|
-
const mcpCommand = program.command("mcp").description("\u6D4F\u89C8
|
|
1039
|
+
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(
|
|
1040
|
+
"after",
|
|
1041
|
+
`
|
|
1042
|
+
\u7528\u9014:
|
|
1043
|
+
\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
|
|
1044
|
+
|
|
1045
|
+
\u63A8\u8350\u987A\u5E8F:
|
|
1046
|
+
1. yingmi-cli mcp list
|
|
1047
|
+
2. yingmi-cli mcp schema <toolName>
|
|
1048
|
+
3. yingmi-cli mcp call <toolName> --input '<json>'
|
|
1049
|
+
|
|
1050
|
+
\u8BF4\u660E:
|
|
1051
|
+
- 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
|
|
1052
|
+
- schema \u7528\u4E8E\u786E\u8BA4\u5B57\u6BB5\u540D\u3001\u53C2\u6570\u4F4D\u7F6E\u548C requestBody
|
|
1053
|
+
- call \u7684\u8F93\u5165\u662F JSON \u534F\u8BAE\uFF0C\u4E0D\u662F\u81EA\u7136\u8BED\u8A00 prompt
|
|
1054
|
+
- \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
|
|
1055
|
+
|
|
1056
|
+
\u6700\u5C0F\u6210\u529F\u793A\u4F8B:
|
|
1057
|
+
yingmi-cli mcp schema GetCurrentTime
|
|
1058
|
+
yingmi-cli mcp call GetCurrentTime
|
|
1059
|
+
`
|
|
1060
|
+
);
|
|
985
1061
|
registerListCommand(mcpCommand);
|
|
986
1062
|
registerSchemaCommand(mcpCommand);
|
|
987
1063
|
registerCallCommand(mcpCommand);
|
|
@@ -1083,7 +1159,7 @@ function validateRemoteSkillName(skillName) {
|
|
|
1083
1159
|
return normalizedName;
|
|
1084
1160
|
}
|
|
1085
1161
|
async function fetchRemoteSkillSummaries(apiKey) {
|
|
1086
|
-
const serverBaseUrl = normalizeServerBaseUrl(
|
|
1162
|
+
const serverBaseUrl = normalizeServerBaseUrl(getStargateBaseUrl());
|
|
1087
1163
|
const response = await axios.get(`${serverBaseUrl}/api/get-skills`, {
|
|
1088
1164
|
headers: buildRequestHeaders(apiKey),
|
|
1089
1165
|
timeout: REQUEST_TIMEOUT
|
|
@@ -1092,7 +1168,7 @@ async function fetchRemoteSkillSummaries(apiKey) {
|
|
|
1092
1168
|
}
|
|
1093
1169
|
async function prepareRemoteSkillContext(skillName, apiKey) {
|
|
1094
1170
|
const normalizedSkillName = validateRemoteSkillName(skillName);
|
|
1095
|
-
const serverBaseUrl = normalizeServerBaseUrl(
|
|
1171
|
+
const serverBaseUrl = normalizeServerBaseUrl(getStargateBaseUrl());
|
|
1096
1172
|
const detailResponse = await axios.get(
|
|
1097
1173
|
`${serverBaseUrl}/api/get-skill-by-name`,
|
|
1098
1174
|
{
|
|
@@ -1169,8 +1245,35 @@ function readScriptInput(options) {
|
|
|
1169
1245
|
}
|
|
1170
1246
|
}
|
|
1171
1247
|
function registerRemoteSkillCommand(program) {
|
|
1172
|
-
const remoteSkillCommand = program.command("remote-skill").description("\u67E5\u770B skill
|
|
1173
|
-
|
|
1248
|
+
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(
|
|
1249
|
+
"after",
|
|
1250
|
+
`
|
|
1251
|
+
\u7528\u9014:
|
|
1252
|
+
\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
|
|
1253
|
+
|
|
1254
|
+
\u63A8\u8350\u987A\u5E8F:
|
|
1255
|
+
1. yingmi-cli remote-skill list
|
|
1256
|
+
2. yingmi-cli remote-skill enter <skillName>
|
|
1257
|
+
3. yingmi-cli remote-skill exec --script 'cat SKILL.md'
|
|
1258
|
+
4. \u6309 skill \u8BF4\u660E\u6267\u884C\u5B9E\u9645\u811A\u672C\uFF0C\u4F8B\u5982:
|
|
1259
|
+
yingmi-cli remote-skill exec --script 'python main.py'
|
|
1260
|
+
|
|
1261
|
+
\u6CE8\u610F:
|
|
1262
|
+
- 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
|
|
1263
|
+
- \u4E00\u4E2A skill \u5185\u90E8\u53EF\u4EE5\u6309\u9700\u8C03\u7528\u4E00\u4E2A\u6216\u591A\u4E2A mcp
|
|
1264
|
+
- remote-skill exec \u6267\u884C\u7684\u662F shell \u811A\u672C\uFF0C\u4E0D\u662F\u81EA\u7136\u8BED\u8A00\u4EFB\u52A1
|
|
1265
|
+
- \u5EFA\u8BAE\u4F18\u5148\u9605\u8BFB skill \u5185\u7684 SKILL.md\uFF0C\u518D\u6267\u884C\u7EA6\u5B9A\u5165\u53E3
|
|
1266
|
+
`
|
|
1267
|
+
);
|
|
1268
|
+
remoteSkillCommand.command("list").description("\u5C55\u793A\u5F53\u524D\u652F\u6301\u7684\u91D1\u878D\u573A\u666F skill \u6458\u8981").addHelpText(
|
|
1269
|
+
"after",
|
|
1270
|
+
`
|
|
1271
|
+
\u4E0B\u4E00\u6B65:
|
|
1272
|
+
1. \u4ECE\u8F93\u51FA\u91CC\u6311\u4E00\u4E2A\u6700\u8D34\u8FD1\u5F53\u524D\u91D1\u878D\u573A\u666F\u4EFB\u52A1\u7684 skillName
|
|
1273
|
+
2. \u6267\u884C yingmi-cli remote-skill enter <skillName>
|
|
1274
|
+
3. \u518D\u6267\u884C yingmi-cli remote-skill exec --script 'cat SKILL.md'
|
|
1275
|
+
`
|
|
1276
|
+
).action(async () => {
|
|
1174
1277
|
try {
|
|
1175
1278
|
const apiKey = requireApiKey();
|
|
1176
1279
|
const skills = await fetchRemoteSkillSummaries(apiKey);
|
|
@@ -1179,7 +1282,21 @@ function registerRemoteSkillCommand(program) {
|
|
|
1179
1282
|
fail(error.message);
|
|
1180
1283
|
}
|
|
1181
1284
|
});
|
|
1182
|
-
remoteSkillCommand.command("enter").description("\u8FDB\u5165\u67D0\u4E2A skill \u4E0A\u4E0B\u6587\uFF0C\u5E76\u5C55\u793A\u76EE\u5F55\
|
|
1285
|
+
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(
|
|
1286
|
+
"after",
|
|
1287
|
+
`
|
|
1288
|
+
\u8BF4\u660E:
|
|
1289
|
+
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
|
|
1290
|
+
\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
|
|
1291
|
+
|
|
1292
|
+
\u793A\u4F8B:
|
|
1293
|
+
yingmi-cli remote-skill enter fund-analyst
|
|
1294
|
+
|
|
1295
|
+
\u4E0B\u4E00\u6B65:
|
|
1296
|
+
1. yingmi-cli remote-skill exec --script 'cat SKILL.md'
|
|
1297
|
+
2. \u6309 skill \u6587\u6863\u8BF4\u660E\u6267\u884C\u5165\u53E3\u811A\u672C
|
|
1298
|
+
`
|
|
1299
|
+
).action(async (skillName) => {
|
|
1183
1300
|
try {
|
|
1184
1301
|
const apiKey = requireApiKey();
|
|
1185
1302
|
const context = await prepareRemoteSkillContext(skillName, apiKey);
|
|
@@ -1192,7 +1309,21 @@ function registerRemoteSkillCommand(program) {
|
|
|
1192
1309
|
fail(error.message);
|
|
1193
1310
|
}
|
|
1194
1311
|
});
|
|
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").
|
|
1312
|
+
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(
|
|
1313
|
+
"after",
|
|
1314
|
+
`
|
|
1315
|
+
\u6CE8\u610F:
|
|
1316
|
+
1. \u8FD9\u91CC\u6267\u884C\u7684\u662F shell \u811A\u672C\uFF0C\u4E0D\u662F\u81EA\u7136\u8BED\u8A00 prompt
|
|
1317
|
+
2. \u5EFA\u8BAE\u4F18\u5148\u9605\u8BFB skill \u5185\u7684 SKILL.md\uFF0C\u6309 skill \u7EA6\u5B9A\u6267\u884C\u811A\u672C
|
|
1318
|
+
3. skill \u5728\u6267\u884C\u8FC7\u7A0B\u4E2D\u53EF\u80FD\u4F1A\u7EE7\u7EED\u8C03\u7528\u4E00\u4E2A\u6216\u591A\u4E2A mcp
|
|
1319
|
+
4. \u5BF9\u4E8E Python skill\uFF0C\u4F18\u5148\u4F7F\u7528 python \u547D\u4EE4\u6267\u884C\u5165\u53E3\u811A\u672C
|
|
1320
|
+
|
|
1321
|
+
\u793A\u4F8B:
|
|
1322
|
+
yingmi-cli remote-skill exec --script 'cat SKILL.md'
|
|
1323
|
+
yingmi-cli remote-skill exec --script 'python main.py'
|
|
1324
|
+
yingmi-cli remote-skill exec --script-file ./scripts/run.sh
|
|
1325
|
+
`
|
|
1326
|
+
).action(async (options) => {
|
|
1196
1327
|
try {
|
|
1197
1328
|
if (options.script && options.scriptFile) {
|
|
1198
1329
|
fail("--script \u548C --script-file \u4E0D\u80FD\u540C\u65F6\u4F7F\u7528");
|
|
@@ -1215,7 +1346,6 @@ function registerRemoteSkillCommand(program) {
|
|
|
1215
1346
|
JSON.stringify(
|
|
1216
1347
|
{
|
|
1217
1348
|
skillName: currentSession.skillName,
|
|
1218
|
-
workingDirectory: currentSession.workingDirectory,
|
|
1219
1349
|
execution
|
|
1220
1350
|
},
|
|
1221
1351
|
null,
|
|
@@ -1319,7 +1449,22 @@ async function checkAndUpdate(checkOnly = false) {
|
|
|
1319
1449
|
}
|
|
1320
1450
|
|
|
1321
1451
|
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").
|
|
1452
|
+
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(
|
|
1453
|
+
"after",
|
|
1454
|
+
`
|
|
1455
|
+
\u7528\u9014:
|
|
1456
|
+
\u68C0\u67E5 CLI \u662F\u5426\u6709\u65B0\u7248\u672C\uFF0C\u5E76\u5728\u9700\u8981\u65F6\u6267\u884C\u5347\u7EA7\u3002
|
|
1457
|
+
|
|
1458
|
+
\u793A\u4F8B:
|
|
1459
|
+
yingmi-cli upgrade --check-only
|
|
1460
|
+
yingmi-cli upgrade
|
|
1461
|
+
|
|
1462
|
+
\u8BF4\u660E:
|
|
1463
|
+
- --check-only \u53EA\u68C0\u67E5\u7248\u672C\uFF0C\u4E0D\u6267\u884C\u5B89\u88C5
|
|
1464
|
+
- \u771F\u6B63\u5347\u7EA7\u524D\u5E94\u660E\u786E\u4E86\u89E3\u526F\u4F5C\u7528
|
|
1465
|
+
- \u975E\u4EA4\u4E92\u73AF\u5883\u4E0B\u4E0D\u5E94\u4F9D\u8D56\u786E\u8BA4\u8F93\u5165
|
|
1466
|
+
`
|
|
1467
|
+
).action(async (options) => {
|
|
1323
1468
|
try {
|
|
1324
1469
|
await checkAndUpdate(Boolean(options.checkOnly));
|
|
1325
1470
|
} catch (error) {
|
|
@@ -1340,6 +1485,31 @@ function createProgram() {
|
|
|
1340
1485
|
registerHelpCommand(program);
|
|
1341
1486
|
registerUpgradeCommand(program);
|
|
1342
1487
|
program.showHelpAfterError("(\u4F7F\u7528 --help \u67E5\u770B\u547D\u4EE4\u5E2E\u52A9)");
|
|
1488
|
+
program.addHelpText(
|
|
1489
|
+
"after",
|
|
1490
|
+
`
|
|
1491
|
+
\u5E38\u89C1\u4EFB\u52A1:
|
|
1492
|
+
\u9996\u6B21\u914D\u7F6E CLI yingmi-cli help init
|
|
1493
|
+
\u76F4\u63A5\u8C03\u7528\u539F\u5B50\u91D1\u878D\u80FD\u529B yingmi-cli help mcp
|
|
1494
|
+
\u5B8C\u6210\u57FA\u91D1\u6216\u8D22\u5BCC\u573A\u666F\u4EFB\u52A1 yingmi-cli help remote-skill
|
|
1495
|
+
\u67E5\u770B\u67D0\u4E2A\u547D\u4EE4\u7684\u8BE6\u7EC6\u5E2E\u52A9 yingmi-cli help <command...>
|
|
1496
|
+
\u68C0\u67E5\u6216\u5347\u7EA7\u7248\u672C yingmi-cli help upgrade
|
|
1497
|
+
|
|
1498
|
+
\u5FEB\u901F\u5F00\u59CB:
|
|
1499
|
+
1. yingmi-cli init setup
|
|
1500
|
+
2. \u5982\u679C\u8981\u76F4\u63A5\u8C03\u7528\u5355\u4E2A\u80FD\u529B\uFF0C\u6267\u884C yingmi-cli mcp list
|
|
1501
|
+
3. \u5982\u679C\u8981\u5B8C\u6210\u91D1\u878D\u573A\u666F\u4EFB\u52A1\uFF0C\u6267\u884C yingmi-cli remote-skill list
|
|
1502
|
+
4. \u5BF9\u4E8E mcp\uFF0C\u7EE7\u7EED\u6267\u884C yingmi-cli mcp schema <toolName>
|
|
1503
|
+
5. \u5BF9\u4E8E mcp\uFF0C\u6267\u884C yingmi-cli mcp call <toolName> --input '<json>'
|
|
1504
|
+
|
|
1505
|
+
\u534F\u8BAE\u63D0\u793A:
|
|
1506
|
+
- \u7ED3\u6784\u5316\u7ED3\u679C\u8F93\u51FA\u5230 stdout
|
|
1507
|
+
- \u63D0\u793A\u3001\u544A\u8B66\u548C\u9519\u8BEF\u8F93\u51FA\u5230 stderr
|
|
1508
|
+
- \u4F18\u5148\u4F7F\u7528\u975E\u4EA4\u4E92\u53C2\u6570\uFF0C\u4FBF\u4E8E\u811A\u672C\u548C Agent \u8C03\u7528
|
|
1509
|
+
- mcp \u7528\u4E8E\u539F\u5B50\u80FD\u529B\u8C03\u7528\uFF0Cremote-skill \u7528\u4E8E\u91D1\u878D\u573A\u666F\u7F16\u6392
|
|
1510
|
+
- \u8C03\u7528 mcp \u524D\u5EFA\u8BAE\u5148\u67E5\u770B schema \u786E\u8BA4\u8F93\u5165\u5B57\u6BB5
|
|
1511
|
+
`
|
|
1512
|
+
);
|
|
1343
1513
|
return program;
|
|
1344
1514
|
}
|
|
1345
1515
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yingmi-skill-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
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
|
+
}
|