feat: support workspace skills in dashboard

This commit is contained in:
icodelife
2026-03-21 02:44:44 +08:00
parent 4d1ceaea3e
commit 4a3d4e5b23
3 changed files with 14 additions and 3 deletions
+8 -2
View File
@@ -173,6 +173,7 @@ export default function SkillsPage() {
const filtered = skills.filter((skill) => {
if (filter === "builtin" && skill.source !== "builtin") return false;
if (filter === "extension" && !skill.source.startsWith("extension:")) return false;
if (filter === "workspace" && skill.source !== "workspace") return false;
if (filter === "custom" && skill.source !== "custom") return false;
if (!search) return true;
@@ -188,12 +189,14 @@ export default function SkillsPage() {
const sourceLabel = (source: string) => {
if (source === "builtin") return t("skills.source.builtin");
if (source.startsWith("extension:")) return source.replace("extension:", `${t("skills.extension")}:`);
if (source === "workspace") return t("skills.workspace");
return t("skills.source.custom");
};
const sourceBadgeClass = (source: string) => {
if (source === "builtin") return "bg-blue-500/20 text-blue-400";
if (source.startsWith("extension:")) return "bg-purple-500/20 text-purple-400";
if (source === "workspace") return "bg-orange-500/20 text-orange-400";
return "bg-green-500/20 text-green-400";
};
@@ -218,6 +221,7 @@ export default function SkillsPage() {
const builtinCount = skills.filter((skill) => skill.source === "builtin").length;
const extensionCount = skills.filter((skill) => skill.source.startsWith("extension:")).length;
const workspaceCount = skills.filter((skill) => skill.source === "workspace").length;
const customCount = skills.filter((skill) => skill.source === "custom").length;
return (
@@ -226,7 +230,7 @@ export default function SkillsPage() {
<div>
<h1 className="text-2xl font-bold">{t("skills.title")}</h1>
<p className="text-[var(--text-muted)] text-sm mt-1">
{skills.length} {t("skills.count")}{t("skills.builtin")} {builtinCount} / {t("skills.extension")} {extensionCount} / {t("skills.custom")} {customCount}
{skills.length} {t("skills.count")}{t("skills.builtin")} {builtinCount} / {t("skills.extension")} {extensionCount} / {t("skills.workspace")} {workspaceCount} / {t("skills.custom")} {customCount}
</p>
</div>
<div className="flex flex-wrap items-center gap-3">
@@ -241,7 +245,7 @@ export default function SkillsPage() {
<div className="flex flex-col gap-3 mb-6 md:flex-row md:items-center">
<div className="flex flex-wrap rounded-lg border border-[var(--border)] overflow-hidden">
{(["all", "builtin", "extension", "custom"] as const).map((nextFilter) => (
{(["all", "builtin", "extension", "workspace", "custom"] as const).map((nextFilter) => (
<button
key={nextFilter}
onClick={() => setFilter(nextFilter)}
@@ -257,6 +261,8 @@ export default function SkillsPage() {
? t("skills.builtin")
: nextFilter === "extension"
? t("skills.extension")
: nextFilter === "workspace"
? t("skills.workspace")
: t("skills.custom")}
</button>
))}
+4
View File
@@ -232,6 +232,7 @@ const translations: Record<Locale, Record<string, string>> = {
"skills.count": "個技能",
"skills.builtin": "內建",
"skills.extension": "擴充",
"skills.workspace": "工作區",
"skills.custom": "自訂",
"skills.all": "全部",
"skills.search": "搜尋技能...",
@@ -239,6 +240,7 @@ const translations: Record<Locale, Record<string, string>> = {
"skills.unit": "個",
"skills.noDesc": "無描述",
"skills.source.builtin": "內建",
"skills.source.workspace": "工作區",
"skills.source.custom": "自訂",
"skills.viewSource": "查看 SKILL.md",
"skills.contentTitle": "SKILL.md 內容",
@@ -520,6 +522,7 @@ const translations: Record<Locale, Record<string, string>> = {
"skills.count": "个技能",
"skills.builtin": "内置",
"skills.extension": "扩展",
"skills.workspace": "工作区",
"skills.custom": "自定义",
"skills.all": "全部",
"skills.search": "搜索技能...",
@@ -527,6 +530,7 @@ const translations: Record<Locale, Record<string, string>> = {
"skills.unit": "个",
"skills.noDesc": "无描述",
"skills.source.builtin": "内置",
"skills.source.workspace": "工作区",
"skills.source.custom": "自定义",
"skills.viewSource": "查看 SKILL.md",
"skills.contentTitle": "SKILL.md 内容",
+2 -1
View File
@@ -126,7 +126,8 @@ export function listOpenclawSkills(): { skills: SkillInfo[]; agents: Record<stri
}
const customSkills = scanSkillsDir(path.join(OPENCLAW_HOME, "skills"), "custom");
const allSkills = [...builtinSkills, ...extSkills, ...customSkills];
const workspaceSkills = scanSkillsDir(path.join(OPENCLAW_HOME, "workspace", "skills"), "workspace");
const allSkills = [...builtinSkills, ...extSkills, ...customSkills, ...workspaceSkills];
const agentSkills = getAgentSkillsFromSessions();
for (const skill of allSkills) {