byteplan-cli 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,14 +43,55 @@ byteplan model columns <modelCode>
43
43
  byteplan data query <modelCode>
44
44
  ```
45
45
 
46
- ### Dimension & LOV Commands
46
+ ### Skills Commands
47
+
48
+ BytePlan CLI 提供了一系列 Claude Code Skills,可以安装到多个 AI CLI 平台。
49
+
50
+ ### 查看可用 Skills
51
+
52
+ ```bash
53
+ byteplan skills list
54
+ ```
55
+
56
+ ### 安装 Skills
57
+
58
+ 支持多平台安装,使用 `-p` 或 `--platform` 参数指定目标平台:
59
+
60
+ ```bash
61
+ # 安装到 Claude Code
62
+ byteplan skills install byteplan-api -p claude-code
63
+
64
+ # 安装到多个平台
65
+ byteplan skills install -p claude-code,codex,openclaw
66
+
67
+ # 安装所有 Skills
68
+ byteplan skills install-all -p claude-code
69
+ ```
70
+
71
+ ### 支持的平台
72
+
73
+ | Platform | 目录 | 说明 |
74
+ |----------|------|------|
75
+ | `claude-code` (alias: `claude`) | `~/.claude/commands` | Claude Code CLI |
76
+ | `codex` | `~/.codex` | OpenAI Codex CLI |
77
+ | `openclaw` | `~/.openclaw/skills` | OpenClaw |
78
+
79
+ ### 自定义目录
80
+
81
+ 也可以使用 `-d` 参数指定自定义目录:
47
82
 
48
83
  ```bash
49
- # Get dimension values
50
- byteplan dim <dimCode>
84
+ # 向后兼容:指定自定义目录
85
+ byteplan skills install byteplan-api -d ~/.claude/commands
86
+
87
+ # 组合使用:覆盖平台默认目录
88
+ byteplan skills install byteplan-api -p claude-code -d /custom/path
89
+ ```
51
90
 
52
- # Get LOV values
53
- byteplan lov <lovCode>
91
+ ### 查看已安装 Skills
92
+
93
+ ```bash
94
+ byteplan skills installed -p claude-code
54
95
  ```
55
96
 
56
97
  ## Options
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "byteplan-cli",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "BytePlan CLI - Command line tool for BytePlan API",
5
5
  "keywords": [
6
6
  "byteplan",
package/src/cli.js CHANGED
@@ -246,13 +246,15 @@ dataCmd
246
246
  pageSize: parseInt(options.size),
247
247
  });
248
248
 
249
+ // result.data 可能是数组(直接数据)或对象(包含 data 子字段)
250
+ const rows = Array.isArray(result.data) ? result.data : (result.data?.data || []);
249
251
  printJSON({
250
- headers: result.data?.headers || [],
251
- data: result.data?.data || [],
252
+ headers: result.headers || result.data?.headers || [],
253
+ data: rows,
252
254
  pagination: {
253
- pageNum: result.data?.pageNum || parseInt(options.page),
254
- pageSize: result.data?.pageSize || parseInt(options.size),
255
- total: result.data?.total || 0,
255
+ pageNum: result.pageNum || result.data?.pageNum || parseInt(options.page),
256
+ pageSize: result.pageSize || result.data?.pageSize || parseInt(options.size),
257
+ total: result.total || result.data?.total || 0,
256
258
  },
257
259
  });
258
260
  } catch (error) {
@@ -12,6 +12,14 @@ import { createRequire } from 'module';
12
12
 
13
13
  const require = createRequire(import.meta.url);
14
14
 
15
+ // 平台默认目录映射
16
+ const PLATFORM_DIRS = {
17
+ 'claude-code': path.join(homedir(), '.claude', 'commands'),
18
+ 'claude': path.join(homedir(), '.claude', 'commands'), // alias
19
+ 'codex': path.join(homedir(), '.codex'),
20
+ 'openclaw': path.join(homedir(), '.openclaw', 'skills'),
21
+ };
22
+
15
23
  // Skills 源目录(在 npm 包中)
16
24
  const getSkillsSourceDir = () => {
17
25
  // 获取当前模块所在目录,然后向上找到项目根目录
@@ -20,10 +28,47 @@ const getSkillsSourceDir = () => {
20
28
  return path.join(currentDir, '..', '..', 'skills');
21
29
  };
22
30
 
23
- // Skills 默认目标目录(仅用于提示)
24
- const getDefaultSkillsTargetDir = () => {
25
- return path.join(homedir(), '.claude', 'skills');
26
- };
31
+ // 解析平台和目录参数,返回目标目录列表
32
+ function resolveTargetDirs(platformArg, dirArg) {
33
+ const targets = [];
34
+
35
+ if (platformArg) {
36
+ // 解析平台列表(逗号分隔)
37
+ const platforms = platformArg.split(',').map(p => p.trim());
38
+
39
+ for (const platform of platforms) {
40
+ const normalizedName = platform.toLowerCase();
41
+ const defaultDir = PLATFORM_DIRS[normalizedName];
42
+
43
+ if (!defaultDir) {
44
+ return {
45
+ error: true,
46
+ message: `Unknown platform: ${platform}`,
47
+ available: Object.keys(PLATFORM_DIRS).filter(k => !k.includes('-')),
48
+ };
49
+ }
50
+
51
+ targets.push({
52
+ platform: normalizedName,
53
+ targetDir: dirArg || defaultDir, // 如果指定了 -d,覆盖所有平台的默认目录
54
+ });
55
+ }
56
+ } else if (dirArg) {
57
+ // 向后兼容:只指定 -d 的情况
58
+ targets.push({
59
+ platform: 'custom',
60
+ targetDir: dirArg,
61
+ });
62
+ } else {
63
+ // 都不指定,返回错误
64
+ return {
65
+ error: true,
66
+ message: 'Must specify at least one of --platform or --dir',
67
+ };
68
+ }
69
+
70
+ return { targets };
71
+ }
27
72
 
28
73
  function printJSON(data) {
29
74
  console.log(JSON.stringify(data, null, 2));
@@ -108,20 +153,28 @@ function getInstalledSkills(targetDir) {
108
153
  // Skills 命令
109
154
  const skillsCmd = new Command('skills')
110
155
  .description('Manage BytePlan Claude Code skills')
111
- .requiredOption('-d, --dir <directory>', 'Target installation directory (required)')
156
+ .option('-d, --dir <directory>', 'Target installation directory (overrides platform default)')
157
+ .option('-p, --platform <platforms>', 'Target platform(s): claude-code, codex, openclaw (comma-separated for multiple)')
112
158
  .addHelpText('after', `
113
159
  Commands:
114
160
  skills list List all available skills
115
- skills installed List installed skills (requires -d)
116
- skills install [names] Install skills to target directory (requires -d)
117
- skills install-all Install all BytePlan skills (requires -d)
161
+ skills installed List installed skills (requires -p or -d)
162
+ skills install [names] Install skills (requires -p or -d)
163
+ skills install-all Install all BytePlan skills (requires -p or -d)
164
+
165
+ Supported Platforms:
166
+ claude-code (alias: claude) → ~/.claude/commands
167
+ codex → ~/.codex
168
+ openclaw → ~/.openclaw/skills
118
169
 
119
170
  Examples:
120
171
  $ byteplan skills list
121
- $ byteplan skills installed -d ~/.claude/skills
122
- $ byteplan skills install byteplan-api byteplan-analysis -d ~/.claude/skills
123
- $ byteplan skills install-all -d ~/.claude/skills
124
- $ byteplan skills install-all -d /custom/path/skills
172
+ $ byteplan skills installed -p claude-code
173
+ $ byteplan skills install byteplan-api -p claude-code
174
+ $ byteplan skills install byteplan-api byteplan-analysis -p claude-code,codex
175
+ $ byteplan skills install-all -p claude-code,openclaw
176
+ $ byteplan skills install byteplan-api -d ~/.claude/commands
177
+ $ byteplan skills install byteplan-api -p claude-code -d /custom/path
125
178
  `);
126
179
 
127
180
  // skills list 子命令
@@ -151,18 +204,32 @@ skillsCmd
151
204
  .description('List installed BytePlan skills in target directory')
152
205
  .action(() => {
153
206
  try {
154
- // 获取父命令的 -d 选项(requiredOption 已确保必传)
155
207
  const parentOptions = skillsCmd.opts();
156
- const targetDir = parentOptions.dir;
157
- const skills = getInstalledSkills(targetDir);
208
+ const platformArg = parentOptions.platform;
209
+ const dirArg = parentOptions.dir;
210
+
211
+ const resolved = resolveTargetDirs(platformArg, dirArg);
212
+ if (resolved.error) {
213
+ printJSON(resolved);
214
+ process.exit(1);
215
+ }
216
+
217
+ const results = {};
218
+ for (const target of resolved.targets) {
219
+ const skills = getInstalledSkills(target.targetDir);
220
+ results[target.platform] = {
221
+ targetDir: target.targetDir,
222
+ skills: skills.map(s => ({
223
+ name: s.name,
224
+ description: s.description,
225
+ })),
226
+ count: skills.length,
227
+ };
228
+ }
158
229
 
159
230
  printJSON({
160
- skills: skills.map(s => ({
161
- name: s.name,
162
- description: s.description,
163
- })),
164
- total: skills.length,
165
- targetDir: targetDir,
231
+ platforms: results,
232
+ totalPlatforms: resolved.targets.length,
166
233
  });
167
234
  } catch (error) {
168
235
  printError(error);
@@ -176,22 +243,26 @@ skillsCmd
176
243
  .option('-a, --all', 'Install all BytePlan skills', false)
177
244
  .addHelpText('after', `
178
245
  Examples:
179
- $ byteplan skills install byteplan-api byteplan-analysis -d ~/.claude/skills
180
- $ byteplan skills install --all -d ~/.claude/skills
181
- $ byteplan skills install byteplan-api -d /custom/path/skills
246
+ $ byteplan skills install byteplan-api -p claude-code
247
+ $ byteplan skills install byteplan-api byteplan-analysis -p claude-code,codex
248
+ $ byteplan skills install --all -p claude-code
249
+ $ byteplan skills install byteplan-api -d ~/.claude/commands
250
+ $ byteplan skills install byteplan-api -p claude-code -d /custom/path
182
251
  `)
183
252
  .action(async (names, options) => {
184
253
  try {
185
- // 获取父命令的 -d 选项(requiredOption 已确保必传)
186
254
  const parentOptions = skillsCmd.opts();
187
- const targetDir = parentOptions.dir;
188
- const sourceDir = getSkillsSourceDir();
255
+ const platformArg = parentOptions.platform;
256
+ const dirArg = parentOptions.dir;
189
257
 
190
- // 确保目标目录存在
191
- if (!existsSync(targetDir)) {
192
- mkdirSync(targetDir, { recursive: true });
258
+ const resolved = resolveTargetDirs(platformArg, dirArg);
259
+ if (resolved.error) {
260
+ printJSON(resolved);
261
+ process.exit(1);
193
262
  }
194
263
 
264
+ const sourceDir = getSkillsSourceDir();
265
+
195
266
  // 获取要安装的 skills
196
267
  let toInstall = names || [];
197
268
  if (options.all || toInstall.length === 0) {
@@ -213,22 +284,39 @@ Examples:
213
284
  process.exit(1);
214
285
  }
215
286
 
216
- // 安装 skills
217
- const installed = [];
218
- for (const skillName of toInstall) {
219
- const skillSourcePath = path.join(sourceDir, skillName);
220
- const skillTargetPath = path.join(targetDir, skillName);
221
-
222
- // 复制 skill 目录
223
- cpSync(skillSourcePath, skillTargetPath, { recursive: true });
224
- installed.push(skillName);
287
+ // 安装到各目标目录
288
+ const results = {};
289
+ for (const target of resolved.targets) {
290
+ const targetDir = target.targetDir;
291
+
292
+ // 确保目标目录存在
293
+ if (!existsSync(targetDir)) {
294
+ mkdirSync(targetDir, { recursive: true });
295
+ }
296
+
297
+ // 安装 skills
298
+ const installed = [];
299
+ for (const skillName of toInstall) {
300
+ const skillSourcePath = path.join(sourceDir, skillName);
301
+ const skillTargetPath = path.join(targetDir, skillName);
302
+
303
+ // 复制 skill 目录
304
+ cpSync(skillSourcePath, skillTargetPath, { recursive: true });
305
+ installed.push(skillName);
306
+ }
307
+
308
+ results[target.platform] = {
309
+ targetDir: targetDir,
310
+ installed: installed,
311
+ count: installed.length,
312
+ };
225
313
  }
226
314
 
227
315
  printJSON({
228
316
  success: true,
229
- installed: installed,
230
- total: installed.length,
231
- targetDir: targetDir,
317
+ platforms: results,
318
+ totalPlatforms: resolved.targets.length,
319
+ totalSkills: toInstall.length,
232
320
  });
233
321
  } catch (error) {
234
322
  printError(error);
@@ -241,35 +329,55 @@ skillsCmd
241
329
  .description('Install all BytePlan skills to target directory')
242
330
  .action(async () => {
243
331
  try {
244
- // 获取父命令的 -d 选项(requiredOption 已确保必传)
245
332
  const parentOptions = skillsCmd.opts();
246
- const targetDir = parentOptions.dir;
247
- const sourceDir = getSkillsSourceDir();
333
+ const platformArg = parentOptions.platform;
334
+ const dirArg = parentOptions.dir;
248
335
 
249
- // 确保目标目录存在
250
- if (!existsSync(targetDir)) {
251
- mkdirSync(targetDir, { recursive: true });
336
+ const resolved = resolveTargetDirs(platformArg, dirArg);
337
+ if (resolved.error) {
338
+ printJSON(resolved);
339
+ process.exit(1);
252
340
  }
253
341
 
342
+ const sourceDir = getSkillsSourceDir();
343
+
254
344
  // 获取所有 skills
255
345
  const availableSkills = getAvailableSkills();
256
-
257
- // 安装所有 skills
258
- const installed = [];
259
- for (const skill of availableSkills) {
260
- const skillSourcePath = path.join(sourceDir, skill.name);
261
- const skillTargetPath = path.join(targetDir, skill.name);
262
-
263
- // 复制 skill 目录
264
- cpSync(skillSourcePath, skillTargetPath, { recursive: true });
265
- installed.push(skill.name);
346
+ const toInstall = availableSkills.map(s => s.name);
347
+
348
+ // 安装到各目标目录
349
+ const results = {};
350
+ for (const target of resolved.targets) {
351
+ const targetDir = target.targetDir;
352
+
353
+ // 确保目标目录存在
354
+ if (!existsSync(targetDir)) {
355
+ mkdirSync(targetDir, { recursive: true });
356
+ }
357
+
358
+ // 安装所有 skills
359
+ const installed = [];
360
+ for (const skillName of toInstall) {
361
+ const skillSourcePath = path.join(sourceDir, skillName);
362
+ const skillTargetPath = path.join(targetDir, skillName);
363
+
364
+ // 复制 skill 目录
365
+ cpSync(skillSourcePath, skillTargetPath, { recursive: true });
366
+ installed.push(skillName);
367
+ }
368
+
369
+ results[target.platform] = {
370
+ targetDir: targetDir,
371
+ installed: installed,
372
+ count: installed.length,
373
+ };
266
374
  }
267
375
 
268
376
  printJSON({
269
377
  success: true,
270
- installed: installed,
271
- total: installed.length,
272
- targetDir: targetDir,
378
+ platforms: results,
379
+ totalPlatforms: resolved.targets.length,
380
+ totalSkills: toInstall.length,
273
381
  });
274
382
  } catch (error) {
275
383
  printError(error);