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.
Files changed (3) hide show
  1. package/README.md +71 -55
  2. package/bin/index.js +453 -157
  3. 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`:浏览 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 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 并进入 skill 上下文工作”。
113
+ `remote-skill` 面向远端 skill 运行服务,核心是“发现 skill、进入 skill 上下文,并按 skill 协议完成金融场景任务”。
105
114
 
106
115
  常用命令:
107
116
 
108
117
  ```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
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
- - `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`
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
- - 每个命令帮助都应包含 2 到 3 个最常见示例
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. `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`。
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.2";
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
- 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-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 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
 
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 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
  }
@@ -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 getRemoteSkillServerBaseUrl() {
123
- const configuredBaseUrl = readConfig().remoteSkillServerBaseUrl?.trim();
124
- return configuredBaseUrl || DEFAULT_REMOTE_SKILL_SERVER_BASE_URL;
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
- 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
- });
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 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;
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 browser = await puppeteer.launch({
340
- executablePath: resolveExecutablePath(options.executablePath),
341
- headless: options.headless ?? true,
342
- args: ["--no-sandbox", "--disable-setuid-sandbox"]
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
- 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();
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("\u672A\u627E\u5230\u9A8C\u8BC1\u7801\u767B\u5F55\u4E0A\u4E0B\u6587\uFF0C\u8BF7\u5148\u6267\u884C: yingmi-cli init setup --phone <\u624B\u673A\u53F7>");
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("\u7533\u8BF7\u4E0A\u4E0B\u6587\u7F3A\u5C11\u767B\u5F55 token\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C: yingmi-cli init setup --phone <\u624B\u673A\u53F7>");
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 remoteSkillServerBaseUrl = options.remoteSkillServerBaseUrl?.trim();
519
+ const stargateBaseUrl = options.stargateBaseUrl?.trim();
541
520
  const qiemanBaseUrl = options.qiemanBaseUrl?.trim();
542
- if (!remoteSkillServerBaseUrl && !qiemanBaseUrl) {
521
+ if (!stargateBaseUrl && !qiemanBaseUrl) {
543
522
  return;
544
523
  }
545
524
  writeConfig({
546
525
  ...readConfig(),
547
- ...remoteSkillServerBaseUrl ? { remoteSkillServerBaseUrl } : {},
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.remoteSkillServerBaseUrl?.trim();
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("`--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");
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").action(() => {
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
- 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) => {
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").action(() => {
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\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"
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").action(async (toolName, options) => {
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").action(async () => {
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 = listOperations(document);
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").action(async (toolName) => {
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 MCP \u6458\u8981\u3001\u67E5\u770B Schema \u5E76\u8C03\u7528\u5DE5\u5177");
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(getRemoteSkillServerBaseUrl());
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(getRemoteSkillServerBaseUrl());
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 \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 () => {
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 fetchRemoteSkillSummaries(apiKey);
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\u548C\u6587\u4EF6\u7ED3\u6784").argument("<skillName>", "skill \u540D\u79F0").action(async (skillName) => {
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 context = await prepareRemoteSkillContext(skillName, apiKey);
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").action(async (options) => {
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").action(async (options) => {
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.2",
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
  }