rushangle-cli 0.4.0 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rushangle-cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "SkillHub CLI - 数智凯航技能市场命令行工具",
5
5
  "bin": {
6
6
  "rushangle": "./bin/rushangle.js"
package/src/api.js CHANGED
@@ -100,18 +100,19 @@ module.exports = {
100
100
  installedCli() { return apiCall('GET', '/api/cli/installed'); },
101
101
  myCli() { return apiCall('GET', '/api/cli/my'); },
102
102
 
103
- // CLI file upload
103
+ // CLI file upload (native FormData — compatible with backend busboy/multer)
104
104
  async uploadCliFiles(cliId, files) {
105
105
  const token = auth.getToken();
106
- const FormData = require('form-data');
107
106
  const form = new FormData();
108
107
  for (const { fieldName, filePath } of files) {
109
- form.append(fieldName, fs.createReadStream(filePath), path.basename(filePath));
108
+ const content = fs.readFileSync(filePath);
109
+ const blob = new Blob([content], { type: 'application/octet-stream' });
110
+ form.append(fieldName, blob, path.basename(filePath));
110
111
  }
111
112
 
112
113
  const res = await fetch(`${SITE_URL}/api/cli/${encodeURIComponent(cliId)}/files`, {
113
114
  method: 'POST',
114
- headers: { ...form.getHeaders(), 'Authorization': `Bearer ${token}` },
115
+ headers: { 'Authorization': `Bearer ${token}` },
115
116
  body: form,
116
117
  });
117
118
 
@@ -2,12 +2,43 @@ const { Command } = require('commander');
2
2
  const chalk = require('chalk');
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
+ const os = require('os');
5
6
  const readline = require('readline');
6
7
  const auth = require('../auth');
7
8
  const api = require('../api');
8
9
 
9
10
  const VALID_TYPES = ['skill', 'mcp', 'code', 'doc', 'cli'];
10
11
 
12
+ const EXCLUDED_DIRS = ['.git', 'node_modules', 'dist', 'build', 'coverage', '.DS_Store', '._', 'rushangle-cli'];
13
+
14
+ /**
15
+ * Zip a project directory (excluding common build/dependency dirs).
16
+ */
17
+ function zipProject(dir, destPath) {
18
+ const AdmZip = require('adm-zip');
19
+ const zip = new AdmZip();
20
+
21
+ function walk(currentDir, zipPrefix) {
22
+ const entries = fs.readdirSync(currentDir, { withFileTypes: true });
23
+ for (const entry of entries) {
24
+ if (EXCLUDED_DIRS.some(e => entry.name === e || entry.name.startsWith(e))) continue;
25
+
26
+ const fullPath = path.join(currentDir, entry.name);
27
+ const zipEntryPath = zipPrefix ? path.join(zipPrefix, entry.name) : entry.name;
28
+
29
+ if (entry.isDirectory()) {
30
+ walk(fullPath, zipEntryPath);
31
+ } else {
32
+ zip.addFile(zipEntryPath, fs.readFileSync(fullPath));
33
+ }
34
+ }
35
+ }
36
+
37
+ walk(dir, '');
38
+ zip.writeZip(destPath);
39
+ return destPath;
40
+ }
41
+
11
42
  /**
12
43
  * Simple YAML frontmatter parser for SKILL.md.
13
44
  * Extracts key-value pairs from --- delimited frontmatter block.
@@ -181,7 +212,7 @@ module.exports = new Command('publish')
181
212
  name, version, description, category, tags, readme,
182
213
  });
183
214
 
184
- // Upload skill files (SKILL.md + scripts)
215
+ // Upload skill files: SKILL.md + scripts + full project zip
185
216
  try {
186
217
  const uploadFiles = [];
187
218
 
@@ -206,10 +237,17 @@ module.exports = new Command('publish')
206
237
  }
207
238
  }
208
239
 
240
+ // Package entire project directory as a zip for full file support (lib/, root files, etc.)
241
+ const zipPath = path.join(os.tmpdir(), `skill-${result.id}-${Date.now()}.zip`);
242
+ zipProject(absDir, zipPath);
243
+ uploadFiles.push({ fieldName: 'skill_zip', filePath: zipPath });
244
+
209
245
  if (uploadFiles.length > 0) {
210
- console.log(chalk.gray(` 上传 ${uploadFiles.length} 个文件...`));
246
+ console.log(chalk.gray(` 上传 ${uploadFiles.length} 个文件(含项目 zip 包)...`));
211
247
  await api.uploadSkillFiles(result.id, uploadFiles);
212
248
  console.log(chalk.green(` ✓ 文件上传完成`));
249
+ // Clean up temp zip file
250
+ try { fs.unlinkSync(zipPath); } catch { /* ignore */ }
213
251
  }
214
252
  } catch (uploadErr) {
215
253
  console.log(chalk.yellow(` ⚠ 文件上传失败: ${uploadErr.message}`));