yingmi-skill-cli 0.0.1 → 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.
Files changed (3) hide show
  1. package/README.md +64 -55
  2. package/bin/index.js +312 -142
  3. 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`:浏览 MCP 摘要、查看某个工具的完整 OpenAPI 定义,并发起工具调用
21
- - `remote-skill`:列出可用 skill,进入某个 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 并进入 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 'node index.js'
112
- yingmi-cli remote-skill exec --script-file ./scripts/run.sh
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>` 后输出本地工作目录和文件清单,并把当前 skill 上下文写入本地配置
119
- - `exec --script/--script-file`:只能在最近一次成功 `enter` 后使用,在当前 skill 目录执行脚本,并输出执行状态、退出码、stdout 和 stderr
120
- - 远端服务地址默认读取 `https://stargate-staging.yingmi-inc.com/`,也可在 `~/.yingmi-cli/config.json` 里手工设置 `remoteSkillServerBaseUrl`
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
- - 每个命令帮助都应包含 2 到 3 个最常见示例
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. `yingmi-cli mcp list` 浏览可用工具。
172
- 3. `yingmi-cli mcp schema <toolName>` 查看完整定义。
173
- 4. `yingmi-cli mcp call <toolName>` 发起调用。
174
- 5. 需要处理远端 skill 时,先用 `yingmi-cli remote-skill list` 发现 skill,再用 `yingmi-cli remote-skill enter <skillName>` 刷新并查看目录,最后用 `yingmi-cli remote-skill exec` 在该上下文执行脚本。
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
13
  var name = "yingmi-cli";
15
- var version = "0.0.10";
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
- pathSegments.forEach((segment) => {
25
- current = current?.commands.find((command) => command.name() === segment);
26
- });
27
- return current;
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").action((commandPath) => {
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 targetCommand = resolveCommand(program, commandPath);
36
- if (!targetCommand) {
37
- fail(`\u672A\u627E\u5230\u547D\u4EE4: ${commandPath.join(" ")}`);
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
- targetCommand.outputHelp();
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 DEFAULT_REMOTE_SKILL_SERVER_BASE_URL = "https://stargate-staging.yingmi-inc.com/";
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 getRemoteSkillServerBaseUrl() {
123
- const configuredBaseUrl = readConfig().remoteSkillServerBaseUrl?.trim();
124
- return configuredBaseUrl || DEFAULT_REMOTE_SKILL_SERVER_BASE_URL;
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
- function getHeaderValue(headers, headerName) {
257
- const expectedHeaderName = headerName.toLowerCase();
258
- const matchedEntry = Object.entries(headers).find(
259
- ([currentHeaderName]) => currentHeaderName.toLowerCase() === expectedHeaderName
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
- 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
- }
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 browser = await puppeteer.launch({
340
- executablePath: resolveExecutablePath(options.executablePath),
341
- headless: options.headless ?? true,
342
- args: ["--no-sandbox", "--disable-setuid-sandbox"]
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
- try {
345
- const page = await browser.newPage();
346
- const firstFetchRequestPromise = waitForFirstFetchRequest(page, timeoutMs);
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 remoteSkillServerBaseUrl = options.remoteSkillServerBaseUrl?.trim();
498
+ const stargateBaseUrl = options.stargateBaseUrl?.trim();
541
499
  const qiemanBaseUrl = options.qiemanBaseUrl?.trim();
542
- if (!remoteSkillServerBaseUrl && !qiemanBaseUrl) {
500
+ if (!stargateBaseUrl && !qiemanBaseUrl) {
543
501
  return;
544
502
  }
545
503
  writeConfig({
546
504
  ...readConfig(),
547
- ...remoteSkillServerBaseUrl ? { remoteSkillServerBaseUrl } : {},
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.remoteSkillServerBaseUrl?.trim();
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("`--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");
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").action(() => {
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
- new commander.Option("--remote-skill-server-base-url <value>", "\u8986\u76D6 remote-skill \u670D\u52A1\u57FA\u5730\u5740").hideHelp()
585
- ).addOption(new commander.Option("--qieman-base-url <value>", "\u8986\u76D6\u4E14\u6162\u670D\u52A1\u57FA\u5730\u5740").hideHelp()).action(async (options) => {
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").action(() => {
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").action(async (toolName, options) => {
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").action(async () => {
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 = listOperations(document);
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").action(async (toolName) => {
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 MCP \u6458\u8981\u3001\u67E5\u770B Schema \u5E76\u8C03\u7528\u5DE5\u5177");
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(getRemoteSkillServerBaseUrl());
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(getRemoteSkillServerBaseUrl());
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 \u6458\u8981\uFF0C\u5E76\u8FDB\u5165\u67D0\u4E2A skill \u4E0A\u4E0B\u6587");
1173
- remoteSkillCommand.command("list").description("\u5C55\u793A\u5F53\u524D\u652F\u6301\u7684 skill \u6458\u8981").action(async () => {
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\u548C\u6587\u4EF6\u7ED3\u6784").argument("<skillName>", "skill \u540D\u79F0").action(async (skillName) => {
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").action(async (options) => {
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").action(async (options) => {
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.1",
3
+ "version": "0.0.6",
4
4
  "author": "yingmi",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -8,11 +8,12 @@
8
8
  "README.md"
9
9
  ],
10
10
  "bin": {
11
- "yingmi-cli": "bin/index.js"
11
+ "yingmi-skill-cli": "bin/index.js"
12
12
  },
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
  }