dsh-subagent-workspace-ui 1.2.4 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- package/README.zh.md +44 -5
- package/lib/client.js +17 -16
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -49,7 +49,17 @@ If you previously disabled `ui-subagent` manually in `$DSH_HOME/profiles/web/cor
|
|
|
49
49
|
|
|
50
50
|
The public DSH Web session store exposes subagent summaries that have been discovered in the current browser runtime. It deliberately does not expose a global historical subagent index or a mode for every unvisited child. Therefore this first plugin version manages the discovered catalog; rows whose type is not yet loaded remain visible and searchable and fall back to DSH's retained session navigation. Exact catalog navigation is used automatically as soon as DSH supplies the address and mode.
|
|
51
51
|
|
|
52
|
-
A full persistent workspace-wide archive view requires a host-side catalog RPC (or an upstream DSH API) that enumerates every child address and its mode. The public `SessionSummary` does not expose the original prompt or provider/model route, so those are intentionally not queried or displayed. Live output and tool/context activity
|
|
52
|
+
A full persistent workspace-wide archive view requires a host-side catalog RPC (or an upstream DSH API) that enumerates every child address and its mode. The public `SessionSummary` does not expose the original prompt or provider/model route, so those are intentionally not queried or displayed. Live output and tool/context activity are read from the bound session automatically: on dsh **0.1.2-alpha.2** they are derived from the raw `binding.eventSource` event stream (showing the tool description or target filename), while older hosts (e.g. **0.1.1-rc.2**) fall back to `session.getSnapshot().chat.legacy`. Capability detection selects the path, so the plugin stays forward compatible. If the host publishes neither, the panel falls back to the durable summary. The UI is isolated in [`lib/client.js`](lib/client.js), so it can switch to a richer source without changing the panel interaction model.
|
|
53
|
+
|
|
54
|
+
## Compatibility
|
|
55
|
+
|
|
56
|
+
v1.3.1 is compatible with dsh **0.1.2-alpha.2** (new `binding.eventSource` live-output path) and **0.1.1-rc.2** (legacy `chat.legacy` snapshot path). Live output is selected by capability detection, so older hosts behave as before.
|
|
57
|
+
|
|
58
|
+
## v1.3.2
|
|
59
|
+
|
|
60
|
+
- **Performance**: the manager now does one base scan (`subagentRows`) and derives `allRows`/`activeRows`/`tabCounts` from it (no repeated full scans or `modeMap` merges), `tabCounts` is computed from a deferred value and is skipped while the panel is closed, and `useSessions` subscribes only the fields the manager reads. Live output is capped to a few simultaneous subagents (`liveCap`, default 3, `0` = unlimited) and fully releases its subscriptions when live display is off or the float/panel is closed.
|
|
61
|
+
- **UX**: opening a subagent now auto-switches the session to the Chat tab.
|
|
62
|
+
- **Fix**: the batch "select N hours ago" now selects the truly-old subagents in the current view (accurate count) and no longer overwrites or re-selects your manual changes.
|
|
53
63
|
|
|
54
64
|
## Validation
|
|
55
65
|
|
|
@@ -57,6 +67,13 @@ A full persistent workspace-wide archive view requires a host-side catalog RPC (
|
|
|
57
67
|
pnpm run check
|
|
58
68
|
```
|
|
59
69
|
|
|
70
|
+
Smoke-test a specific dsh version:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
./test.sh # local dsh, port 8084
|
|
74
|
+
DSH_VERSION=0.1.1-rc.2 ./test.sh # pnpx @deepseek-ai/dsh@0.1.1-rc.2 (via proxychains4 -q)
|
|
75
|
+
```
|
|
76
|
+
|
|
60
77
|
## Acknowledgements
|
|
61
78
|
|
|
62
79
|
- Subagent permanent deletion and session cleanup design inspired by and referencing [@heiheiha798/dsh-plugin-subagent-delete](https://github.com/heiheiha798/dsh-plugin-subagent-delete).
|
package/README.zh.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
面向 DeepSeek Harness Web 的子代理管理插件。插件在会话标题栏提供一个紧凑的 `🧩 子代理 active/total` 入口,用于搜索、筛选、分组、排序、查看和批量归档当前运行时已发现的子代理。
|
|
4
4
|
|
|
5
|
-
当前发布版本:**v1.2
|
|
5
|
+
当前发布版本:**v1.3.2**
|
|
6
6
|
|
|
7
7
|
## 主要功能
|
|
8
8
|
|
|
@@ -132,16 +132,23 @@
|
|
|
132
132
|
|
|
133
133
|
### 实时活动与流式输出
|
|
134
134
|
|
|
135
|
-
当 DSH 会话 API
|
|
135
|
+
当 DSH 会话 API 提供绑定会话与实时事件时,卡片底部会显示实时活动:
|
|
136
136
|
|
|
137
137
|
- 最新两行模型文本或思考文本。
|
|
138
|
-
- 正在运行的工具调用,例如 `Read`、`Bash
|
|
138
|
+
- 正在运行的工具调用,例如 `Read`、`Bash`(优先显示工具说明或目标文件名)。
|
|
139
139
|
- 最近完成的工具调用及成功/失败状态。
|
|
140
140
|
- 上下文注入,例如 `skill-catalog` 或插件系统提示。
|
|
141
141
|
- 命令状态。
|
|
142
142
|
|
|
143
143
|
实时输出具有金属光泽扫光动效;子代理结束后保留最后显示快照,并变为灰色。输出区域最多显示两行,避免持续滚动导致内容难以阅读。
|
|
144
144
|
|
|
145
|
+
**兼容两个 API 代际(自动探测)**:
|
|
146
|
+
|
|
147
|
+
- dsh **0.1.2-alpha.2**:使用 `binding.eventSource`(原始 `SessionEvent` 事件流)推导实时输出。
|
|
148
|
+
- dsh **0.1.1-rc.2** 及更早:回退 `session.getSnapshot().chat.legacy`(对话快照)路径。
|
|
149
|
+
|
|
150
|
+
按能力探测自动切换,向前兼容,老版本行为不变。
|
|
151
|
+
|
|
145
152
|
## 界面说明
|
|
146
153
|
|
|
147
154
|
从上到下依次为:
|
|
@@ -183,15 +190,21 @@ http://127.0.0.1:3080
|
|
|
183
190
|
|
|
184
191
|
插件只管理当前 DSH Web 客户端运行时已经发现的子代理目录,不伪造不存在的历史数据。首次加载以 40 条为一页;普通分页可以继续加载,批量时间选择最多扩展到 1000 条。
|
|
185
192
|
|
|
186
|
-
公共 `SessionSummary` 不保证提供原始提示词、provider/model 或全部历史日志,因此插件不会查询或显示 provider/model
|
|
193
|
+
公共 `SessionSummary` 不保证提供原始提示词、provider/model 或全部历史日志,因此插件不会查询或显示 provider/model。实时输出按能力探测自动切换两种公开接口:
|
|
187
194
|
|
|
188
195
|
```text
|
|
196
|
+
# dsh 0.1.2-alpha.2(新 API):绑定的事件源
|
|
197
|
+
sessions.binding(childId).eventSource
|
|
198
|
+
→ open()
|
|
199
|
+
→ getSnapshot().entries # 原始 SessionEvent:assistant/chunk、tool/call、tool/result…
|
|
200
|
+
|
|
201
|
+
# dsh 0.1.1-rc.2 及更早(旧 API):对话快照
|
|
189
202
|
sessions.binding(childId).session
|
|
190
203
|
→ session.open()
|
|
191
204
|
→ session.getSnapshot().chat.legacy
|
|
192
205
|
```
|
|
193
206
|
|
|
194
|
-
|
|
207
|
+
如果在当前宿主拿不到对应的实时数据,插件只能显示持久化的会话摘要和统计信息。本版本兼容 **dsh 0.1.2-alpha.2** 与 **0.1.1-rc.2**。
|
|
195
208
|
|
|
196
209
|
归档、分类和最近使用顺序保存在浏览器本地 `localStorage` 中,不会写入 DSH 会话日志。
|
|
197
210
|
|
|
@@ -210,10 +223,36 @@ pnpm run check
|
|
|
210
223
|
- `lib/client.js`
|
|
211
224
|
- `lib/index.js`
|
|
212
225
|
|
|
226
|
+
### 冒烟测试(可指定 dsh 版本)
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
./test.sh # 本地 dsh 跑 web,端口 8084
|
|
230
|
+
./test.sh 8085 # 指定端口
|
|
231
|
+
DSH_VERSION=0.1.1-rc.2 ./test.sh # 用 pnpx 拉取指定 dsh 版本跑 web(默认经 proxychains4 -q 走代理)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
`DSH_HOME` 固定为 `$HOME/tmp/dsh-test`;`DSH_VERSION` 非空时用 `pnpx @deepseek-ai/dsh@<version>` 运行,可用于冒烟测试旧版本(如 0.1.1-rc.2)的兼容性。
|
|
235
|
+
|
|
213
236
|
## 致谢与参考
|
|
214
237
|
|
|
215
238
|
- 子代理永久删除、会话生命周期清理及快照刷新机制的设计参考并致谢开源项目:[@heiheiha798/dsh-plugin-subagent-delete](https://github.com/heiheiha798/dsh-plugin-subagent-delete)。
|
|
216
239
|
|
|
240
|
+
## v1.3.2 发布说明
|
|
241
|
+
|
|
242
|
+
- **性能优化(显著降低卡顿)**:
|
|
243
|
+
- 子代理管理器改为单次基础扫描(`subagentRows`),`allRows`/`activeRows`/`tabCounts` 不再各自全表扫描并重复合并 `modeMap`;`tabCounts` 用延迟值计算、面板关闭时不计算。
|
|
244
|
+
- `useSessions` 细粒度订阅(只订阅 `byId`/`subagentsByParent`/`current` 三字段并浅比较),无关的会话帧不再触发整组重渲染。
|
|
245
|
+
- 活跃浮窗/面板**限制同时实时订阅的子代理数**(`liveCap`,默认 3,`0`=不设限);关闭实时显示或关闭浮窗/面板时**完全停止 live 订阅并释放资源**,而非仅隐藏。
|
|
246
|
+
- **点击子代理自动切换到「对话」选项卡**:进入子代理时自动落到对话视图。
|
|
247
|
+
- **修复:批量「选择 N 小时前」**:按当前视图一次性选中真正超过 N 小时的子代理(数量准确),可正常增减,取消后不会自动勾回。
|
|
248
|
+
|
|
249
|
+
## v1.3.1 发布说明
|
|
250
|
+
|
|
251
|
+
- **兼容 dsh 0.1.2-alpha.2 与 0.1.1-rc.2**:实时输出按能力探测自动切换两条链路——新版本(0.1.2-alpha.2)走 `binding.eventSource` 原始事件流推导;旧版本(0.1.1-rc.2 及更早)回退 `chat.legacy` 对话快照。老版本行为不变,向前兼容。
|
|
252
|
+
- **实时工具调用显示说明/文件名**:进行中与已完成的工具调用现在优先显示工具 `description` 或目标 `path/file_path`(例如 `bash · Print current working directory`、`write · subagent-AJ.txt`),不再只有工具名。工具参数跨分片累积,参数完整后才渲染详情,避免流式过程中显示残缺 JSON。
|
|
253
|
+
- **清理**:移除已不存在的 `dsh-client-runtime` 客户端注入引用。
|
|
254
|
+
- **测试脚本支持指定版本**:`DSH_VERSION=0.1.1-rc.2 ./test.sh` 可冒烟测试旧版本兼容性。
|
|
255
|
+
|
|
217
256
|
## v1.2.4 发布说明
|
|
218
257
|
|
|
219
258
|
- **批量选择优化**:修复批量模式下直接点击 checkbox 偶现无响应的问题;支持 Shift 连选与连续批量取消选中(跟随上一次点击意图)。
|
package/lib/client.js
CHANGED
|
@@ -26,29 +26,30 @@ body[data-ds-dark-theme] .dsh-sam-row-hidden{background:rgba(255,255,255,0.03)!i
|
|
|
26
26
|
const DEFAULT_LIGHT_BG='#edf3fe', DEFAULT_DARK_BG='#1c2333'
|
|
27
27
|
const load=()=>{try{return JSON.parse(localStorage.getItem(key))||{}}catch{return {}}}
|
|
28
28
|
const age=t=>{const seconds=Math.max(0,Math.floor((Date.now()-(t||Date.now()))/1000));if(seconds<60)return `${seconds} 秒前`;const minutes=Math.floor(seconds/60);if(minutes<60)return `${minutes} 分钟前`;const hours=Math.floor(minutes/60);if(hours<24)return `${hours} 小时 ${minutes%60} 分钟前`;return `${Math.floor(hours/24)} 天前`}
|
|
29
|
-
const title=s=>s.title||s.displayTitle||s.id, short=v=>v?v.replace(/^session-/,'').slice(0,8):'未知', workspace=s=>s?.cwd?s.cwd.split(/[\\/]/).filter(Boolean).pop():'未知工作区', modeLabel=m=>m==='one-shot'?'一次性':m==='continuable'?'可继续':'类型待加载', tokenTotal=s=>{const u=s?.projectionValues?.tokenUsage;return u?u.uncachedInputTokens+u.outputTokens+u.cacheReadTokens+u.cacheWriteTokens:undefined},fmt=n=>n==null?'未知':n>=1e6?`${(n/1e6).toFixed(1)}m`:n>=1e3?`${(n/1e3).toFixed(1)}k`:String(n), promptPreview=s=>String(s?.prompt||s?.projectionValues?.prompt||'').slice(0,100)
|
|
29
|
+
const title=s=>s.title||s.displayTitle||s.id, short=v=>v?v.replace(/^session-/,'').slice(0,8):'未知', workspace=s=>s?.cwd?s.cwd.split(/[\\/]/).filter(Boolean).pop():'未知工作区', modeLabel=m=>m==='one-shot'?'一次性':m==='continuable'?'可继续':'类型待加载', tokenTotal=s=>{const u=s?.projectionValues?.tokenUsage;return u?u.uncachedInputTokens+u.outputTokens+u.cacheReadTokens+u.cacheWriteTokens:undefined},fmt=n=>n==null?'未知':n>=1e6?`${(n/1e6).toFixed(1)}m`:n>=1e3?`${(n/1e3).toFixed(1)}k`:String(n), promptPreview=s=>String(s?.prompt||s?.projectionValues?.prompt||'').slice(0,100)
|
|
30
30
|
const category=name=>{const clean=name.trim();const part=clean.split(/[::|—–-]/)[0].trim();return part.length>1&&part.length<28?part:clean.split(/\\s+/).slice(0,2).join(' ')||'未分类'},rootSession=(byId,id)=>{let current=id,seen=new Set();while(current&&byId[current]?.origin==='subagent'&&byId[current].parentId&&!seen.has(current)){seen.add(current);current=byId[current].parentId}return current}
|
|
31
31
|
const modeMap=c=>Object.values(c||{}).flatMap(x=>x.entries||[]).reduce((o,e)=>{if(e.kind==='child')o[e.id]={mode:e.mode,label:e.label};return o},{}), highlight=(text,term)=>{if(!term)return text;const parts=String(text).split(new RegExp(`(${term.replace(/[.*+?^${}()|[\\]\\\\]/g,'\\\\$&')})`,'ig'));return parts.map((part,i)=>i%2?jsx('mark',{children:part},i):part)}
|
|
32
32
|
let sessionsRt=null
|
|
33
33
|
const NOOP=()=>()=>{}
|
|
34
|
-
function LiveOutput({parentId,childId,running,prefix=true,autoLoad=true,onLoad}){
|
|
35
|
-
const [loading,setLoading]=React.useState(false),[,bump]=React.useState(0),[lastText,setLastText]=React.useState(''),
|
|
36
|
-
React.useEffect(()=>{if(!
|
|
37
|
-
const snap=session?.getSnapshot?.(),chat=snap?.chat,blocks=chat?.legacy?.partial?.blocks||[],runningCalls=chat?.legacy?.runningCalls||[],nodes=chat?.legacy?.nodes||[];
|
|
34
|
+
function LiveOutput({parentId,childId,running,prefix=true,autoLoad=true,onLoad,live=true}){
|
|
35
|
+
const [loading,setLoading]=React.useState(false),[,bump]=React.useState(0),[lastText,setLastText]=React.useState(''),wantLive=live&&(running||autoLoad),binding=React.useMemo(()=>{if(!wantLive)return null;try{return sessionsRt?.binding?.(childId)||null}catch{return null}},[childId,wantLive]),session=binding?.session||null,feed=binding?.eventSource||null
|
|
36
|
+
React.useEffect(()=>{if(!binding)return;let alive=true,timer=null,scheduled=false;const notify=()=>{if(!alive||scheduled)return;scheduled=true;timer=setTimeout(()=>{scheduled=false;timer=null;if(alive)bump(v=>v+1)},100)};const setup=async()=>{try{if(parentId){const entries=sessionsRt?.list?.getSnapshot?.().subagentsByParent?.[parentId]?.entries||[],entry=entries.find(e=>e.kind==='child'&&e.id===childId);if(entry)session?.configureSubagent?.({parentSessionId:parentId,childSessionId:childId,mode:entry.mode})}await session?.open?.()}catch{}finally{if(alive){setLoading(false);bump(v=>v+1)}}};setup();const source=feed||session,unsub=source?.subscribe?.(notify)||NOOP();return()=>{alive=false;if(timer)clearTimeout(timer);unsub()}},[binding,session,feed,parentId,childId])
|
|
37
|
+
let text='';if(feed){const win=feed.getSnapshot?.();if(win&&win.entries){const out=liveFromEvents(win.entries,running);if(out.pendingCount)text=out.activity.join('\n');else if(running&&out.streamText)text=out.streamText;else if(out.activity.length)text=out.activity.join('\n');else text=out.finalText}}else{const snap=session?.getSnapshot?.(),chat=snap?.chat,blocks=chat?.legacy?.partial?.blocks||[],runningCalls=chat?.legacy?.runningCalls||[],nodes=chat?.legacy?.nodes||[];const activity=[];runningCalls.slice(-2).forEach(c=>activity.push(`▶ ${c.name||'工具调用'}${c.argsRaw?` · ${toolDetail(c.argsRaw)}`:''}`));if(!activity.length)nodes.slice(-8).filter(n=>n.kind==='context'||n.kind==='tool-result'||n.kind==='command').slice(-2).forEach(n=>{if(n.kind==='context')activity.push(`上下文注入 · ${n.provenance?.label||n.form||'context'}`);else if(n.kind==='tool-result')activity.push(`${n.isError?'✖':'✓'} ${n.call?.name||'工具调用'}${n.call?.argsRaw?` · ${toolDetail(n.call.argsRaw)}`:''}`);else activity.push(`⌘ ${n.name||'命令'}`)});let streamText='';for(let i=blocks.length-1;i>=0;i--){const b=blocks[i];if((b.kind==='text'||b.kind==='reasoning')&&b.text){const lines=b.text.split('\n').map(x=>x.trim()).filter(Boolean);if(lines.length){streamText=(b.kind==='reasoning'?'💭 ':'')+lines.slice(-2).join('\n');break}}}if(runningCalls.length)text=activity.join('\n');else if(running&&streamText)text=streamText;else if(activity.length)text=activity.join('\n');else for(let i=blocks.length-1;i>=0;i--){const b=blocks[i];if((b.kind==='text'||b.kind==='reasoning')&&b.text){const lines=b.text.split('\n').map(x=>x.trim()).filter(Boolean);if(lines.length){text=(b.kind==='reasoning'?'💭 ':'')+lines.slice(-2).join('\n');break}}else if(b.kind==='tool-call'&&b.name){text='⚙ 调用工具 '+b.name;break}}}
|
|
38
38
|
React.useEffect(()=>{if(text)setLastText(text)},[text])
|
|
39
|
-
if(!
|
|
39
|
+
if(!wantLive){return jsx('button',{type:'button',className:'dsh-sam-load-live-btn',onClick:e=>{e.stopPropagation();setLoading(true);onLoad?.()},title:'加载该子代理的历史最新消息',children:loading?'⏳ 加载中...':'📥 加载最新消息'})}
|
|
40
40
|
if(!session)return null
|
|
41
41
|
const shown=text||lastText,lines=shown.slice(-400).split('\n').filter(Boolean);return shown?jsx('div',{className:`dsh-sam-live ${running?'dsh-sam-live-running':'dsh-sam-live-final'}`,children:[prefix&&jsx('span',{className:'dsh-sam-live-prefix',children:'实时输出:'}),lines.map((line,index)=>jsx('span',{className:index===lines.length-1?'dsh-sam-live-latest':'dsh-sam-live-old',children:line},index))]}):null
|
|
42
42
|
}
|
|
43
43
|
const elapsed=t=>{const seconds=Math.max(0,Math.floor((Date.now()-(t||Date.now()))/1000));return seconds>=3600?`${Math.floor(seconds/3600)}时${Math.floor(seconds%3600/60)}分`:seconds>=60?`${Math.floor(seconds/60)}分${seconds%60}秒`:`${seconds}秒`},compactPath=v=>{const value=String(v).replace(/\\/g,'/'),max=72;if(value.length<=max)return value;const parts=value.split('/').filter(Boolean);let result=parts.pop()||value;while(parts.length&&(`.../${parts[parts.length-1]}/${result}`).length<=max)result=`${parts.pop()}/${result}`;return `.../${result}`},toolDetail=v=>{if(!v)return '';try{const value=JSON.parse(v),key=value.description!=null?'description':value.command!=null?'command':value.file_path!=null?'file_path':value.path!=null?'path':value.prompt!=null?'prompt':null,preferred=key?value[key]:undefined;if(preferred)return (key==='file_path'||key==='path'?compactPath: String)(String(preferred).split('\n')[0].slice(0,100));const first=Object.values(value).find(x=>typeof x==='string');return first?first.split('\n')[0].slice(0,100):String(v).slice(0,100)}catch{return String(v).split('\n')[0].slice(0,100)}}
|
|
44
|
-
|
|
45
|
-
function
|
|
46
|
-
|
|
44
|
+
const liveFromEvents=(entries,running)=>{const tail=s=>{const lines=String(s||'').split('\n').map(x=>x.trim()).filter(Boolean);return lines.length?lines.slice(-2).join('\n'):''},finalOf=blocks=>{const list=Array.isArray(blocks)?blocks:[];for(let i=list.length-1;i>=0;i--){const b=list[i];if(b?.type==='text'||b?.type==='reasoning'){const t=tail(b.text);if(t)return (b.type==='reasoning'?'💭 ':'')+t}if(b?.type==='tool-call'&&b.name)return '⚙ 调用工具 '+b.name}return ''};let text='',reasoning='',finalText='',hasStream=false,lastKind='text';const pending=[],done=[],byCall=new Map();for(const entry of entries){if(!entry||entry.type!=='event')continue;const e=entry.event;if(!e||typeof e.type!=='string')continue;switch(e.type){case 'assistant/chunk':{const c=e.data?.chunk;if(!c)break;if(c.type==='text-delta'){text+=c.text||'';hasStream=true;lastKind='text'}else if(c.type==='reasoning-delta'){reasoning+=c.text||'';hasStream=true;lastKind='reasoning'}else if(c.type==='tool-call-delta'&&c.id){let rec=byCall.get(c.id);if(!rec){rec={name:c.name||'工具调用',args:'',complete:false,running:true};byCall.set(c.id,rec);pending.push(rec)}if(c.name)rec.name=c.name;rec.args+=c.argumentsDelta||''}else if(c.type==='block-end'&&c.block?.type==='tool-call'){let rec=byCall.get(c.block.id);if(!rec){rec={name:c.block.name||'工具调用',args:'',complete:false,running:true};byCall.set(c.block.id,rec);pending.push(rec)}if(c.block.name)rec.name=c.block.name;rec.args=c.block.arguments||rec.args;rec.complete=true}break}case 'assistant/message':{finalText=finalOf(e.data?.message?.content);text='';reasoning='';hasStream=false;break}case 'tool/call':{let rec=byCall.get(e.data?.callId);if(!rec){rec={name:e.data?.name||'工具调用',args:'',complete:false,running:true};byCall.set(e.data?.callId,rec);pending.push(rec)}if(e.data?.name)rec.name=e.data?.name;if(e.data?.arguments!=null){rec.args=e.data?.arguments;rec.complete=true}rec.running=true;break}case 'tool/result':{const rec=byCall.get(e.data?.message?.source?.callId),block=e.data?.message?.content?.[0];if(rec){rec.running=false;done.push({name:rec.name,args:rec.args,complete:rec.complete,isError:block?.isError})}break}default:break}}const open=pending.filter(r=>r.running!==false);return{pendingCount:open.length,activity:[...open.slice(-2).map(r=>`▶ ${r.name||'工具调用'}${r.complete&&r.args?` · ${toolDetail(r.args)}`:''}`),...done.slice(-2).map(r=>`${r.isError?'✖':'✓'} ${r.name||'工具调用'}${r.complete&&r.args?` · ${toolDetail(r.args)}`:''}`)],streamText:hasStream?((lastKind==='reasoning'?'💭 ':'')+tail(lastKind==='reasoning'?reasoning:text)):'',finalText}}
|
|
45
|
+
function ActiveFloat({rows,openRow,onHide,stopAgent,stopAllAgents,stoppingIds,liveEnabled,onLiveChange,liveCap}){const [,tick]=React.useState(0),[position,setPosition]=React.useState(null),drag=React.useRef(null);React.useEffect(()=>{const timer=setInterval(()=>tick(v=>v+1),1000);return()=>clearInterval(timer)},[]);const move=e=>{if(!drag.current)return;const {offsetX,offsetY,width,height}=drag.current;setPosition({x:Math.max(8,Math.min(window.innerWidth-width-8,e.clientX-offsetX)),y:Math.max(8,Math.min(window.innerHeight-height-8,e.clientY-offsetY))})},startDrag=e=>{if(e.button!==0||e.target.closest('button,input,label'))return;const rect=e.currentTarget.parentElement.getBoundingClientRect();drag.current={offsetX:e.clientX-rect.left,offsetY:e.clientY-rect.top,width:rect.width,height:rect.height};e.currentTarget.setPointerCapture?.(e.pointerId)},stopDrag=()=>{drag.current=null},dragStyle=position?{left:position.x,top:position.y,right:'auto'}:undefined;const continuableRows=rows.filter(r=>r.mode!=='one-shot');return jsx('aside',{className:'dsh-sam-active-float',style:dragStyle,onPointerMove:move,onPointerUp:stopDrag,onPointerCancel:stopDrag,role:'status',children:[jsxs('div',{className:'dsh-sam-active-head dsh-sam-active-drag-handle',onPointerDown:startDrag,children: [jsx('span',{children:`活跃子代理 · ${rows.length}`}),jsxs('div',{className:'dsh-sam-active-actions',children:[continuableRows.length>0&&jsx('button',{type:'button',className:'dsh-sam-stop-all-btn',title:'一键暂停所有活跃可继续子代理',disabled:continuableRows.some(r=>stoppingIds.has(r.id)),onClick:e=>{e.stopPropagation();stopAllAgents(continuableRows)},children:continuableRows.some(r=>stoppingIds.has(r.id))?'暂停中':'⏸ 一键暂停'}),jsx('label',{className:'dsh-sam-active-live-toggle',children:[jsx('input',{type:'checkbox',checked:liveEnabled,onChange:e=>onLiveChange(e.target.checked)}),'实时输出']}),jsx('button',{type:'button',className:'dsh-sam-active-close',onClick:e=>{e.stopPropagation();onHide()},'aria-label':'隐藏活跃子代理浮窗',children:'×'})]})]}),rows.map((row,idx)=>jsxs('div',{className:'dsh-sam-active-item',onClick:()=>openRow(row),children:[jsxs('div',{className:'dsh-sam-active-title',children:[jsx('span',{className:'dsh-sam-active-icon',children:'🧩'}),jsx('span',{className:'dsh-sam-active-name',children:row.name}),jsx('span',{className:'dsh-sam-active-elapsed',children:elapsed(row.createdAt||row.updatedAt)}),row.mode!=='one-shot'&&jsx('button',{type:'button',className:'dsh-sam-stop-btn',disabled:stoppingIds.has(row.id),onClick:e=>{e.stopPropagation();stopAgent(row)},'aria-label':`暂停 ${row.name}`,'title':'暂停子代理',children:stoppingIds.has(row.id)?'暂停中':'⏸ 暂停'})]}),liveEnabled&&(liveCap<=0||idx<liveCap)&&jsx(LiveOutput,{parentId:row.parentId,childId:row.id,running:true,prefix:false}),jsx('div',{className:'dsh-sam-active-stats',children:`输入 ${fmt(row.projectionValues?.tokenUsage?.uncachedInputTokens)} / 输出 ${fmt(row.projectionValues?.tokenUsage?.outputTokens)} · 缓存命中 ${row.projectionValues?.tokenUsage?.cacheReadTokens!=null&&tokenTotal(row)?Math.round(row.projectionValues.tokenUsage.cacheReadTokens/tokenTotal(row)*100):'未知'}% · 轮数 ${row.projectionValues?.sessionStats?.turns??row.projectionValues?.turns??'未知'} · 步数 ${row.projectionValues?.sessionStats?.steps??row.projectionValues?.steps??'未知'}`})]},row.id))]})}
|
|
46
|
+
function Manager({useSessions,openChild,openSession,refresh,setCatalogOpen,sessionId,actions}){
|
|
47
|
+
const state=useSessions(s=>s,(a,b)=>a?.byId===b?.byId&&a?.subagentsByParent===b?.subagentsByParent&&a?.current===b?.current),[open,setOpen]=React.useState(false),[query,setQuery]=React.useState(''),[grouping,setGrouping]=React.useState('session'),[sort,setSort]=React.useState('recent'),[prefs,setPrefs]=React.useState(load),[limit,setLimit]=React.useState(PAGE),[tab,setTab]=React.useState('all'),[scope,setScope]=React.useState('currentWorkspace'),[filterOpen,setFilterOpen]=React.useState(false),[activeOpen,setActiveOpen]=React.useState(true),[scopeDetail,setScopeDetail]=React.useState(''),[sessionScope,setSessionScope]=React.useState(''),[recentIds,setRecentIds]=React.useState([]),[batchMode,setBatchMode]=React.useState(false),[selectedIds,setSelectedIds]=React.useState(new Set),[lastSelectedIndex,setLastSelectedIndex]=React.useState(-1),[lastSelectedAction,setLastSelectedAction]=React.useState(null),[oldHours,setOldHours]=React.useState(null),[newAgents,setNewAgents]=React.useState([]),[floatHidden,setFloatHidden]=React.useState(false),[stoppingIds,setStoppingIds]=React.useState(new Set),[manualLoadedIds,setManualLoadedIds]=React.useState(new Set),runningSeen=React.useRef(false),runningIdsSeen=React.useRef(new Set),noticeTimers=React.useRef(new Map)
|
|
47
48
|
const tabs=[...defaultTabs,...(prefs.tabs||[])].filter(t=>t.id!=='filtered').filter((t,i,a)=>a.findIndex(x=>x.id===t.id)===i), archived=new Set(prefs.archived||[]), archivedParents=prefs.archivedParents||{}, currentId=rootSession(state.byId,sessionId||state.current), current=state.byId[currentId], currentCwd=current?.cwd, parentRows=Object.values(state.byId).filter(s=>s.origin!=='subagent'), scopeOptions=[...new Set(parentRows.map(s=>s.cwd).filter(Boolean))],workspaceKey=scope.startsWith('workspace:')?scope.slice(10):scope==='currentWorkspace'?currentCwd:undefined,availableSessions=parentRows.filter(s=>!workspaceKey||s.cwd===workspaceKey),selectedSession=sessionScope||currentId
|
|
48
|
-
const
|
|
49
|
-
const activeRows=React.useMemo(()=>
|
|
50
|
-
const stopAgent=async row=>{if(row.mode==='one-shot'||stoppingIds.has(row.id))return;if(!window.confirm(`确认暂停子代理“${row.name}”?`))return;setStoppingIds(prev=>new Set(prev).add(row.id));try{const session=sessionsRt?.binding?.(row.id)?.session;if(session){if(row.parentId&&row.mode){session.configureSubagent?.({parentSessionId:row.parentId,childSessionId:row.id,mode:row.mode}
|
|
51
|
-
const stopAllAgents=async rowsToStop=>{const targetRows=rowsToStop.filter(r=>r.mode!=='one-shot'&&!stoppingIds.has(r.id));if(!targetRows.length)return;if(!window.confirm(`确认暂停选中的 ${targetRows.length} 个子代理?`))return;const ids=targetRows.map(r=>r.id);setStoppingIds(prev=>new Set([...prev,...ids]));try{await Promise.allSettled(targetRows.map(async row=>{try{const session=sessionsRt?.binding?.(row.id)?.session;if(session){if(row.parentId&&row.mode){session.configureSubagent?.({parentSessionId:row.parentId,childSessionId:row.id,mode:row.mode}
|
|
49
|
+
const modes=React.useMemo(()=>modeMap(state.subagentsByParent),[state.subagentsByParent]),subagentRows=React.useMemo(()=>{const byId=state.byId;return Object.values(byId).filter(s=>s.origin==='subagent').map(s=>({...s,...modes[s.id],name:modes[s.id]?.label||title(s),parentCwd:byId[s.parentId]?.cwd}))},[state.byId,modes]),allRows=React.useMemo(()=>{if(!open)return [];const rawTerm=query.trim().toLocaleLowerCase(),idOnly=rawTerm.startsWith('id:'),term=idOnly?rawTerm.slice(3).trim():rawTerm;return subagentRows.filter(s=>{if(workspaceKey&&s.parentCwd!==workspaceKey)return false;if(selectedSession!=='all'&&s.parentId!==selectedSession)return false;const unfiltered=tab==='all';if(!prefs.showArchived&&archived.has(s.id))return false;if(prefs.hideOneShot&&s.mode==='one-shot')return false;if(!unfiltered&&prefs.hideOld&&!s.running&&Date.now()-s.updatedAt>(prefs.oldDays||30)*DAY)return false;const custom=tabs.find(t=>t.id===tab);if(custom?.regex==='__OTHER__'){const matched=tabs.some(t=>!['filtered','all','other'].includes(t.id)&&t.regex&&(()=>{try{return new RegExp(t.regex,'i').test(s.name)}catch{return false}})());if(matched)return false}else if(custom?.regex&&custom.regex!=='__ALL__'){try{if(!new RegExp(custom.regex,'i').test(s.name))return false}catch{return false}}return !term||`${idOnly?`${s.id} ${s.parentId||''}`:`${s.name} ${title(s)} ${workspace(s)}`}`.toLocaleLowerCase().includes(term)}).sort((a,b)=>{const ar=recentIds.indexOf(a.id),br=recentIds.indexOf(b.id);return ar!==br?(ar<0?1:br<0?-1:ar-br):a.running!==b.running?(b.running?1:-1):sort==='title'?a.name.localeCompare(b.name):sort==='type'?modeLabel(a.mode).localeCompare(modeLabel(b.mode)):b.updatedAt-a.updatedAt})},[open,subagentRows,query,sort,prefs,scope,currentCwd,currentId,scopeDetail,workspaceKey,selectedSession,tab,tabs,recentIds])
|
|
50
|
+
const deferredSubagentRows=React.useDeferredValue(subagentRows),activeRows=React.useMemo(()=>subagentRows.filter(s=>s.running).filter(s=>(!currentCwd||s.parentCwd===currentCwd)&&(prefs.showArchived||!archived.has(s.id))&&(!prefs.hideOneShot||s.mode!=='one-shot')).sort((a,b)=>b.updatedAt-a.updatedAt),[subagentRows,currentCwd,prefs,archived])
|
|
51
|
+
const stopAgent=async row=>{if(row.mode==='one-shot'||stoppingIds.has(row.id))return;if(!window.confirm(`确认暂停子代理“${row.name}”?`))return;setStoppingIds(prev=>new Set(prev).add(row.id));try{const session=sessionsRt?.binding?.(row.id)?.session;if(session){if(row.parentId&&row.mode){session.configureSubagent?.({parentSessionId:row.parentId,childSessionId:row.id,mode:row.mode})}await session.open?.();await session.cancel?.();if(row.parentId){sessionsRt?.refreshSubagents?.(row.parentId)}}}catch(e){console.warn('Unable to stop subagent',e)}finally{setStoppingIds(prev=>{const next=new Set(prev);next.delete(row.id);return next})}}
|
|
52
|
+
const stopAllAgents=async rowsToStop=>{const targetRows=rowsToStop.filter(r=>r.mode!=='one-shot'&&!stoppingIds.has(r.id));if(!targetRows.length)return;if(!window.confirm(`确认暂停选中的 ${targetRows.length} 个子代理?`))return;const ids=targetRows.map(r=>r.id);setStoppingIds(prev=>new Set([...prev,...ids]));try{await Promise.allSettled(targetRows.map(async row=>{try{const session=sessionsRt?.binding?.(row.id)?.session;if(session){if(row.parentId&&row.mode){session.configureSubagent?.({parentSessionId:row.parentId,childSessionId:row.id,mode:row.mode})}await session.open?.();await session.cancel?.();if(row.parentId){sessionsRt?.refreshSubagents?.(row.parentId)}}}catch(e){console.warn('Unable to stop subagent',row.id,e)}}))}finally{setStoppingIds(prev=>{const next=new Set(prev);ids.forEach(id=>next.delete(id));return next})}}
|
|
52
53
|
|
|
53
54
|
const deleteSubagent=async row=>{
|
|
54
55
|
if(row.running){
|
|
@@ -113,13 +114,13 @@ body[data-ds-dark-theme] .dsh-sam-row-hidden{background:rgba(255,255,255,0.03)!i
|
|
|
113
114
|
currentSortName=sort==='recent'?'最近活跃':sort==='title'?'名字':'类型',
|
|
114
115
|
currentGroupName=grouping==='session'?'按会话':grouping==='workspace'?'按工作区':grouping==='category'?'按分类':grouping==='type'?'按类型':'不分组'
|
|
115
116
|
|
|
116
|
-
const tabCounts=React.useMemo(()=>{const
|
|
117
|
+
const tabCounts=React.useMemo(()=>{if(!open)return {};const candidates=deferredSubagentRows.filter(s=>(!workspaceKey||s.parentCwd===workspaceKey)&&(selectedSession==='all'||s.parentId===selectedSession)&&(prefs.showArchived||!archived.has(s.id))&&(!prefs.hideOneShot||s.mode!=='one-shot')&&(!prefs.hideOld||s.running||Date.now()-s.updatedAt<=(prefs.oldDays||30)*DAY)),counts={};for(const t of tabs){if(t.id==='all')counts[t.id]=candidates.length;else if(t.regex==='__OTHER__')counts[t.id]=candidates.filter(s=>!tabs.some(x=>!['all','other','filtered'].includes(x.id)&&x.regex&&(()=>{try{return new RegExp(x.regex,'i').test(s.name)}catch{return false}})())).length;else counts[t.id]=candidates.filter(s=>{try{return t.regex&&new RegExp(t.regex,'i').test(s.name)}catch{return false}}).length}return counts},[open,deferredSubagentRows,workspaceKey,selectedSession,prefs,tabs]),rows=allRows.slice(0,limit),currentSessionRows=subagentRows.filter(r=>r.parentId===currentId&&(prefs.showArchived||!archived.has(r.id))&&(!prefs.hideOneShot||r.mode!=='one-shot')),active=currentSessionRows.filter(r=>r.running).length,currentCount=currentSessionRows.length,liveCap=Math.max(0,prefs.liveCap??3),runningLiveIds=liveCap>0?new Set(rows.filter(r=>r.running).slice(0,liveCap).map(r=>r.id)):null
|
|
117
118
|
const groups=React.useMemo(()=>{const out={};for(const row of rows){const parent=row.parentId?state.byId[row.parentId]:undefined,sameSession=row.parentId===currentId,sameWorkspace=currentCwd&&parent?.cwd===currentCwd;let bucket=row.running?'活跃子代理':grouping==='session'?`${workspace(parent||row)} · ${title(parent||current)}`:grouping==='type'?modeLabel(row.mode):grouping==='category'?(()=>{const hit=tabs.find(t=>t.id!=='filtered'&&t.id!=='all'&&t.regex&&(()=>{try{return new RegExp(t.regex,'i').test(row.name)}catch{return false}})());return hit?hit.name:'其他'})():grouping==='workspace'?workspace(parent||row):grouping==='none'?'全部结果':sameSession?'当前会话':sameWorkspace?`当前工作区 · ${workspace(parent||row)}`:(parent?`${workspace(parent)} · ${title(parent)}`:'其他会话');(out[bucket]||=[]).push(row)}return out},[rows,grouping,state.byId,sessionId,state.current,currentCwd])
|
|
118
119
|
React.useEffect(()=>{localStorage.setItem(key,JSON.stringify(prefs))},[prefs]);React.useEffect(()=>{if(!open)return;const ps=[...new Set(rows.map(r=>r.parentId).filter(Boolean))];ps.forEach(p=>{setCatalogOpen(p,true);refresh(p)});return()=>ps.forEach(p=>setCatalogOpen(p,false))},[open,limit,grouping,sort,query])
|
|
119
|
-
React.useEffect(()=>{const runningIds=
|
|
120
|
+
React.useEffect(()=>{const runningIds=subagentRows.filter(r=>r.running).map(r=>r.id);if(!runningIds.length)return;setRecentIds(prev=>{const next=[...runningIds,...prev.filter(id=>!runningIds.includes(id))].slice(0,100);return next.length===prev.length&&next.every((id,i)=>id===prev[i])?prev:next})},[subagentRows]);React.useEffect(()=>{if(!subagentRows.length)return;const runningIds=subagentRows.filter(r=>r.running).map(r=>r.id),current=new Set(runningIds);if(!runningSeen.current){runningSeen.current=true;runningIdsSeen.current=current;return}const fresh=runningIds.filter(id=>!runningIdsSeen.current.has(id));runningIdsSeen.current=current;if(!fresh.length)return;const names=fresh.map(id=>({id,name:subagentRows.find(r=>r.id===id)?.name})).filter(r=>r.name).slice(0,5);if(!names.length)return;setFloatHidden(false);setNewAgents(prev=>[...prev,...names].slice(-5));names.forEach(item=>{const timer=setTimeout(()=>{setNewAgents(prev=>prev.filter(x=>x.id!==item.id));noticeTimers.current.delete(item.id)},5000);if(noticeTimers.current.has(item.id))clearTimeout(noticeTimers.current.get(item.id));noticeTimers.current.set(item.id,timer)})},[subagentRows]);React.useEffect(()=>()=>{noticeTimers.current.forEach(timer=>clearTimeout(timer));noticeTimers.current.clear()},[]);const toggleSelected=(row,index,e)=>{const isShift=Boolean(e?.shiftKey&&lastSelectedIndex>=0);setSelectedIds(prev=>{const next=new Set(prev);if(isShift){const from=Math.min(lastSelectedIndex,index),to=Math.max(lastSelectedIndex,index);const shouldSelect=lastSelectedAction!==false;for(let i=from;i<=to;i++){const id=rows[i]?.id;if(!id)continue;if(shouldSelect)next.add(id);else next.delete(id)}}else{const willSelect=!next.has(row.id);if(willSelect)next.add(row.id);else next.delete(row.id);setLastSelectedAction(willSelect)};return next});setLastSelectedIndex(index)},batchArchive=(ids,restore=false)=>setPrefs(p=>{const current=new Set(p.archived||[]);ids.forEach(id=>restore?current.delete(id):current.add(id));const nextParents={...(p.archivedParents||{})};if(restore)ids.forEach(id=>delete nextParents[id]);else ids.forEach(id=>{const row=state.byId[id];if(row)nextParents[id]=row.parentId});return {...p,archived:[...current],archivedParents:nextParents}}),archiveSelected=(restore=false)=>{const ids=[...selectedIds];if(ids.length){batchArchive(ids,restore);setSelectedIds(new Set)}},selectOld=()=>{const hours=Number(window.prompt('选择多少小时前的子代理?','24'));if(!Number.isFinite(hours)||hours<0)return;const cutoff=Date.now()-hours*3600000;setSelectedIds(new Set(allRows.filter(r=>r.updatedAt&&r.updatedAt<=cutoff).slice(0,1000).map(r=>r.id)));setLimit(1000);setOldHours(hours);parentRows.forEach(p=>{setCatalogOpen(p.id,true);refresh(p.id)})},archive=row=>setPrefs(p=>{const was=p.archived?.includes(row.id);const nextArchived=was?p.archived.filter(x=>x!==row.id):[...(p.archived||[]),row.id];const nextParents={...(p.archivedParents||{})};if(was)delete nextParents[row.id];else nextParents[row.id]=row.parentId;return {...p,archived:nextArchived,archivedParents:nextParents}}),openRow=r=>{try{if(r.parentId&&r.mode)openChild({parentSessionId:r.parentId,childSessionId:r.id,mode:r.mode});else openSession(r.id);actions?.setView?.('chat');setOpen(false);setBatchMode(false)}catch(e){console.warn('Unable to open subagent',e)}}
|
|
120
121
|
React.useEffect(()=>{const styleId='dsh-sam-subagent-bg-style';let el=document.getElementById(styleId);const isSubagent=sessionId&&state.byId[sessionId]?.origin==='subagent';if(isSubagent){const lightBg=prefs.subagentBgLight||DEFAULT_LIGHT_BG,darkBg=prefs.subagentBgDark||DEFAULT_DARK_BG;const bgRule=prefs.customSubagentBg!==false?`body:not([data-ds-dark-theme]) [data-conversation-scroll],body:not([data-ds-dark-theme]) [data-conversation-scroll] > *{--dsw-alias-bg-base:${lightBg}!important}body[data-ds-dark-theme] [data-conversation-scroll],body[data-ds-dark-theme] [data-conversation-scroll] > *{--dsw-alias-bg-base:${darkBg}!important}`:'';const statsRule=`div[class*="StatsLine_root"],.FJxK0a_root{background:var(--dsw-alias-bg-layer-2,rgba(128,128,128,0.08))!important;border:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,0.15))!important;border-radius:999px!important;padding:3px 14px 4px 10px!important;margin:6px auto!important;width:fit-content!important;max-width:min(calc(100% - 32px),var(--dsh-chat-content-width,748px))!important;box-shadow:var(--dsw-shadow-lv1,0 1px 3px rgba(0,0,0,0.05))!important;backdrop-filter:blur(8px)!important;color:var(--dsw-alias-label-secondary)!important;display:flex!important;align-items:center!important;justify-content:center!important}div[class*="StatsLine_root"]::before,.FJxK0a_root::before{content:"\\1F9E9";margin-right:6px;font-size:13px;line-height:1;display:inline-block;flex:none}`;if(!el){el=document.createElement('style');el.id=styleId;document.head.appendChild(el)}el.textContent=`${bgRule}${statsRule}`}else{if(el)el.remove()}},[sessionId,state.byId,prefs.customSubagentBg,prefs.subagentBgLight,prefs.subagentBgDark])
|
|
121
122
|
const activeGroupContinuableRows=groups['活跃子代理']?.filter(r=>r.mode!=='one-shot')||[]
|
|
122
|
-
return jsxs(React.Fragment,{children:[(!open&&prefs.activeFloat!==false&&Boolean(activeRows.length)&&!floatHidden)?jsx(ActiveFloat,{rows:activeRows,openRow,onHide:()=>setFloatHidden(true),stopAgent,stopAllAgents,stoppingIds,liveEnabled:prefs.activeFloatLive!==false,onLiveChange:value=>setPrefs(p=>({...p,activeFloatLive:value}))}):null,jsxs('div',{className:'dsh-sam-trigger-wrap',children:[jsx('button',{type:'button',className:'dsh-sam-trigger',onClick:()=>{setLimit(PAGE);setOpen(true)},title:'打开子代理管理',children:[jsx('span',{className:`dsh-sam-icon ${active>0?'dsh-sam-pulse':''}`,children:'🧩'}),jsx('span',{children:`子代理 ${active}/${currentCount}`})]}),!open&&newAgents.map((item,index)=>jsx('div',{className:'dsh-sam-new-agent',style:{top:`calc(100% + ${6+index*34}px)`},role:'status',children:`新子代理:${item.name}`},item.id))]}),open&&jsx('div',{className:'dsh-sam-backdrop',onMouseDown:e=>{if(e.target===e.currentTarget){setOpen(false);setBatchMode(false);setSelectedIds(new Set);setLastSelectedIndex(-1);setLastSelectedAction(null)}},children:jsxs('section',{className:'dsh-sam-panel',role:'dialog','aria-modal':true,children:[jsxs('header',{className:'dsh-sam-head',children:[jsxs('div',{style:{flex:1,minWidth:0},children:[jsx('h2',{children:'子代理管理'}),jsxs('div',{className:'dsh-sam-head-sub',children:[jsx('div',{className:'dsh-sam-summary',children:`当前会话 ${allRows.filter(r=>r.parentId===currentId).length} 个 · 当前工作区 ${allRows.filter(r=>currentCwd&&state.byId[r.parentId]?.cwd===currentCwd).length} 个 · 活跃 ${active} 个`}),jsx('span',{className:'dsh-sam-summary',style:{opacity:0.6},children:'·'}),jsx('label',{className:'dsh-sam-head-float-toggle',children:[jsx('input',{type:'checkbox',checked:prefs.activeFloat!==false,onChange:()=>{setFloatHidden(false);setPrefs(p=>({...p,activeFloat:p.activeFloat===false}))}}),'显示活跃浮窗']})]})]}),jsx('button',{className:'dsh-sam-close',type:'button',onClick:()=>{setOpen(false);setBatchMode(false);setSelectedIds(new Set);setLastSelectedIndex(-1)},children:'×'})]}),!prefs.filterCollapsed&&jsxs('div',{className:'dsh-sam-tabs',children:[tabs.map(t=>jsxs('span',{className:`dsh-sam-tab-wrap ${(prefs.tabs?.some(x=>x.id===t.id)&&!defaultTabs.some(x=>x.id===t.id))?`dsh-sam-custom-wrap ${tab===t.id?'dsh-sam-tab-selected':''}`:''}`,children:[jsx('button',{type:'button',className:`${t.id==='other'?'dsh-sam-other-tab ':''}${(prefs.tabs?.some(x=>x.id===t.id)&&!defaultTabs.some(x=>x.id===t.id))?'dsh-sam-custom-tab':''}`,'aria-pressed':tab===t.id,onClick:()=>{setTab(t.id);setLimit(PAGE)},children:jsxs(React.Fragment,{children:[t.name,jsx('small',{className:'dsh-sam-tab-count',children:tabCounts[t.id]>99?'99+':tabCounts[t.id]||0})]})},`tab-select-${t.id}`),...((prefs.tabs?.some(x=>x.id===t.id)&&!defaultTabs.some(x=>x.id===t.id))?[jsx('button',{type:'button',className:'dsh-sam-delete-tab',title:`删除分类“${t.name}”`,'aria-label':`删除分类“${t.name}”`,onClick:e=>{e.stopPropagation();if(!window.confirm(`确认删除分类“${t.name}”?`))return;setPrefs(p=>({...p,tabs:(p.tabs||[]).filter(x=>x.id!==t.id)}));if(tab===t.id)setTab('all')},children:'×'},`tab-delete-${t.id}`)]:[])]},t.id)),jsx('button',{type:'button',className:'dsh-sam-new-tab',onClick:()=>{const name=window.prompt('分类名称');if(!name)return;const regex=window.prompt('匹配正则(例如:^审计|review)');if(!regex)return;setPrefs(p=>({...p,tabs:[...(p.tabs||defaultTabs),{id:`tab-${Date.now()}`,name,regex}]}))},children:'+ 新建分类'})]}),jsxs('div',{className:'dsh-sam-controls',children:[jsx('button',{type:'button',className:'dsh-sam-filter-btn',onClick:()=>setFilterOpen(v=>!v),children:`⚙ 筛选排序 · ${scope==='currentWorkspace'?'当前工作区':scope==='currentSession'?'当前会话':'自定义范围'} · ${sort==='recent'?'最近活跃':sort==='title'?'名字':'类型'}`}),!prefs.filterCollapsed&&jsx('select',{value:scope,onChange:e=>{setScope(e.target.value);setSessionScope('all');setLimit(PAGE)},'aria-label':'显示范围',children:[jsx('option',{value:'currentWorkspace',children:'当前工作区'}),jsx('option',{value:'all',children:'全部工作区'}),...scopeOptions.map(c=>jsx('option',{value:`workspace:${c}`,children:workspace({cwd:c})},c))]}),!prefs.filterCollapsed&&jsx('select',{value:selectedSession,onChange:e=>setSessionScope(e.target.value),children:[jsx('option',{value:'all',children:'全部会话'}),...availableSessions.map(s=>jsx('option',{value:s.id,children:s.id===currentId?`当前会话 · ${title(s)}`:title(s)},s.id))]}),jsxs('div',{className:'dsh-sam-search-wrap',children:[jsx('input',{autoFocus:true,value:query,placeholder:'搜索名称、标题或工作区;输入 id: 搜索 Session ID',onChange:e=>{setQuery(e.target.value);setLimit(PAGE)}}),jsxs('div',{className:'dsh-sam-search-actions',children:[query&&jsx('button',{type:'button',className:'dsh-sam-search-clear',title:'清空搜索',onClick:()=>setQuery(''),children:'×'}),jsx('button',{type:'button',className:'dsh-sam-filter-toggle',title:prefs.filterCollapsed?'展开筛选与配置':'折叠筛选与配置',onClick:()=>setPrefs(p=>({...p,filterCollapsed:!p.filterCollapsed})),children:prefs.filterCollapsed?'⚙ 展开筛选 ▾':'⚙ 折叠 ▴'})]})]}),!prefs.filterCollapsed&&jsx('select',{value:grouping,onChange:e=>{setGrouping(e.target.value);setLimit(PAGE)},children:[['session','分组:按会话'],['workspace','分组:按工作区'],['category','分组:按分类'],['type','分组:按类型'],['none','分组:不分组']].map(([v,l])=>jsx('option',{value:v,children:l},v))}),!prefs.filterCollapsed&&jsx('select',{value:sort,onChange:e=>setSort(e.target.value),children:[['recent','排序:最近活跃'],['title','排序:名字'],['type','排序:类型']].map(([v,l])=>jsx('option',{value:v,children:l},v))})]}),filterOpen&&jsxs('div',{className:'dsh-sam-filter-popover',children:[jsx('label',{children:['范围',jsx('select',{value:scope,onChange:e=>{setScope(e.target.value);setSessionScope('all');setLimit(PAGE)},children:[jsx('option',{value:'currentWorkspace',children:'当前工作区'}),jsx('option',{value:'currentSession',children:'当前会话'}),jsx('option',{value:'all',children:'全部工作区'}),...scopeOptions.map(c=>jsx('option',{value:`workspace:${c}`,children:`工作区 · ${workspace({cwd:c})}`},c)),...parentRows.map(s=>jsx('option',{value:`session:${s.id}`,children:`会话 · ${workspace(s)} / ${title(s)}`},s.id))]})]}),jsx('label',{children:['分组',jsx('select',{value:grouping,onChange:e=>{setGrouping(e.target.value);setLimit(PAGE)},children:[['session','按会话'],['workspace','按工作区'],['category','按分类'],['type','按类型'],['none','不分组']].map(([v,l])=>jsx('option',{value:v,children:l},v))})]}),jsx('label',{children:['排序',jsx('select',{value:sort,onChange:e=>{setSort(e.target.value);setLimit(PAGE)},children:[['recent','最近活跃'],['title','名字'],['type','类型']].map(([v,l])=>jsx('option',{value:v,children:l},v))})]})]}),!prefs.filterCollapsed&&jsxs('div',{className:'dsh-sam-options',children:[jsx('label',{children:[jsx('input',{type:'checkbox',checked:!!prefs.hideOneShot,onChange:()=>setPrefs(p=>({...p,hideOneShot:!p.hideOneShot}))}),'隐藏一次性']}),jsx('label',{children:[jsx('input',{type:'checkbox',checked:!!prefs.hideOld,onChange:()=>setPrefs(p=>({...p,hideOld:!p.hideOld}))}),'隐藏长期未活跃']}),jsxs('span',{className:'dsh-sam-bg-config',children:[jsx('label',{children:[jsx('input',{type:'checkbox',checked:prefs.customSubagentBg!==false,onChange:()=>setPrefs(p=>({...p,customSubagentBg:p.customSubagentBg===false}))}),'子代理背景色']}),prefs.customSubagentBg!==false&&jsxs(React.Fragment,{children:[jsx('label',{title:'浅色主题下的子代理背景色',children:[jsx('input',{type:'color',className:'dsh-sam-color-input',value:prefs.subagentBgLight||DEFAULT_LIGHT_BG,onChange:e=>setPrefs(p=>({...p,subagentBgLight:e.target.value}))}),'浅色']}),jsx('label',{title:'深色主题下的子代理背景色',children:[jsx('input',{type:'color',className:'dsh-sam-color-input',value:prefs.subagentBgDark||DEFAULT_DARK_BG,onChange:e=>setPrefs(p=>({...p,subagentBgDark:e.target.value}))}),'深色']})]})]}),jsx('button',{type:'button',onClick:()=>{setQuery('');setScope('currentWorkspace');setScopeDetail('');setSessionScope('all');setTab('all');setGrouping('session');setSort('recent');setLimit(PAGE)},children:'重置筛选'})]}),prefs.filterCollapsed&&jsxs('div',{className:'dsh-sam-collapsed-info',children:[jsxs('div',{className:'dsh-sam-collapsed-left',children:[jsx('span',{className:'dsh-sam-collapsed-tag',children:currentScopeName}),jsx('span',{children:'·'}),jsx('span',{className:'dsh-sam-collapsed-tag',children:currentSessionName}),jsx('span',{children:'·'}),jsx('span',{className:'dsh-sam-collapsed-tag',children:currentTabName})]}),jsxs('div',{className:'dsh-sam-collapsed-right',children:[jsx('span',{children:`排序 · ${currentSortName}`}),jsx('span',{children:`分组 · ${currentGroupName}`})]})]}),jsxs('div',{className:'dsh-sam-summary-line',children:[jsxs('div',{className:'dsh-sam-summary-items',children:[jsx('span',{className:'dsh-sam-summary',children:`显示 ${rows.length}/${allRows.length} 个`}),jsx('label',{className:'dsh-sam-summary-hidden-toggle',children:[jsx('input',{type:'checkbox',checked:prefs.showDetails!==false,onChange:()=>setPrefs(p=>({...p,showDetails:p.showDetails===false}))}),'显示详情']}),jsx('label',{className:'dsh-sam-summary-hidden-toggle',children:[jsx('input',{type:'checkbox',checked:!!prefs.showArchived,onChange:()=>setPrefs(p=>({...p,showArchived:!p.showArchived}))}),'显示已隐藏']}),jsx('span',{className:'dsh-sam-summary',style:{fontSize:'11px'},children:'隐藏仅在列表不显示,不删除会话'})]}),jsx('button',{type:'button',className:`dsh-sam-batch-btn ${batchMode?'dsh-sam-batch-done':''}`,onClick:()=>{setBatchMode(v=>!v);setSelectedIds(new Set)},children:batchMode?'完成':'批量操作'})]}),batchMode&&jsxs('div',{className:'dsh-sam-batch-bar',children:[jsx('button',{type:'button',onClick:()=>setSelectedIds(new Set(allRows.map(r=>r.id))),children:'全选'}),jsx('button',{type:'button',onClick:()=>setSelectedIds(new Set),children:'清空'}),jsx('button',{type:'button',onClick:selectOld,children:'选择 N 小时前'}),jsx('button',{type:'button',disabled:!selectedIds.size,onClick:()=>archiveSelected(false),title:'将选中的子代理隐藏',children:`批量隐藏 (${selectedIds.size})`}),jsx('button',{type:'button',disabled:!selectedIds.size,onClick:()=>archiveSelected(true),title:'取消隐藏选中的子代理',children:'批量显示'}),jsx('button',{type:'button',onClick:()=>{if(!window.confirm('确认隐藏当前筛选出的全部子代理?'))return;batchArchive(allRows.map(r=>r.id));setSelectedIds(new Set)},children:'一键全部隐藏'}),jsx('button',{type:'button',className:'dsh-sam-batch-delete-btn',disabled:!selectedIds.size,onClick:()=>batchDeleteSubagents([...selectedIds]),children:`批量删除 (${selectedIds.size})`}),jsx('button',{type:'button',className:'dsh-sam-batch-delete-btn',onClick:()=>batchDeleteSubagents(allRows.map(r=>r.id)),children:'一键删除全部'})]}),jsx('div',{className:'dsh-sam-list',onWheel:e=>e.stopPropagation(),children:Object.keys(groups).length===0?jsx('div',{className:'dsh-sam-empty',children:'没有符合条件的子代理。'}):Object.entries(groups).map(([name,entries])=>jsxs('section',{className:'dsh-sam-group',children:[jsxs('div',{className:'dsh-sam-group-head',onClick:()=>name==='活跃子代理'&&setActiveOpen(v=>!v),children:[jsx('span',{children:`${name}${name==='活跃子代理'?(activeOpen?' ▾':' ▸'):''}`}),jsxs('div',{className:'dsh-sam-group-head-actions',children:[name==='活跃子代理'&&activeGroupContinuableRows.length>0&&jsx('button',{type:'button',className:'dsh-sam-stop-all-btn',title:'一键暂停所有活跃可继续子代理',disabled:activeGroupContinuableRows.some(r=>stoppingIds.has(r.id)),onClick:e=>{e.stopPropagation();stopAllAgents(activeGroupContinuableRows)},children:activeGroupContinuableRows.some(r=>stoppingIds.has(r.id))?'暂停中':'⏸ 一键暂停'}),jsx('span',{children:entries.length})]})]}),(name==='活跃子代理'&&!activeOpen?[]:entries).map(row=>jsx('div',{className:`dsh-sam-row ${batchMode?'dsh-sam-row-batch':''}${selectedIds.has(row.id)?' dsh-sam-row-selected':''}${archived.has(row.id)?' dsh-sam-row-hidden':''}`,onClick:e=>{if(batchMode)toggleSelected(row,rows.indexOf(row),e);else openRow(row)},children:[jsx('span',{className:'dsh-sam-marker',children:[batchMode&&jsx('input',{type:'checkbox',checked:selectedIds.has(row.id),onChange:e=>toggleSelected(row,rows.indexOf(row),e),onClick:e=>e.stopPropagation(),'aria-label':`选择 ${row.name}`}),archived.has(row.id)?jsx('span',{className:'dsh-sam-dot hidden-dot',title:'已隐藏',children:'\u{1F648}'}):jsx('span',{className:`dsh-sam-dot ${row.running?'running':''}`})]}),jsx('button',{type:'button',className:'dsh-sam-row-open',style:{all:'unset',cursor:batchMode?'default':'pointer',minWidth:0},onClick:e=>{e.stopPropagation();if(batchMode)toggleSelected(row,rows.indexOf(row),e);else openRow(row)},title:`${row.name}\n${row.id}`,children:jsxs('span',{children:[jsx('div',{className:'dsh-sam-title',children:jsxs('span',{children:[highlight(row.name,query),row.mode==='one-shot'&&jsx('small',{className:'dsh-sam-one-shot',children:'⚡ 一次性'}),jsx('small',{className:'dsh-sam-session-id',children:row.id})]})}),grouping==='session'?null:jsx('div',{className:'dsh-sam-meta',children:highlight(`${modeLabel(row.mode)}${grouping==='session'?'':` · ${row.parentId?`${workspace(state.byId[row.parentId]||row)} / ${title(state.byId[row.parentId]||row)}`:'无父会话'}`}`,query)})]})}),jsx('span',{className:'dsh-sam-time',title:`最近活动:${new Date(row.updatedAt).toLocaleString()}`,children:age(row.updatedAt)}),batchMode?(archived.has(row.id)&&jsx('span',{className:'dsh-sam-archived-label',children:'已隐藏'})):jsxs('span',{className:'dsh-sam-row-actions',children:[row.running&&row.mode!=='one-shot'&&jsx('button',{type:'button',className:'dsh-sam-stop-btn',disabled:stoppingIds.has(row.id),onClick:e=>{e.stopPropagation();stopAgent(row)},'aria-label':`暂停 ${row.name}`,'title':'暂停子代理',children:stoppingIds.has(row.id)?'暂停中':'⏸ 暂停'}),jsx('button',{type:'button',className:'dsh-sam-hide-btn',onClick:e=>{e.stopPropagation();archive(row)},title:archived.has(row.id)?'取消隐藏':'隐藏(仅在列表隐藏,不删除会话)','aria-label':`${archived.has(row.id)?'取消隐藏':'隐藏'} ${row.name}`,children:archived.has(row.id)?'👁 显示':'⊘ 隐藏'}),jsx('button',{type:'button',className:'dsh-sam-delete-btn',onClick:e=>{e.stopPropagation();deleteSubagent(row)},title:'永久删除该子代理','aria-label':`删除 ${row.name}`,children:'\u{1F5D1} 删除'})]}),prefs.showDetails!==false&&jsxs('div',{className:'dsh-sam-details',children:[jsx('div',{children:`输入 ${fmt(row.projectionValues?.tokenUsage?.uncachedInputTokens)} / 输出 ${fmt(row.projectionValues?.tokenUsage?.outputTokens)} · 缓存命中 ${row.projectionValues?.tokenUsage?.cacheReadTokens!=null&&tokenTotal(row)?Math.round(row.projectionValues.tokenUsage.cacheReadTokens/tokenTotal(row)*100):'未知'}% · 轮数 ${row.projectionValues?.sessionStats?.turns??row.projectionValues?.turns??'未知'} · 步数 ${row.projectionValues?.sessionStats?.steps??row.projectionValues?.steps??'未知'}`}),promptPreview(row)&&jsx('div',{children:`提示词:${promptPreview(row)}`}),jsx(LiveOutput,{parentId:row.parentId,childId:row.id,running:row.running,autoLoad:rows.slice(0,10).some(r=>r.id===row.id)||manualLoadedIds.has(row.id),onLoad:()=>setManualLoadedIds(prev=>new Set(prev).add(row.id))})]})]},row.id)),limit<allRows.length&&jsx('button',{type:'button',className:'dsh-sam-more',onClick:()=>setLimit(n=>n+PAGE),children:`加载下一页(剩余 ${allRows.length-limit} 个)`})]},name))})]})})]})
|
|
123
|
+
return jsxs(React.Fragment,{children:[(!open&&prefs.activeFloat!==false&&Boolean(activeRows.length)&&!floatHidden)?jsx(ActiveFloat,{rows:activeRows,openRow,onHide:()=>setFloatHidden(true),stopAgent,stopAllAgents,stoppingIds,liveEnabled:prefs.activeFloatLive!==false,onLiveChange:value=>setPrefs(p=>({...p,activeFloatLive:value})),liveCap}):null,jsxs('div',{className:'dsh-sam-trigger-wrap',children:[jsx('button',{type:'button',className:'dsh-sam-trigger',onClick:()=>{setLimit(PAGE);setOpen(true)},title:'打开子代理管理',children:[jsx('span',{className:`dsh-sam-icon ${active>0?'dsh-sam-pulse':''}`,children:'🧩'}),jsx('span',{children:`子代理 ${active}/${currentCount}`})]}),!open&&newAgents.map((item,index)=>jsx('div',{className:'dsh-sam-new-agent',style:{top:`calc(100% + ${6+index*34}px)`},role:'status',children:`新子代理:${item.name}`},item.id))]}),open&&jsx('div',{className:'dsh-sam-backdrop',onMouseDown:e=>{if(e.target===e.currentTarget){setOpen(false);setBatchMode(false);setSelectedIds(new Set);setLastSelectedIndex(-1);setLastSelectedAction(null)}},children:jsxs('section',{className:'dsh-sam-panel',role:'dialog','aria-modal':true,children:[jsxs('header',{className:'dsh-sam-head',children:[jsxs('div',{style:{flex:1,minWidth:0},children:[jsx('h2',{children:'子代理管理'}),jsxs('div',{className:'dsh-sam-head-sub',children:[jsx('div',{className:'dsh-sam-summary',children:`当前会话 ${allRows.filter(r=>r.parentId===currentId).length} 个 · 当前工作区 ${allRows.filter(r=>currentCwd&&state.byId[r.parentId]?.cwd===currentCwd).length} 个 · 活跃 ${active} 个`}),jsx('span',{className:'dsh-sam-summary',style:{opacity:0.6},children:'·'}),jsx('label',{className:'dsh-sam-head-float-toggle',children:[jsx('input',{type:'checkbox',checked:prefs.activeFloat!==false,onChange:()=>{setFloatHidden(false);setPrefs(p=>({...p,activeFloat:p.activeFloat===false}))}}),'显示活跃浮窗']})]})]}),jsx('button',{className:'dsh-sam-close',type:'button',onClick:()=>{setOpen(false);setBatchMode(false);setSelectedIds(new Set);setLastSelectedIndex(-1)},children:'×'})]}),!prefs.filterCollapsed&&jsxs('div',{className:'dsh-sam-tabs',children:[tabs.map(t=>jsxs('span',{className:`dsh-sam-tab-wrap ${(prefs.tabs?.some(x=>x.id===t.id)&&!defaultTabs.some(x=>x.id===t.id))?`dsh-sam-custom-wrap ${tab===t.id?'dsh-sam-tab-selected':''}`:''}`,children:[jsx('button',{type:'button',className:`${t.id==='other'?'dsh-sam-other-tab ':''}${(prefs.tabs?.some(x=>x.id===t.id)&&!defaultTabs.some(x=>x.id===t.id))?'dsh-sam-custom-tab':''}`,'aria-pressed':tab===t.id,onClick:()=>{setTab(t.id);setLimit(PAGE)},children:jsxs(React.Fragment,{children:[t.name,jsx('small',{className:'dsh-sam-tab-count',children:tabCounts[t.id]>99?'99+':tabCounts[t.id]||0})]})},`tab-select-${t.id}`),...((prefs.tabs?.some(x=>x.id===t.id)&&!defaultTabs.some(x=>x.id===t.id))?[jsx('button',{type:'button',className:'dsh-sam-delete-tab',title:`删除分类“${t.name}”`,'aria-label':`删除分类“${t.name}”`,onClick:e=>{e.stopPropagation();if(!window.confirm(`确认删除分类“${t.name}”?`))return;setPrefs(p=>({...p,tabs:(p.tabs||[]).filter(x=>x.id!==t.id)}));if(tab===t.id)setTab('all')},children:'×'},`tab-delete-${t.id}`)]:[])]},t.id)),jsx('button',{type:'button',className:'dsh-sam-new-tab',onClick:()=>{const name=window.prompt('分类名称');if(!name)return;const regex=window.prompt('匹配正则(例如:^审计|review)');if(!regex)return;setPrefs(p=>({...p,tabs:[...(p.tabs||defaultTabs),{id:`tab-${Date.now()}`,name,regex}]}))},children:'+ 新建分类'})]}),jsxs('div',{className:'dsh-sam-controls',children:[jsx('button',{type:'button',className:'dsh-sam-filter-btn',onClick:()=>setFilterOpen(v=>!v),children:`⚙ 筛选排序 · ${scope==='currentWorkspace'?'当前工作区':scope==='currentSession'?'当前会话':'自定义范围'} · ${sort==='recent'?'最近活跃':sort==='title'?'名字':'类型'}`}),!prefs.filterCollapsed&&jsx('select',{value:scope,onChange:e=>{setScope(e.target.value);setSessionScope('all');setLimit(PAGE)},'aria-label':'显示范围',children:[jsx('option',{value:'currentWorkspace',children:'当前工作区'}),jsx('option',{value:'all',children:'全部工作区'}),...scopeOptions.map(c=>jsx('option',{value:`workspace:${c}`,children:workspace({cwd:c})},c))]}),!prefs.filterCollapsed&&jsx('select',{value:selectedSession,onChange:e=>setSessionScope(e.target.value),children:[jsx('option',{value:'all',children:'全部会话'}),...availableSessions.map(s=>jsx('option',{value:s.id,children:s.id===currentId?`当前会话 · ${title(s)}`:title(s)},s.id))]}),jsxs('div',{className:'dsh-sam-search-wrap',children:[jsx('input',{autoFocus:true,value:query,placeholder:'搜索名称、标题或工作区;输入 id: 搜索 Session ID',onChange:e=>{setQuery(e.target.value);setLimit(PAGE)}}),jsxs('div',{className:'dsh-sam-search-actions',children:[query&&jsx('button',{type:'button',className:'dsh-sam-search-clear',title:'清空搜索',onClick:()=>setQuery(''),children:'×'}),jsx('button',{type:'button',className:'dsh-sam-filter-toggle',title:prefs.filterCollapsed?'展开筛选与配置':'折叠筛选与配置',onClick:()=>setPrefs(p=>({...p,filterCollapsed:!p.filterCollapsed})),children:prefs.filterCollapsed?'⚙ 展开筛选 ▾':'⚙ 折叠 ▴'})]})]}),!prefs.filterCollapsed&&jsx('select',{value:grouping,onChange:e=>{setGrouping(e.target.value);setLimit(PAGE)},children:[['session','分组:按会话'],['workspace','分组:按工作区'],['category','分组:按分类'],['type','分组:按类型'],['none','分组:不分组']].map(([v,l])=>jsx('option',{value:v,children:l},v))}),!prefs.filterCollapsed&&jsx('select',{value:sort,onChange:e=>setSort(e.target.value),children:[['recent','排序:最近活跃'],['title','排序:名字'],['type','排序:类型']].map(([v,l])=>jsx('option',{value:v,children:l},v))})]}),filterOpen&&jsxs('div',{className:'dsh-sam-filter-popover',children:[jsx('label',{children:['范围',jsx('select',{value:scope,onChange:e=>{setScope(e.target.value);setSessionScope('all');setLimit(PAGE)},children:[jsx('option',{value:'currentWorkspace',children:'当前工作区'}),jsx('option',{value:'currentSession',children:'当前会话'}),jsx('option',{value:'all',children:'全部工作区'}),...scopeOptions.map(c=>jsx('option',{value:`workspace:${c}`,children:`工作区 · ${workspace({cwd:c})}`},c)),...parentRows.map(s=>jsx('option',{value:`session:${s.id}`,children:`会话 · ${workspace(s)} / ${title(s)}`},s.id))]})]}),jsx('label',{children:['分组',jsx('select',{value:grouping,onChange:e=>{setGrouping(e.target.value);setLimit(PAGE)},children:[['session','按会话'],['workspace','按工作区'],['category','按分类'],['type','按类型'],['none','不分组']].map(([v,l])=>jsx('option',{value:v,children:l},v))})]}),jsx('label',{children:['排序',jsx('select',{value:sort,onChange:e=>{setSort(e.target.value);setLimit(PAGE)},children:[['recent','最近活跃'],['title','名字'],['type','类型']].map(([v,l])=>jsx('option',{value:v,children:l},v))})]})]}),!prefs.filterCollapsed&&jsxs('div',{className:'dsh-sam-options',children:[jsx('label',{children:[jsx('input',{type:'checkbox',checked:!!prefs.hideOneShot,onChange:()=>setPrefs(p=>({...p,hideOneShot:!p.hideOneShot}))}),'隐藏一次性']}),jsx('label',{children:[jsx('input',{type:'checkbox',checked:!!prefs.hideOld,onChange:()=>setPrefs(p=>({...p,hideOld:!p.hideOld}))}),'隐藏长期未活跃']}),jsxs('span',{className:'dsh-sam-bg-config',children:[jsx('label',{children:[jsx('input',{type:'checkbox',checked:prefs.customSubagentBg!==false,onChange:()=>setPrefs(p=>({...p,customSubagentBg:p.customSubagentBg===false}))}),'子代理背景色']}),prefs.customSubagentBg!==false&&jsxs(React.Fragment,{children:[jsx('label',{title:'浅色主题下的子代理背景色',children:[jsx('input',{type:'color',className:'dsh-sam-color-input',value:prefs.subagentBgLight||DEFAULT_LIGHT_BG,onChange:e=>setPrefs(p=>({...p,subagentBgLight:e.target.value}))}),'浅色']}),jsx('label',{title:'深色主题下的子代理背景色',children:[jsx('input',{type:'color',className:'dsh-sam-color-input',value:prefs.subagentBgDark||DEFAULT_DARK_BG,onChange:e=>setPrefs(p=>({...p,subagentBgDark:e.target.value}))}),'深色']})]})]}),jsx('button',{type:'button',onClick:()=>{setQuery('');setScope('currentWorkspace');setScopeDetail('');setSessionScope('all');setTab('all');setGrouping('session');setSort('recent');setLimit(PAGE)},children:'重置筛选'})]}),prefs.filterCollapsed&&jsxs('div',{className:'dsh-sam-collapsed-info',children:[jsxs('div',{className:'dsh-sam-collapsed-left',children:[jsx('span',{className:'dsh-sam-collapsed-tag',children:currentScopeName}),jsx('span',{children:'·'}),jsx('span',{className:'dsh-sam-collapsed-tag',children:currentSessionName}),jsx('span',{children:'·'}),jsx('span',{className:'dsh-sam-collapsed-tag',children:currentTabName})]}),jsxs('div',{className:'dsh-sam-collapsed-right',children:[jsx('span',{children:`排序 · ${currentSortName}`}),jsx('span',{children:`分组 · ${currentGroupName}`})]})]}),jsxs('div',{className:'dsh-sam-summary-line',children:[jsxs('div',{className:'dsh-sam-summary-items',children:[jsx('span',{className:'dsh-sam-summary',children:`显示 ${rows.length}/${allRows.length} 个`}),jsx('label',{className:'dsh-sam-summary-hidden-toggle',children:[jsx('input',{type:'checkbox',checked:prefs.showDetails!==false,onChange:()=>setPrefs(p=>({...p,showDetails:p.showDetails===false}))}),'显示详情']}),jsx('label',{className:'dsh-sam-summary-hidden-toggle',children:[jsx('input',{type:'checkbox',checked:!!prefs.showArchived,onChange:()=>setPrefs(p=>({...p,showArchived:!p.showArchived}))}),'显示已隐藏']}),jsx('span',{className:'dsh-sam-summary',style:{fontSize:'11px'},children:'隐藏仅在列表不显示,不删除会话'})]}),jsx('button',{type:'button',className:`dsh-sam-batch-btn ${batchMode?'dsh-sam-batch-done':''}`,onClick:()=>{setBatchMode(v=>!v);setSelectedIds(new Set)},children:batchMode?'完成':'批量操作'})]}),batchMode&&jsxs('div',{className:'dsh-sam-batch-bar',children:[jsx('button',{type:'button',onClick:()=>setSelectedIds(new Set(allRows.map(r=>r.id))),children:'全选'}),jsx('button',{type:'button',onClick:()=>setSelectedIds(new Set),children:'清空'}),jsx('button',{type:'button',onClick:selectOld,children:'选择 N 小时前'}),jsx('button',{type:'button',disabled:!selectedIds.size,onClick:()=>archiveSelected(false),title:'将选中的子代理隐藏',children:`批量隐藏 (${selectedIds.size})`}),jsx('button',{type:'button',disabled:!selectedIds.size,onClick:()=>archiveSelected(true),title:'取消隐藏选中的子代理',children:'批量显示'}),jsx('button',{type:'button',onClick:()=>{if(!window.confirm('确认隐藏当前筛选出的全部子代理?'))return;batchArchive(allRows.map(r=>r.id));setSelectedIds(new Set)},children:'一键全部隐藏'}),jsx('button',{type:'button',className:'dsh-sam-batch-delete-btn',disabled:!selectedIds.size,onClick:()=>batchDeleteSubagents([...selectedIds]),children:`批量删除 (${selectedIds.size})`}),jsx('button',{type:'button',className:'dsh-sam-batch-delete-btn',onClick:()=>batchDeleteSubagents(allRows.map(r=>r.id)),children:'一键删除全部'})]}),jsx('div',{className:'dsh-sam-list',onWheel:e=>e.stopPropagation(),children:Object.keys(groups).length===0?jsx('div',{className:'dsh-sam-empty',children:'没有符合条件的子代理。'}):Object.entries(groups).map(([name,entries])=>jsxs('section',{className:'dsh-sam-group',children:[jsxs('div',{className:'dsh-sam-group-head',onClick:()=>name==='活跃子代理'&&setActiveOpen(v=>!v),children:[jsx('span',{children:`${name}${name==='活跃子代理'?(activeOpen?' ▾':' ▸'):''}`}),jsxs('div',{className:'dsh-sam-group-head-actions',children:[name==='活跃子代理'&&activeGroupContinuableRows.length>0&&jsx('button',{type:'button',className:'dsh-sam-stop-all-btn',title:'一键暂停所有活跃可继续子代理',disabled:activeGroupContinuableRows.some(r=>stoppingIds.has(r.id)),onClick:e=>{e.stopPropagation();stopAllAgents(activeGroupContinuableRows)},children:activeGroupContinuableRows.some(r=>stoppingIds.has(r.id))?'暂停中':'⏸ 一键暂停'}),jsx('span',{children:entries.length})]})]}),(name==='活跃子代理'&&!activeOpen?[]:entries).map(row=>jsx('div',{className:`dsh-sam-row ${batchMode?'dsh-sam-row-batch':''}${selectedIds.has(row.id)?' dsh-sam-row-selected':''}${archived.has(row.id)?' dsh-sam-row-hidden':''}`,onClick:e=>{if(batchMode)toggleSelected(row,rows.indexOf(row),e);else openRow(row)},children:[jsx('span',{className:'dsh-sam-marker',children:[batchMode&&jsx('input',{type:'checkbox',checked:selectedIds.has(row.id),onChange:e=>toggleSelected(row,rows.indexOf(row),e),onClick:e=>e.stopPropagation(),'aria-label':`选择 ${row.name}`}),archived.has(row.id)?jsx('span',{className:'dsh-sam-dot hidden-dot',title:'已隐藏',children:'\u{1F648}'}):jsx('span',{className:`dsh-sam-dot ${row.running?'running':''}`})]}),jsx('button',{type:'button',className:'dsh-sam-row-open',style:{all:'unset',cursor:batchMode?'default':'pointer',minWidth:0},onClick:e=>{e.stopPropagation();if(batchMode)toggleSelected(row,rows.indexOf(row),e);else openRow(row)},title:`${row.name}\n${row.id}`,children:jsxs('span',{children:[jsx('div',{className:'dsh-sam-title',children:jsxs('span',{children:[highlight(row.name,query),row.mode==='one-shot'&&jsx('small',{className:'dsh-sam-one-shot',children:'⚡ 一次性'}),jsx('small',{className:'dsh-sam-session-id',children:row.id})]})}),grouping==='session'?null:jsx('div',{className:'dsh-sam-meta',children:highlight(`${modeLabel(row.mode)}${grouping==='session'?'':` · ${row.parentId?`${workspace(state.byId[row.parentId]||row)} / ${title(state.byId[row.parentId]||row)}`:'无父会话'}`}`,query)})]})}),jsx('span',{className:'dsh-sam-time',title:`最近活动:${new Date(row.updatedAt).toLocaleString()}`,children:age(row.updatedAt)}),batchMode?(archived.has(row.id)&&jsx('span',{className:'dsh-sam-archived-label',children:'已隐藏'})):jsxs('span',{className:'dsh-sam-row-actions',children:[row.running&&row.mode!=='one-shot'&&jsx('button',{type:'button',className:'dsh-sam-stop-btn',disabled:stoppingIds.has(row.id),onClick:e=>{e.stopPropagation();stopAgent(row)},'aria-label':`暂停 ${row.name}`,'title':'暂停子代理',children:stoppingIds.has(row.id)?'暂停中':'⏸ 暂停'}),jsx('button',{type:'button',className:'dsh-sam-hide-btn',onClick:e=>{e.stopPropagation();archive(row)},title:archived.has(row.id)?'取消隐藏':'隐藏(仅在列表隐藏,不删除会话)','aria-label':`${archived.has(row.id)?'取消隐藏':'隐藏'} ${row.name}`,children:archived.has(row.id)?'👁 显示':'⊘ 隐藏'}),jsx('button',{type:'button',className:'dsh-sam-delete-btn',onClick:e=>{e.stopPropagation();deleteSubagent(row)},title:'永久删除该子代理','aria-label':`删除 ${row.name}`,children:'\u{1F5D1} 删除'})]}),prefs.showDetails!==false&&jsxs('div',{className:'dsh-sam-details',children:[jsx('div',{children:`输入 ${fmt(row.projectionValues?.tokenUsage?.uncachedInputTokens)} / 输出 ${fmt(row.projectionValues?.tokenUsage?.outputTokens)} · 缓存命中 ${row.projectionValues?.tokenUsage?.cacheReadTokens!=null&&tokenTotal(row)?Math.round(row.projectionValues.tokenUsage.cacheReadTokens/tokenTotal(row)*100):'未知'}% · 轮数 ${row.projectionValues?.sessionStats?.turns??row.projectionValues?.turns??'未知'} · 步数 ${row.projectionValues?.sessionStats?.steps??row.projectionValues?.steps??'未知'}`}),promptPreview(row)&&jsx('div',{children:`提示词:${promptPreview(row)}`}),jsx(LiveOutput,{parentId:row.parentId,childId:row.id,running:row.running,autoLoad:rows.slice(0,10).some(r=>r.id===row.id)||manualLoadedIds.has(row.id),live:(!row.running||(runningLiveIds?runningLiveIds.has(row.id):true)||manualLoadedIds.has(row.id)),onLoad:()=>setManualLoadedIds(prev=>new Set(prev).add(row.id))})]})]},row.id)),limit<allRows.length&&jsx('button',{type:'button',className:'dsh-sam-more',onClick:()=>setLimit(n=>n+PAGE),children:`加载下一页(剩余 ${allRows.length-limit} 个)`})]},name))})]})})]})
|
|
123
124
|
}
|
|
124
125
|
function apply(ctx){sessionsRt=ctx.sessions;const actions={openChild:a=>ctx.sessions.openSubagent(a),openSession:id=>ctx.sessions.open(id),refresh:p=>ctx.sessions.refreshSubagents(p),setCatalogOpen:(p,o)=>ctx.sessions.setSubagentCatalogOpen(p,o)},face=()=>actions;ctx.slots.inject('conversation.session.header.actions',()=>ctx.slots.register({name:'conversation.session.header.actions',id:'subagent-workspace-manager',order:100,inject:face},Manager))}
|
|
125
126
|
return {inject:['sessions','slots'],apply}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-subagent-workspace-ui",
|
|
3
|
-
"version": "1.2
|
|
3
|
+
"version": "1.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Searchable workspace subagent manager for DeepSeek Harness Web",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
},
|
|
28
28
|
"client": {
|
|
29
29
|
"inject": [
|
|
30
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
31
30
|
"@deepseek-ai/dsh-client-locale",
|
|
32
31
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
33
32
|
"@deepseek-ai/dsh-client-ui-sidebar"
|