@qzsy/dsh-command-palette 1.5.0 → 1.5.1

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 qzsy
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 qzsy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,230 +1,233 @@
1
- # @qzsy/dsh-command-palette
2
-
3
- > Packaged from the local DSH plugin dsh-command-palette; published under the @qzsy scope.
4
-
5
- ## Install
6
-
7
- ~~~bash
8
- dsh plugin add @qzsy/dsh-command-palette
9
- ~~~
10
-
11
- ## Upstream README
12
-
13
- # Command Palette for DSH
14
-
15
- A persistent DeepSeek Harness Client plugin that turns `Command+K` into a command
16
- palette for the Web/Desktop GUI: recent sessions with live status, workspaces,
17
- files, and actions — searchable in Chinese, English, full pinyin, pinyin
18
- initials, or any mixed form.
19
-
20
- ## What it does
21
-
22
- - **Command+K on the Desktop app** opens a floating palette; the same chord toggles
23
- it closed. In the browser profile it adopts the browser-safe chord that
24
- `session.search` used before (Mod+Alt+K on macOS).
25
- - **Sections and filters**: All / Sessions / Workspaces / Files / Actions.
26
- - *Sessions*: every non-blank, non-archived Session ordered by `updatedAt`,
27
- with its Workspace label, a compact relative age, and a **live status
28
- badge**: `工作中` (pulsing blue dot), `待批准` / `待审阅` / `待回答`
29
- (amber), `出错` (red, failed run), or `已完成` (green, unread completion).
30
- A success that has already been viewed shows no badge. The section label
31
- counts Sessions by state, e.g. `近期会话 · 2 个进行中 · 1 个出错 · 3 个未读`
32
- (only nonzero segments), and updates live while the palette stays open.
33
- When the Git badge bundle is installed, the Workspace name under each
34
- thread title also carries that Workspace's `+N −M` / `干净` / `无 Git`
35
- badge. Choosing a Session also
36
- reveals it in the left Workspace sidebar: a folded Workspace (and every
37
- folded Workspace Tree ancestor) expands, the Session row watermark rises,
38
- the group smooth-scrolls into view, and the Workspace header flashes.
39
- - **Sub-agent threads are hidden by default.** Sessions whose
40
- `origin === "subagent"` are excluded from rows, search results, workspace
41
- activity badges and counts. When any exist, the footer shows
42
- `显示 N 个子代理会话`; the toggle includes them for the current palette
43
- session and returns to the hidden default on the next open, so teammate and
44
- research threads never crowd the list unless asked for.
45
- - *Workspaces*: Workspaces ordered by their most recent Session activity, with
46
- an abbreviated path and an aggregate status badge that reports one state by
47
- priority pending > failed > running > unread (`N 个待处理` / `N 个出错` /
48
- `N 个工作中` / `N 个未读`). When the `@qzsy/dsh-git-badge` bundle is
49
- installed, each workspace name also carries its Git badge: `+N −M` line
50
- changes, `干净` for a clean repository, `无 Git` outside a repository, or
51
- the file count when only
52
- untracked files changed. Git data comes from the Host's
53
- `POST /api/git-badge` route (8 s palette cache); without that route the
54
- badges are simply absent. Enter opens the newest Session in the Workspace,
55
- or a fresh blank Session when it has none.
56
- - *Files*: live, debounced Host file-reference lookup scoped to the Session in
57
- the main panel; choosing a row opens the file in the right-hand preview.
58
- Every file row carries a `项目 · <Workspace>` badge below its path so the
59
- search scope stays visible, and the Files placeholder names the same project.
60
- Opened files are remembered locally (origin-scoped `localStorage`) and listed
61
- as *Recent files* when the search box is empty; recent files resolve their
62
- project from the Session's Workspace. File matching stays Host-ranked path
63
- matching (see limitations).
64
- - *Actions*: every registered shortcut command (labels and keys come from the
65
- live shortcut catalog, so plugin commands appear automatically). Enter
66
- invokes the command through the shortcut registry; Settings and the keyboard
67
- shortcut reference open from here.
68
- - **Mixed Chinese/English search** through [`text-search-engine`](https://github.com/cjinhuo/text-search-engine):
69
- one query covers Han characters (`登录`), full pinyin (`denglu`), pinyin
70
- initials (`dl`), English subsequences (`nextjs`), space-separated terms, and
71
- mixed forms (`qunxingerp`, `群erp`, `qxkf`). Matched ranges are highlighted in
72
- titles and subtitles. Ranking prefers tighter, earlier title hits, then
73
- detail hits, then recency.
74
- - **Keyboard**: Up/Down move the selection, Enter opens, Escape closes. The
75
- filter switches with bare ← / → (both directions, wrapping) or Tab /
76
- Shift+Tab; holding Alt/Ctrl/Cmd with an arrow keeps native caret or word
77
- movement inside the query. IME composition is never intercepted, so pinyin
78
- candidate selection keeps working. Focus returns to whatever had it before
79
- opening.
80
- - **Mobile**: at `(max-width: 720px), (pointer: coarse) and (max-width: 1024px)`
81
- the palette becomes a bottom sheet at 90% of the layer height. It opens
82
- without focusing the search input, so the soft keyboard stays closed until
83
- the user taps the field. All keyboard hints (Esc key, row shortcuts, footer
84
- key legend) are hidden; the footer only remains for the subagent toggle.
85
- - **Unread count**: the sidebar row shows the number of Sessions that finished
86
- successfully but have not been viewed (the green 已完成 badge; failed,
87
- archived, blank and subagent Sessions are excluded). The collapsed rail shows
88
- a dot instead. The always-mounted overlay computes the count and mirrors it
89
- into a plugin-local store read by the sidebar glyph.
90
- - **Sidebar entry**: the *命令面板 / Command palette* row joins the global panel
91
- stack directly below 自动化任务 / Automations (glyph-only in the collapsed
92
- rail). Choosing it opens the overlay without switching the main panel: the row
93
- is an action, so the plugin answers that one panel id in the layout selection
94
- and delegates every other id to the layout owner.
95
- - Light/dark themes follow `--dsw-*` tokens; all copy is registered in the Client
96
- locale service (zh/en).
97
-
98
- ## Search engine integration
99
-
100
- DSH's browser module table only resolves its own platform modules and
101
- client-plugin rows, so a plain-JS plugin cannot `require('text-search-engine')`
102
- at runtime. The package's minified browser IIFE is therefore vendored and
103
- injected into the client bundle:
104
-
105
- - `vendor/text-search-engine.min.js` — exact browser build from the pinned
106
- `text-search-engine@1.6.0` dependency (MIT; license in
107
- `vendor/text-search-engine.LICENSE`).
108
- - `scripts/sync-vendor-engine.mjs` — rewrites the marked region in `client.js`
109
- from the vendored file; run `node scripts/sync-vendor-engine.mjs` after
110
- updating the vendored build.
111
- - `client.js` — the generated region captures the engine exports in a factory
112
- scope constant and uses `createSearcher()` with `title`/`detail` fields,
113
- custom ranking, and hit ranges for highlighting. If the engine fails to
114
- initialize, a built-in subsequence matcher keeps the palette usable.
115
-
116
- File search is delegated to the Host (`ctx.remote.fileReferences.list`), which
117
- retrieves and ranks paths from the current Session workspace; pinyin is applied
118
- to sessions, workspaces, and actions, where titles are user-facing Chinese text.
119
-
120
- ## Session status
121
-
122
- The palette reads the root `useSessionStatus` hook of the `shell.overlay` slot
123
- (provided by `dsh-client-ui-session`). That observable snapshot carries
124
- `running`, `pendingInteraction.kind`, and `completionUnread` per Session, so
125
- badges and counts change live as agents start, wait for input, and finish.
126
-
127
- A Session settles into one of three terminal states:
128
-
129
- - **Viewed success — no badge.** The completion has been acknowledged, so the
130
- row is a plain Session and the badge clears.
131
- - **Unread success — green `已完成`.** Shown while the snapshot still reports
132
- `completionUnread`; the tooltip reads `已完成,尚未查看`.
133
- - **Failed run — red `出错`.** The tooltip reads `运行出错:<message>`, or
134
- `运行出错(尚未查看):<message>` when the same Session is also an unread
135
- completion. An empty failure message falls back to `未知错误`.
136
-
137
- The unified snapshot answers whether a run is going, waiting, or finished
138
- unread; it does not say why a run ended. Failures therefore come from the
139
- forwarded Host event `api-session/error`, which carries Agent failures —
140
- including network and provider errors. The palette keeps the latest message
141
- per Session and drops it when the next turn starts (`api-session/status` with
142
- `running` true), when a new user prompt arrives (`api-session/activity`), or
143
- when the Session is removed (`api-session/removed`). Aborted runs and
144
- transient tool errors never reach that event, so they never raise the badge.
145
-
146
- The map is in-memory for the app session — the same lifetime as unread
147
- completions — so a reload starts clean. A failure that predates the palette
148
- stays clear until the Host forwards a new `api-session/error`.
149
-
150
- When several states apply, one badge wins in this order: pending interaction >
151
- running > failure > unread completion. A stale failure can therefore never
152
- mask a Session that is working or waiting for the user.
153
-
154
- Workspace badges aggregate their Sessions with the priority pending > failed >
155
- running > unread, counting each Session once (`N 个待处理` / `N 个出错` /
156
- `N 个工作中` / `N 个未读`). The Sessions group label appends the counts in
157
- running/pending/error/unread order, keeping only nonzero segments:
158
- `近期会话 · N 个进行中 · N 个待处理 · N 个出错 · N 个未读`.
159
-
160
- Error excerpts are whitespace-collapsed onto one line and capped at 180
161
- characters with an ellipsis.
162
-
163
- `scripts/verify-status.mjs` is the browser-free node harness that verifies this
164
- state matrix. `docs/palette-statuses.png` renders the five states above from the
165
- same component (running, pending, failed, unread, viewed).
166
-
167
- ## Sidebar reveal
168
-
169
- Selecting a Session or Workspace closes the palette, navigates, and then reveals
170
- the target in the left Workspace browser. The browser owns reveal for its own
171
- search in private React state, so the palette drives the stable DOM markers the
172
- browser publishes instead: `data-row-key` identifies Workspace / Session /
173
- watermark rows, `aria-expanded` reports a folded Workspace, and `role="tree"`
174
- is the scrolling list. The persisted `dsh.workspace.view.v5` store supplies the
175
- grouping mode, which distinguishes sibling Workspace groups from Workspace Tree
176
- ancestry.
177
-
178
- The reveal is bounded (about 2.4 s of retries): it expands the owning group and
179
- its tree ancestors, raises hidden session rows through the same **Show more**
180
- control the browser owns, then scrolls the group and chosen row into view with
181
- `behavior: "smooth"` (or `auto` under reduced motion) and briefly rings the
182
- Workspace header with a `--dsw-*` token outline. If the sidebar is a collapsed
183
- rail, or the target is hidden by the current archive filter, the reveal is a
184
- silent no-op — navigation still succeeds.
185
-
186
- ## Marketplace palette
187
-
188
- The DSH Market landing page in this repository (`apps/market`) mounts the same
189
- keyboard-first interaction as a live demo: `⌘K` / `Ctrl+K` searches the plugin
190
- directory, opens plugin pages, and offers the install command. The palette footer
191
- credits this package, and `@qzsy` packages stay pinned ahead of upstream
192
- duplicates so the command palette itself is always one keystroke away.
193
-
194
- ## Shortcut ownership
195
-
196
- `session.search` already owns `Command+K` in the shipped UI. The palette registers
197
- with the free `Command+Shift+P` default and, once per device preference document,
198
- uses the public `ctx.shortcuts.edit()` API to:
199
-
200
- 1. clear `session.search`'s binding, and
201
- 2. bind `palette.open` to the chord `session.search` had (Command+K on Desktop,
202
- Mod+Alt+K in the browser).
203
-
204
- That is a normal, visible override in Settings → Keyboard shortcuts: both rows
205
- show as modified, and *Restore All Defaults* restores the palette to
206
- `Command+Shift+P` and search to `Command+K`. On the next launch the plugin
207
- re-adopts the chord while both rows are still at their unmodified defaults, so
208
- `Command+K` keeps opening the palette. Session search itself stays available from
209
- the palette's Actions list and from the sidebar search icon.
210
-
211
- ## Install
212
-
213
- The bundle is installed into the current profile with
214
- `plugin_manager install_bundle` (absolute package directory). It needs no build
215
- step at install time: `client.js` is a plain-JS `__ModuleLoader__` module that
216
- only requires `react` from the browser module table, with the vendored engine
217
- already inlined.
218
-
219
- ## Files
220
-
221
- - `package.json` — bundle manifest (`dsh.bundle.patch`, `dsh.client`, display resources)
222
- - `cordis.patch.yml` — inserts the Host row
223
- - `index.js` — Host half (no-op; the palette is client-only)
224
- - `client.js` — shortcut adoption, overlay palette, live status badges, ranked
225
- mixed-script search, sidebar trigger, zh/en dictionaries
226
- - `vendor/` — vendored engine build and its MIT license
227
- - `scripts/sync-vendor-engine.mjs` — regenerates the vendored engine region
228
- - `locale/en.json`, `locale/zh.json` — Plugin Manager title/description
229
- - `icon.svg` — original artwork
230
- - `docs/` — verification screenshots
1
+ # @qzsy/dsh-command-palette
2
+
3
+ > Packaged from the local DSH plugin dsh-command-palette; published under the @qzsy scope.
4
+
5
+ ## Install
6
+
7
+ ~~~bash
8
+ dsh plugin add @qzsy/dsh-command-palette
9
+ ~~~
10
+
11
+ ## Upstream README
12
+
13
+ # Command Palette for DSH
14
+
15
+ A persistent DeepSeek Harness Client plugin that turns `Command+K` into a command
16
+ palette for the Web/Desktop GUI: recent sessions with live status, workspaces,
17
+ files, and actions — searchable in Chinese, English, full pinyin, pinyin
18
+ initials, or any mixed form.
19
+
20
+ ## What it does
21
+
22
+ - **Command+K on the Desktop app** opens a floating palette; the same chord toggles
23
+ it closed. In the browser profile it adopts the browser-safe chord that
24
+ `session.search` used before (Mod+Alt+K on macOS).
25
+ - **Sections and filters**: All / Sessions / Workspaces / Files / Actions.
26
+ - *Sessions*: every non-blank, non-archived Session ordered by `updatedAt`,
27
+ with its Workspace label, a compact relative age, and a **live status
28
+ badge**: `工作中` (pulsing blue dot), `待批准` / `待审阅` / `待回答`
29
+ (amber), `出错` (red, failed run), or `已完成` (green, unread completion).
30
+ A success that has already been viewed shows no badge. The section label
31
+ counts Sessions by state, e.g. `近期会话 · 2 个进行中 · 1 个出错 · 3 个未读`
32
+ (only nonzero segments), and updates live while the palette stays open.
33
+ When the Git badge bundle is installed, the Workspace name under each
34
+ thread title also carries that Workspace's `+N −M` / `干净` / `无 Git`
35
+ badge. Choosing a Session also
36
+ reveals it in the left Workspace sidebar: a folded Workspace (and every
37
+ folded Workspace Tree ancestor) expands, the Session row watermark rises,
38
+ the group smooth-scrolls into view, and the Workspace header flashes.
39
+ - **Sub-agent threads are hidden by default.** Sessions whose
40
+ `origin === "subagent"` are excluded from rows, search results, workspace
41
+ activity badges and counts. When any exist, the footer shows
42
+ `显示 N 个子代理会话`; the toggle includes them for the current palette
43
+ session and returns to the hidden default on the next open, so teammate and
44
+ research threads never crowd the list unless asked for.
45
+ - *Workspaces*: Workspaces ordered by their most recent Session activity, with
46
+ an abbreviated path and an aggregate status badge that reports one state by
47
+ priority pending > failed > running > unread (`N 个待处理` / `N 个出错` /
48
+ `N 个工作中` / `N 个未读`). When the `@qzsy/dsh-git-badge` bundle is
49
+ installed, each workspace name also carries its Git badge: `+N −M` line
50
+ changes, `干净` for a clean repository, `无 Git` outside a repository, or
51
+ the file count when only
52
+ untracked files changed. Git data comes from the Host's
53
+ `POST /api/git-badge` route (8 s palette cache); without that route the
54
+ badges are simply absent. Enter opens the newest Session in the Workspace,
55
+ or a fresh blank Session when it has none.
56
+ - *Files*: live, debounced Host file-reference lookup scoped to the Session in
57
+ the main panel; choosing a row opens the file in the right-hand preview.
58
+ Every file row carries a `项目 · <Workspace>` badge below its path so the
59
+ search scope stays visible, and the Files placeholder names the same project.
60
+ Opened files are remembered locally (origin-scoped `localStorage`) and listed
61
+ as *Recent files* when the search box is empty; recent files resolve their
62
+ project from the Session's Workspace. File matching stays Host-ranked path
63
+ matching (see limitations).
64
+ - *Actions*: every registered shortcut command (labels and keys come from the
65
+ live shortcut catalog, so plugin commands appear automatically). Enter
66
+ invokes the command through the shortcut registry; Settings and the keyboard
67
+ shortcut reference open from here.
68
+ - **Mixed Chinese/English search** through [`text-search-engine`](https://github.com/cjinhuo/text-search-engine):
69
+ one query covers Han characters (`登录`), full pinyin (`denglu`), pinyin
70
+ initials (`dl`), English subsequences (`nextjs`), space-separated terms, and
71
+ mixed forms (`qunxingerp`, `群erp`, `qxkf`). Matched ranges are highlighted in
72
+ titles and subtitles. Ranking prefers tighter, earlier title hits, then
73
+ detail hits, then recency.
74
+ - **Keyboard**: Up/Down move the selection, Enter opens, Escape closes. The
75
+ filter switches with bare ← / → (both directions, wrapping) or Tab /
76
+ Shift+Tab; holding Alt/Ctrl/Cmd with an arrow keeps native caret or word
77
+ movement inside the query. IME composition is never intercepted, so pinyin
78
+ candidate selection keeps working. Focus returns to whatever had it before
79
+ opening.
80
+ - **Mobile**: at `(max-width: 720px), (pointer: coarse) and (max-width: 1024px)`
81
+ the palette becomes a bottom sheet at 90% of the layer height. It opens
82
+ without focusing the search input, so the soft keyboard stays closed until
83
+ the user taps the field. All keyboard hints (Esc key, row shortcuts, footer
84
+ key legend) are hidden; the footer only remains for the subagent toggle.
85
+ The layer is portalled to the top of the stacking order and collapses the
86
+ phone's left-sidebar drawer as it opens, so choosing 命令面板 from the drawer
87
+ shows the sheet instead of opening it behind the still-open sidebar.
88
+ - **Unread count**: the sidebar row shows the number of Sessions that finished
89
+ successfully but have not been viewed (the green 已完成 badge; failed,
90
+ archived, blank and subagent Sessions are excluded). The collapsed rail shows
91
+ a dot instead. The always-mounted overlay computes the count and mirrors it
92
+ into a plugin-local store read by the sidebar glyph.
93
+ - **Sidebar entry**: the *命令面板 / Command palette* row joins the global panel
94
+ stack directly below 自动化任务 / Automations (glyph-only in the collapsed
95
+ rail). Choosing it opens the overlay without switching the main panel: the row
96
+ is an action, so the plugin answers that one panel id in the layout selection
97
+ and delegates every other id to the layout owner.
98
+ - Light/dark themes follow `--dsw-*` tokens; all copy is registered in the Client
99
+ locale service (zh/en).
100
+
101
+ ## Search engine integration
102
+
103
+ DSH's browser module table only resolves its own platform modules and
104
+ client-plugin rows, so a plain-JS plugin cannot `require('text-search-engine')`
105
+ at runtime. The package's minified browser IIFE is therefore vendored and
106
+ injected into the client bundle:
107
+
108
+ - `vendor/text-search-engine.min.js` — exact browser build from the pinned
109
+ `text-search-engine@1.6.0` dependency (MIT; license in
110
+ `vendor/text-search-engine.LICENSE`).
111
+ - `scripts/sync-vendor-engine.mjs` — rewrites the marked region in `client.js`
112
+ from the vendored file; run `node scripts/sync-vendor-engine.mjs` after
113
+ updating the vendored build.
114
+ - `client.js` — the generated region captures the engine exports in a factory
115
+ scope constant and uses `createSearcher()` with `title`/`detail` fields,
116
+ custom ranking, and hit ranges for highlighting. If the engine fails to
117
+ initialize, a built-in subsequence matcher keeps the palette usable.
118
+
119
+ File search is delegated to the Host (`ctx.remote.fileReferences.list`), which
120
+ retrieves and ranks paths from the current Session workspace; pinyin is applied
121
+ to sessions, workspaces, and actions, where titles are user-facing Chinese text.
122
+
123
+ ## Session status
124
+
125
+ The palette reads the root `useSessionStatus` hook of the `shell.overlay` slot
126
+ (provided by `dsh-client-ui-session`). That observable snapshot carries
127
+ `running`, `pendingInteraction.kind`, and `completionUnread` per Session, so
128
+ badges and counts change live as agents start, wait for input, and finish.
129
+
130
+ A Session settles into one of three terminal states:
131
+
132
+ - **Viewed success — no badge.** The completion has been acknowledged, so the
133
+ row is a plain Session and the badge clears.
134
+ - **Unread success — green `已完成`.** Shown while the snapshot still reports
135
+ `completionUnread`; the tooltip reads `已完成,尚未查看`.
136
+ - **Failed run — red `出错`.** The tooltip reads `运行出错:<message>`, or
137
+ `运行出错(尚未查看):<message>` when the same Session is also an unread
138
+ completion. An empty failure message falls back to `未知错误`.
139
+
140
+ The unified snapshot answers whether a run is going, waiting, or finished
141
+ unread; it does not say why a run ended. Failures therefore come from the
142
+ forwarded Host event `api-session/error`, which carries Agent failures —
143
+ including network and provider errors. The palette keeps the latest message
144
+ per Session and drops it when the next turn starts (`api-session/status` with
145
+ `running` true), when a new user prompt arrives (`api-session/activity`), or
146
+ when the Session is removed (`api-session/removed`). Aborted runs and
147
+ transient tool errors never reach that event, so they never raise the badge.
148
+
149
+ The map is in-memory for the app session — the same lifetime as unread
150
+ completions — so a reload starts clean. A failure that predates the palette
151
+ stays clear until the Host forwards a new `api-session/error`.
152
+
153
+ When several states apply, one badge wins in this order: pending interaction >
154
+ running > failure > unread completion. A stale failure can therefore never
155
+ mask a Session that is working or waiting for the user.
156
+
157
+ Workspace badges aggregate their Sessions with the priority pending > failed >
158
+ running > unread, counting each Session once (`N 个待处理` / `N 个出错` /
159
+ `N 个工作中` / `N 个未读`). The Sessions group label appends the counts in
160
+ running/pending/error/unread order, keeping only nonzero segments:
161
+ `近期会话 · N 个进行中 · N 个待处理 · N 个出错 · N 个未读`.
162
+
163
+ Error excerpts are whitespace-collapsed onto one line and capped at 180
164
+ characters with an ellipsis.
165
+
166
+ `scripts/verify-status.mjs` is the browser-free node harness that verifies this
167
+ state matrix. `docs/palette-statuses.png` renders the five states above from the
168
+ same component (running, pending, failed, unread, viewed).
169
+
170
+ ## Sidebar reveal
171
+
172
+ Selecting a Session or Workspace closes the palette, navigates, and then reveals
173
+ the target in the left Workspace browser. The browser owns reveal for its own
174
+ search in private React state, so the palette drives the stable DOM markers the
175
+ browser publishes instead: `data-row-key` identifies Workspace / Session /
176
+ watermark rows, `aria-expanded` reports a folded Workspace, and `role="tree"`
177
+ is the scrolling list. The persisted `dsh.workspace.view.v5` store supplies the
178
+ grouping mode, which distinguishes sibling Workspace groups from Workspace Tree
179
+ ancestry.
180
+
181
+ The reveal is bounded (about 2.4 s of retries): it expands the owning group and
182
+ its tree ancestors, raises hidden session rows through the same **Show more**
183
+ control the browser owns, then scrolls the group and chosen row into view with
184
+ `behavior: "smooth"` (or `auto` under reduced motion) and briefly rings the
185
+ Workspace header with a `--dsw-*` token outline. If the sidebar is a collapsed
186
+ rail, or the target is hidden by the current archive filter, the reveal is a
187
+ silent no-op — navigation still succeeds.
188
+
189
+ ## Marketplace palette
190
+
191
+ The DSH Market landing page in this repository (`apps/market`) mounts the same
192
+ keyboard-first interaction as a live demo: `⌘K` / `Ctrl+K` searches the plugin
193
+ directory, opens plugin pages, and offers the install command. The palette footer
194
+ credits this package, and `@qzsy` packages stay pinned ahead of upstream
195
+ duplicates so the command palette itself is always one keystroke away.
196
+
197
+ ## Shortcut ownership
198
+
199
+ `session.search` already owns `Command+K` in the shipped UI. The palette registers
200
+ with the free `Command+Shift+P` default and, once per device preference document,
201
+ uses the public `ctx.shortcuts.edit()` API to:
202
+
203
+ 1. clear `session.search`'s binding, and
204
+ 2. bind `palette.open` to the chord `session.search` had (Command+K on Desktop,
205
+ Mod+Alt+K in the browser).
206
+
207
+ That is a normal, visible override in Settings → Keyboard shortcuts: both rows
208
+ show as modified, and *Restore All Defaults* restores the palette to
209
+ `Command+Shift+P` and search to `Command+K`. On the next launch the plugin
210
+ re-adopts the chord while both rows are still at their unmodified defaults, so
211
+ `Command+K` keeps opening the palette. Session search itself stays available from
212
+ the palette's Actions list and from the sidebar search icon.
213
+
214
+ ## Install
215
+
216
+ The bundle is installed into the current profile with
217
+ `plugin_manager install_bundle` (absolute package directory). It needs no build
218
+ step at install time: `client.js` is a plain-JS `__ModuleLoader__` module that
219
+ only requires `react` from the browser module table, with the vendored engine
220
+ already inlined.
221
+
222
+ ## Files
223
+
224
+ - `package.json` — bundle manifest (`dsh.bundle.patch`, `dsh.client`, display resources)
225
+ - `cordis.patch.yml` — inserts the Host row
226
+ - `index.js` — Host half (no-op; the palette is client-only)
227
+ - `client.js` — shortcut adoption, overlay palette, live status badges, ranked
228
+ mixed-script search, sidebar trigger, zh/en dictionaries
229
+ - `vendor/` — vendored engine build and its MIT license
230
+ - `scripts/sync-vendor-engine.mjs` — regenerates the vendored engine region
231
+ - `locale/en.json`, `locale/zh.json` — Plugin Manager title/description
232
+ - `icon.svg` — original artwork
233
+ - `docs/` — verification screenshots
package/cordis.patch.yml CHANGED
@@ -1,3 +1,3 @@
1
- - insert:
2
- - id: command-palette
3
- name: '@qzsy/dsh-command-palette'
1
+ - insert:
2
+ - id: command-palette
3
+ name: '@qzsy/dsh-command-palette'