// 技能 modal:查看「平台 skill」/「我的 skill」两组列表,点任一项展开完整 SKILL.md, // 「我的」每项可删除(平台 skill 只读)。左侧 rail 底部「技能」按钮触发。 // 后端:GET /v1/skills(列表)、GET /v1/skills/{name}(正文)、DELETE /v1/skills/{name}(只删 user 源)。 // 创建 / 改 / fork 仍走对话(save_skill / fork_skill / skill-creator)。 import { $ } from "./dom.js"; import { state } from "./state.js"; import { api } from "./api.js"; import { escapeHtml } from "./format.js"; import { renderMd, highlightIn } from "./markdown.js"; function openSkillsModal() { $("skills-modal").classList.add("show"); renderList(); } export function closeSkillsModal() { $("skills-modal").classList.remove("show"); } function itemHtml(s) { const badge = s.overrides_builtin ? ' 已覆盖平台同名' : ""; const del = s.source === "user" ? `` : ""; return `
${escapeHtml(s.name)}${badge}
${escapeHtml(s.description || "")}
${del}
`; } async function renderList() { const body = $("sk-body"); $("sk-title").textContent = "技能"; body.innerHTML = '
加载中…
'; let data; try { data = await api("GET", "/v1/skills"); } catch (e) { body.innerHTML = `
加载失败: ${escapeHtml(e.message)}
`; return; } state.skills = data.skills || []; // 顺手刷新新建任务下拉的缓存 const platform = state.skills.filter((s) => s.source === "builtin"); const mine = state.skills.filter((s) => s.source === "user"); let html = ""; html += `
平台 skill (${platform.length})
`; html += platform.map(itemHtml).join("") || '
(无)
'; html += `
我的 skill (${mine.length})
`; html += mine.length ? mine.map(itemHtml).join("") : '
还没有。让助手「帮我做个 skill」或「把某个平台 skill fork 成我的」即可创建。
'; if (data.load_errors && data.load_errors.length) { const errs = data.load_errors .map((e) => `${escapeHtml(e.name)}(${escapeHtml(e.reason)})`) .join(";"); html += `
⚠ ${data.load_errors.length} 个 skill 因格式问题未加载:${errs}
`; } body.innerHTML = html; } async function showDetail(name) { const body = $("sk-body"); $("sk-title").innerHTML = `${escapeHtml(name)}`; $("sk-back").onclick = renderList; body.innerHTML = '
加载中…
'; let data; try { data = await api("GET", "/v1/skills/" + encodeURIComponent(name)); } catch (e) { body.innerHTML = `
加载失败: ${escapeHtml(e.message)}
`; return; } body.innerHTML = `
${renderMd(data.content)}
`; highlightIn(body); } // ───── 顶层绑定 ───── $("hd-skills").onclick = openSkillsModal; $("sk-close").onclick = closeSkillsModal; $("skills-modal").addEventListener("click", (e) => { if (e.target.id === "skills-modal") closeSkillsModal(); // 点遮罩关闭 }); // 列表区事件委托:删除(冒泡到 [data-del])优先于点开详情(.sk-item) $("sk-body").addEventListener("click", async (e) => { const del = e.target.closest("[data-del]"); if (del) { e.stopPropagation(); const name = del.getAttribute("data-del"); if (!confirm(`删除你的 skill「${name}」?不可撤销(平台同名 skill 不受影响)。`)) return; del.disabled = true; try { await api("DELETE", "/v1/skills/" + encodeURIComponent(name)); state.skills = null; // 失效缓存,新建任务下拉下次重拉 renderList(); } catch (err) { alert("删除失败: " + err.message); del.disabled = false; } return; } const item = e.target.closest(".sk-item"); if (item) showDetail(item.getAttribute("data-name")); });