Merge pull request #373 from Jstn-1g/fix/162-narrow-auto-activation
fix: avoid forcing mobile drawer on auto-activation
This commit is contained in:
@@ -163,7 +163,7 @@ dsh registry enable dsh-external/dsh-better-sidebar
|
||||
| **🗂️ 文件工作台:资源管理器**<br/><sub>支持两种格式的资源管理器:内嵌在文件预览中 / 独立显示文件树。懒加载目录树、软链接按目标类型展示(目录软链接可展开、失效链接标红)、全局文件名搜索、上传文件/文件夹与拖放上传、右键菜单(在新 Tab 打开 / 在侧边打开 / 复制路径)、悬浮 `@文件` 一键引用进输入框。</sub><br/><div align="center"><img width="420" alt="文件资源管理器" src="https://github.com/user-attachments/assets/a410bfd2-a8ba-43e6-873e-22417756e94d" /></div> | **📝 Markdown · 图片 · PDF 内联预览**<br/><sub>Markdown 预览支持 **Mermaid 图表**(`securityLevel: 'strict'` 安全渲染 + 二次清洗;点击图表弹窗放大、滚轮缩放、拖拽平移)、**README 级内嵌 HTML**(徽章墙 `<div align=center>`、`<details>` 折叠块内嵌 markdown、表格单元格内联标签——DOMPurify 白名单消毒真实渲染,`<script>` 等活性内容剥除,本地图片经会话媒体路由重写)与**浮动目录大纲**(≥3 标题出现,点击平滑跳转、自动展开折叠块);图片 / PDF 走媒体路由内联展示;Office 三件套由生态插件补齐。</sub><br/><div align="center"><img width="420" alt="Markdown + Mermaid 预览" src="https://github.com/user-attachments/assets/fe0e5182-55bb-45cc-b98b-a2877c2bdd38" /></div> |
|
||||
| **🖥️ CodeMirror 代码编辑器**<br/><div align="center"><img width="420" alt="CodeMirror 代码编辑器" src="https://github.com/user-attachments/assets/b44b488e-568c-4ee0-b96c-e9c906598a77" /></div> | **🖼️ 图片内联预览**<br/><div align="center"><img width="420" alt="图片内联预览" src="https://github.com/user-attachments/assets/f9a58c30-5b7a-48b5-9e22-37d7e071f593" /></div> |
|
||||
| **💻 真实终端**<br/><sub>xterm.js + node-pty 真实 shell(不是模拟器):断线重连 transcript 回放、shell / shellArgs 可配置(设置页或 `cordis.patch.yml`)、可选为模型注入 `terminal_*` 工具(agent 可直接开终端跑命令)。</sub><br/><div align="center"><img width="420" alt="真实终端" src="https://github.com/user-attachments/assets/0dad6ad3-ff3f-4b5a-86d2-f832ce65323e" /></div> | **🌿 文件变动:Git 视角 + 本轮文件**<br/><sub>双视角合一:**Git 视角**保留完整源代码管理(暂存 / 取消暂存 / 提交(`Ctrl+Enter`)/ 还原、历史、worktree 与子仓库选择);**本轮文件视角**实时折叠会话事件日志,记录模型读 / 写 / 编辑的每个文件(按文件分组、按类型筛选、操作数角标)。点击任意改动在底部**可拖拽预览面板**查看统一 diff——删红 / 增绿 / 改蓝配对 + 行内字符级高亮 + 语法着色 + 上下文折叠——也可一键展开为 VSCode 式独立 diff tab(同一渲染栈)。</sub><br/><div align="center"><img width="420" alt="文件变动" src="https://github.com/user-attachments/assets/e7fc1220-305f-4bca-8583-e77ab4f4fa78" /></div> |
|
||||
| **🌐 内嵌浏览器**<br/><sub>多开网页 tab:后退 / 前进 / 刷新 / 地址栏;内容运行在**不透明源沙箱 iframe**(界面实时显示沙箱状态,可按页面临时解锁);聊天里的外链点击可被接管到侧边栏打开(按协议分流,可配)。</sub><br/><div align="center"><img width="420" alt="内嵌浏览器" src="https://github.com/user-attachments/assets/9bc6b65a-64fc-4942-a685-76e391e55606" /></div> | **🧩 任务页:子代理拓扑 + 后台任务**<br/><sub>子代理树实时拓扑(运行状态、批量实时预览)+ 后台任务清单(退出码 / 实时输出 / 强制终止);新子代理 / 新任务可自动展开侧边栏(可关)。</sub><br/><div align="center"><img width="420" alt="任务页:子代理拓扑" src="https://github.com/user-attachments/assets/dcd8ed2f-59fa-405b-937b-2d250f5034dd" /></div> |
|
||||
| **🌐 内嵌浏览器**<br/><sub>多开网页 tab:后退 / 前进 / 刷新 / 地址栏;内容运行在**不透明源沙箱 iframe**(界面实时显示沙箱状态,可按页面临时解锁);聊天里的外链点击可被接管到侧边栏打开(按协议分流,可配)。</sub><br/><div align="center"><img width="420" alt="内嵌浏览器" src="https://github.com/user-attachments/assets/9bc6b65a-64fc-4942-a685-76e391e55606" /></div> | **🧩 任务页:子代理拓扑 + 后台任务**<br/><sub>子代理树实时拓扑(运行状态、批量实时预览)+ 后台任务清单(退出码 / 实时输出 / 强制终止);新子代理 / 新任务可自动激活任务页,宽屏同时展开侧边栏,窄屏不强制展开全屏抽屉(可关)。</sub><br/><div align="center"><img width="420" alt="任务页:子代理拓扑" src="https://github.com/user-attachments/assets/dcd8ed2f-59fa-405b-937b-2d250f5034dd" /></div> |
|
||||
| **💬 侧边对话(beta)**<br/><sub>Codex 风格侧边线程:**每个对话一个独立 Tab**;线程继承主会话完整上下文(含进行中回合,以 interrupted 诚实冻结)独立运行,不污染主会话;可持续追问、重启冷恢复;一键「保存为新会话」提升为顶层会话。</sub><br/><div align="center"><img width="420" alt="侧边对话(beta)" src="https://github.com/user-attachments/assets/3a338c36-f5de-4000-95f3-4b1cd04f60fc" /></div> | **🪟 双工作台:右侧栏 + 底部面板 + 分栏**<br/><sub>右侧栏与底部面板可同时展开;拖 Tab 到分栏边缘**拆分**、拖到中间**合并**(可跨面板);面板宽高左缘/上缘拖拽调节;移动端自动合并为全宽抽屉;把 tab 拖到主会话区域可变为**自由窗口**(悬浮 / 缩放 / 置顶,拖回 pane 停靠)。</sub><br/><div align="center"><img width="420" alt="双工作台(右侧栏 + 底部面板)" src="https://github.com/user-attachments/assets/dfdb875e-a1a8-4d4b-8340-353736b1708f" /></div> |
|
||||
| **⚙️ 声明式设置**<br/><sub>设置页「侧边卡片」分区:每个 tab / 预览器一张小卡片,独立开关(高亮启用态 + 品牌开关滑块);二级设置经卡片底部「功能设置」条弹窗(开关 / 文本 / 数字 / 下拉);插件自有设置持久化在 `pluginSettings`。</sub><br/><div align="center"><img width="420" alt="声明式设置:侧边卡片" src="https://github.com/user-attachments/assets/0800ca64-621e-48da-b7df-aecfddc3ec29" /></div> | **📱 移动端**<br/><sub>窄屏(<768px)自动切换为全宽抽屉:底栏 tab 一次性并入右侧栏,触屏拖拽可调。</sub><br/><div align="center"><img width="360" alt="移动端全宽抽屉" src="https://github.com/user-attachments/assets/a82ba78a-f4cf-4d85-80e8-050a05beb144" /></div> |
|
||||
|
||||
@@ -367,7 +367,7 @@ GitHub topic [`dsh-better-sidebar`](https://github.com/topics/dsh-better-sidebar
|
||||
|
||||
- 🖥️ **终端跨会话切换保活**([#323](https://github.com/omdsh-dev/DSH-better-sidebar/pull/323)):切到其他会话不再被当作瞬时掉线——客户端卸载时发送 `park` 控制帧,主机跳过 30s 重连宽限倒计时;切回会话(`open()` 取消 parked)或显式关闭恢复正常生命周期;agent 终端保持无限期存活
|
||||
- 📂 **文件树上传遮罩不再拦截 Tab 拖拽**([#317](https://github.com/omdsh-dev/DSH-better-sidebar/pull/317)):拖拽 Tab(重排 / 跨 pane split)经过资源管理器时不再弹上传遮罩、不吞事件——统一按 `dataTransfer.types` 含 `Files` 门控(与面板宿主 shield 一致),Tab 正常落下;OS 文件拖拽行为不变
|
||||
- 💬 **子代理自动展开去抖**([#314](https://github.com/omdsh-dev/DSH-better-sidebar/pull/314)):Side Chat 线程创建不再误弹任务页——0→N 触发 500ms 重臂并对实时快照按原基线重评估,标题过滤器识别线程后才放行;真实子代理依然自动展开
|
||||
- 💬 **子代理自动展开去抖**([#314](https://github.com/omdsh-dev/DSH-better-sidebar/pull/314)):Side Chat 线程创建不再误弹任务页——0→N 触发 500ms 重臂并对实时快照按原基线重评估,标题过滤器识别线程后才放行;真实子代理依然自动激活任务页(宽屏展开侧边栏,窄屏只准备 Tab、不强制展开抽屉)
|
||||
|
||||
### v0.15.0
|
||||
|
||||
|
||||
+2
-2
@@ -163,7 +163,7 @@ Update: `git pull && pnpm install && pnpm build` → `node scripts/package-regis
|
||||
| **🗂️ File Workbench: Explorer**<br/><sub>Two explorer modes: embedded in the file preview / standalone file tree. Lazy-loading directory tree, symlinks classified by target kind (directory links expand, dangling links flagged), global filename search, file/folder upload buttons plus drag-drop upload, context menu (open in new tab / open to the side / copy paths), and a hover `@file` button that references a file straight into the composer.</sub><br/><div align="center"><img width="420" alt="File explorer" src="https://github.com/user-attachments/assets/a410bfd2-a8ba-43e6-873e-22417756e94d" /></div> | **📝 Inline Preview: Markdown · Images · PDF**<br/><sub>The Markdown preview renders **Mermaid diagrams** (strict-mode safe rendering + a second sanitize pass; click a diagram for a zoom modal with wheel-zoom and drag-pan), **README-level inline HTML** (badge walls `<div align=center>`, `<details>` blocks nesting markdown, inline tags in table cells — DOMPurify-sanitized, `<script>` stripped, local media rewritten to the session media route) and a floating **table of contents** (appears with ≥3 headings, smooth-scroll jumping, auto-expanding folded blocks); images / PDFs display inline via the media route; the Office suite is covered by an ecosystem plugin.</sub><br/><div align="center"><img width="420" alt="Markdown + Mermaid preview" src="https://github.com/user-attachments/assets/fe0e5182-55bb-45cc-b98b-a2877c2bdd38" /></div> |
|
||||
| **🖥️ CodeMirror editor**<br/><div align="center"><img width="420" alt="CodeMirror editor" src="https://github.com/user-attachments/assets/b44b488e-568c-4ee0-b96c-e9c906598a77" /></div> | **🖼️ Inline image preview**<br/><div align="center"><img width="420" alt="Inline image preview" src="https://github.com/user-attachments/assets/f9a58c30-5b7a-48b5-9e22-37d7e071f593" /></div> |
|
||||
| **💻 Real Terminal**<br/><sub>xterm.js + node-pty real shell (not an emulator): transcript replay on reconnect, configurable shell / shellArgs (settings page or `cordis.patch.yml`), and optional `terminal_*` model tools so the agent can open terminals and run commands itself.</sub><br/><div align="center"><img width="420" alt="Real terminal" src="https://github.com/user-attachments/assets/0dad6ad3-ff3f-4b5a-86d2-f832ce65323e" /></div> | **🌿 Changes: Git lens + This-Session lens**<br/><sub>Two lenses on "what changed?": the **Git lens** keeps the full source-control surface (stage / unstage / commit (`Ctrl+Enter`) / revert, history, worktree and child-repo selectors); the **This Session** lens folds the session event log live, recording every file the model read / wrote / edited (grouped by file, kind-filtered, op-count badge). Clicking any change previews it in the **draggable bottom pane** with the unified diff — del red / add green / mod-blue pairing + intra-line character highlights + syntax coloring + context folding — or expands into a VSCode-style dedicated diff tab (same rendering stack).</sub><br/><div align="center"><img width="420" alt="Changes" src="https://github.com/user-attachments/assets/e7fc1220-305f-4bca-8583-e77ab4f4fa78" /></div> |
|
||||
| **🌐 Embedded Browser**<br/><sub>Multiple web tabs with back / forward / reload / address bar; content runs in an **opaque-origin sandboxed iframe** (live sandbox status in the UI, per-page temporary unlock available); external-link clicks in the chat can be taken over into the sidebar (protocol-based routing, configurable).</sub><br/><div align="center"><img width="420" alt="Embedded browser" src="https://github.com/user-attachments/assets/9bc6b65a-64fc-4942-a685-76e391e55606" /></div> | **🧩 Tasks: Agent Topology + Background Jobs**<br/><sub>Live subagent-tree topology (run states, batched live previews) plus the background-jobs list (exit codes / live output / force-kill); new subagents / jobs can auto-expand the sidebar (configurable).</sub><br/><div align="center"><img width="420" alt="Tasks: subagent topology" src="https://github.com/user-attachments/assets/dcd8ed2f-59fa-405b-937b-2d250f5034dd" /></div> |
|
||||
| **🌐 Embedded Browser**<br/><sub>Multiple web tabs with back / forward / reload / address bar; content runs in an **opaque-origin sandboxed iframe** (live sandbox status in the UI, per-page temporary unlock available); external-link clicks in the chat can be taken over into the sidebar (protocol-based routing, configurable).</sub><br/><div align="center"><img width="420" alt="Embedded browser" src="https://github.com/user-attachments/assets/9bc6b65a-64fc-4942-a685-76e391e55606" /></div> | **🧩 Tasks: Agent Topology + Background Jobs**<br/><sub>Live subagent-tree topology (run states, batched live previews) plus the background-jobs list (exit codes / live output / force-kill); new subagents / jobs can auto-activate the Tasks page, expanding the sidebar on wide viewports without forcing narrow full-screen drawers open (configurable).</sub><br/><div align="center"><img width="420" alt="Tasks: subagent topology" src="https://github.com/user-attachments/assets/dcd8ed2f-59fa-405b-937b-2d250f5034dd" /></div> |
|
||||
| **💬 Side Chat (beta)**<br/><sub>Codex-style side threads: **one independent tab per conversation**; the thread inherits the parent's full context (including the in-progress turn, honestly frozen as "interrupted") and runs independently without polluting the main session; follow-ups survive restarts; one click promotes the thread to a top-level session.</sub><br/><div align="center"><img width="420" alt="Side Chat (beta)" src="https://github.com/user-attachments/assets/3a338c36-f5de-4000-95f3-4b1cd04f60fc" /></div> | **🪟 Dual Workbench: Sidebar + Bottom Panel + Split Panes**<br/><sub>The right sidebar and the bottom panel can stay open together; drag a tab to a pane edge to **split**, to the middle to **merge** (works across panels); panel width/height drag from the left/top edge; on mobile everything merges into a full-width drawer; drag a tab onto the main conversation area to turn it into a **free window** (float / resize / raise, drag back onto a pane to dock).</sub><br/><div align="center"><img width="420" alt="Dual workbench (right sidebar + bottom panel)" src="https://github.com/user-attachments/assets/dfdb875e-a1a8-4d4b-8340-353736b1708f" /></div> |
|
||||
| **⚙️ Declarative Settings**<br/><sub>The "Side card" section in DSH settings: one small card per tab / viewer with an independent toggle (highlighted enabled state + brand switch); secondary settings open from the "Feature settings" strip at the card bottom (switch / text / number / select rows); plugin-owned settings persist under `pluginSettings`.</sub><br/><div align="center"><img width="420" alt="Declarative settings: side cards" src="https://github.com/user-attachments/assets/0800ca64-621e-48da-b7df-aecfddc3ec29" /></div> | **📱 Mobile**<br/><sub>On narrow screens (<768px) the panels become a full-width drawer: bottom-panel tabs merge into the sidebar once, with touch-friendly dragging.</sub><br/><div align="center"><img width="360" alt="Mobile full-width drawer" src="https://github.com/user-attachments/assets/a82ba78a-f4cf-4d85-80e8-050a05beb144" /></div> |
|
||||
|
||||
@@ -371,7 +371,7 @@ All changes since v0.15.0:
|
||||
|
||||
- 🖥️ **Terminal pty stays alive across conversation switches** ([#323](https://github.com/omdsh-dev/DSH-better-sidebar/pull/323)): switching sessions is no longer treated as a transient drop — the client sends a `park` control frame on unmount and the host skips the 30s reconnect-grace countdown; switching back (`open()` cancels parked) or explicitly closing the tab resumes the normal lifecycle; agent terminals keep their indefinite lifetime
|
||||
- 📂 **File-tree upload overlay no longer intercepts Tab drags** ([#317](https://github.com/omdsh-dev/DSH-better-sidebar/pull/317)): dragging tabs (reorder / cross-pane split) across the explorer no longer shows the upload overlay or swallows the event — gated on `dataTransfer.types` containing `Files` (consistent with the panel-host shield), so tabs land normally; OS file drags behave as before
|
||||
- 💬 **Subagent auto-open debounced** ([#314](https://github.com/omdsh-dev/DSH-better-sidebar/pull/314)): Side Chat thread creation no longer pops the task page — the 0→N trigger rearms for 500ms and re-evaluates the original baseline against the live snapshot, by which time the title filter recognizes the thread; genuine subagents still auto-open
|
||||
- 💬 **Subagent auto-open debounced** ([#314](https://github.com/omdsh-dev/DSH-better-sidebar/pull/314)): Side Chat thread creation no longer pops the task page — the 0→N trigger rearms for 500ms and re-evaluates the original baseline against the live snapshot, by which time the title filter recognizes the thread; genuine subagents still auto-activate the Tasks page (wide viewports expand the sidebar, while narrow viewports prepare the tab without forcing the drawer open)
|
||||
|
||||
### v0.15.0
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
### 4.4 行为修正
|
||||
|
||||
- `state.ts` `loadState`:窄屏新会话默认 `panelOpen=false`(首开才生效;用户手动展开后照常持久化)。
|
||||
- `state.ts` `loadState`:窄屏加载一律以 `panelOpen=false` 开始(包括持久化布局恢复);仅覆盖抽屉可见性,右侧/底部 pane、tab 与自由窗口状态原样恢复。宽屏仍按持久化值或新会话偏好决定展开状态。
|
||||
- `service.ts` `openTab`:窄屏且 seed 带 `path`/`url` 且面板收起 → 自动展开抽屉(dedupe-focus 分支同样生效);纯类型打开不展开;宽屏行为不变。
|
||||
|
||||
### 4.5 样式(`sidebar.module.css`)
|
||||
@@ -61,7 +61,7 @@
|
||||
### 4.6 测试
|
||||
|
||||
- `tests/breakpoints.spec.ts`:断点边界(767 窄 / 768 宽;1024 明确为宽)。
|
||||
- `tests/unit.spec.ts`:`migrateBottomTabs` 4 例(并入第一 leaf 且底部清空/面板关/activePane 重指、右树为 split 时并入最左 leaf、幂等性、空底部树但 activePane 在底部树时重指)+ 窄屏新会话默认收起(stub `window.innerWidth=390`)。
|
||||
- `tests/unit.spec.ts`:`migrateBottomTabs` 4 例(并入第一 leaf 且底部清空/面板关/activePane 重指、右树为 split 时并入最左 leaf、幂等性、空底部树但 activePane 在底部树时重指)+ 窄屏新会话默认收起;`tests/state.spec.ts` 守护窄屏恢复强制收起且 pane / free-window 状态不丢,768px 宽屏仍恢复持久化展开值。
|
||||
- `tests/service.spec.ts`:窄屏 auto-expand 5 例(390 < 768 仍窄)。
|
||||
|
||||
## 5. 边界情况
|
||||
|
||||
+24
-13
@@ -553,9 +553,12 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
||||
/**
|
||||
* Subagent auto-activation: the moment the current conversation spawns its
|
||||
* FIRST direct subagent (a 0 → N transition on the list feed), the "auto
|
||||
* open" pref is on, and the Subagent tab type is enabled in settings,
|
||||
* open the panel (if collapsed) and focus the Subagent page
|
||||
* (single-instance: an existing tab is focused, never duplicated).
|
||||
* open" pref is on, and the Tasks tab type is enabled in settings, activate
|
||||
* the Tasks page. Single-instance semantics focus an existing pane tab in
|
||||
* place or raise an existing free window; a new tab lands in the right pane
|
||||
* and is never duplicated. On wide viewports the right panel also expands;
|
||||
* on narrow viewports background activity never forces the full-screen
|
||||
* drawer open over the chat.
|
||||
* Switching to a session that already has subagents never triggers — its
|
||||
* baseline starts at the current count — so a deliberate layout is never
|
||||
* fought.
|
||||
@@ -581,10 +584,15 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
||||
if (!detectNewDirectSubagent(baseline, ctx.sessions.list.getSnapshot(), sessionId)) return
|
||||
if (!store.getPrefs().autoOpenSubagent) return
|
||||
if (ctx.get('betterSidebar')?.isTabEnabled('subagent') === false) return
|
||||
store.reduce(s => s.panelOpen ? s : togglePanel(s))
|
||||
// Pin the landing to the right panel: the auto-opened Subagent page must
|
||||
// appear where the panel just expanded, not in a bottom-panel pane the
|
||||
// user last touched.
|
||||
// Read the viewport when the delayed activation fires: a resize while
|
||||
// the debounce is armed must not let background activity force the
|
||||
// narrow full-screen drawer open over the chat.
|
||||
if (!isNarrowWidth(window.innerWidth)) {
|
||||
store.reduce(s => s.panelOpen ? s : togglePanel(s))
|
||||
}
|
||||
// Choose the right panel as the landing pane for a newly created Tasks
|
||||
// tab. Single-instance dedupe still activates an existing pane tab in
|
||||
// place or raises an existing free window.
|
||||
store.reduce(s => ({ ...s, activePane: firstLeaf(s.splits).id }))
|
||||
ctx.get('betterSidebar')?.openTab({ type: 'subagent', title: t('subagent') })
|
||||
}, AUTO_OPEN_DEBOUNCE_MS)
|
||||
@@ -601,11 +609,12 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
||||
/**
|
||||
* Job auto-activation: the moment a NEW background job appears for the
|
||||
* current conversation (a job id the previous snapshot lacked), the
|
||||
* auto-open pref is on, and the Jobs tab type is enabled, open the panel
|
||||
* (if collapsed) and focus the Jobs page. Unlike the subagent trigger
|
||||
* (0 → N only), ANY new job id triggers: the agent may start several
|
||||
* jobs in one session, and each should surface. A fresh page load never
|
||||
* triggers — its baseline starts at the current snapshot.
|
||||
* auto-open pref is on, and the Tasks tab type is enabled, activate the Tasks
|
||||
* page that contains the background-jobs section. The right panel expands
|
||||
* only on wide viewports. Unlike the subagent trigger (0 → N only), ANY
|
||||
* new job id triggers: the agent may start several jobs in one session, and
|
||||
* each should surface. A fresh page load never triggers — its baseline starts
|
||||
* at the current snapshot.
|
||||
*/
|
||||
const jobBaselineRef = useRef<SidebarSessionList | undefined>(undefined)
|
||||
useEffect(() => {
|
||||
@@ -615,7 +624,9 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
|
||||
if (!detectNewJob(prev, sessionList, sessionId)) return
|
||||
if (!store.getPrefs().autoOpenJobs) return
|
||||
if (ctx.get('betterSidebar')?.isTabEnabled('subagent') === false) return
|
||||
store.reduce(s => s.panelOpen ? s : togglePanel(s))
|
||||
if (!isNarrowWidth(window.innerWidth)) {
|
||||
store.reduce(s => s.panelOpen ? s : togglePanel(s))
|
||||
}
|
||||
store.reduce(s => ({ ...s, activePane: firstLeaf(s.splits).id }))
|
||||
ctx.get('betterSidebar')?.openTab({ type: 'subagent', title: t('subagent') })
|
||||
}, [sessionList, sessionId, store, ctx])
|
||||
|
||||
@@ -199,7 +199,7 @@ export function builtinTabs(ctx: Context, options: BuiltinTabOptions = {}): read
|
||||
order: 30,
|
||||
single: true,
|
||||
// Declarative settings: the auto-open switches render under this row in
|
||||
// the Side card settings page (the Jobs page's own related settings).
|
||||
// the Side card settings page (the Tasks page's related settings).
|
||||
settings: {
|
||||
toggles: [{
|
||||
key: 'autoOpenSubagent',
|
||||
|
||||
@@ -244,10 +244,10 @@ export const ar: Record<string, string> = {
|
||||
settingsConflict: 'تغيّر الإعداد في نافذة أخرى — يُرجى إعادة المحاولة',
|
||||
binaryNoPreview: 'لا يمكن معاينة هذا النوع من الملفات',
|
||||
downloadToView: 'تنزيل للعرض',
|
||||
settingsSubagentTitle: 'فتح صفحة المهام تلقائياً عند ظهور وكيل فرعي',
|
||||
settingsSubagentDesc: 'توسيع البطاقة الجانبية وفتح صفحة المهام عند توليد المحادثة الحالية لوكيل فرعي جديد؛ أوقفها للفتح يدوياً',
|
||||
settingsJobsTitle: 'فتح صفحة المهام الخلفية تلقائياً عند مهمة خلفية جديدة',
|
||||
settingsJobsDesc: 'توسيع البطاقة الجانبية وفتح صفحة المهام الخلفية عند ظهور مهمة خلفية جديدة للمحادثة الحالية (كل مهمة جديدة تُطلق ذلك)؛ أوقفها للفتح يدوياً',
|
||||
settingsSubagentTitle: 'تفعيل صفحة المهام تلقائياً عند ظهور وكيل فرعي',
|
||||
settingsSubagentDesc: 'تُفعَّل صفحة المهام عندما تُنشئ المحادثة الحالية وكيلاً فرعياً جديداً؛ في الشاشات العريضة تُوسَّع البطاقة الجانبية أيضاً، أما في الشاشات الضيقة فلا يُفرض فتح الدرج بملء الشاشة؛ عند إيقاف الخيار يصبح الفتح يدوياً',
|
||||
settingsJobsTitle: 'تفعيل صفحة المهام تلقائياً عند ظهور مهمة خلفية جديدة',
|
||||
settingsJobsDesc: 'تُفعَّل صفحة المهام كلما ظهرت مهمة خلفية جديدة للمحادثة الحالية (كل مهمة جديدة تُطلق التفعيل)؛ في الشاشات العريضة تُوسَّع البطاقة الجانبية أيضاً، أما في الشاشات الضيقة فلا يُفرض فتح الدرج بملء الشاشة؛ عند إيقاف الخيار يصبح الفتح يدوياً',
|
||||
settingsToolsTitle: 'حقن أدوات الطرفية للنموذج',
|
||||
settingsToolsDesc: 'عند التفعيل، يمكن للنموذج إنشاء وتشغيل طرفيات الشريط الجانبي عبر أدوات terminal_* الثمانية (معطّل افتراضياً)',
|
||||
settingsFenceTitle: 'فحص مسارات مساحة العمل',
|
||||
|
||||
@@ -229,10 +229,10 @@ export const de: Record<string, string> = {
|
||||
settingsConflict: 'Die Einstellung wurde in einem anderen Fenster geändert – bitte erneut versuchen',
|
||||
binaryNoPreview: 'Dieser Dateityp kann nicht in der Vorschau angezeigt werden',
|
||||
downloadToView: 'Zum Ansehen herunterladen',
|
||||
settingsSubagentTitle: 'Aufgaben-Seite bei einem Subagenten automatisch öffnen',
|
||||
settingsSubagentDesc: 'Die Seitenkarte wird ausgeklappt und die Aufgaben-Seite geöffnet, wenn die aktuelle Unterhaltung einen neuen Subagenten erzeugt; ausschalten, um sie manuell zu öffnen',
|
||||
settingsJobsTitle: 'Aufgaben-Seite bei einer neuen Hintergrundaufgabe automatisch öffnen',
|
||||
settingsJobsDesc: 'Die Seitenkarte wird ausgeklappt und die Aufgaben-Seite geöffnet, sobald für die aktuelle Unterhaltung eine neue Hintergrundaufgabe erscheint (jede neue Aufgabe löst dies aus); ausschalten, um sie manuell zu öffnen',
|
||||
settingsSubagentTitle: 'Aufgaben-Seite bei einem neuen Subagenten automatisch aktivieren',
|
||||
settingsSubagentDesc: 'Die Aufgaben-Seite aktivieren, wenn die aktuelle Unterhaltung einen neuen Subagenten erzeugt; auf breiten Ansichten wird zusätzlich die Seitenkarte ausgeklappt, auf schmalen Ansichten wird das Öffnen der Vollbild-Schublade nicht erzwungen; ausschalten, um sie manuell zu öffnen',
|
||||
settingsJobsTitle: 'Aufgaben-Seite bei einer neuen Hintergrundaufgabe automatisch aktivieren',
|
||||
settingsJobsDesc: 'Die Aufgaben-Seite aktivieren, sobald für die aktuelle Unterhaltung eine neue Hintergrundaufgabe erscheint (jede neue Aufgabe löst dies aus); auf breiten Ansichten wird zusätzlich die Seitenkarte ausgeklappt, auf schmalen Ansichten wird das Öffnen der Vollbild-Schublade nicht erzwungen; ausschalten, um sie manuell zu öffnen',
|
||||
settingsToolsTitle: 'Terminal-Werkzeuge für das Modell bereitstellen',
|
||||
settingsToolsDesc: 'Wenn aktiviert, kann das Modell über die 8 terminal_*-Werkzeuge Terminale in der Seitenleiste erstellen und steuern (standardmäßig deaktiviert)',
|
||||
settingsFenceTitle: 'Workspace-Pfadkontrolle',
|
||||
|
||||
@@ -236,10 +236,10 @@ export const fr: Record<string, string> = {
|
||||
settingsConflict: 'Les réglages ont été modifiés par une autre fenêtre, veuillez réessayer',
|
||||
binaryNoPreview: 'Ce type de fichier ne prend pas en charge l’aperçu',
|
||||
downloadToView: 'Télécharger pour consulter',
|
||||
settingsSubagentTitle: 'Déployer automatiquement la page de gestion des tâches à la détection d’un sous-agent',
|
||||
settingsSubagentDesc: 'Lorsque la session actuelle produit un nouveau sous-agent, déployer automatiquement la barre latérale et ouvrir la page de gestion des tâches ; une fois désactivé, l’ouverture est manuelle',
|
||||
settingsJobsTitle: 'Déployer automatiquement la page des tâches d’arrière-plan sur nouvelle tâche',
|
||||
settingsJobsDesc: 'Lorsque la session actuelle produit une nouvelle tâche d’arrière-plan, déployer automatiquement la barre latérale et ouvrir la page des tâches (déclenché à chaque nouvelle tâche) ; une fois désactivé, l’ouverture est manuelle',
|
||||
settingsSubagentTitle: 'Activer automatiquement la page Gestion des tâches lorsqu’un sous-agent apparaît',
|
||||
settingsSubagentDesc: 'Lorsqu’un nouveau sous-agent est créé dans la session actuelle, activer la page Gestion des tâches ; sur les écrans larges, déployer également la carte latérale ; sur les écrans étroits, ne pas forcer l’ouverture du tiroir plein écran ; une fois l’option désactivée, l’ouverture est manuelle',
|
||||
settingsJobsTitle: 'Activer automatiquement la page Gestion des tâches à l’arrivée d’une tâche d’arrière-plan',
|
||||
settingsJobsDesc: 'À chaque nouvelle tâche d’arrière-plan dans la session actuelle, activer la page Gestion des tâches (chaque nouvelle tâche déclenche l’activation) ; sur les écrans larges, déployer également la carte latérale ; sur les écrans étroits, ne pas forcer l’ouverture du tiroir plein écran ; une fois l’option désactivée, l’ouverture est manuelle',
|
||||
settingsToolsTitle: 'Injecter des outils de terminal au modèle',
|
||||
settingsToolsDesc: 'Une fois activé, le modèle peut créer et piloter des terminaux de la barre latérale via les 8 outils terminal_* (désactivé par défaut)',
|
||||
settingsFenceTitle: 'Contrôle des chemins de l\'espace de travail',
|
||||
|
||||
@@ -243,10 +243,10 @@ export const hi: Record<string, string> = {
|
||||
settingsConflict: 'सेटिंग दूसरी विंडो में बदली — कृपया पुनः प्रयास करें',
|
||||
binaryNoPreview: 'इस फ़ाइल प्रकार का पूर्वावलोकन नहीं हो सकता',
|
||||
downloadToView: 'देखने के लिए डाउनलोड करें',
|
||||
settingsSubagentTitle: 'सबएजेंट दिखने पर स्वतः कार्य पृष्ठ खोलें',
|
||||
settingsSubagentDesc: 'वर्तमान वार्तालाप में नया सबएजेंट बनने पर साइडबार विस्तृत करें और कार्य पृष्ठ खोलें; बंद करने पर मैन्युअल रूप से खोलें',
|
||||
settingsJobsTitle: 'नया बैकग्राउंड कार्य आने पर स्वतः कार्य पृष्ठ खोलें',
|
||||
settingsJobsDesc: 'वर्तमान वार्तालाप में नया बैकग्राउंड कार्य दिखने पर साइडबार विस्तृत करें और कार्य पृष्ठ खोलें (हर नया कार्य ट्रिगर करता है); बंद करने पर मैन्युअल रूप से खोलें',
|
||||
settingsSubagentTitle: 'सबएजेंट दिखने पर कार्य पृष्ठ स्वतः सक्रिय करें',
|
||||
settingsSubagentDesc: 'वर्तमान वार्तालाप में नया सबएजेंट बनने पर कार्य पृष्ठ सक्रिय करें; चौड़ी स्क्रीन पर साइड कार्ड भी विस्तृत होता है, जबकि संकीर्ण स्क्रीन पर पूर्ण-स्क्रीन दराज को जबरन नहीं खोला जाता; विकल्प बंद होने पर इसे मैन्युअल रूप से खोलना होगा',
|
||||
settingsJobsTitle: 'नया बैकग्राउंड कार्य आने पर कार्य पृष्ठ स्वतः सक्रिय करें',
|
||||
settingsJobsDesc: 'वर्तमान वार्तालाप में हर नया बैकग्राउंड कार्य आने पर कार्य पृष्ठ सक्रिय करें (हर नया कार्य ट्रिगर करता है); चौड़ी स्क्रीन पर साइड कार्ड भी विस्तृत होता है, जबकि संकीर्ण स्क्रीन पर पूर्ण-स्क्रीन दराज को जबरन नहीं खोला जाता; विकल्प बंद होने पर इसे मैन्युअल रूप से खोलना होगा',
|
||||
settingsToolsTitle: 'मॉडल के लिए टर्मिनल टूल इंजेक्ट करें',
|
||||
settingsToolsDesc: 'सक्षम होने पर, मॉडल 8 terminal_* टूल्स से साइडबार टर्मिनल बना और चला सकता है (डिफ़ॉल्ट रूप से बंद)',
|
||||
settingsFenceTitle: 'वर्कस्पेस पाथ जाँच',
|
||||
|
||||
@@ -241,10 +241,10 @@ export const id: Record<string, string> = {
|
||||
settingsConflict: 'Pengaturan diubah di jendela lain — silakan coba lagi',
|
||||
binaryNoPreview: 'Tipe berkas ini tidak dapat dipratinjau',
|
||||
downloadToView: 'Unduh untuk melihat',
|
||||
settingsSubagentTitle: 'Buka otomatis halaman Tasks saat subagen muncul',
|
||||
settingsSubagentDesc: 'Bentangkan kartu samping dan buka halaman Tasks saat obrolan saat ini menelurkan subagen baru; matikan untuk membukanya secara manual',
|
||||
settingsJobsTitle: 'Buka otomatis halaman Jobs saat ada tugas latar baru',
|
||||
settingsJobsDesc: 'Bentangkan kartu samping dan buka halaman Jobs setiap kali tugas latar baru muncul untuk obrolan saat ini (setiap tugas baru memicu); matikan untuk membukanya secara manual',
|
||||
settingsSubagentTitle: 'Aktifkan otomatis halaman Tasks saat subagen muncul',
|
||||
settingsSubagentDesc: 'Aktifkan halaman Tasks saat obrolan saat ini membuat subagen baru; pada layar lebar, kartu samping juga dibentangkan; pada layar sempit, laci layar penuh tidak dipaksa terbuka; matikan untuk membukanya secara manual',
|
||||
settingsJobsTitle: 'Aktifkan otomatis halaman Tasks saat ada tugas latar baru',
|
||||
settingsJobsDesc: 'Aktifkan halaman Tasks setiap kali tugas latar baru muncul untuk obrolan saat ini (setiap tugas baru memicu aktivasi); pada layar lebar, kartu samping juga dibentangkan; pada layar sempit, laci layar penuh tidak dipaksa terbuka; matikan untuk membukanya secara manual',
|
||||
settingsToolsTitle: 'Suntik alat terminal untuk model',
|
||||
settingsToolsDesc: 'Saat diaktifkan, model dapat membuat dan mengendalikan terminal sidebar melalui 8 alat terminal_* (nonaktif secara default)',
|
||||
settingsFenceTitle: 'Pemeriksaan path workspace',
|
||||
|
||||
@@ -234,10 +234,10 @@ export const it: Record<string, string> = {
|
||||
settingsConflict: 'L’impostazione è stata modificata in un’altra finestra — riprovi',
|
||||
binaryNoPreview: 'Questo tipo di file non può essere visualizzato in anteprima',
|
||||
downloadToView: 'Scarica per visualizzare',
|
||||
settingsSubagentTitle: 'Apri automaticamente la pagina Attività quando compare un sottoagente',
|
||||
settingsSubagentDesc: 'Espande la barra laterale e apre la pagina Attività quando la conversazione attuale genera un nuovo sottoagente; disattivato va aperta manualmente',
|
||||
settingsJobsTitle: 'Apri automaticamente la pagina Attività in background in caso di nuova attività',
|
||||
settingsJobsDesc: 'Espande la barra laterale e apre la pagina Attività in background ogni volta che compare una nuova attività in background per la conversazione attuale (ogni nuova attività la attiva); disattivato va aperta manualmente',
|
||||
settingsSubagentTitle: 'Attiva automaticamente la pagina Attività quando compare un sottoagente',
|
||||
settingsSubagentDesc: 'Quando nella conversazione attuale compare un nuovo sottoagente, attiva automaticamente la pagina Attività; sugli schermi ampi espande anche la barra laterale, mentre sugli schermi stretti non forza l’apertura del pannello a schermo intero; disattiva per selezionare la pagina manualmente',
|
||||
settingsJobsTitle: 'Attiva automaticamente la pagina Attività quando compare una nuova attività in background',
|
||||
settingsJobsDesc: 'Quando nella conversazione attuale compare una nuova attività in background, attiva automaticamente la pagina Attività (l’attivazione avviene per ogni nuova attività); sugli schermi ampi espande anche la barra laterale, mentre sugli schermi stretti non forza l’apertura del pannello a schermo intero; disattiva per selezionare la pagina manualmente',
|
||||
settingsToolsTitle: 'Inietta strumenti del terminale per il modello',
|
||||
settingsToolsDesc: 'Se attivato, il modello può creare e gestire terminali della barra laterale attraverso gli 8 strumenti terminal_* (disattivato per impostazione predefinita)',
|
||||
settingsFenceTitle: 'Controllo dei percorsi del workspace',
|
||||
|
||||
@@ -243,10 +243,10 @@ export const ja: Record<string, string> = {
|
||||
settingsConflict: '設定が別のウィンドウで変更されました、再試行してください',
|
||||
binaryNoPreview: 'このファイル形式はプレビューできません',
|
||||
downloadToView: 'ダウンロードして表示',
|
||||
settingsSubagentTitle: 'サブエージェント検出時に自動展開',
|
||||
settingsSubagentDesc: '現在の会話で新しいサブエージェントが発生した際、サイドバーを自動展開してタスク管理ページを開く。オフ時は手動で開く必要あり',
|
||||
settingsJobsTitle: '新規バックグラウンドタスク時に自動展開',
|
||||
settingsJobsDesc: '現在の会話で新しいバックグラウンドタスクが発生するたびにサイドバーを展開してタスクページを開く(新規タスクごとに発火)。オフ時は手動で開く必要あり',
|
||||
settingsSubagentTitle: 'サブエージェント検出時にタスク管理ページを自動的にアクティブ化',
|
||||
settingsSubagentDesc: '現在の会話で新しいサブエージェントが発生した際にタスク管理ページをアクティブ化する。広い画面ではサイドカードも展開するが、狭い画面では全画面ドロワーを強制的に開かない。オフにすると手動で開く必要がある',
|
||||
settingsJobsTitle: '新規バックグラウンドタスク時にタスク管理ページを自動的にアクティブ化',
|
||||
settingsJobsDesc: '現在の会話で新しいバックグラウンドタスクが発生するたびにタスク管理ページをアクティブ化する(新規タスクごとに発火)。広い画面ではサイドカードも展開するが、狭い画面では全画面ドロワーを強制的に開かない。オフにすると手動で開く必要がある',
|
||||
settingsToolsTitle: 'モデルにターミナルツールを注入',
|
||||
settingsToolsDesc: 'オンにすると、モデルが terminal_create 等 8 個のツールでサイドバーターミナルを作成・操作可能(デフォルトオフ)',
|
||||
settingsFenceTitle: 'ワークスペースパスガード',
|
||||
|
||||
@@ -235,10 +235,10 @@ export const ko: Record<string, string> = {
|
||||
settingsConflict: '설정이 다른 창에서 수정되었습니다. 다시 시도하세요',
|
||||
binaryNoPreview: '이 파일 형식은 미리보기를 지원하지 않습니다',
|
||||
downloadToView: '다운로드하여 보기',
|
||||
settingsSubagentTitle: '서브 에이전트를 감지하면 작업 관리 페이지를 자동으로 펼치기',
|
||||
settingsSubagentDesc: '현재 대화에 새 서브 에이전트가 생기면 사이드바를 자동으로 펼치고 작업 관리 페이지를 엽니다. 끄면 수동으로 열어야 합니다',
|
||||
settingsJobsTitle: '새 백그라운드 작업이 있으면 백그라운드 작업 페이지를 자동으로 펼치기',
|
||||
settingsJobsDesc: '현재 대화에 새 백그라운드 작업이 생기면 사이드바를 자동으로 펼치고 백그라운드 작업 페이지를 엽니다(새 작업마다 트리거됨). 끄면 수동으로 열어야 합니다',
|
||||
settingsSubagentTitle: '서브 에이전트를 감지하면 작업 관리 페이지 자동 활성화',
|
||||
settingsSubagentDesc: '현재 대화에 새 서브 에이전트가 생기면 작업 관리 페이지를 활성화합니다. 넓은 화면에서는 사이드 카드도 펼치지만, 좁은 화면에서는 전체 화면 드로어를 강제로 열지 않습니다. 끄면 수동으로 열어야 합니다',
|
||||
settingsJobsTitle: '새 백그라운드 작업이 생기면 작업 관리 페이지 자동 활성화',
|
||||
settingsJobsDesc: '현재 대화에 새 백그라운드 작업이 생길 때마다 작업 관리 페이지를 활성화합니다(새 작업마다 트리거됨). 넓은 화면에서는 사이드 카드도 펼치지만, 좁은 화면에서는 전체 화면 드로어를 강제로 열지 않습니다. 끄면 수동으로 열어야 합니다',
|
||||
settingsToolsTitle: '모델에 터미널 도구 주입',
|
||||
settingsToolsDesc: '켜면 모델이 terminal_create 등 8개 도구로 사이드바 터미널을 만들고 조작할 수 있습니다(기본 꺼짐)',
|
||||
settingsFenceTitle: '워크스페이스 경로 검사',
|
||||
|
||||
@@ -241,10 +241,10 @@ export const nl: Record<string, string> = {
|
||||
settingsConflict: 'De instelling is in een ander venster gewijzigd — probeer het opnieuw',
|
||||
binaryNoPreview: 'Dit bestandstype kan niet worden gepreviewed',
|
||||
downloadToView: 'Downloaden om te bekijken',
|
||||
settingsSubagentTitle: 'Taken-pagina automatisch openen wanneer een subagent verschijnt',
|
||||
settingsSubagentDesc: 'De zijkaart uitklappen en de Taken-pagina openen wanneer de huidige conversatie een nieuwe subagent voortbrengt; schakel uit om het handmatig te openen',
|
||||
settingsJobsTitle: 'Jobs-pagina automatisch openen bij een nieuwe achtergrondtaak',
|
||||
settingsJobsDesc: 'De zijkaart uitklappen en de Jobs-pagina openen telkens een nieuwe achtergrondtaak verschijnt voor de huidige conversatie (elke nieuwe taak triggert); schakel uit om het handmatig te openen',
|
||||
settingsSubagentTitle: 'Activeer de Taken-pagina automatisch wanneer een subagent verschijnt',
|
||||
settingsSubagentDesc: 'Wanneer de huidige conversatie een nieuwe subagent start, wordt de Taken-pagina automatisch geactiveerd; op brede schermen wordt ook de zijkaart uitgeklapt, terwijl op smalle schermen het schuifpaneel op volledig scherm niet geforceerd wordt geopend; schakel uit om de pagina handmatig te selecteren',
|
||||
settingsJobsTitle: 'Activeer de Taken-pagina automatisch bij een nieuwe achtergrondtaak',
|
||||
settingsJobsDesc: 'Wanneer er voor de huidige conversatie een nieuwe achtergrondtaak verschijnt, wordt de Taken-pagina automatisch geactiveerd (dit gebeurt bij elke nieuwe taak); op brede schermen wordt ook de zijkaart uitgeklapt, terwijl op smalle schermen het schuifpaneel op volledig scherm niet geforceerd wordt geopend; schakel uit om de pagina handmatig te selecteren',
|
||||
settingsToolsTitle: 'Terminaltools voor het model injecteren',
|
||||
settingsToolsDesc: 'Indien ingeschakeld kan het model zijbalk-terminals aanmaken en besturen via de 8 terminal_*-tools (standaard uit)',
|
||||
settingsFenceTitle: 'Workspace-padcontrole',
|
||||
|
||||
@@ -245,10 +245,10 @@ export const pl: Record<string, string> = {
|
||||
settingsConflict: 'Ustawienie zmienione w innym oknie — spróbuj ponownie',
|
||||
binaryNoPreview: 'Tego typu pliku nie można wyświetlić w podglądzie',
|
||||
downloadToView: 'Pobierz, aby zobaczyć',
|
||||
settingsSubagentTitle: 'Automatycznie otwieraj stronę Zadań przy pojawieniu się podagenta',
|
||||
settingsSubagentDesc: 'Gdy bieżąca rozmowa powoła nowego podagenta, rozwiń panel boczny i otwórz stronę Zadań; wyłącz, aby otwierać ręcznie',
|
||||
settingsJobsTitle: 'Automatycznie otwieraj stronę zadań w tle przy nowym zadaniu',
|
||||
settingsJobsDesc: 'Gdy w bieżącej rozmowie pojawi się nowe zadanie w tle, rozwiń panel boczny i otwórz stronę zadań w tle (każde nowe zadanie wyzwala); wyłącz, aby otwierać ręcznie',
|
||||
settingsSubagentTitle: 'Automatycznie aktywuj stronę „Zadania” po pojawieniu się podagenta',
|
||||
settingsSubagentDesc: 'Gdy w bieżącej rozmowie pojawi się nowy podagent, automatycznie aktywuj stronę „Zadania”; na szerokich ekranach rozwiń także panel boczny, a na wąskich nie wymuszaj otwarcia pełnoekranowego panelu; wyłącz, aby wybierać stronę ręcznie',
|
||||
settingsJobsTitle: 'Automatycznie aktywuj stronę „Zadania” po pojawieniu się nowego zadania w tle',
|
||||
settingsJobsDesc: 'Gdy w bieżącej rozmowie pojawi się nowe zadanie w tle, automatycznie aktywuj stronę „Zadania” (akcja jest wyzwalana przez każde nowe zadanie); na szerokich ekranach rozwiń także panel boczny, a na wąskich nie wymuszaj otwarcia pełnoekranowego panelu; wyłącz, aby wybierać stronę ręcznie',
|
||||
settingsToolsTitle: 'Wstrzyknij narzędzia terminala dla modelu',
|
||||
settingsToolsDesc: 'Po włączeniu model może tworzyć i sterować terminalami panelu bocznego przez 8 narzędzi terminal_* (domyślnie wyłączone)',
|
||||
settingsFenceTitle: 'Kontrola ścieżek obszaru roboczego',
|
||||
|
||||
@@ -226,10 +226,10 @@ export const pt: Record<string, string> = {
|
||||
settingsConflict: 'A configuração foi alterada em outra janela — tente novamente',
|
||||
binaryNoPreview: 'Este tipo de arquivo não pode ser pré-visualizado',
|
||||
downloadToView: 'Baixar para ver',
|
||||
settingsSubagentTitle: 'Abrir automaticamente a página de Tarefas quando um subagente aparecer',
|
||||
settingsSubagentDesc: 'Expandir o cartão lateral e abrir a página de Tarefas quando a conversa atual gerar um novo subagente; desative para abrir manualmente',
|
||||
settingsJobsTitle: 'Abrir automaticamente a página de Tarefas em segundo plano quando houver uma nova tarefa',
|
||||
settingsJobsDesc: 'Expandir o cartão lateral e abrir a página de Tarefas sempre que uma nova tarefa em segundo plano aparecer para a conversa atual (cada nova tarefa dispara); desative para abrir manualmente',
|
||||
settingsSubagentTitle: 'Ativar automaticamente a página de Tarefas quando um subagente aparecer',
|
||||
settingsSubagentDesc: 'Ativar a página de Tarefas quando a conversa atual gerar um novo subagente; em telas largas, expandir também o cartão lateral; em telas estreitas, não forçar a abertura da gaveta em tela cheia; desative para abri-la manualmente',
|
||||
settingsJobsTitle: 'Ativar automaticamente a página de Tarefas quando houver uma nova tarefa em segundo plano',
|
||||
settingsJobsDesc: 'Ativar a página de Tarefas sempre que uma nova tarefa em segundo plano aparecer na conversa atual (cada nova tarefa aciona a ativação); em telas largas, expandir também o cartão lateral; em telas estreitas, não forçar a abertura da gaveta em tela cheia; desative para abri-la manualmente',
|
||||
settingsToolsTitle: 'Injetar ferramentas de terminal para o modelo',
|
||||
settingsToolsDesc: 'Quando ativado, o modelo pode criar e operar terminais da barra lateral por meio das 8 ferramentas terminal_* (desativado por padrão)',
|
||||
settingsFenceTitle: 'Controle de caminhos do workspace',
|
||||
|
||||
@@ -240,10 +240,10 @@ export const ru: Record<string, string> = {
|
||||
settingsConflict: 'Настройки были изменены в другом окне — повторите',
|
||||
binaryNoPreview: 'Этот тип файла не поддерживает предпросмотр',
|
||||
downloadToView: 'Скачать для просмотра',
|
||||
settingsSubagentTitle: 'Автоматически разворачивать страницу «Задачи» при появлении субагента',
|
||||
settingsSubagentDesc: 'При появлении нового субагента в текущей сессии боковая панель автоматически разворачивается и открывается страница «Задачи»; при отключении нужно открывать вручную',
|
||||
settingsJobsTitle: 'Автоматически разворачивать страницу «Фоновые задачи» при новой задаче',
|
||||
settingsJobsDesc: 'При появлении новой фоновой задачи в текущей сессии боковая панель автоматически разворачивается и открывается страница «Фоновые задачи» (срабатывает на каждую новую задачу); при отключении нужно открывать вручную',
|
||||
settingsSubagentTitle: 'Автоматически активировать страницу «Задачи» при появлении субагента',
|
||||
settingsSubagentDesc: 'При появлении нового субагента в текущей сессии автоматически активируется страница «Задачи»; на широких экранах также разворачивается боковая панель, а на узких экранах полноэкранная выдвижная панель не открывается принудительно; отключите, чтобы выбирать страницу вручную',
|
||||
settingsJobsTitle: 'Автоматически активировать страницу «Задачи» при появлении новой фоновой задачи',
|
||||
settingsJobsDesc: 'При появлении новой фоновой задачи в текущей сессии автоматически активируется страница «Задачи» (срабатывает для каждой новой задачи); на широких экранах также разворачивается боковая панель, а на узких экранах полноэкранная выдвижная панель не открывается принудительно; отключите, чтобы выбирать страницу вручную',
|
||||
settingsToolsTitle: 'Внедрить терминальные инструменты для модели',
|
||||
settingsToolsDesc: 'Если включено, модель может через 8 инструментов (terminal_create и др.) создавать терминалы боковой панели и управлять ими (по умолчанию выключено)',
|
||||
settingsFenceTitle: 'Контроль путей рабочей области',
|
||||
|
||||
@@ -226,10 +226,10 @@ export const sv: Record<string, string> = {
|
||||
settingsConflict: 'Inställningen ändrades i ett annat fönster — vänligen försök igen',
|
||||
binaryNoPreview: 'Denna filtyp kan inte förhandsgranskas',
|
||||
downloadToView: 'Ladda ner för att visa',
|
||||
settingsSubagentTitle: 'Öppna automatiskt Uppgiftssidan när en subagent dyker upp',
|
||||
settingsSubagentDesc: 'Expandera sidokortet och öppna Uppgiftssidan när aktuell konversation skapar en ny subagent; stäng av för att öppna manuellt',
|
||||
settingsJobsTitle: 'Öppna automatiskt Jobbsidan vid nytt bakgrundsjobb',
|
||||
settingsJobsDesc: 'Expandera sidokortet och öppna Jobbsidan när ett nytt bakgrundsjobb dyker upp för aktuell konversation (varje nytt jobb utlöser); stäng av för att öppna manuellt',
|
||||
settingsSubagentTitle: 'Aktivera sidan Uppgifter automatiskt när en subagent dyker upp',
|
||||
settingsSubagentDesc: 'När den aktuella konversationen skapar en ny subagent aktiveras sidan Uppgifter automatiskt; på breda skärmar expanderas även sidokortet, medan helskärmspanelen inte tvingas öppnas på smala skärmar; stäng av för att välja sidan manuellt',
|
||||
settingsJobsTitle: 'Aktivera sidan Uppgifter automatiskt vid ett nytt bakgrundsjobb',
|
||||
settingsJobsDesc: 'När ett nytt bakgrundsjobb dyker upp för den aktuella konversationen aktiveras sidan Uppgifter automatiskt (detta sker för varje nytt jobb); på breda skärmar expanderas även sidokortet, medan helskärmspanelen inte tvingas öppnas på smala skärmar; stäng av för att välja sidan manuellt',
|
||||
settingsToolsTitle: 'Injicera terminalverktyg för modellen',
|
||||
settingsToolsDesc: 'När aktiverat kan modellen skapa och styra sidopanelsterminaler via de 8 terminal_*-verktygen (av som standard)',
|
||||
settingsFenceTitle: 'Kontroll av workspace-sökvägar',
|
||||
|
||||
@@ -243,10 +243,10 @@ export const th: Record<string, string> = {
|
||||
settingsConflict: 'การตั้งค่าถูกเปลี่ยนในหน้าต่างอื่น — โปรดลองอีกครั้ง',
|
||||
binaryNoPreview: 'ไม่สามารถพรีวิวประเภทไฟล์นี้ได้',
|
||||
downloadToView: 'ดาวน์โหลดเพื่อดู',
|
||||
settingsSubagentTitle: 'เปิดหน้า Tasks อัตโนมัติเมื่อมีตัวแทนย่อยปรากฏ',
|
||||
settingsSubagentDesc: 'ขยายการ์ดด้านข้างและเปิดหน้า Tasks เมื่อแชทปัจจุบันสร้างตัวแทนย่อยใหม่; ปิดเพื่อเปิดเอง',
|
||||
settingsJobsTitle: 'เปิดหน้า Jobs อัตโนมัติเมื่อมีงานเบื้องหลังใหม่',
|
||||
settingsJobsDesc: 'ขยายการ์ดด้านข้างและเปิดหน้า Jobs เมื่อใดก็ตามที่มีงานเบื้องหลังใหม่ปรากฏสำหรับแชทปัจจุบัน (ทุกงานใหม่จะทริกเกอร์); ปิดเพื่อเปิดเอง',
|
||||
settingsSubagentTitle: 'เลือกหน้า Tasks โดยอัตโนมัติเมื่อมีตัวแทนย่อยปรากฏ',
|
||||
settingsSubagentDesc: 'เมื่อแชทปัจจุบันสร้างตัวแทนย่อยใหม่ ระบบจะเลือกหน้า Tasks โดยอัตโนมัติ; ในมุมมองแบบกว้าง ระบบจะขยายการ์ดด้านข้างด้วย ส่วนในมุมมองแบบแคบ ระบบจะไม่บังคับเปิดลิ้นชักเต็มหน้าจอ; ปิดเพื่อเลือกหน้าด้วยตนเอง',
|
||||
settingsJobsTitle: 'เลือกหน้า Tasks โดยอัตโนมัติเมื่อมีงานเบื้องหลังใหม่',
|
||||
settingsJobsDesc: 'เมื่อมีงานเบื้องหลังใหม่ปรากฏในแชทปัจจุบัน ระบบจะเลือกหน้า Tasks โดยอัตโนมัติ (ทุกงานใหม่จะทริกเกอร์); ในมุมมองแบบกว้าง ระบบจะขยายการ์ดด้านข้างด้วย ส่วนในมุมมองแบบแคบ ระบบจะไม่บังคับเปิดลิ้นชักเต็มหน้าจอ; ปิดเพื่อเลือกหน้าด้วยตนเอง',
|
||||
settingsToolsTitle: 'ฉีดเครื่องมือเทอร์มินัลสำหรับโมเดล',
|
||||
settingsToolsDesc: 'เมื่อเปิดใช้ โมเดลสามารถสร้างและควบคุมเทอร์มินัลแถบด้านข้างผ่านเครื่องมือ terminal_* 8 ตัว (ปิดเป็นค่าเริ่มต้น)',
|
||||
settingsFenceTitle: 'การตรวจสอบเส้นทางเวิร์กสเปซ',
|
||||
|
||||
@@ -243,10 +243,10 @@ export const tr: Record<string, string> = {
|
||||
settingsConflict: 'Ayar başka bir pencerede değiştirildi — lütfen yeniden deneyin',
|
||||
binaryNoPreview: 'Bu dosya türü önizlenemiyor',
|
||||
downloadToView: 'Görüntülemek için indir',
|
||||
settingsSubagentTitle: 'Bir alt aracı belirdiğinde Görevler sayfasını otomatik aç',
|
||||
settingsSubagentDesc: 'Geçerli sohbet yeni bir alt aracı doğurduğunda yan kartı genişlet ve Görevler sayfasını aç; elle açmak için kapatın',
|
||||
settingsJobsTitle: 'Yeni arka plan işinde İşler sayfasını otomatik aç',
|
||||
settingsJobsDesc: 'Geçerli sohbet için yeni bir arka plan işi belirdiğinde yan kartı genişlet ve İşler sayfasını aç (her yeni iş tetikler); elle açmak için kapatın',
|
||||
settingsSubagentTitle: 'Bir alt aracı belirdiğinde Görevler sayfasını otomatik etkinleştir',
|
||||
settingsSubagentDesc: 'Geçerli sohbet yeni bir alt aracı oluşturduğunda Görevler sayfasını etkinleştir; geniş ekranlarda yan kart da genişletilir, dar ekranlarda tam ekran çekmecesi zorla açılmaz; kapalıyken elle açılması gerekir',
|
||||
settingsJobsTitle: 'Yeni bir arka plan işi belirdiğinde Görevler sayfasını otomatik etkinleştir',
|
||||
settingsJobsDesc: 'Geçerli sohbette her yeni arka plan işi belirdiğinde Görevler sayfasını etkinleştir (her yeni iş tetikler); geniş ekranlarda yan kart da genişletilir, dar ekranlarda tam ekran çekmecesi zorla açılmaz; kapalıyken elle açılması gerekir',
|
||||
settingsToolsTitle: 'Model için terminal araçları enjekte et',
|
||||
settingsToolsDesc: 'Etkinleştirildiğinde model, 8 terminal_* aracı üzerinden kenar çubuğu terminalleri oluşturup kullanabilir (varsayılan kapalı)',
|
||||
settingsFenceTitle: 'Çalışma alanı yol denetimi',
|
||||
|
||||
@@ -243,10 +243,10 @@ export const vi: Record<string, string> = {
|
||||
settingsConflict: 'Cài đặt đã bị sửa bởi cửa sổ khác, vui lòng thử lại',
|
||||
binaryNoPreview: 'Loại tệp này không hỗ trợ xem trước',
|
||||
downloadToView: 'Tải xuống để xem',
|
||||
settingsSubagentTitle: 'Tự động mở trang Quản lý tác vụ khi phát hiện tác nhân con',
|
||||
settingsSubagentDesc: 'Khi phiên hiện tại tạo tác nhân con mới, tự động mở rộng thanh bên và mở trang Quản lý tác vụ; tắt thì phải mở thủ công',
|
||||
settingsJobsTitle: 'Tự động mở trang Tác vụ nền khi có tác vụ nền mới',
|
||||
settingsJobsDesc: 'Khi phiên hiện tại có tác vụ nền mới, tự động mở rộng thanh bên và mở trang Tác vụ nền (mỗi tác vụ mới đều kích hoạt); tắt thì phải mở thủ công',
|
||||
settingsSubagentTitle: 'Tự động kích hoạt trang Quản lý tác vụ khi phát hiện tác nhân con',
|
||||
settingsSubagentDesc: 'Khi phiên hiện tại tạo tác nhân con mới, kích hoạt trang Quản lý tác vụ; trên màn hình rộng, thẻ bên cũng được mở rộng; trên màn hình hẹp, ngăn kéo toàn màn hình không bị ép mở; tắt để mở thủ công',
|
||||
settingsJobsTitle: 'Tự động kích hoạt trang Quản lý tác vụ khi có tác vụ nền mới',
|
||||
settingsJobsDesc: 'Mỗi khi phiên hiện tại có tác vụ nền mới, kích hoạt trang Quản lý tác vụ (mỗi tác vụ mới đều kích hoạt); trên màn hình rộng, thẻ bên cũng được mở rộng; trên màn hình hẹp, ngăn kéo toàn màn hình không bị ép mở; tắt để mở thủ công',
|
||||
settingsToolsTitle: 'Tiêm công cụ terminal cho mô hình',
|
||||
settingsToolsDesc: 'Khi bật, mô hình có thể tạo và điều khiển terminal thanh bên qua 8 công cụ terminal_* (mặc định tắt)',
|
||||
settingsFenceTitle: 'Kiểm tra đường dẫn workspace',
|
||||
|
||||
@@ -258,10 +258,10 @@ export const zhHK: Record<string, string> = {
|
||||
settingsConflict: '設定已被其他視窗修改,請重試',
|
||||
binaryNoPreview: '此檔案類型不支援預覽',
|
||||
downloadToView: '下載檢視',
|
||||
settingsSubagentTitle: '偵測到子代理時自動展開任務管理頁',
|
||||
settingsSubagentDesc: '目前工作階段產生新的子代理時,自動展開側邊欄並開啟任務管理頁;關閉後需手動開啟',
|
||||
settingsJobsTitle: '有新背景任務時自動展開背景任務頁',
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟',
|
||||
settingsSubagentTitle: '偵測到子代理時自動選取任務管理頁',
|
||||
settingsSubagentDesc: '目前工作階段產生新的子代理時,自動選取任務管理頁;寬螢幕時亦會展開側邊欄,窄螢幕時不會強制開啟全螢幕抽屜;關閉後需手動選取',
|
||||
settingsJobsTitle: '有新背景任務時自動選取任務管理頁',
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動選取任務管理頁(每個新任務都會觸發);寬螢幕時亦會展開側邊欄,窄螢幕時不會強制開啟全螢幕抽屜;關閉後需手動選取',
|
||||
settingsToolsTitle: '為模型注入終端工具',
|
||||
settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)',
|
||||
settingsFenceTitle: '工作區路徑檢測',
|
||||
|
||||
@@ -258,10 +258,10 @@ export const zhMO: Record<string, string> = {
|
||||
settingsConflict: '設定已被其他視窗修改,請重試',
|
||||
binaryNoPreview: '此檔案類型不支援預覽',
|
||||
downloadToView: '下載檢視',
|
||||
settingsSubagentTitle: '偵測到子代理時自動展開任務管理頁',
|
||||
settingsSubagentDesc: '目前工作階段產生新的子代理時,自動展開側邊欄並開啟任務管理頁;關閉後需手動開啟',
|
||||
settingsJobsTitle: '有新背景任務時自動展開背景任務頁',
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟',
|
||||
settingsSubagentTitle: '偵測到子代理時自動選取任務管理頁',
|
||||
settingsSubagentDesc: '目前工作階段產生新的子代理時,自動選取任務管理頁;寬螢幕時亦會展開側邊欄,窄螢幕時不會強制開啟全螢幕抽屜;關閉後需手動選取',
|
||||
settingsJobsTitle: '有新背景任務時自動選取任務管理頁',
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動選取任務管理頁(每個新任務都會觸發);寬螢幕時亦會展開側邊欄,窄螢幕時不會強制開啟全螢幕抽屜;關閉後需手動選取',
|
||||
settingsToolsTitle: '為模型注入終端工具',
|
||||
settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)',
|
||||
settingsFenceTitle: '工作區路徑檢測',
|
||||
|
||||
@@ -258,10 +258,10 @@ export const zhTW: Record<string, string> = {
|
||||
settingsConflict: '設定已被其他視窗修改,請重試',
|
||||
binaryNoPreview: '此檔案類型不支援預覽',
|
||||
downloadToView: '下載檢視',
|
||||
settingsSubagentTitle: '偵測到子代理時自動展開任務管理頁',
|
||||
settingsSubagentDesc: '目前工作階段產生新的子代理時,自動展開側邊欄並開啟任務管理頁;關閉後需手動開啟',
|
||||
settingsJobsTitle: '有新背景任務時自動展開背景任務頁',
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動展開側邊欄並開啟背景任務頁(每個新任務都會觸發);關閉後需手動開啟',
|
||||
settingsSubagentTitle: '偵測到子代理時自動選取任務管理頁',
|
||||
settingsSubagentDesc: '目前工作階段產生新的子代理時,自動選取任務管理頁;寬螢幕時亦會展開側邊欄,窄螢幕時不會強制開啟全螢幕抽屜;關閉後需手動選取',
|
||||
settingsJobsTitle: '有新背景任務時自動選取任務管理頁',
|
||||
settingsJobsDesc: '目前工作階段出現新的背景任務時,自動選取任務管理頁(每個新任務都會觸發);寬螢幕時亦會展開側邊欄,窄螢幕時不會強制開啟全螢幕抽屜;關閉後需手動選取',
|
||||
settingsToolsTitle: '為模型注入終端工具',
|
||||
settingsToolsDesc: '開啟後,模型可透過 terminal_create 等 8 個工具建立並操作側邊欄終端(預設關閉)',
|
||||
settingsFenceTitle: '工作區路徑檢測',
|
||||
|
||||
@@ -250,10 +250,10 @@ export const zh = {
|
||||
settingsConflict: '设置已被其他窗口修改,请重试',
|
||||
binaryNoPreview: '此文件类型不支持预览',
|
||||
downloadToView: '下载查看',
|
||||
settingsSubagentTitle: '检测到子代理时自动展开任务管理页',
|
||||
settingsSubagentDesc: '当前会话产生新的子代理时,自动展开侧边栏并打开任务管理页;关闭后需手动打开',
|
||||
settingsJobsTitle: '有新后台任务时自动展开后台任务页',
|
||||
settingsJobsDesc: '当前会话出现新的后台任务时,自动展开侧边栏并打开后台任务页(每个新任务都会触发);关闭后需手动打开',
|
||||
settingsSubagentTitle: '检测到子代理时自动激活任务管理页',
|
||||
settingsSubagentDesc: '当前会话产生新的子代理时,自动激活任务管理页;宽屏同时展开侧边栏,窄屏不强制展开全屏抽屉;关闭后需手动打开',
|
||||
settingsJobsTitle: '有新后台任务时自动激活任务管理页',
|
||||
settingsJobsDesc: '当前会话出现新的后台任务时,自动激活任务管理页(每个新任务都会触发);宽屏同时展开侧边栏,窄屏不强制展开全屏抽屉;关闭后需手动打开',
|
||||
settingsToolsTitle: '为模型注入终端工具',
|
||||
settingsToolsDesc: '开启后,模型可通过 terminal_create 等 8 个工具创建并操作侧边栏终端(默认关闭)',
|
||||
settingsFenceTitle: '工作区路径检测',
|
||||
@@ -659,10 +659,10 @@ export const en: Record<keyof typeof zh, string> = {
|
||||
settingsConflict: 'The setting changed in another window — please retry',
|
||||
binaryNoPreview: 'This file type cannot be previewed',
|
||||
downloadToView: 'Download to view',
|
||||
settingsSubagentTitle: 'Auto-open the Tasks page when a subagent appears',
|
||||
settingsSubagentDesc: 'Expand the side card and open the Tasks page when the current conversation spawns a new subagent; turn off to open it manually',
|
||||
settingsJobsTitle: 'Auto-open the Jobs page on a new background job',
|
||||
settingsJobsDesc: 'Expand the side card and open the Jobs page whenever a new background job appears for the current conversation (every new job triggers); turn off to open it manually',
|
||||
settingsSubagentTitle: 'Auto-activate the Tasks page when a subagent appears',
|
||||
settingsSubagentDesc: 'Activate the Tasks page when the current conversation spawns a new subagent; wide viewports also expand the side card, while narrow full-screen drawers are not forced open; turn off to open it manually',
|
||||
settingsJobsTitle: 'Auto-activate the Tasks page on a new background job',
|
||||
settingsJobsDesc: 'Activate the Tasks page whenever a new background job appears for the current conversation (every new job triggers); wide viewports also expand the side card, while narrow full-screen drawers are not forced open; turn off to open it manually',
|
||||
settingsToolsTitle: 'Inject terminal tools for the model',
|
||||
settingsToolsDesc: 'When enabled, the model can create and drive sidebar terminals through the 8 terminal_* tools (off by default)',
|
||||
settingsFenceTitle: 'Workspace path fence',
|
||||
|
||||
+12
-5
@@ -1142,6 +1142,7 @@ function resetRequested(): boolean {
|
||||
|
||||
function loadState(sessionId: string, prefs: SidebarPrefs): SidebarState {
|
||||
const reset = resetRequested()
|
||||
const viewport = typeof window !== 'undefined' ? window.innerWidth : undefined
|
||||
if (reset) {
|
||||
try {
|
||||
localStorage.removeItem(`${STORAGE_PREFIX}:${sessionId}`)
|
||||
@@ -1164,7 +1165,15 @@ function loadState(sessionId: string, prefs: SidebarPrefs): SidebarState {
|
||||
nextIdCounter = maxCounterId(parsed)
|
||||
const sanitized = sanitizeState(parsed)
|
||||
if (sanitized !== undefined) {
|
||||
return globalWidth === undefined ? sanitized : { ...sanitized, width: globalWidth }
|
||||
const restored = globalWidth === undefined ? sanitized : { ...sanitized, width: globalWidth }
|
||||
// A narrow panel is a full-screen drawer, so every page/session load
|
||||
// starts it closed even when the prior desktop/mobile state persisted
|
||||
// `panelOpen: true`. Preserve the entire restored workbench (panes,
|
||||
// tabs, bottom panel, and free windows); visibility is the sole
|
||||
// viewport-derived override.
|
||||
return viewport !== undefined && isNarrowWidth(viewport) && restored.panelOpen
|
||||
? { ...restored, panelOpen: false }
|
||||
: restored
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -1179,10 +1188,8 @@ function loadState(sessionId: string, prefs: SidebarPrefs): SidebarState {
|
||||
// disabled editor type seeds nothing. On a NARROW viewport a brand-new
|
||||
// session starts collapsed instead — the panel is a full-screen drawer
|
||||
// there, and auto-opening it on first paint would cover the conversation
|
||||
// before the user asked. Only the first seeding is affected: once the
|
||||
// user expands the drawer, `panelOpen: true` persists like any other
|
||||
// state.
|
||||
const viewport = typeof window !== 'undefined' ? window.innerWidth : undefined
|
||||
// before the user asked. Persisted layouts follow the same narrow-load
|
||||
// visibility rule above, while their workbench contents remain intact.
|
||||
const width = globalWidth ?? (viewport === undefined
|
||||
? PANEL_DEFAULT
|
||||
: defaultWidthFor(viewport, prefs.defaultWidthPercent))
|
||||
|
||||
@@ -62,8 +62,8 @@ export function treeSessionIds(
|
||||
* consecutive list snapshots (a job id the previous snapshot lacked).
|
||||
* Unlike the subagent auto-open (0 → N only), ANY new job id triggers: the
|
||||
* agent may start several jobs over a session, and each new one should
|
||||
* surface the Jobs page (a fresh page load never triggers — its baseline
|
||||
* starts at the current snapshot).
|
||||
* surface the Tasks page containing the background-jobs section (a fresh page
|
||||
* load never triggers — its baseline starts at the current snapshot).
|
||||
*/
|
||||
export function detectNewJob(
|
||||
prev: SidebarSessionList,
|
||||
|
||||
+8
-5
@@ -16,14 +16,17 @@ export interface SidebarPrefs {
|
||||
/** Default panel width as a percent of the window width (20–60). */
|
||||
defaultWidthPercent: number
|
||||
/**
|
||||
* Whether the sidebar auto-activates (opens the panel) and expands the
|
||||
* Subagent page when the current conversation spawns a new subagent.
|
||||
* Whether the sidebar auto-activates the Tasks page when the current
|
||||
* conversation spawns a new subagent. Wide viewports also open the panel;
|
||||
* narrow viewports prepare the tab without opening the full-screen drawer.
|
||||
*/
|
||||
autoOpenSubagent: boolean
|
||||
/**
|
||||
* Whether the sidebar auto-activates (opens the panel) and expands the
|
||||
* Jobs page when a NEW background job appears for the current
|
||||
* conversation (any new job id, not just the first one).
|
||||
* Whether the sidebar auto-activates the Tasks page containing the
|
||||
* background-jobs section when a NEW job appears for the current
|
||||
* conversation (any new job id, not just the first one). Wide viewports also
|
||||
* open the panel; narrow viewports prepare the tab without opening the
|
||||
* full-screen drawer.
|
||||
*/
|
||||
autoOpenJobs: boolean
|
||||
/**
|
||||
|
||||
+2
-2
@@ -306,8 +306,8 @@ describe('side card preferences', () => {
|
||||
}
|
||||
try {
|
||||
const store = createSidebarStore()
|
||||
// The narrow viewport keeps a fresh session collapsed for the FIRST
|
||||
// seeding only (a later user expansion persists).
|
||||
// The narrow viewport keeps a fresh session collapsed. Persisted
|
||||
// sessions follow the same load-time visibility rule in state.spec.ts.
|
||||
store.setSession('narrow-fresh')
|
||||
expect(store.getSnapshot().state?.panelOpen).toBe(false)
|
||||
// The width seeding still follows the window (clamped to the floor).
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* Real-Sidebar regressions for issue #162: background activity should activate
|
||||
* the Tasks page on every viewport, but must not force a narrow full-screen
|
||||
* drawer open over the chat.
|
||||
*/
|
||||
// @vitest-environment jsdom
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createElement } from 'react'
|
||||
import { createRoot, type Root } from 'react-dom/client'
|
||||
import { act } from 'react-dom/test-utils'
|
||||
|
||||
;(globalThis as Record<string, unknown>).IS_REACT_ACT_ENVIRONMENT = true
|
||||
|
||||
import { Sidebar } from '../src/client/Sidebar.tsx'
|
||||
import { allLeaves, createSidebarStore, firstLeaf, type SidebarStore } from '../src/client/state.ts'
|
||||
import { createBetterSidebarService, type BetterSidebarService } from '../src/client/service.ts'
|
||||
import type { Context, SidebarSessionList } from '../src/context-types.ts'
|
||||
|
||||
class FakeWebSocket {
|
||||
onmessage: ((event: { data: unknown }) => void) | null = null
|
||||
onclose: (() => void) | null = null
|
||||
onerror: (() => void) | null = null
|
||||
close = (): void => {}
|
||||
constructor(_url: string) {}
|
||||
}
|
||||
|
||||
function makeSessionFeed(initial: SidebarSessionList) {
|
||||
let snapshot = initial
|
||||
const listeners = new Set<() => void>()
|
||||
return {
|
||||
getSnapshot: () => snapshot,
|
||||
subscribe: (listener: () => void) => {
|
||||
listeners.add(listener)
|
||||
return () => { listeners.delete(listener) }
|
||||
},
|
||||
set(next: SidebarSessionList): void {
|
||||
snapshot = next
|
||||
for (const listener of [...listeners]) listener()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type SessionFeed = ReturnType<typeof makeSessionFeed>
|
||||
|
||||
interface MountedSidebar {
|
||||
store: SidebarStore
|
||||
service: BetterSidebarService
|
||||
feed: SessionFeed
|
||||
unmount: () => void
|
||||
}
|
||||
|
||||
let sessionSeq = 0
|
||||
const mounted: MountedSidebar[] = []
|
||||
|
||||
function setViewport(width: number): void {
|
||||
Object.defineProperty(window, 'innerWidth', { configurable: true, value: width })
|
||||
}
|
||||
|
||||
function mountSidebar(width: number, panelOpen = false): MountedSidebar {
|
||||
setViewport(width)
|
||||
vi.stubGlobal('WebSocket', FakeWebSocket)
|
||||
const sessionId = `auto-activation-${++sessionSeq}`
|
||||
const initial: SidebarSessionList = {
|
||||
current: sessionId,
|
||||
byId: {
|
||||
[sessionId]: { id: sessionId, cwd: '/tmp', displayTitle: 'Root' },
|
||||
},
|
||||
jobsBySession: { [sessionId]: [] },
|
||||
}
|
||||
const feed = makeSessionFeed(initial)
|
||||
const store = createSidebarStore()
|
||||
store.setPrefs({ ...store.getPrefs(), autoOpenSubagent: true, autoOpenJobs: true })
|
||||
store.setSession(sessionId)
|
||||
store.reduce(state => ({ ...state, panelOpen }))
|
||||
const service = createBetterSidebarService(store)
|
||||
service.registerTab({ id: 'subagent', title: 'Subagent', component: () => null })
|
||||
const localeSnapshot = { active: 'en' }
|
||||
const ctx = {
|
||||
locale: { subscribe: () => () => {}, getSnapshot: () => localeSnapshot },
|
||||
sessions: { list: feed },
|
||||
betterSidebar: service,
|
||||
get: (name: string) => name === 'betterSidebar' ? service : undefined,
|
||||
} as unknown as Context
|
||||
const container = document.createElement('div')
|
||||
document.body.append(container)
|
||||
const root: Root = createRoot(container)
|
||||
act(() => { root.render(createElement(Sidebar, { ctx, store })) })
|
||||
const result = {
|
||||
store,
|
||||
service,
|
||||
feed,
|
||||
unmount: () => {
|
||||
act(() => { root.unmount() })
|
||||
container.remove()
|
||||
},
|
||||
}
|
||||
mounted.push(result)
|
||||
return result
|
||||
}
|
||||
|
||||
function publishSubagent(sidebar: MountedSidebar): void {
|
||||
const before = sidebar.feed.getSnapshot()
|
||||
const sessionId = before.current!
|
||||
act(() => {
|
||||
sidebar.feed.set({
|
||||
...before,
|
||||
byId: {
|
||||
...before.byId,
|
||||
child: {
|
||||
id: 'child',
|
||||
displayTitle: 'Worker',
|
||||
origin: 'subagent',
|
||||
parentId: sessionId,
|
||||
running: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function flushSubagentDebounce(): void {
|
||||
act(() => { vi.advanceTimersByTime(500) })
|
||||
}
|
||||
|
||||
function publishJob(sidebar: MountedSidebar): void {
|
||||
const before = sidebar.feed.getSnapshot()
|
||||
const sessionId = before.current!
|
||||
act(() => {
|
||||
sidebar.feed.set({
|
||||
...before,
|
||||
jobsBySession: {
|
||||
...before.jobsBySession,
|
||||
[sessionId]: [{
|
||||
id: 'bash-1',
|
||||
kind: 'bash',
|
||||
label: 'sleep 30',
|
||||
status: 'running',
|
||||
startedAt: 1_000,
|
||||
}],
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function expectSubagentFocused(sidebar: MountedSidebar, panelOpen: boolean): void {
|
||||
const state = sidebar.store.getSnapshot().state!
|
||||
const right = firstLeaf(state.splits)
|
||||
expect(state.panelOpen).toBe(panelOpen)
|
||||
expect(state.activePane).toBe(right.id)
|
||||
expect(allLeaves(state.splits).flatMap(leaf => leaf.tabs)
|
||||
.filter(tab => tab.type === 'subagent')).toHaveLength(1)
|
||||
expect(right.tabs.find(tab => tab.id === right.active)?.type).toBe('subagent')
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
localStorage.clear()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
while (mounted.length > 0) mounted.pop()!.unmount()
|
||||
vi.clearAllTimers()
|
||||
vi.useRealTimers()
|
||||
vi.unstubAllGlobals()
|
||||
localStorage.clear()
|
||||
document.body.innerHTML = ''
|
||||
setViewport(1024)
|
||||
})
|
||||
|
||||
describe('Sidebar background-activity auto-activation (#162)', () => {
|
||||
it.each([
|
||||
{ source: 'subagent', width: 390, opens: false },
|
||||
{ source: 'job', width: 390, opens: false },
|
||||
{ source: 'subagent', width: 1024, opens: true },
|
||||
{ source: 'job', width: 1024, opens: true },
|
||||
] as const)('$source activation at $width px sets panelOpen=$opens', ({ source, width, opens }) => {
|
||||
const sidebar = mountSidebar(width)
|
||||
if (source === 'subagent') {
|
||||
publishSubagent(sidebar)
|
||||
flushSubagentDebounce()
|
||||
} else {
|
||||
publishJob(sidebar)
|
||||
}
|
||||
expectSubagentFocused(sidebar, opens)
|
||||
})
|
||||
|
||||
it.each(['subagent', 'job'] as const)('%s activation preserves an already-open narrow drawer', (source) => {
|
||||
const sidebar = mountSidebar(390, true)
|
||||
if (source === 'subagent') {
|
||||
publishSubagent(sidebar)
|
||||
flushSubagentDebounce()
|
||||
} else {
|
||||
publishJob(sidebar)
|
||||
}
|
||||
expectSubagentFocused(sidebar, true)
|
||||
})
|
||||
|
||||
it('uses the current viewport when the delayed subagent activation fires', () => {
|
||||
const sidebar = mountSidebar(1024)
|
||||
publishSubagent(sidebar)
|
||||
setViewport(390)
|
||||
flushSubagentDebounce()
|
||||
expectSubagentFocused(sidebar, false)
|
||||
})
|
||||
})
|
||||
@@ -1328,6 +1328,105 @@ describe('pinned terminals (v0.17.0)', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('narrow persisted-layout visibility (issue #162)', () => {
|
||||
const persistedLayout = JSON.stringify({
|
||||
panelOpen: true,
|
||||
width: 420,
|
||||
nextTerminal: 2,
|
||||
nextBrowser: 2,
|
||||
activePane: 'pane:2',
|
||||
expanded: ['/workspace/src'],
|
||||
splits: {
|
||||
kind: 'split',
|
||||
id: 'split:1',
|
||||
dir: 'row',
|
||||
sizes: [0.5, 0.5],
|
||||
children: [
|
||||
{
|
||||
kind: 'leaf',
|
||||
id: 'pane:1',
|
||||
active: 'editor:readme',
|
||||
tabs: [{ id: 'editor:readme', type: 'editor', title: 'README.md', path: '/workspace/README.md' }],
|
||||
},
|
||||
{
|
||||
kind: 'leaf',
|
||||
id: 'pane:2',
|
||||
active: 'terminal:1',
|
||||
tabs: [{ id: 'terminal:1', type: 'terminal', title: 'Terminal 1' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
bottomOpen: true,
|
||||
bottomHeight: 300,
|
||||
bottomOpenedOnce: true,
|
||||
bottomSplits: {
|
||||
kind: 'leaf',
|
||||
id: 'pane:3',
|
||||
active: 'browser:1',
|
||||
tabs: [{ id: 'browser:1', type: 'browser', title: 'Docs', path: 'https://example.com' }],
|
||||
},
|
||||
floats: [{
|
||||
id: 'float:4',
|
||||
tab: { id: 'notes:1', type: 'plugin:notes', title: 'Notes', meta: { draft: true } },
|
||||
x: 16,
|
||||
y: 24,
|
||||
w: 320,
|
||||
h: 240,
|
||||
}],
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
const g = globalThis as Record<string, unknown>
|
||||
delete g.window
|
||||
delete g.localStorage
|
||||
})
|
||||
|
||||
it.each([
|
||||
{ width: 390, expectedOpen: false },
|
||||
{ width: 768, expectedOpen: true },
|
||||
])('restores panelOpen=$expectedOpen at $width px without changing pane or free-window state', ({ width, expectedOpen }) => {
|
||||
const g = globalThis as Record<string, unknown>
|
||||
g.window = {
|
||||
clearTimeout: () => {},
|
||||
setTimeout: () => 0,
|
||||
innerWidth: width,
|
||||
innerHeight: 800,
|
||||
location: { search: '' },
|
||||
}
|
||||
g.localStorage = {
|
||||
getItem: (key: string) => key === 'dsh-sidebar:v1:restored' ? persistedLayout : null,
|
||||
setItem: () => {},
|
||||
removeItem: () => {},
|
||||
}
|
||||
|
||||
const store = createSidebarStore()
|
||||
store.setSession('restored')
|
||||
const state = store.getSnapshot().state!
|
||||
|
||||
expect(state.panelOpen).toBe(expectedOpen)
|
||||
expect(state.activePane).toBe('pane:2')
|
||||
expect(allLeaves(state.splits).map(leaf => ({
|
||||
id: leaf.id,
|
||||
active: leaf.active,
|
||||
tabs: leaf.tabs.map(tab => tab.id),
|
||||
}))).toEqual([
|
||||
{ id: 'pane:1', active: 'editor:readme', tabs: ['editor:readme'] },
|
||||
{ id: 'pane:2', active: 'terminal:1', tabs: ['terminal:1'] },
|
||||
])
|
||||
expect(state.bottomOpen).toBe(true)
|
||||
expect(allLeaves(state.bottomSplits).map(leaf => ({ id: leaf.id, tabs: leaf.tabs.map(tab => tab.id) })))
|
||||
.toEqual([{ id: 'pane:3', tabs: ['browser:1'] }])
|
||||
expect(state.floats).toEqual([{
|
||||
id: 'float:4',
|
||||
tab: { id: 'notes:1', type: 'plugin:notes', title: 'Notes', meta: { draft: true } },
|
||||
x: 16,
|
||||
y: 24,
|
||||
w: 320,
|
||||
h: 240,
|
||||
}])
|
||||
})
|
||||
})
|
||||
|
||||
describe('URL reset escape hatch (issue #369)', () => {
|
||||
// Same browser-global stubs as the v0.12.0 block above; loadState reads
|
||||
// window.location.search (reset param) and localStorage (persisted state).
|
||||
|
||||
Reference in New Issue
Block a user