diff --git a/CHANGELOG.md b/CHANGELOG.md index ff137b1..1ae81fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ > 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。 > 工程口径的完整记录见 `PROGRESS.md` / git log。 +## 0.60.15 — 2026-07-31 + +- 从 platform、企业微信或 App 携带指定对话进入时,现在会直接打开该对话对应的工作目录,右侧文件栏不再停留在用户根目录。 + ## 0.60.14 — 2026-07-31 - 自动命名的普通对话在清空后会回到“新对话”,并根据下一次询问重新生成标题;用户手动设置的任务名以及微信、企业微信等固定会话名保持不变。 diff --git a/PROGRESS.md b/PROGRESS.md index 8f6453f..1319af6 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-31(清空对话后自动标题重生成,bump 0.60.14) +最后更新:2026-07-31(嵌入初始 task 直接进入工作目录,bump 0.60.15) --- @@ -23,6 +23,7 @@ ### 2026-07-31 +- **07-31 / 0.60.15 / 嵌入初始 task 直接进入工作目录**:platform iframe、企业微信和 App 携带 `task_id` 首次进入时,由 `enterApp` 直接选择目标 task,跳过新对话草稿及 user_root 文件面板初始化,随后沿既有 `selectTask` 链路同步 `working_dir`;401 重签仍不重复定位,普通登录空态不变。JavaScript 语法、7 项静态前端测试及 diff 格式检查通过;无 API、schema、migration 或依赖变化。 - **07-31 / 0.60.14 / 清空对话后自动标题重生成**:tasks 新增 `title_source`(auto/manual/fixed)与 `auto_title_version`(0024 migration);快速新对话的自动标题在清空后重置为“新对话”,下一条消息重新生成,人工重命名及微信/企微/调度固定标题保持不变。版本闸阻止清空前在途标题跨轮次写回;历史任务无法可靠判定“自动命名后又人工改名”,除当前 pending 外保守回填 manual。相关 18 项无 DB 测试、Python 编译、Alembic 单 head 与 diff 格式检查通过;DB 路由用例已补,未配置 `ZCBOT_TEST_DB_URL` 时按安全门控跳过。 - **07-31 / 0.60.13 / 渠道常驻会话操作收口**:微信与企业微信的 web 只读镜像只保留导出和清空对话,隐藏普通任务才适用的完成、废弃、重命名和删除操作,顶部独立完成按钮同步隐藏;普通任务菜单不变。纯前端行为修正,无 API、schema、migration 或依赖变化;JavaScript 语法及 diff 格式检查通过。 diff --git a/core/__init__.py b/core/__init__.py index bb86f1d..9186075 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,3 +1,3 @@ # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # 改版本只动这一行。 -__version__ = "0.60.14" +__version__ = "0.60.15" diff --git a/tests/test_static_vendor.py b/tests/test_static_vendor.py index 6b79b30..d4ed095 100644 --- a/tests/test_static_vendor.py +++ b/tests/test_static_vendor.py @@ -83,6 +83,19 @@ class StaticVendorTests(unittest.TestCase): self.assertIn("context_original_chars", src) self.assertIn("cache_hit_tokens", src) + def test_embed_initial_task_skips_root_directory_bootstrap(self) -> None: + main_js = (JS_DIR / "main.js").read_text(encoding="utf-8") + embed_js = (JS_DIR / "embed.js").read_text(encoding="utf-8") + + self.assertIn('export function enterApp(initialTaskId = "")', main_js) + self.assertIn("selectTask(initialTaskId);", main_js) + self.assertIn( + "showNewConversationDraft(); // 登录空态与“+ 新对话”共用同一草稿页", + main_js, + ) + self.assertIn("enterApp(takeInitialTaskId());", embed_js) + self.assertNotIn("gotoInitialTask()", embed_js) + def test_static_js_is_served_with_revalidation_header(self) -> None: with tempfile.TemporaryDirectory() as tmp: static_dir = Path(tmp) diff --git a/web/static/js/embed.js b/web/static/js/embed.js index 14560c7..e21dd28 100644 --- a/web/static/js/embed.js +++ b/web/static/js/embed.js @@ -8,7 +8,7 @@ import { state, LS_TOKEN, EMBED_WECOM, EMBED_PARENT_ORIGIN, EMBED_RELOGIN_URL, EMBED_INITIAL_TASK_ID, setIdentity } from "./state.js"; import { $ } from "./dom.js"; import { enterApp } from "./main.js"; -import { loadTaskList, selectTask } from "./chat.js"; +import { loadTaskList } from "./chat.js"; // embed 首个 task 自动定位的一次性标志(仅 embed 段使用) let _embedInitialTaskHandled = false; @@ -44,9 +44,8 @@ function embedHandleMessage(e) { // 401 后重签:重载列表,不重复 enterApp / 不重复定位 task(尊重用户中间切过的选择) loadTaskList(); } else { - enterApp(); - // 首次签发:若 URL 带 task_id,定位到该 task(loadMessages 由 selectTask 触发) - gotoInitialTask(); + // 首次签发:若 URL 带 task_id,直接进入该 task;enterApp 不再先加载根目录。 + enterApp(takeInitialTaskId()); } } } @@ -62,11 +61,12 @@ function readFragmentToken() { setIdentity({ user_id: uid }); history.replaceState(null, "", location.pathname + location.search); } -function gotoInitialTask() { +function takeInitialTaskId() { if (EMBED_INITIAL_TASK_ID && !_embedInitialTaskHandled) { _embedInitialTaskHandled = true; - selectTask(EMBED_INITIAL_TASK_ID); + return EMBED_INITIAL_TASK_ID; } + return ""; } // ───── wecom 免登变体 ───── @@ -79,8 +79,7 @@ function embedWecomInit() { document.body.classList.add("embed-mode"); readFragmentToken(); if (!state.token) { embedWecomRelogin(); return; } - enterApp(); - gotoInitialTask(); + enterApp(takeInitialTaskId()); } // ───── app 套壳变体 ───── @@ -93,8 +92,7 @@ function embedAppInit() { document.body.classList.add("embed-mode"); readFragmentToken(); if (!state.token) { embedAppRelogin(); return; } - enterApp(); - gotoInitialTask(); + enterApp(takeInitialTaskId()); } export function embedInit() { @@ -108,8 +106,7 @@ export function embedInit() { document.body.classList.add("embed-mode"); window.addEventListener("message", embedHandleMessage); if (state.token) { - enterApp(); - gotoInitialTask(); + enterApp(takeInitialTaskId()); } else { document.body.classList.add("embed-waiting"); embedShowWaiting("等待登录…", false); diff --git a/web/static/js/main.js b/web/static/js/main.js index 00043ac..86415b0 100644 --- a/web/static/js/main.js +++ b/web/static/js/main.js @@ -16,18 +16,24 @@ import { closeFilePreview, closeMiniPreview } from "./preview.js"; import { closeSrcPicker, loadFiles } from "./files.js"; import { loadFolderSuggestions } from "./newtask.js"; import { embedInit } from "./embed.js"; -import { loadTaskList, loadModels, loadChannelCards, showNewConversationDraft } from "./chat.js"; +import { loadTaskList, loadModels, loadChannelCards, selectTask, showNewConversationDraft } from "./chat.js"; import { refreshProcs } from "./procs.js"; // ───── enter app ───── -export function enterApp() { +export function enterApp(initialTaskId = "") { $("login").style.display = "none"; $("app").classList.add("ready"); renderWho(); // 顶栏用户:默认显 name(兜底 user_name/email/uid8),hover 显完整身份 - showNewConversationDraft(); // 登录空态与“+ 新对话”共用同一草稿页,不先落 tasks 行 + if (initialTaskId) { + // platform / App 带 task_id 进入时直接选中目标 task;selectTask 会同步 working_dir, + // 不先初始化新对话草稿和 user_root 文件面板,避免右栏短暂或最终停在根目录。 + selectTask(initialTaskId); + } else { + showNewConversationDraft(); // 登录空态与“+ 新对话”共用同一草稿页,不先落 tasks 行 + loadFiles(); // 文件面板与 task 解耦 — 无初始 task 时启动即拉 user_root + } loadTaskList(); loadChannelCards(); // 渠道镜像对话(微信 / 企业微信)固定卡片,与列表并行拉 - loadFiles(); // 文件面板与 task 解耦 — 启动即拉 user_root loadModels(); // 模型清单缓存:chat-meta 下拉 + 新建对话框 + 历史小标 loadFolderSuggestions(); // 灌 filter-wd select(modal 打开时会重拉,这里让左 pane 先有选项) loadStorage(); // 顶栏存储用量(后台扫描快照,非实时)