psyclaw 0.30.16 → 0.30.17
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/dist/apps/panel/index.html +51 -17
- package/dist/src/adapters/pi/extension.js +2 -2
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/panel/server.js +82 -14
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/skills/recommended.d.ts +5 -0
- package/dist/src/skills/recommended.js +26 -2
- package/dist/src/skills/recommended.js.map +1 -1
- package/dist/src/tui/skill-manager.js +24 -1
- package/dist/src/tui/skill-manager.js.map +1 -1
- package/package.json +1 -1
|
@@ -2673,14 +2673,20 @@ async function loadEcosystem() {
|
|
|
2673
2673
|
json("/api/recommended-agents"),
|
|
2674
2674
|
json("/api/enabled-capabilities")
|
|
2675
2675
|
]);
|
|
2676
|
-
const
|
|
2677
|
-
const
|
|
2676
|
+
const skillStatus = new Map((enabled.skills || []).map(item => [item.id, item]));
|
|
2677
|
+
const mcpStatus = new Map((enabled.mcp || []).map(item => [item.id, item]));
|
|
2678
2678
|
state.eco = [
|
|
2679
2679
|
...(enabled.coreSkills || []).map(item => ({ ...item, kind: "core", description: item.description || "PsyClaw 内置科研核心 Skill", sourceRef: "bundled", enabled: item.enabled, installed: true })),
|
|
2680
|
-
...(skills.items || []).map(item =>
|
|
2680
|
+
...(skills.items || []).map(item => {
|
|
2681
|
+
const status = skillStatus.get(item.id) || {};
|
|
2682
|
+
return { ...item, kind: "skill", enabled: Boolean(status.enabled), installed: Boolean(status.installed) };
|
|
2683
|
+
}),
|
|
2681
2684
|
...(plugins.items || []).map(item => ({ ...item, kind: "plugin", enabled: Boolean(item.enabled), installed: Boolean(item.installed) })),
|
|
2682
2685
|
...(enabled.localSkills || []).map(item => ({ ...item, kind: "local", sourceRef: item.path || "用户配置目录", installed: true })),
|
|
2683
|
-
...(mcps.items || []).map(item =>
|
|
2686
|
+
...(mcps.items || []).map(item => {
|
|
2687
|
+
const status = mcpStatus.get(item.id) || {};
|
|
2688
|
+
return { ...item, kind: "mcp", enabled: Boolean(status.enabled), installed: Boolean(status.installed) };
|
|
2689
|
+
}),
|
|
2684
2690
|
...(agents.items || []).map(item => ({ ...item, kind: "agent", enabled: Boolean(item.enabled), installed: Boolean(item.installed), locked: Boolean(item.locked) })),
|
|
2685
2691
|
...(skills.externalTools || []).map(item => ({ ...item, kind: "external", enabled: false, installed: false }))
|
|
2686
2692
|
];
|
|
@@ -2724,7 +2730,13 @@ function renderEcosystem() {
|
|
|
2724
2730
|
$("ecosystem-body").innerHTML = items.map(item => {
|
|
2725
2731
|
const prereqs = itemPrereqs(item);
|
|
2726
2732
|
const busy = Boolean(state.installing[item.id]);
|
|
2727
|
-
const
|
|
2733
|
+
const statusLabel = busy ? "正在安装…"
|
|
2734
|
+
: item.locked ? "内置可用"
|
|
2735
|
+
: item.enabled ? (item.kind === "plugin" ? "已安装" : "已启用")
|
|
2736
|
+
: item.installed ? "已安装未启用"
|
|
2737
|
+
: item.kind === "plugin" && item.configured ? "配置存在,文件缺失"
|
|
2738
|
+
: item.kind === "external" ? "可安装外部工具"
|
|
2739
|
+
: "未安装";
|
|
2728
2740
|
return `
|
|
2729
2741
|
<tr>
|
|
2730
2742
|
<td>
|
|
@@ -2747,25 +2759,46 @@ function renderEcosystem() {
|
|
|
2747
2759
|
</span>
|
|
2748
2760
|
</td>
|
|
2749
2761
|
<td>
|
|
2750
|
-
<span class="tag ${item.enabled ? "ok" : item.configured ? "warn" : ""}">
|
|
2751
|
-
${
|
|
2762
|
+
<span class="tag ${item.enabled ? "ok" : item.installed || item.configured ? "warn" : ""}">
|
|
2763
|
+
${esc(statusLabel)}
|
|
2752
2764
|
</span>
|
|
2753
2765
|
</td>
|
|
2754
2766
|
<td style="text-align:right">
|
|
2755
|
-
${item
|
|
2756
|
-
item.kind === "plugin" && item.local ? "—" :
|
|
2757
|
-
item.kind === "plugin" ? `<button class="button small ${item.installed ? "" : "primary"}" ${busy ? "disabled" : ""} onclick="installCapability('plugin','${esc(item.id)}')">${installLabel}</button>` :
|
|
2758
|
-
item.kind === "external" ? `<button class="button small primary" ${busy ? "disabled" : ""} onclick="installCapability('external','${esc(item.id)}')">${installLabel}</button>` :
|
|
2759
|
-
item.enabled ? `<button class="button small" onclick="toggleCapability('${item.kind}','${esc(item.id)}',false)">停用</button>` :
|
|
2760
|
-
item.kind === "local" ? `<button class="button small primary" onclick="toggleCapability('local','${esc(item.id)}',true)">启用</button>` :
|
|
2761
|
-
`<button class="button small primary" ${busy ? "disabled" : ""} onclick="installCapability('${item.kind}','${esc(item.id)}')">${installLabel}</button>`
|
|
2762
|
-
}
|
|
2767
|
+
${capabilityActionButtons(item, busy)}
|
|
2763
2768
|
</td>
|
|
2764
2769
|
</tr>
|
|
2765
2770
|
`;
|
|
2766
2771
|
}).join("") || '<tr><td colspan="5" class="empty" style="min-height:100px">未找到匹配的能力项</td></tr>';
|
|
2767
2772
|
}
|
|
2768
2773
|
|
|
2774
|
+
function capabilityActionButtons(item, busy) {
|
|
2775
|
+
if (item.locked || item.kind === "agent") return "—";
|
|
2776
|
+
if (item.kind === "plugin" && item.local) return "—";
|
|
2777
|
+
if (item.kind === "plugin") {
|
|
2778
|
+
const label = busy ? "正在安装…" : item.installed ? "重新安装" : "安装";
|
|
2779
|
+
return `<button class="button small ${item.installed ? "" : "primary"}" ${busy ? "disabled" : ""} onclick="installCapability('plugin','${esc(item.id)}')">${label}</button>`;
|
|
2780
|
+
}
|
|
2781
|
+
if (item.kind === "external") {
|
|
2782
|
+
return `<button class="button small primary" ${busy ? "disabled" : ""} onclick="installCapability('external','${esc(item.id)}')">${busy ? "正在安装…" : "安装"}</button>`;
|
|
2783
|
+
}
|
|
2784
|
+
if (item.kind === "core" || item.kind === "local") {
|
|
2785
|
+
return item.enabled
|
|
2786
|
+
? `<button class="button small" onclick="toggleCapability('${item.kind}','${esc(item.id)}',false)">停用</button>`
|
|
2787
|
+
: `<button class="button small primary" onclick="toggleCapability('${item.kind}','${esc(item.id)}',true)">启用</button>`;
|
|
2788
|
+
}
|
|
2789
|
+
// Recommended Skill / MCP: keep enable/disable separate from install/reinstall.
|
|
2790
|
+
const buttons = [];
|
|
2791
|
+
if (item.installed) {
|
|
2792
|
+
buttons.push(item.enabled
|
|
2793
|
+
? `<button class="button small" onclick="toggleCapability('${item.kind}','${esc(item.id)}',false)">停用</button>`
|
|
2794
|
+
: `<button class="button small primary" onclick="toggleCapability('${item.kind}','${esc(item.id)}',true)">启用</button>`);
|
|
2795
|
+
buttons.push(`<button class="button small" ${busy ? "disabled" : ""} onclick="installCapability('${item.kind}','${esc(item.id)}')">${busy ? "正在安装…" : "重新安装"}</button>`);
|
|
2796
|
+
} else {
|
|
2797
|
+
buttons.push(`<button class="button small primary" ${busy ? "disabled" : ""} onclick="installCapability('${item.kind}','${esc(item.id)}')">${busy ? "正在安装…" : "安装"}</button>`);
|
|
2798
|
+
}
|
|
2799
|
+
return buttons.join(" ");
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2769
2802
|
async function toggleCapability(kind, id, enabled) {
|
|
2770
2803
|
await json("/api/recommendation-state", {
|
|
2771
2804
|
method: "POST",
|
|
@@ -2790,14 +2823,15 @@ async function installCapability(kind, id) {
|
|
|
2790
2823
|
const scope = kind === "skill" || kind === "plugin"
|
|
2791
2824
|
? (confirm("安装到系统全局还是当前项目?\n确定:全局所有项目可用;取消:仅当前项目。") ? "user" : "project")
|
|
2792
2825
|
: undefined;
|
|
2793
|
-
|
|
2826
|
+
const reinstall = Boolean(item?.installed);
|
|
2827
|
+
let confirmText = `确认${reinstall ? "重新安装" : "安装"}「${item?.name || id}」?`;
|
|
2794
2828
|
if (kind === "external") {
|
|
2795
2829
|
confirmText += "\n\n系统将按官方可信来源安装;任务会交给当前 PsyClaw 对话中的模型执行。请保持终端会话打开。";
|
|
2796
2830
|
} else if (kind === "mcp" || kind === "skill") {
|
|
2797
2831
|
if (prereqs.length) {
|
|
2798
2832
|
confirmText += `\n\n前置依赖也将一并排队安装:${prereqs.join("、")}。\n安装任务会交给当前 PsyClaw 对话中的模型执行;请保持终端会话打开,完成后执行 /reload。`;
|
|
2799
2833
|
} else {
|
|
2800
|
-
confirmText +=
|
|
2834
|
+
confirmText += `\n\n${reinstall ? "将覆盖当前安装目录并重新交给模型安装" : "安装任务会交给当前 PsyClaw 对话中的模型执行"};请保持终端会话打开,完成后执行 /reload。`;
|
|
2801
2835
|
}
|
|
2802
2836
|
} else {
|
|
2803
2837
|
confirmText += "\n\n安装完成后需要执行 /reload 生效。";
|
|
@@ -448,7 +448,7 @@ async function skillManagerRows(root, state) {
|
|
|
448
448
|
scope,
|
|
449
449
|
blocked: typeof item.sourceRef !== "string" || !/^https:\/\//.test(item.sourceRef),
|
|
450
450
|
reason: onDisk
|
|
451
|
-
? `已检测到目录但未通过来源/许可/哈希校验${state.skills.includes(id) ? "(当前配置为启用,但校验失败不会加载)" : ""};可按
|
|
451
|
+
? `已检测到目录但未通过来源/许可/哈希校验${state.skills.includes(id) ? "(当前配置为启用,但校验失败不会加载)" : ""};可按 r 重新安装修复`
|
|
452
452
|
: typeof item.sourceRef === "string" && /^https:\/\//.test(item.sourceRef)
|
|
453
453
|
? "尚未安装;按 Enter 选择安装范围并交给当前模型处理"
|
|
454
454
|
: "没有可交给模型检查的来源网址",
|
|
@@ -599,7 +599,7 @@ async function openMcpManager(ctx, rows) {
|
|
|
599
599
|
return ctx.ui.custom((tui, theme, keybindings, done) => (new SkillManagerComponent(mcpManagerItems(rows), tui, theme, keybindings, done, {
|
|
600
600
|
title: "MCP 管理",
|
|
601
601
|
itemLabel: "MCP",
|
|
602
|
-
footer: "↑/↓ 移动 · Space/Enter 安装或启停 · a 全部开启 · d 全部关闭 · Esc 关闭",
|
|
602
|
+
footer: "↑/↓ 移动 · Space/Enter 安装或启停 · r 重新安装 · a 全部开启 · d 全部关闭 · Esc 关闭",
|
|
603
603
|
enabledText: "已开启;再次点击可关闭",
|
|
604
604
|
disabledText: "已安装,当前未启用;点击可开启",
|
|
605
605
|
missingMessage: "尚未安装;点击交给模型安装并默认启用",
|