dsh-better-workspace 0.4.3 → 0.6.0
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 +2 -2
- package/README_EN.md +2 -2
- package/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +35 -8
- package/src/index.js +10 -1
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ web/ ← 虚拟分组(不是真实目录,纯命名层级)
|
|
|
34
34
|
<table>
|
|
35
35
|
<tr>
|
|
36
36
|
<td align="center" width="58%"><img src="docs/screenshots/3-appearance-dialog.png" alt="外观自定义弹窗(实时预览)"/></td>
|
|
37
|
-
<td valign="top"><b>外观自定义</b><br/>右键任意一层(工作区分组 / 工作区 / 会话 / 会话分组)→「自定义外观」:颜色(预设色板 + 取色器 + RGB)、发光强度(0..14 拖动条,只作用于文字)、字体粗细、字体阴影开关、图标(与 dsh 图标库同族的
|
|
37
|
+
<td valign="top"><b>外观自定义</b><br/>右键任意一层(工作区分组 / 工作区 / 会话 / 会话分组)→「自定义外观」:颜色(预设色板 + 取色器 + RGB)、发光强度(0..14 拖动条,只作用于文字)、字体粗细、字体阴影开关、图标(与 dsh 图标库同族的 69 个,工作区与工作区分组专属),底部带实时预览。清除自定义一键复原。</td>
|
|
38
38
|
</tr>
|
|
39
39
|
<tr>
|
|
40
40
|
<td align="center" width="58%"><img src="docs/screenshots/2-customized-tree.png" alt="外观自定义效果"/></td>
|
|
@@ -60,7 +60,7 @@ web/ ← 虚拟分组(不是真实目录,纯命名层级)
|
|
|
60
60
|
|
|
61
61
|
- **文件夹式收起**:点工作区行 = 收起/展开该工作区的全部会话(收起后行上保留会话数角标);会话分组同样可收起;搜索时自动全部展开。
|
|
62
62
|
- **拖拽还原原版能力**:工作区行可拖拽——拖到另一工作区行上/下半即调整顺序(写回宿主 registry 序),拖到分组行则移动进该分组;会话行可拖拽——同工作区拖到另一会话上/下调整顺序,拖到会话子分组即移动进该分组。显示顺序 = 宿主手动序,拖拽结果立即生效。
|
|
63
|
-
- **不丢原生能力**:会话行(打开/重命名/分叉/归档)、每工作区「新会话」、当前会话高亮、官方状态灯(蓝色运行环 / 琥珀待交互 / 绿色完成提醒)、未分组会话兜底、中英双语跟随界面语言。
|
|
63
|
+
- **不丢原生能力**:会话行(打开/重命名/分叉/归档)、每工作区「新会话」、当前会话高亮、官方状态灯(蓝色运行环 / 琥珀待交互 / 绿色完成提醒)、**活跃定时任务角标**(有活动 Schedule 的会话显示闹钟图标,与官方行一致)、未分组会话兜底、中英双语跟随界面语言。
|
|
64
64
|
- **对话空态页同样生效**:会话空态页的「添加工作区」菜单走的也是本插件的拾取交互,同样带所属分组弹窗。
|
|
65
65
|
|
|
66
66
|
## 安装
|
package/README_EN.md
CHANGED
|
@@ -32,7 +32,7 @@ Session titles nest on `/` too (e.g. `test1/plugin maintenance`). Session groups
|
|
|
32
32
|
<table>
|
|
33
33
|
<tr>
|
|
34
34
|
<td align="center" width="58%"><img src="docs/screenshots/3-appearance-dialog.png" alt="Appearance dialog with live preview"/></td>
|
|
35
|
-
<td valign="top"><b>Appearance customization</b><br/>Right-click any row (workspace folder / workspace / session / session group) → Customize: color (swatches + picker + RGB), glow strength (0–14 slider, text only), font weight, font shadow, an icon grid (
|
|
35
|
+
<td valign="top"><b>Appearance customization</b><br/>Right-click any row (workspace folder / workspace / session / session group) → Customize: color (swatches + picker + RGB), glow strength (0–14 slider, text only), font weight, font shadow, an icon grid (69 icons from the dsh primitives family, workspace & folder rows only), with a live preview at the bottom. Reset returns to default in one click.</td>
|
|
36
36
|
</tr>
|
|
37
37
|
<tr>
|
|
38
38
|
<td align="center" width="58%"><img src="docs/screenshots/2-customized-tree.png" alt="Custom appearance result"/></td>
|
|
@@ -58,7 +58,7 @@ Session titles nest on `/` too (e.g. `test1/plugin maintenance`). Session groups
|
|
|
58
58
|
|
|
59
59
|
- **Folder-style collapse**: clicking a workspace row collapses/expands all of its sessions (the row keeps a session counter when collapsed); session groups collapse too; search force-expands everything.
|
|
60
60
|
- **Native drag restored**: drag a workspace row above/below another to reorder (writes back the host registry order) or onto a folder row to move it into that group; drag session rows to reorder within the same workspace or onto a session group to move. Display order = host manual order, drag results are visible immediately.
|
|
61
|
-
- **Native capabilities kept**: open/rename/fork/archive sessions, per-workspace new-session, current-session highlight, official status dots (blue running ring / amber pending / green done), ungrouped-session fallback, zh/en localization.
|
|
61
|
+
- **Native capabilities kept**: open/rename/fork/archive sessions, per-workspace new-session, current-session highlight, official status dots (blue running ring / amber pending / green done), **active-schedule badge** (alarm clock icon for sessions with active Schedule records, matching the official rows), ungrouped-session fallback, zh/en localization.
|
|
62
62
|
- **Conversation hero too**: the empty-state “Add workspace” menu uses the same picking interaction with the same group popup.
|
|
63
63
|
|
|
64
64
|
## Install
|
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-better-workspace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "侧边栏工作区层级树:名称中的 / 即虚拟分组(web/前端 · web/后端),添加工作区的目录流附所属分组弹窗,重命名即时重排层级,可新建空分组。Hierarchy tree for the DSH sidebar workspace list.",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-better-workspace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "DSH web plugin: a hierarchical workspace tree for the sidebar. Workspace titles containing \"/\" group into virtual folders (web/前端 · web/后端); the add-workspace directory flow gains a parent-group popup; renames re-derive the tree; a new-folder button creates empty levels.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/client.js
CHANGED
|
@@ -52,6 +52,7 @@ window.__ModuleLoader__.load({
|
|
|
52
52
|
'status.planReview': '等待计划确认',
|
|
53
53
|
'status.question': '等待回答',
|
|
54
54
|
'status.subagents': '{n} 个子任务运行中',
|
|
55
|
+
'schedule.active': '有活动定时任务',
|
|
55
56
|
'menu.rename': '重命名',
|
|
56
57
|
'menu.delete': '删除',
|
|
57
58
|
'menu.fork': '分叉',
|
|
@@ -137,6 +138,7 @@ window.__ModuleLoader__.load({
|
|
|
137
138
|
'status.planReview': 'Waiting for plan review',
|
|
138
139
|
'status.question': 'Waiting for answer',
|
|
139
140
|
'status.subagents': '{n} subagent(s) running',
|
|
141
|
+
'schedule.active': 'Has active scheduled task',
|
|
140
142
|
'menu.rename': 'Rename',
|
|
141
143
|
'menu.delete': 'Delete',
|
|
142
144
|
'menu.fork': 'Fork',
|
|
@@ -268,18 +270,33 @@ window.__ModuleLoader__.load({
|
|
|
268
270
|
&& !(archivedSet && archivedSet.has(summary.id))
|
|
269
271
|
&& (!summary.blank || summary.id === current)
|
|
270
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Active-schedule marker, mirroring the official tree's
|
|
275
|
+
* hasActiveSchedule(): the list projection carries one entry per active
|
|
276
|
+
* Schedule record, and a non-empty projection is the badge's only gate.
|
|
277
|
+
* Defensive shapes (missing/mis-typed projection) degrade to false.
|
|
278
|
+
*/
|
|
279
|
+
const hasActiveScheduleOf = (summary) => !!(summary
|
|
280
|
+
&& summary.projectionValues
|
|
281
|
+
&& Array.isArray(summary.projectionValues.schedule)
|
|
282
|
+
&& summary.projectionValues.schedule.length > 0)
|
|
283
|
+
|
|
271
284
|
/**
|
|
272
285
|
* Running subagent descendants per session (light lineage walk over
|
|
273
|
-
*
|
|
274
|
-
*
|
|
286
|
+
* parent links) — a parent row keeps its "ongoing" ring while a spawned
|
|
287
|
+
* subagent is still working. The client SessionSummary exposes the
|
|
288
|
+
* parent as parentId (the session controller maps parentSessionId to
|
|
289
|
+
* parentId on the wire); the old parentSessionId spelling is kept as a
|
|
290
|
+
* fallback for profiles serving the pre-rename shape.
|
|
275
291
|
*/
|
|
276
292
|
const subagentRunningCounts = (byId) => {
|
|
277
293
|
const children = new Map()
|
|
278
294
|
for (const id of Object.keys(byId || {})) {
|
|
279
295
|
const summary = byId[id]
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
296
|
+
const parentId = summary && (summary.parentId || summary.parentSessionId)
|
|
297
|
+
if (!summary || !parentId) continue
|
|
298
|
+
let list = children.get(parentId)
|
|
299
|
+
if (!list) { list = []; children.set(parentId, list) }
|
|
283
300
|
list.push(summary)
|
|
284
301
|
}
|
|
285
302
|
const countFor = (rootId) => {
|
|
@@ -458,9 +475,10 @@ window.__ModuleLoader__.load({
|
|
|
458
475
|
'.bw-row-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}',
|
|
459
476
|
'.bw-row-count{flex:none;font-size:11px;color:var(--dsw-alias-label-quaternary,#8a8a8a)}',
|
|
460
477
|
'.bw-row-time{flex:none;font-size:11px;color:var(--dsw-alias-label-quaternary,#8a8a8a)}',
|
|
478
|
+
'.bw-schedule-badge{flex:none;display:inline-flex;align-items:center;color:var(--dsw-alias-label-tertiary,#9a9a9a);margin:0 6px}',
|
|
461
479
|
'.bw-row-actions{flex:none;display:none;align-items:center;gap:2px}',
|
|
462
480
|
'.bw-row:hover .bw-row-actions{display:flex}',
|
|
463
|
-
'.bw-row:hover .bw-row-time,.bw-row:hover .bw-row-count{display:none}',
|
|
481
|
+
'.bw-row:hover .bw-row-time,.bw-row:hover .bw-row-count,.bw-row:hover .bw-schedule-badge{display:none}',
|
|
464
482
|
'.bw-dot{flex:none;width:6px;height:6px;border-radius:50%;background:transparent}',
|
|
465
483
|
'.bw-session-row{font-size:12.5px;color:var(--dsw-alias-label-secondary,#b8b8b8);min-height:26px}',
|
|
466
484
|
'.bw-sgroup-row{font-size:12.5px;color:var(--dsw-alias-label-tertiary,#9a9a9a);min-height:24px}',
|
|
@@ -842,6 +860,9 @@ window.__ModuleLoader__.load({
|
|
|
842
860
|
: E('span', { className: 'bw-dot' }),
|
|
843
861
|
),
|
|
844
862
|
E('span', { className: 'bw-row-label' }, node.leaf || node.title),
|
|
863
|
+
node.hasActiveSchedule
|
|
864
|
+
? E('span', { className: 'bw-schedule-badge', role: 'img', 'aria-label': t('schedule.active'), title: t('schedule.active') }, icon('IconAlarmClockOutline16', 14))
|
|
865
|
+
: null,
|
|
845
866
|
E('span', { className: 'bw-row-time' }, timeLabel(node.updatedAt, now, t)),
|
|
846
867
|
)
|
|
847
868
|
}
|
|
@@ -890,6 +911,7 @@ window.__ModuleLoader__.load({
|
|
|
890
911
|
'IconSettingsOutline16', 'IconShareOutline16', 'IconStopFill16', 'IconThinkOutline14',
|
|
891
912
|
'IconThinkOutline16', 'IconTrashOutline16', 'IconUserOutline16', 'IconWarningOutline16',
|
|
892
913
|
'IconLikeOutline16', 'IconDislikeOutline16', 'IconFollowsystemOutline16',
|
|
914
|
+
'IconAlarmClockOutline16', 'IconClockOutline16', 'IconDatabaseOutline16',
|
|
893
915
|
]
|
|
894
916
|
|
|
895
917
|
/**
|
|
@@ -1178,6 +1200,7 @@ window.__ModuleLoader__.load({
|
|
|
1178
1200
|
blank: !!summary.blank,
|
|
1179
1201
|
running: !!summary.running,
|
|
1180
1202
|
completed: summary.completed === true,
|
|
1203
|
+
hasActiveSchedule: hasActiveScheduleOf(summary),
|
|
1181
1204
|
subagents: subCounts.get(id) || 0,
|
|
1182
1205
|
updatedAt: summary.updatedAt || 0,
|
|
1183
1206
|
pending: pendingKindOf(pending, id),
|
|
@@ -1204,6 +1227,7 @@ window.__ModuleLoader__.load({
|
|
|
1204
1227
|
blank: !!summary.blank,
|
|
1205
1228
|
running: !!summary.running,
|
|
1206
1229
|
completed: summary.completed === true,
|
|
1230
|
+
hasActiveSchedule: hasActiveScheduleOf(summary),
|
|
1207
1231
|
subagents: subCounts.get(id) || 0,
|
|
1208
1232
|
updatedAt: summary.updatedAt || 0,
|
|
1209
1233
|
pending: pendingKindOf(pending, id),
|
|
@@ -2000,14 +2024,17 @@ window.__ModuleLoader__.load({
|
|
|
2000
2024
|
}
|
|
2001
2025
|
|
|
2002
2026
|
// 1+2. the two directory-flow holes (hero picker, shipped sidebar browser).
|
|
2027
|
+
// Since dsh 0.1.2-alpha.1 the shell's own directory picker occupies each
|
|
2028
|
+
// hole at priority 0, so shadow at -1 (ascending, lowest renders) exactly
|
|
2029
|
+
// like the sidebar.workspaces browser below.
|
|
2003
2030
|
slots.inject('conversation.hero.workspace.directoryFlow', guarded(
|
|
2004
2031
|
'conversation.hero.workspace.directoryFlow',
|
|
2005
|
-
{ name: 'conversation.hero.workspace.directoryFlow', inject: flowInjected('conversation.hero.workspace.directoryFlow'), locale: NS },
|
|
2032
|
+
{ name: 'conversation.hero.workspace.directoryFlow', inject: flowInjected('conversation.hero.workspace.directoryFlow'), locale: NS, priority: -1 },
|
|
2006
2033
|
BetterFlow,
|
|
2007
2034
|
))
|
|
2008
2035
|
slots.inject('sidebar.workspaces.directoryFlow', guarded(
|
|
2009
2036
|
'sidebar.workspaces.directoryFlow',
|
|
2010
|
-
{ name: 'sidebar.workspaces.directoryFlow', inject: flowInjected('sidebar.workspaces.directoryFlow'), locale: NS },
|
|
2037
|
+
{ name: 'sidebar.workspaces.directoryFlow', inject: flowInjected('sidebar.workspaces.directoryFlow'), locale: NS, priority: -1 },
|
|
2011
2038
|
BetterFlow,
|
|
2012
2039
|
))
|
|
2013
2040
|
|
package/src/index.js
CHANGED
|
@@ -40,7 +40,16 @@ export function apply(ctx) {
|
|
|
40
40
|
const settings = sctx && sctx.settings
|
|
41
41
|
if (!settings || typeof settings.register !== 'function') return
|
|
42
42
|
const Schema = sm.default
|
|
43
|
-
|
|
43
|
+
// dsh >= 0.1.2-alpha.2 removed the settingsNamespace() helper from
|
|
44
|
+
// @deepseek-ai/dsh-settings: register() now takes a plain string and
|
|
45
|
+
// validates it at runtime (parseSettingsNamespace). The helper's old
|
|
46
|
+
// signature was compile-time branding only, so a plain string is also
|
|
47
|
+
// accepted by the older register() — one call, both eras. Only use the
|
|
48
|
+
// helper when the installed package still ships it.
|
|
49
|
+
const ns = typeof ds.settingsNamespace === 'function'
|
|
50
|
+
? ds.settingsNamespace('better-workspace')
|
|
51
|
+
: 'better-workspace'
|
|
52
|
+
settings.register(ns, Schema.object({ compactChains: Schema.boolean().default(true) }))
|
|
44
53
|
log('[dsh-better-workspace] settings namespace registered: better-workspace')
|
|
45
54
|
})
|
|
46
55
|
.catch((error) => {
|