mdk-skills 2.3.1 → 2.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/package.json +1 -1
- package/scripts/web-ui/dist/assets/{index-Cj7FAJgB.css → index-BItq1iGH.css} +1 -1
- package/scripts/web-ui/dist/assets/{index-CuiL4aIa.js → index-BnMBIily.js} +26 -26
- package/scripts/web-ui/dist/index.html +2 -2
- package/scripts/web-ui/server.js +37 -15
- package/scripts/web-ui/src/api/skills.js +4 -0
- package/scripts/web-ui/src/views/Dashboard.vue +7 -1
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>mdk-skills 管理面板</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-BnMBIily.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BItq1iGH.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="app"></div>
|
package/scripts/web-ui/server.js
CHANGED
|
@@ -2,7 +2,7 @@ const fs = require("fs");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const http = require("http");
|
|
4
4
|
const crypto = require("crypto");
|
|
5
|
-
const { execSync } = require("child_process");
|
|
5
|
+
const { execSync, exec } = require("child_process");
|
|
6
6
|
const os = require("os");
|
|
7
7
|
const core = require("../core");
|
|
8
8
|
|
|
@@ -167,6 +167,24 @@ function writeSkillMeta(dest, wasUpdated) {
|
|
|
167
167
|
fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2) + "\n", "utf-8");
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
// ---------- 异步 npx 管理:支持取消正在执行的进程 ----------
|
|
171
|
+
|
|
172
|
+
let _npxProcess = null;
|
|
173
|
+
|
|
174
|
+
function runNpx(cmd, cwd) {
|
|
175
|
+
return new Promise((resolve, reject) => {
|
|
176
|
+
const proc = exec(cmd, { cwd, timeout: 120000 }, (err) => {
|
|
177
|
+
_npxProcess = null;
|
|
178
|
+
if (err) {
|
|
179
|
+
reject(err.killed ? new Error("已取消") : err);
|
|
180
|
+
} else {
|
|
181
|
+
resolve();
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
_npxProcess = proc;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
170
188
|
// 读取 profiles.json
|
|
171
189
|
function loadProfiles() {
|
|
172
190
|
const profilesPath = path.join(skillsSource, ".claude", "profiles.json");
|
|
@@ -392,14 +410,11 @@ async function handleApi(req, res) {
|
|
|
392
410
|
const tmpDir = path.join(os.tmpdir(), "mdk-pull-" + Date.now());
|
|
393
411
|
fs.mkdirSync(path.join(tmpDir, ".claude", "skills"), { recursive: true });
|
|
394
412
|
try {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
stdio: "pipe",
|
|
398
|
-
timeout: 120000,
|
|
399
|
-
});
|
|
400
|
-
} catch {
|
|
413
|
+
await runNpx("npx --yes skills add \"" + url + "\" --copy -y -a claude-code", tmpDir);
|
|
414
|
+
} catch (e) {
|
|
401
415
|
cleanNpxTemp();
|
|
402
416
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
417
|
+
if (e.message === "已取消") return sendJSON(res, { cancelled: true }, 499);
|
|
403
418
|
return sendJSON(res, { error: "拉取失败,请检查地址或网络连接" }, 400);
|
|
404
419
|
}
|
|
405
420
|
cleanNpxTemp();
|
|
@@ -457,12 +472,11 @@ async function handleApi(req, res) {
|
|
|
457
472
|
const tmpDir = path.join(os.tmpdir(), "mdk-update-" + Date.now());
|
|
458
473
|
fs.mkdirSync(path.join(tmpDir, ".claude", "skills"), { recursive: true });
|
|
459
474
|
try {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
});
|
|
463
|
-
} catch {
|
|
475
|
+
await runNpx("npx --yes skills add \"" + source.url + "\" --copy -y -a claude-code", tmpDir);
|
|
476
|
+
} catch (e) {
|
|
464
477
|
cleanNpxTemp();
|
|
465
478
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
479
|
+
if (e.message === "已取消") return sendJSON(res, { cancelled: true }, 499);
|
|
466
480
|
return sendJSON(res, { error: "重新拉取失败,请检查网络连接" }, 400);
|
|
467
481
|
}
|
|
468
482
|
|
|
@@ -519,12 +533,11 @@ async function handleApi(req, res) {
|
|
|
519
533
|
const tmpDir = path.join(os.tmpdir(), "mdk-batch-" + Date.now());
|
|
520
534
|
fs.mkdirSync(path.join(tmpDir, ".claude", "skills"), { recursive: true });
|
|
521
535
|
try {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
});
|
|
525
|
-
} catch {
|
|
536
|
+
await runNpx("npx --yes skills add \"" + url + "\" --copy -y -a claude-code", tmpDir);
|
|
537
|
+
} catch (e) {
|
|
526
538
|
cleanNpxTemp();
|
|
527
539
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
540
|
+
if (e.message === "已取消") return sendJSON(res, { cancelled: true }, 499);
|
|
528
541
|
return sendJSON(res, { error: "拉取失败,请检查网络连接" }, 400);
|
|
529
542
|
}
|
|
530
543
|
|
|
@@ -1144,6 +1157,15 @@ ${skillsList}
|
|
|
1144
1157
|
return sendJSON(res, results);
|
|
1145
1158
|
}
|
|
1146
1159
|
|
|
1160
|
+
// POST /api/tasks/cancel — 取消正在执行的 npx 操作
|
|
1161
|
+
if (method === "POST" && pathname === "/api/tasks/cancel") {
|
|
1162
|
+
if (_npxProcess) {
|
|
1163
|
+
_npxProcess.kill();
|
|
1164
|
+
_npxProcess = null;
|
|
1165
|
+
}
|
|
1166
|
+
return sendJSON(res, { ok: true });
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1147
1169
|
// 404
|
|
1148
1170
|
sendJSON(res, { error: "Not Found: " + pathname }, 404);
|
|
1149
1171
|
} catch (err) {
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
style="width: 720px"
|
|
100
100
|
content-style="padding: 0;"
|
|
101
101
|
:mask-closable="true"
|
|
102
|
+
@update:show="(v) => { if (!v) { updatingSkill = false; detailLoading = false; cancelTask(); } }"
|
|
102
103
|
>
|
|
103
104
|
<div class="detail-body">
|
|
104
105
|
<!-- 编辑面板 -->
|
|
@@ -174,6 +175,7 @@
|
|
|
174
175
|
preset="card"
|
|
175
176
|
style="width: 600px"
|
|
176
177
|
:mask-closable="true"
|
|
178
|
+
@update:show="(v) => { if (!v) { pulling = false; cancelTask(); } }"
|
|
177
179
|
>
|
|
178
180
|
<div class="pull-modal-body">
|
|
179
181
|
<div class="pull-input-row">
|
|
@@ -251,7 +253,7 @@ import { RefreshOutline } from "@vicons/ionicons5";
|
|
|
251
253
|
import { marked } from "marked";
|
|
252
254
|
import hljs from "highlight.js";
|
|
253
255
|
import SkillCard from "../components/SkillCard.vue";
|
|
254
|
-
import { getSkills, getReadme, getSkillReadme, updateSkillMeta, deleteSkill, pullSkills, installSkills, getSkillSource, updateSkill, batchUpdateSkills, openSkillDir } from "../api/skills";
|
|
256
|
+
import { getSkills, getReadme, getSkillReadme, updateSkillMeta, deleteSkill, pullSkills, installSkills, getSkillSource, updateSkill, batchUpdateSkills, openSkillDir, cancelTask } from "../api/skills";
|
|
255
257
|
import { sortSkills, getUsageMap } from "../utils/usage";
|
|
256
258
|
|
|
257
259
|
// marked 配置:代码高亮 + 外链安全
|
|
@@ -374,6 +376,7 @@ async function handlePull() {
|
|
|
374
376
|
pullError.value = "";
|
|
375
377
|
try {
|
|
376
378
|
const res = await pullSkills(pullUrl.value.trim());
|
|
379
|
+
if (!showPullModal.value) return;
|
|
377
380
|
if (res.ok) {
|
|
378
381
|
pullResult.value = { imported: res.imported, skipped: res.skipped };
|
|
379
382
|
// 默认全选
|
|
@@ -385,6 +388,7 @@ async function handlePull() {
|
|
|
385
388
|
pullError.value = res.error || "拉取失败";
|
|
386
389
|
}
|
|
387
390
|
} catch (e) {
|
|
391
|
+
if (!showPullModal.value) return;
|
|
388
392
|
pullError.value = "拉取失败,请检查地址或网络";
|
|
389
393
|
} finally {
|
|
390
394
|
pulling.value = false;
|
|
@@ -541,6 +545,7 @@ async function handleUpdate() {
|
|
|
541
545
|
updatingSkill.value = true;
|
|
542
546
|
try {
|
|
543
547
|
const res = await updateSkill(detailSkill.value.name);
|
|
548
|
+
if (!detailVisible.value) return;
|
|
544
549
|
if (res.ok) {
|
|
545
550
|
if (res.updated === false) {
|
|
546
551
|
message.info("已是最新版本,无需更新");
|
|
@@ -565,6 +570,7 @@ async function handleUpdate() {
|
|
|
565
570
|
message.error(res.error || "更新失败");
|
|
566
571
|
}
|
|
567
572
|
} catch {
|
|
573
|
+
if (!detailVisible.value) return;
|
|
568
574
|
message.error("更新失败");
|
|
569
575
|
} finally {
|
|
570
576
|
updatingSkill.value = false;
|