fix(web): open embedded task working directory

This commit is contained in:
caoqianming 2026-07-31 13:54:22 +08:00
parent 3c022494f5
commit da265b88d5
6 changed files with 39 additions and 18 deletions

View File

@ -5,6 +5,10 @@
> 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。 > 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。
> 工程口径的完整记录见 `PROGRESS.md` / git log。 > 工程口径的完整记录见 `PROGRESS.md` / git log。
## 0.60.15 — 2026-07-31
- 从 platform、企业微信或 App 携带指定对话进入时,现在会直接打开该对话对应的工作目录,右侧文件栏不再停留在用户根目录。
## 0.60.14 — 2026-07-31 ## 0.60.14 — 2026-07-31
- 自动命名的普通对话在清空后会回到“新对话”,并根据下一次询问重新生成标题;用户手动设置的任务名以及微信、企业微信等固定会话名保持不变。 - 自动命名的普通对话在清空后会回到“新对话”,并根据下一次询问重新生成标题;用户手动设置的任务名以及微信、企业微信等固定会话名保持不变。

View File

@ -2,7 +2,7 @@
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9` > 配合 `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 ### 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.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 格式检查通过。 - **07-31 / 0.60.13 / 渠道常驻会话操作收口**:微信与企业微信的 web 只读镜像只保留导出和清空对话,隐藏普通任务才适用的完成、废弃、重命名和删除操作,顶部独立完成按钮同步隐藏;普通任务菜单不变。纯前端行为修正,无 API、schema、migration 或依赖变化JavaScript 语法及 diff 格式检查通过。

View File

@ -1,3 +1,3 @@
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
# 改版本只动这一行。 # 改版本只动这一行。
__version__ = "0.60.14" __version__ = "0.60.15"

View File

@ -83,6 +83,19 @@ class StaticVendorTests(unittest.TestCase):
self.assertIn("context_original_chars", src) self.assertIn("context_original_chars", src)
self.assertIn("cache_hit_tokens", 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: def test_static_js_is_served_with_revalidation_header(self) -> None:
with tempfile.TemporaryDirectory() as tmp: with tempfile.TemporaryDirectory() as tmp:
static_dir = Path(tmp) static_dir = Path(tmp)

View File

@ -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 { state, LS_TOKEN, EMBED_WECOM, EMBED_PARENT_ORIGIN, EMBED_RELOGIN_URL, EMBED_INITIAL_TASK_ID, setIdentity } from "./state.js";
import { $ } from "./dom.js"; import { $ } from "./dom.js";
import { enterApp } from "./main.js"; import { enterApp } from "./main.js";
import { loadTaskList, selectTask } from "./chat.js"; import { loadTaskList } from "./chat.js";
// embed 首个 task 自动定位的一次性标志(仅 embed 段使用) // embed 首个 task 自动定位的一次性标志(仅 embed 段使用)
let _embedInitialTaskHandled = false; let _embedInitialTaskHandled = false;
@ -44,9 +44,8 @@ function embedHandleMessage(e) {
// 401 后重签:重载列表,不重复 enterApp / 不重复定位 task(尊重用户中间切过的选择) // 401 后重签:重载列表,不重复 enterApp / 不重复定位 task(尊重用户中间切过的选择)
loadTaskList(); loadTaskList();
} else { } else {
enterApp(); // 首次签发:若 URL 带 task_id直接进入该 taskenterApp 不再先加载根目录。
// 首次签发:若 URL 带 task_id,定位到该 task(loadMessages 由 selectTask 触发) enterApp(takeInitialTaskId());
gotoInitialTask();
} }
} }
} }
@ -62,11 +61,12 @@ function readFragmentToken() {
setIdentity({ user_id: uid }); setIdentity({ user_id: uid });
history.replaceState(null, "", location.pathname + location.search); history.replaceState(null, "", location.pathname + location.search);
} }
function gotoInitialTask() { function takeInitialTaskId() {
if (EMBED_INITIAL_TASK_ID && !_embedInitialTaskHandled) { if (EMBED_INITIAL_TASK_ID && !_embedInitialTaskHandled) {
_embedInitialTaskHandled = true; _embedInitialTaskHandled = true;
selectTask(EMBED_INITIAL_TASK_ID); return EMBED_INITIAL_TASK_ID;
} }
return "";
} }
// ───── wecom 免登变体 ───── // ───── wecom 免登变体 ─────
@ -79,8 +79,7 @@ function embedWecomInit() {
document.body.classList.add("embed-mode"); document.body.classList.add("embed-mode");
readFragmentToken(); readFragmentToken();
if (!state.token) { embedWecomRelogin(); return; } if (!state.token) { embedWecomRelogin(); return; }
enterApp(); enterApp(takeInitialTaskId());
gotoInitialTask();
} }
// ───── app 套壳变体 ───── // ───── app 套壳变体 ─────
@ -93,8 +92,7 @@ function embedAppInit() {
document.body.classList.add("embed-mode"); document.body.classList.add("embed-mode");
readFragmentToken(); readFragmentToken();
if (!state.token) { embedAppRelogin(); return; } if (!state.token) { embedAppRelogin(); return; }
enterApp(); enterApp(takeInitialTaskId());
gotoInitialTask();
} }
export function embedInit() { export function embedInit() {
@ -108,8 +106,7 @@ export function embedInit() {
document.body.classList.add("embed-mode"); document.body.classList.add("embed-mode");
window.addEventListener("message", embedHandleMessage); window.addEventListener("message", embedHandleMessage);
if (state.token) { if (state.token) {
enterApp(); enterApp(takeInitialTaskId());
gotoInitialTask();
} else { } else {
document.body.classList.add("embed-waiting"); document.body.classList.add("embed-waiting");
embedShowWaiting("等待登录…", false); embedShowWaiting("等待登录…", false);

View File

@ -16,18 +16,24 @@ import { closeFilePreview, closeMiniPreview } from "./preview.js";
import { closeSrcPicker, loadFiles } from "./files.js"; import { closeSrcPicker, loadFiles } from "./files.js";
import { loadFolderSuggestions } from "./newtask.js"; import { loadFolderSuggestions } from "./newtask.js";
import { embedInit } from "./embed.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"; import { refreshProcs } from "./procs.js";
// ───── enter app ───── // ───── enter app ─────
export function enterApp() { export function enterApp(initialTaskId = "") {
$("login").style.display = "none"; $("login").style.display = "none";
$("app").classList.add("ready"); $("app").classList.add("ready");
renderWho(); // 顶栏用户:默认显 name(兜底 user_name/email/uid8),hover 显完整身份 renderWho(); // 顶栏用户:默认显 name(兜底 user_name/email/uid8),hover 显完整身份
showNewConversationDraft(); // 登录空态与“+ 新对话”共用同一草稿页,不先落 tasks 行 if (initialTaskId) {
// platform / App 带 task_id 进入时直接选中目标 taskselectTask 会同步 working_dir
// 不先初始化新对话草稿和 user_root 文件面板,避免右栏短暂或最终停在根目录。
selectTask(initialTaskId);
} else {
showNewConversationDraft(); // 登录空态与“+ 新对话”共用同一草稿页,不先落 tasks 行
loadFiles(); // 文件面板与 task 解耦 — 无初始 task 时启动即拉 user_root
}
loadTaskList(); loadTaskList();
loadChannelCards(); // 渠道镜像对话(微信 / 企业微信)固定卡片,与列表并行拉 loadChannelCards(); // 渠道镜像对话(微信 / 企业微信)固定卡片,与列表并行拉
loadFiles(); // 文件面板与 task 解耦 — 启动即拉 user_root
loadModels(); // 模型清单缓存:chat-meta 下拉 + 新建对话框 + 历史小标 loadModels(); // 模型清单缓存:chat-meta 下拉 + 新建对话框 + 历史小标
loadFolderSuggestions(); // 灌 filter-wd select(modal 打开时会重拉,这里让左 pane 先有选项) loadFolderSuggestions(); // 灌 filter-wd select(modal 打开时会重拉,这里让左 pane 先有选项)
loadStorage(); // 顶栏存储用量(后台扫描快照,非实时) loadStorage(); // 顶栏存储用量(后台扫描快照,非实时)