diff --git a/CHANGELOG.md b/CHANGELOG.md index 40b3f18..1269726 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ > 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。 > 工程口径的完整记录见 `PROGRESS.md` / git log。 +## 0.60.6 — 2026-07-29 + +- 新对话的工作目录选择改为可直接输入检索的下拉框,不再额外占用一行搜索框;同时支持键盘快速选择。 + ## 0.60.5 — 2026-07-29 - 新对话仍会明确指定文件保存位置,同时目录选择更快捷:最近使用的目录会自动选中并置顶,目录较多时可以直接搜索。 diff --git a/PROGRESS.md b/PROGRESS.md index a2120fa..849ebf4 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -2,7 +2,7 @@ > 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。 -最后更新:2026-07-29(新对话目录选择提速,bump 0.60.5) +最后更新:2026-07-29(新对话可搜索组合框,bump 0.60.6) --- @@ -23,6 +23,7 @@ ### 2026-07-29 +- **07-29 / 0.60.6 / 新对话目录选择改可搜索组合框**:将上一版独立搜索框 + 原生 select 合并为单一 combobox,同一输入区完成已选目录展示、即时过滤和下拉选择,并补方向键、Enter、Esc、失焦恢复与 ARIA 状态;最近目录置顶、明确选择 working_dir 和新建目录入口均保持不变。纯前端改动,无依赖、API、schema 或 migration;全量 387 测试通过(17 项按环境跳过)。 - **07-29 / 0.60.5 / 新对话目录选择提速**:保留首发前明确选择 working_dir 的归档约束;本机最近实际使用目录在候选中自动选中、置顶并标记,目录达到 6 个时按需显示搜索框,目录较少时维持原有简洁界面;同步精简“文件保存位置”文案。纯前端改动,无 API、schema、migration 或目录绑定语义变化;相关静态资源与无 DB 路由 18 项测试通过。 - **07-29 / 0.60.4 / 工具失败信号分层 + run_python 同错保护 + wire 健康观测**:管理端保留近7天低阈值全量事实,默认把近24h活跃数据拆成跨任务系统性故障、单任务反复失败、按设计非零退出的质量门,已归零记录沉入历史区;空输出 shell 关联最近 assistant tool_call 补 `search/no match` / `dependency probe` 等稳定类别。RepeatGuard 仅将 `run_python` traceback+非零退出纳入同错 streak,普通 shell exit 1 保持原语义。新增只读 `/v1/admin/tool-wire-health`,按 model_profile+tool 对既有 `tool_salvaged/tool_malformed` 计算24h/7d抢救率,无新表、migration、索引或执行策略变化。全量387测试通过(17项按环境跳过)。 diff --git a/core/__init__.py b/core/__init__.py index 93fde70..6281410 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,3 +1,3 @@ # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # 改版本只动这一行。 -__version__ = "0.60.5" +__version__ = "0.60.6" diff --git a/web/static/dev.html b/web/static/dev.html index 353812f..ebd9cea 100644 --- a/web/static/dev.html +++ b/web/static/dev.html @@ -772,9 +772,41 @@ .new-chat-start h2 { margin: 0 0 8px; font-size: 20px; } .new-chat-start .lead { margin: 0 0 24px; color: var(--muted); font-size: 13px; } .new-chat-start label { display:block; margin-bottom:7px; font-size:13px; font-weight:600; } - .new-chat-dir-search { width:100%; margin-bottom:8px; } .new-chat-dir-row { display:flex; gap:8px; align-items:center; } - .new-chat-dir-row select, .new-chat-dir-row input { min-width:0; flex:1; } + .new-chat-dir-combobox { position:relative; min-width:0; flex:1; } + .new-chat-dir-picker-wrap { position:relative; } + .new-chat-dir-picker-wrap input { width:100%; padding-right:34px; } + .new-chat-dir-picker-wrap button { + position:absolute; inset:1px 1px 1px auto; width:32px; padding:0; border:0; + background:transparent; + } + .new-chat-dir-picker-wrap button::after { + content:""; display:block; width:7px; height:7px; margin:auto; + border-right:1.5px solid var(--muted); border-bottom:1.5px solid var(--muted); + transform:translateY(-2px) rotate(45deg); transition:transform .15s; + } + .new-chat-dir-combobox.open .new-chat-dir-picker-wrap button::after { + transform:translateY(2px) rotate(225deg); + } + .new-chat-dir-options { + display:none; position:absolute; z-index:12; top:calc(100% + 5px); left:0; right:0; + max-height:260px; overflow:auto; padding:5px; border:1px solid var(--border); + border-radius:8px; background:var(--panel); box-shadow:0 8px 24px rgba(0,0,0,.16); + } + .new-chat-dir-combobox.open .new-chat-dir-options { display:block; } + .new-chat-dir-option { + display:flex; align-items:center; justify-content:space-between; gap:12px; + width:100%; padding:8px 10px; border:0; border-radius:6px; background:transparent; + color:var(--text); text-align:left; + } + .new-chat-dir-option:hover, .new-chat-dir-option.active { background:var(--hover); } + .new-chat-dir-option.selected { color:var(--accent); } + .new-chat-dir-option small { flex:none; color:var(--muted); font-size:11px; } + .new-chat-dir-recent { + margin-left:7px; padding:1px 5px; border-radius:4px; + background:var(--accent-soft); color:var(--accent); font-size:10px; + } + .new-chat-dir-empty { padding:12px 10px; color:var(--muted); font-size:12px; text-align:center; } .new-chat-new-dir { display:none; margin-top:10px; } .new-chat-new-dir.show { display:block; } .new-chat-new-dir input { width:100%; } diff --git a/web/static/js/chat.js b/web/static/js/chat.js index a3ecdf8..0912de8 100644 --- a/web/static/js/chat.js +++ b/web/static/js/chat.js @@ -398,6 +398,8 @@ function draftWorkingDir() { return (state.draftWorkingDir || "").trim(); } +let _draftFolderActiveIndex = -1; + function syncDraftAction() { const ready = !!draftWorkingDir(); setActionMode(ready ? "idle" : "loading"); @@ -411,10 +413,13 @@ function syncDraftAction() { } function renderDraftFolderOptions() { - const sel = $("new-chat-dir-select"); - if (!sel) return; - const search = $("new-chat-dir-search"); - const query = search ? search.value.trim().toLocaleLowerCase() : ""; + const combo = $("new-chat-dir-combobox"); + const input = $("new-chat-dir-picker"); + const list = $("new-chat-dir-options"); + if (!combo || !input || !list) return; + const query = input.dataset.searching === "1" + ? input.value.trim().toLocaleLowerCase() + : ""; const recent = localStorage.getItem(LS_RECENT_WORKING_DIR) || ""; const folders = [...(state.folders || [])]; // API 已按最近使用时间排序;再把本机刚选过的目录固定到第一项,避免 @@ -424,50 +429,128 @@ function renderDraftFolderOptions() { ? folders.filter(f => f.name.toLocaleLowerCase().includes(query)) : folders; const selected = state.draftNewDirMode ? "" : draftWorkingDir(); - const options = visible.map(f => { + list.innerHTML = visible.length + ? visible.map((f, i) => { const tag = f.n_tasks ? `${f.n_tasks} 个任务` : "空目录"; - const recentTag = f.name === recent ? "最近使用 · " : ""; - return ``; - }); - // 搜索词不匹配当前选择时仍保留它,避免仅仅输入搜索词就悄悄清掉目录。 - if (selected && !visible.some(f => f.name === selected)) { - options.unshift(``); + const recentTag = f.name === recent + ? `最近使用` + : ""; + const chosen = f.name === selected ? " selected" : ""; + return ``; + }).join("") + : `
选择文件保存位置,然后告诉助手你想做什么。
- - +