rushangle-cli 0.2.1 → 0.2.3
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 +1 -1
- package/src/commands/install.js +60 -3
package/package.json
CHANGED
package/src/commands/install.js
CHANGED
|
@@ -11,7 +11,7 @@ const INSTALL_DIR = path.join(os.homedir(), '.workbuddy', 'skills');
|
|
|
11
11
|
module.exports = new Command('install')
|
|
12
12
|
.description('安装技能/MCP/代码段')
|
|
13
13
|
.argument('[skill]', '技能名称或 ID')
|
|
14
|
-
.option('-t, --type <type>', '类型: skill | mcp | code', 'skill')
|
|
14
|
+
.option('-t, --type <type>', '类型: skill | mcp | code | doc', 'skill')
|
|
15
15
|
.option('-g, --global', '全局安装(默认)', true)
|
|
16
16
|
.option('--register-only', '仅注册到服务器,不写入本地文件(适用于受限环境)')
|
|
17
17
|
.action(async (nameOrId, opts) => {
|
|
@@ -149,7 +149,7 @@ module.exports = new Command('install')
|
|
|
149
149
|
installDir = path.join(INSTALL_DIR, 'mcp', item.id);
|
|
150
150
|
fs.mkdirSync(installDir, { recursive: true });
|
|
151
151
|
if (item.code) {
|
|
152
|
-
const ext = item.language === 'python' ? '.py'
|
|
152
|
+
const ext = item.language === 'python' || item.language === 'py' ? '.py'
|
|
153
153
|
: item.language === 'javascript' ? '.js'
|
|
154
154
|
: item.language === 'typescript' ? '.ts'
|
|
155
155
|
: item.language === 'json' ? '.json'
|
|
@@ -206,7 +206,7 @@ module.exports = new Command('install')
|
|
|
206
206
|
installDir = path.join(INSTALL_DIR, 'code', item.id);
|
|
207
207
|
fs.mkdirSync(installDir, { recursive: true });
|
|
208
208
|
if (item.code) {
|
|
209
|
-
const extMap = { python: '.py', javascript: '.js', typescript: '.ts', go: '.go', rust: '.rs', java: '.java', c: '.c', cpp: '.cpp', shell: '.sh', bash: '.sh', json: '.json', yaml: '.yml', toml: '.toml', sql: '.sql', ruby: '.rb', php: '.php', swift: '.swift', kotlin: '.kt', scala: '.scala', r: '.r' };
|
|
209
|
+
const extMap = { python: '.py', py: '.py', javascript: '.js', typescript: '.ts', go: '.go', rust: '.rs', java: '.java', c: '.c', cpp: '.cpp', shell: '.sh', bash: '.sh', json: '.json', yaml: '.yml', toml: '.toml', sql: '.sql', ruby: '.rb', php: '.php', swift: '.swift', kotlin: '.kt', scala: '.scala', r: '.r' };
|
|
210
210
|
const ext = extMap[item.language] || `.${item.language}` || '.txt';
|
|
211
211
|
fs.writeFileSync(path.join(installDir, `snippet${ext}`), item.code);
|
|
212
212
|
}
|
|
@@ -227,6 +227,63 @@ module.exports = new Command('install')
|
|
|
227
227
|
console.log(chalk.gray(` 语言: ${item.language}`));
|
|
228
228
|
if (showLocalPath) console.log(chalk.gray(` 本地目录: ${installDir}`));
|
|
229
229
|
|
|
230
|
+
} else if (type === 'doc') {
|
|
231
|
+
// Docs: Try by ID first, then search by name
|
|
232
|
+
try {
|
|
233
|
+
item = await api.getDoc(nameOrId);
|
|
234
|
+
} catch {
|
|
235
|
+
const listData = await api.listDocs({ search: nameOrId });
|
|
236
|
+
if (listData.items && listData.items.length > 0) {
|
|
237
|
+
const match = listData.items.find(
|
|
238
|
+
s => s.name === nameOrId || s.id === nameOrId
|
|
239
|
+
);
|
|
240
|
+
if (match) {
|
|
241
|
+
// Re-fetch full data (list data is sanitized)
|
|
242
|
+
item = await api.getDoc(match.id);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (!item) {
|
|
248
|
+
console.log(chalk.red(`未找到文档: ${nameOrId}`));
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Local file install (best-effort)
|
|
253
|
+
let showLocalPath = false;
|
|
254
|
+
let installDir = '';
|
|
255
|
+
if (!opts.registerOnly) {
|
|
256
|
+
try {
|
|
257
|
+
installDir = path.join(INSTALL_DIR, 'docs', item.id);
|
|
258
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
259
|
+
// Write document content as markdown
|
|
260
|
+
if (item.content) {
|
|
261
|
+
fs.writeFileSync(path.join(installDir, 'document.md'), item.content);
|
|
262
|
+
}
|
|
263
|
+
// Write attached file list if any
|
|
264
|
+
if (item.files && item.files.length > 0) {
|
|
265
|
+
fs.writeFileSync(
|
|
266
|
+
path.join(installDir, 'files.json'),
|
|
267
|
+
JSON.stringify(item.files, null, 2)
|
|
268
|
+
);
|
|
269
|
+
console.log(chalk.gray(` 附带文件: ${item.files.map(f => f.name || f).join(', ')}`));
|
|
270
|
+
}
|
|
271
|
+
fs.writeFileSync(
|
|
272
|
+
path.join(installDir, 'rushangle.json'),
|
|
273
|
+
JSON.stringify({ type: 'doc', ...item, installedAt: new Date().toISOString() }, null, 2)
|
|
274
|
+
);
|
|
275
|
+
showLocalPath = true;
|
|
276
|
+
} catch (fileErr) {
|
|
277
|
+
console.log(chalk.yellow(` 本地文件写入跳过(${fileErr.code || fileErr.message})`));
|
|
278
|
+
if (fileErr.code === 'EPERM' || fileErr.code === 'EACCES') {
|
|
279
|
+
console.log(chalk.gray(` 提示: 使用 --register-only 跳过本地文件操作`));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
console.log(chalk.green(`✓ 安装成功: ${item.name}`));
|
|
285
|
+
if (showLocalPath) console.log(chalk.gray(` 本地目录: ${installDir}`));
|
|
286
|
+
|
|
230
287
|
} else {
|
|
231
288
|
console.log(chalk.red(`不支持的类型: ${type}`));
|
|
232
289
|
}
|