diff --git a/PROGRESS.md b/PROGRESS.md index 4bc69a5..24fbec2 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。 -最后更新:2026-05-18(dev SPA 全套 UI 中文化:菜单/按钮/状态提示/role 标签/弹窗文案全部本地化;状态码 `active/completed/abandoned` 显示为「进行中/已完成/已废弃」) +最后更新:2026-05-18(`GET /v1/skills` 路由 + dev SPA 新建任务弹窗 skill 字段改下拉选择,数据源自 SkillRegistry) --- @@ -21,6 +21,7 @@ ## 已完成关键能力 +- **05-18 / `GET /v1/skills` + dev SPA skill 字段改下拉**:原 `nt-skill` 是自由输入(用户得记住 `coding / ppt / proposal` 拼写),用户反馈"加 skill 接口给前端选"。后端 `web/app.py` lifespan 启动时 `SkillRegistry(ROOT / cfg["skills_dir"])` 扫一次挂到 `app.state.skill_registry`(文件系统静态,运行中不变);新增 `GET /v1/skills` 走 `require_user` JWT 鉴权,返 `{skills:[{name,description}]}` 按 name 升序(registry 已 sorted)。dev SPA(`web/static/dev.html`):`` 换 ` - - + +
@@ -1065,7 +1067,7 @@ $("hd-new").onclick = async () => { $("nt-err").textContent = ""; $("nt-wd-hint").textContent = ""; $("new-task-modal").classList.add("show"); - await loadFolderSuggestions(); // 拉已有目录填 datalist + await Promise.all([loadFolderSuggestions(), loadSkillOptions()]); $("nt-name").focus(); }; $("nt-cancel").onclick = () => $("new-task-modal").classList.remove("show"); @@ -1073,7 +1075,7 @@ $("nt-go").onclick = async () => { const name = $("nt-name").value.trim(); const working_dir = $("nt-wd").value.trim(); const desc = $("nt-desc").value.trim(); - const skill = $("nt-skill").value.trim(); + const skill = $("nt-skill").value; $("nt-err").textContent = ""; if (!name) { $("nt-err").textContent = "任务名为必填项"; return; } try { @@ -1101,6 +1103,27 @@ async function loadFolderSuggestions() { } } +// 智能体类型下拉:skill registry 服务器端静态,首次加载后缓存到 state.skills +async function loadSkillOptions() { + const sel = $("nt-skill"); + if (!state.skills) { + try { + const data = await api("GET", "/v1/skills"); + state.skills = data.skills || []; + } catch (e) { + state.skills = []; // 静默兜底,select 仍保留"(默认)"项 + } + } + // 渲染:第一项固定为"默认"(空 value),其后逐 skill 一项 + const opts = ['']; + for (const s of state.skills) { + const label = `${s.name}${s.description ? " — " + s.description : ""}`; + opts.push(``); + } + sel.innerHTML = opts.join(""); + sel.value = ""; // hd-new 已清空,这里幂等再保一次 +} + $("nt-wd").addEventListener("input", () => { const v = $("nt-wd").value.trim(); const hint = $("nt-wd-hint");