@idoall/dsh-session-colors 0.1.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/CHANGELOG.md +76 -0
- package/LICENSE +21 -0
- package/README.md +262 -0
- package/README.zh.md +192 -0
- package/cordis.patch.yml +11 -0
- package/docs/images/color-picker.png +0 -0
- package/docs/images/mobile-drawer.png +0 -0
- package/docs/images/sidebar-chips.png +0 -0
- package/package.json +87 -0
- package/src/client.js +1109 -0
- package/src/index.js +244 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
## [0.1.0] - 2026-09-22
|
|
12
|
+
|
|
13
|
+
First release.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- A colour mark for any Session, chosen from a system-style picker in the
|
|
18
|
+
conversation header: saturation/value field, hue and alpha sliders, hex and
|
|
19
|
+
RGBA fields, seven theme swatches, a saved-colours row, and screen eyedropper
|
|
20
|
+
where the browser supports `EyeDropper`.
|
|
21
|
+
- A colour chip on the marked Session's sidebar row, painted into a
|
|
22
|
+
frame-wide click-through overlay and clipped to the sidebar's scroll
|
|
23
|
+
container.
|
|
24
|
+
- Host-side storage: marks live in `session-colors.json` under the profile's
|
|
25
|
+
data directory, served by the plugin's own `GET`/`POST /plugins/dsh-session-colors/marks`
|
|
26
|
+
routes, so a colour chosen on one device is visible on every other one,
|
|
27
|
+
including over LAN and tunnels.
|
|
28
|
+
- Live cross-device pickup: the open page re-reads marks when it becomes visible
|
|
29
|
+
again and on a slow interval.
|
|
30
|
+
- Optional `dataDir` config; without it marks live for the process only and the
|
|
31
|
+
feature degrades instead of failing.
|
|
32
|
+
- Diagnostics on the overlay element (`data-dsh-sc-build`, `-status`,
|
|
33
|
+
`-writable`, `-marks`, `-error`) so a device that shows nothing can say why
|
|
34
|
+
from a plain DOM dump.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- The picker's hex field clipped its own value: seven characters (`#FFCC00`) did
|
|
41
|
+
not fit in the 51px it had, so the panel showed `#FFCC0`. The hex column is
|
|
42
|
+
wider than the numeric ones now and the inputs carry tighter padding, so the
|
|
43
|
+
full value is visible.
|
|
44
|
+
- A colour chip is now visible inside a phone's sidebar drawer. Two causes
|
|
45
|
+
stacked: DSH confines `shell.overlay` to a stacking context of its own
|
|
46
|
+
(`z-index: 20`), so a mobile adapter that promotes the sidebar to a
|
|
47
|
+
`position: fixed; z-index: 10000` drawer painted its opaque background over
|
|
48
|
+
every chip; and that drawer slides in with a CSS transition, which fires no
|
|
49
|
+
scroll, resize or DOM mutation, so the layer kept the off-screen coordinates it
|
|
50
|
+
had while the drawer was closed. The layer now renders through a portal on
|
|
51
|
+
`document.body`, measures the row's own ancestor chain to paint one level above
|
|
52
|
+
whatever holds the sidebar (1 on a stock desktop, 10001 behind such a drawer),
|
|
53
|
+
and follows an ancestor's transition. On the desktop the layer still sits below
|
|
54
|
+
dialogs, and the build marker is now `host-routes+drawer-aware`, so a device can
|
|
55
|
+
report which client it runs.
|
|
56
|
+
|
|
57
|
+
### Changed
|
|
58
|
+
|
|
59
|
+
- Both READMEs rewritten around what a reader needs first: the verified DSH
|
|
60
|
+
version, requirements, usage, a compatibility table, cross-device storage,
|
|
61
|
+
configuration, troubleshooting, security boundaries and uninstall. All three
|
|
62
|
+
screenshots were retaken from the current build (sidebar marks, the picker, and
|
|
63
|
+
a phone's drawer).
|
|
64
|
+
- The DSH version this build was verified against is now declared in
|
|
65
|
+
`package.json` as `dsh.compatibility.dshReleases` (DSH ignores the field) and
|
|
66
|
+
both READMEs must repeat exactly that list: a test fails if a README drops a
|
|
67
|
+
version, if the claim falls outside the `peerDependencies` range, or if a
|
|
68
|
+
README image stops resolving.
|
|
69
|
+
- Repository housekeeping, no change to what the package ships: the abandoned
|
|
70
|
+
"pinned Sessions" line is **deleted** — its documents, its two demos, its test
|
|
71
|
+
material and its evidence — so the repository holds only the shipping plugin and
|
|
72
|
+
its own records. A test now keeps `docs/` to the design record plus
|
|
73
|
+
`docs/images/` instead of letting a second spec grow back.
|
|
74
|
+
- `demos/session-color-mark-demo.html` was rebuilt as a single self-contained page
|
|
75
|
+
that mirrors the real picker's styling and the chip's geometry (4×16 bar in the
|
|
76
|
+
row's left padding, clear of the status dot).
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DSH Session Colors contributors
|
|
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
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
<h1 align="center">DSH Session Colors</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">Give any Session a colour and spot it at a glance in the sidebar.</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@idoall/dsh-session-colors"><img alt="npm" src="https://img.shields.io/badge/npm-not%20published-lightgrey"></a>
|
|
7
|
+
<a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-0F172A"></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">English | <a href="README.zh.md">中文</a></p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="#features">Features</a> ·
|
|
14
|
+
<a href="#install">Install</a> ·
|
|
15
|
+
<a href="#usage">Usage</a> ·
|
|
16
|
+
<a href="#compatibility">Compatibility</a> ·
|
|
17
|
+
<a href="#cross-device-and-lan">Cross-device</a> ·
|
|
18
|
+
<a href="#configuration">Configuration</a> ·
|
|
19
|
+
<a href="#troubleshooting">Troubleshooting</a> ·
|
|
20
|
+
<a href="#security-boundaries">Security</a> ·
|
|
21
|
+
<a href="#limitations">Limitations</a> ·
|
|
22
|
+
<a href="#uninstall">Uninstall</a> ·
|
|
23
|
+
<a href="#development">Development</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
> DSH Session Colors is a DeepSeek Harness community plugin. It does not modify
|
|
27
|
+
> DSH core and does not rewrite any Session or Workspace data: a mark is only
|
|
28
|
+
> "Session id → one colour".
|
|
29
|
+
|
|
30
|
+
Work is spread across several workspaces, and the workspace list is a wall of
|
|
31
|
+
look-alike titles. Once a task finishes, the Session you were just in is hard to
|
|
32
|
+
find again — the status dot is idle and the title is one of twenty. **A colour you
|
|
33
|
+
chose yourself is the cheapest way to make one row recognisable.**
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<img src="docs/images/sidebar-chips.png" width="280" alt="Four colour marks in the sidebar: four Sessions in one workspace list, each carrying a differently coloured bar (amber, red, green, blue)">
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- **A colour mark on the Session row** — a short bar in the row's left padding
|
|
42
|
+
that **deliberately avoids the status dot**, so "which one finished" is never
|
|
43
|
+
covered up.
|
|
44
|
+
- **A system-style colour picker** — a large saturation/value field, hue and alpha
|
|
45
|
+
sliders, hex and RGBA fields, seven theme swatches, your saved colours, and
|
|
46
|
+
screen eyedropper where the browser supports `EyeDropper`. It sits in the
|
|
47
|
+
Session header's utilities, not next to the title.
|
|
48
|
+
- **Marked once, visible everywhere.** Marks live on the **Host**, not in the
|
|
49
|
+
browser, so a colour chosen on your computer is also there on your phone —
|
|
50
|
+
over a LAN address or a tunnel alike.
|
|
51
|
+
- **Visible on a phone too.** A phone turns the sidebar into a drawer, and the
|
|
52
|
+
chips follow it: they travel with the drawer as it slides in, and they are
|
|
53
|
+
painted above it.
|
|
54
|
+
- **Changes arrive on their own.** The page re-reads marks when it becomes
|
|
55
|
+
visible again and every 20 seconds, so a colour set on another device shows up
|
|
56
|
+
without a refresh.
|
|
57
|
+
- **Never blocks the UI.** The chip layer is click-through and clipped to the
|
|
58
|
+
sidebar's scroll container; the worst case is that a chip does not appear.
|
|
59
|
+
- **A failure says so.** When the store cannot be reached, the header control
|
|
60
|
+
shows ⚠ with a reason instead of looking like a Session with no colour.
|
|
61
|
+
|
|
62
|
+
<p align="center">
|
|
63
|
+
<img src="docs/images/color-picker.png" width="276" alt="The colour picker: saturation/value field, eyedropper button, hue and alpha sliders, hex and RGBA fields, theme swatches, saved colours and a clear button; the colour control in the Session header is above it">
|
|
64
|
+
</p>
|
|
65
|
+
|
|
66
|
+
## Install
|
|
67
|
+
|
|
68
|
+
Requirements:
|
|
69
|
+
|
|
70
|
+
- DeepSeek Harness with a Web profile
|
|
71
|
+
- Node.js 20 or newer
|
|
72
|
+
- **Verified DSH version: `0.1.6-alpha.2`** (see [Compatibility](#compatibility))
|
|
73
|
+
|
|
74
|
+
`@idoall/dsh-session-colors` is **not published on npm yet**, so install the
|
|
75
|
+
repository directory for now (once published, the same plugin command installs
|
|
76
|
+
the npm version):
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
dsh plugin --profile <profile> add link:/path/to/dsh-session-colors
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Then give it a data directory in the profile's `cordis.patch.yml` — the same
|
|
83
|
+
shape other plugins that need durability use, because **the plugin never guesses
|
|
84
|
+
the profile path**:
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
- id: dsh-session-colors
|
|
88
|
+
config:
|
|
89
|
+
dataDir: /absolute/path/to/profiles/<profile>/data/dsh-session-colors
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Finally **restart `dsh web`** (the Host half loads only at boot), then refresh the
|
|
93
|
+
Web GUI. It also works without `dataDir`, but then marks live only for the life of
|
|
94
|
+
the Host process.
|
|
95
|
+
|
|
96
|
+
## Usage
|
|
97
|
+
|
|
98
|
+
1. Open the Session you want to mark.
|
|
99
|
+
2. Click the colour control in the Session header (🎨 when the Session has no
|
|
100
|
+
colour, the colour itself once it has one).
|
|
101
|
+
3. Pick a colour, or paste a hex value. The bar appears on that Session's sidebar
|
|
102
|
+
row immediately.
|
|
103
|
+
4. To clear it, open the picker again and click **Clear mark**, or choose the
|
|
104
|
+
transparent swatch among the theme colours.
|
|
105
|
+
|
|
106
|
+
Opening the picker on a marked Session starts from its current colour. Colours are
|
|
107
|
+
stored as HSVA, so alpha round-trips exactly.
|
|
108
|
+
|
|
109
|
+
<p align="center">
|
|
110
|
+
<img src="docs/images/mobile-drawer.png" width="300" alt="The sidebar drawer on a phone: the same Session list shows colour marks, with amber, red, green and blue visible at once">
|
|
111
|
+
</p>
|
|
112
|
+
|
|
113
|
+
## Compatibility
|
|
114
|
+
|
|
115
|
+
Current release: plugin **`0.1.0`**, verified against DeepSeek Harness
|
|
116
|
+
**`0.1.6-alpha.2`**.
|
|
117
|
+
|
|
118
|
+
| Plugin version | Verified DeepSeek Harness | npm status | What it is |
|
|
119
|
+
| --- | --- | --- | --- |
|
|
120
|
+
| **`0.1.0`** | `0.1.6-alpha.2` | **Not published** (repository only) | First release: Session colour marks, Host-side storage, visible inside a phone's sidebar drawer |
|
|
121
|
+
|
|
122
|
+
- **Verified DeepSeek Harness** is the exact DSH version this plugin was actually
|
|
123
|
+
run against. That list has one home — `dsh.compatibility.dshReleases` in
|
|
124
|
+
[`package.json`](package.json) — and a test keeps both READMEs' compatibility
|
|
125
|
+
sections word-for-word with it and inside the range `peerDependencies`
|
|
126
|
+
declares. A DSH version that is not listed is **never claimed as compatible**.
|
|
127
|
+
- `peerDependencies` declares `>=0.1.6-0 <0.2.0` for `dsh-client-ui-layout` and
|
|
128
|
+
`dsh-client-ui-conversation`: that is the range allowed to **load**, which is
|
|
129
|
+
not the same as verified.
|
|
130
|
+
- DSH moving faster than this plugin does not break it: chips depend on DSH's row
|
|
131
|
+
DOM (see [Limitations](#limitations)), so a large change to the row structure
|
|
132
|
+
can at worst stop chips from appearing — it cannot block clicking.
|
|
133
|
+
|
|
134
|
+
## Cross-device and LAN
|
|
135
|
+
|
|
136
|
+
Storage goes through the plugin's **own** HTTP route
|
|
137
|
+
(`GET`/`POST /plugins/dsh-session-colors/marks`), persisted to one JSON file in
|
|
138
|
+
the profile's data directory. That is deliberate:
|
|
139
|
+
|
|
140
|
+
DSH's own user-settings service host-backs settings **only for loopback pages** —
|
|
141
|
+
|
|
142
|
+
```js
|
|
143
|
+
persistence = $host.isLoopback ? "host" : "memory"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
— so a page opened over a LAN address or a tunnel gets a permanently unavailable
|
|
147
|
+
scope: it can neither read nor write. An own route is not subject to that rule,
|
|
148
|
+
which is exactly what makes a mark visible on every device. LAN forwarders
|
|
149
|
+
(`dsh-bridge`, `dsh-lan-proxy`, and friends) rewrite `Host`/`Origin` to loopback
|
|
150
|
+
and inject the auth cookie, so a request that arrives over the LAN still looks
|
|
151
|
+
like loopback to DSH and the route answers normally.
|
|
152
|
+
|
|
153
|
+
## Configuration
|
|
154
|
+
|
|
155
|
+
| Field | Type | Meaning |
|
|
156
|
+
| --- | --- | --- |
|
|
157
|
+
| `dataDir` | absolute path | Where `session-colors.json` is written. Without it, marks live in process memory only. |
|
|
158
|
+
|
|
159
|
+
A mark is one JSON document:
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"version": 1,
|
|
164
|
+
"marks": {
|
|
165
|
+
"session-0698599a-…": { "h": 211.3, "s": 1, "v": 1, "a": 1 }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Writes are **atomic** (temporary file, then rename). To drop a mark, use **Clear
|
|
171
|
+
mark** in the picker, or remove that line from the file.
|
|
172
|
+
|
|
173
|
+
## Troubleshooting
|
|
174
|
+
|
|
175
|
+
**The colour still is not visible on my phone.**
|
|
176
|
+
First check which build the device runs:
|
|
177
|
+
|
|
178
|
+
```js
|
|
179
|
+
document.querySelector('.dsh-sc-layer').dataset
|
|
180
|
+
// { dshScBuild, dshScStatus, dshScWritable, dshScMarks, dshScError }
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
If `dshScBuild` is not `host-routes+drawer-aware`, the device is running a
|
|
184
|
+
**cached client**: refresh the page (the browser half reloads on a refresh, no DSH
|
|
185
|
+
restart needed). If `dshScStatus` is not `ready`, the store cannot be read — see
|
|
186
|
+
the next item.
|
|
187
|
+
|
|
188
|
+
**The header control shows ⚠.**
|
|
189
|
+
That means the store cannot be reached: `dshScError` carries the reason and
|
|
190
|
+
`dshScWritable` says whether writes are possible. This happens when the Host route
|
|
191
|
+
was never registered (the profile did not load the plugin) or the data directory
|
|
192
|
+
is not writable. It is **not** the same as "this Session has no colour".
|
|
193
|
+
|
|
194
|
+
**A LAN page behaves differently.**
|
|
195
|
+
Since `0.1.0` this plugin behaves identically on LAN/tunnel pages and loopback
|
|
196
|
+
pages, because storage uses its own route. If you see the old "settings
|
|
197
|
+
unavailable" behaviour, check which version is installed.
|
|
198
|
+
|
|
199
|
+
**Chips are in the wrong place, or gone.**
|
|
200
|
+
The layer finds rows by ARIA role and reads the Session id from the React fiber.
|
|
201
|
+
A large change to DSH's sidebar structure can make it find nothing; chips then
|
|
202
|
+
disappear, but **clicking is unaffected** because the layer is click-through.
|
|
203
|
+
|
|
204
|
+
## Security boundaries
|
|
205
|
+
|
|
206
|
+
- A mark stores **only a Session id and a colour**. It never writes Session logs,
|
|
207
|
+
titles, history, status, archive records, or Workspace membership.
|
|
208
|
+
- It **never creates, copies, moves, or reorders a Session**; a mark is not part
|
|
209
|
+
of Session data.
|
|
210
|
+
- The chip layer **never accepts pointer events** and is clipped to the sidebar's
|
|
211
|
+
scroll container: the worst case is a chip that does not appear.
|
|
212
|
+
- The Host route reuses DSH's own auth fence (`connection.requestRejection`), and
|
|
213
|
+
writes add a same-origin check on top.
|
|
214
|
+
- The plugin registers no model Tool, spawns no subprocess, and makes no network
|
|
215
|
+
requests.
|
|
216
|
+
|
|
217
|
+
## Limitations
|
|
218
|
+
|
|
219
|
+
- **The chip depends on DSH's row DOM.** It reads rows by ARIA role and the
|
|
220
|
+
Session id from React internals. A future DSH release can stop chips from
|
|
221
|
+
appearing; it cannot break clicking.
|
|
222
|
+
- **Marks are per DSH instance.** They live in one profile's data directory, so
|
|
223
|
+
two independent DSH servers do not share them.
|
|
224
|
+
- **No permission model.** Anyone who can reach the Host's authenticated routes
|
|
225
|
+
for this profile can read and write marks.
|
|
226
|
+
- **Colour only.** No labels, icons, or emoji.
|
|
227
|
+
|
|
228
|
+
## Uninstall
|
|
229
|
+
|
|
230
|
+
```sh
|
|
231
|
+
dsh plugin --profile <profile> remove @idoall/dsh-session-colors
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Restart DSH and refresh the Web GUI. `session-colors.json` in the data directory
|
|
235
|
+
is not deleted for you; remove it yourself if you do not want it.
|
|
236
|
+
|
|
237
|
+
## Development
|
|
238
|
+
|
|
239
|
+
```sh
|
|
240
|
+
npm test # 34 tests: bundle shape, store, route, cross-device, geometry, docs
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
The browser half is a hand-authored `__ModuleLoader__` bundle, which is the only
|
|
244
|
+
format the DSH client loader accepts for a package client half. It is written by
|
|
245
|
+
hand on purpose: there is no build step, so nothing can drift from the DSH
|
|
246
|
+
version it targets.
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
src/index.js Host half: routes, the JSON store, auth fence
|
|
250
|
+
src/client.js Browser half: picker, chip layer, the fetch-backed store
|
|
251
|
+
tests/ Unit tests for both halves, plus the doc-consistency checks
|
|
252
|
+
docs/ The design record (Chinese) and the README screenshots
|
|
253
|
+
demos/ A standalone HTML demo of the picker
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Design decisions and measurements live in
|
|
257
|
+
[docs/plugin-design.zh.md](docs/plugin-design.zh.md) (the current part starts at
|
|
258
|
+
the 「会话颜色标记版」 section).
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
[MIT](LICENSE)
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<h1 align="center">DSH 会话颜色标记</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">给任意会话上一个颜色,在侧栏一眼认出它。</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@idoall/dsh-session-colors"><img alt="npm" src="https://img.shields.io/badge/npm-%E6%9C%AA%E5%8F%91%E5%B8%83-lightgrey"></a>
|
|
7
|
+
<a href="LICENSE"><img alt="license" src="https://img.shields.io/badge/license-MIT-0F172A"></a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center"><a href="README.md">English</a> | 中文</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="#功能">功能</a> ·
|
|
14
|
+
<a href="#安装">安装</a> ·
|
|
15
|
+
<a href="#使用">使用</a> ·
|
|
16
|
+
<a href="#兼容性">兼容性</a> ·
|
|
17
|
+
<a href="#跨设备与局域网">跨设备与局域网</a> ·
|
|
18
|
+
<a href="#配置">配置</a> ·
|
|
19
|
+
<a href="#故障排查">故障排查</a> ·
|
|
20
|
+
<a href="#安全边界">安全边界</a> ·
|
|
21
|
+
<a href="#限制">限制</a> ·
|
|
22
|
+
<a href="#卸载">卸载</a> ·
|
|
23
|
+
<a href="#开发">开发</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
> DSH Session Colors 是 DeepSeek Harness 社区插件。它不修改 DSH 核心,也不改写任何会话或工作区数据:一个标记只是"会话 ID → 一个颜色"。
|
|
27
|
+
|
|
28
|
+
工作分散在多个工作区里,而工作区列表就是一堵长得差不多的标题墙。任务跑完之后,刚才那条会话就很难再找回来——状态点已经回到空闲,标题也只是二十个里的一个。**自己选的颜色,是让一行变得好认的最省事办法。**
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="docs/images/sidebar-chips.png" width="280" alt="侧栏里的四个颜色标记:同一个工作区列表里四条会话各自带一条不同颜色的竖条(琥珀、红、绿、蓝)">
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
## 功能
|
|
35
|
+
|
|
36
|
+
- **会话行上的颜色标记**——行左侧内边距里的一小段色条,**刻意避开状态点**,所以"哪个跑完了"这个信号不会被盖掉。
|
|
37
|
+
- **系统风格的颜色选择器**——大色板、色相与透明度滑条、十六进制与 RGBA 输入、七个主题色、我的颜色,以及浏览器支持 `EyeDropper` 时的屏幕吸色。注册在会话头部的工具区,不占标题位置。
|
|
38
|
+
- **一处标记,处处可见。** 标记存在**宿主**而不是浏览器里,所以在电脑上选的颜色,手机上也能看到——局域网地址、隧道访问都算。
|
|
39
|
+
- **手机端同样显示。** 手机把侧栏变成抽屉,色块跟着抽屉走:抽屉滑进来时它一起移动,并且画在抽屉之上。
|
|
40
|
+
- **自动获取改动。** 页面重新可见时、以及每 20 秒会重读一次,别的设备改了颜色不用刷新就能看到。
|
|
41
|
+
- **绝不挡住界面。** 色块浮层**点击穿透**,并且按侧栏滚动容器裁剪;最坏情况只是色块不显示。
|
|
42
|
+
- **失败会说。** 读不到存储时,头部控制会显示 ⚠ 并给出原因,而不是装作"这个会话没有颜色"。
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<img src="docs/images/color-picker.png" width="276" alt="颜色选择器:色相/明度大色板、吸色按钮、色相与透明度滑条、十六进制与 RGBA 输入、主题颜色色板、我的颜色与清除标记按钮;上方是会话头部里的颜色控件">
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
## 安装
|
|
49
|
+
|
|
50
|
+
要求:
|
|
51
|
+
|
|
52
|
+
- 带 Web profile 的 DeepSeek Harness
|
|
53
|
+
- Node.js 20 或更新版本
|
|
54
|
+
- **已验证的 DSH 版本:`0.1.6-alpha.2`**(见[兼容性](#兼容性))
|
|
55
|
+
|
|
56
|
+
npm 上的 `@idoall/dsh-session-colors` **尚未发布**,所以现在装的是本仓库目录(发布后可用同样的插件命令装 npm 版本):
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
dsh plugin --profile <profile> add link:/path/to/dsh-session-colors
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
然后在 profile 的 `cordis.patch.yml` 里给它一个数据目录(与其它需要持久化的插件做法一致,**插件不会去猜 profile 路径**):
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
- id: dsh-session-colors
|
|
66
|
+
config:
|
|
67
|
+
dataDir: /absolute/path/to/profiles/<profile>/data/dsh-session-colors
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
最后**重启 `dsh web`**(宿主半边只在启动时加载),再刷新 Web GUI。不配 `dataDir` 也能用,但标记只活在宿主进程的生命周期里。
|
|
71
|
+
|
|
72
|
+
## 使用
|
|
73
|
+
|
|
74
|
+
1. 打开要标记的会话。
|
|
75
|
+
2. 点会话头部的颜色控件(未设色时显示 🎨,设色后显示该颜色)。
|
|
76
|
+
3. 选一个颜色,或直接粘贴十六进制值。该会话在侧栏的行上会立刻出现色条。
|
|
77
|
+
4. 取消标记:再次打开选择器,点**清除标记**,或选主题色里那个透明色块。
|
|
78
|
+
|
|
79
|
+
在已标记的会话上打开选择器,会从它当前的颜色开始。颜色以 HSVA 保存,所以透明度能原样往返。
|
|
80
|
+
|
|
81
|
+
<p align="center">
|
|
82
|
+
<img src="docs/images/mobile-drawer.png" width="300" alt="手机上的侧栏抽屉:会话列表里同样显示颜色标记,同一个列表里能同时看到琥珀、红、绿、蓝四条">
|
|
83
|
+
</p>
|
|
84
|
+
|
|
85
|
+
## 兼容性
|
|
86
|
+
|
|
87
|
+
当前版本:插件 **`0.1.0`** 已针对 DeepSeek Harness **`0.1.6-alpha.2`** 验证。
|
|
88
|
+
|
|
89
|
+
| 插件版本 | 已验证的 DeepSeek Harness | npm 发布状态 | 该版本是什么 |
|
|
90
|
+
| --- | --- | --- | --- |
|
|
91
|
+
| **`0.1.0`** | `0.1.6-alpha.2` | **未发布**(仅本仓库) | 首个版本:会话颜色标记、宿主侧存储、手机抽屉内可见 |
|
|
92
|
+
|
|
93
|
+
- **已验证的 DeepSeek Harness** 是这个插件**实际跑过**的确切 DSH 版本。这份清单只有一个存放处——[`package.json`](package.json) 的 `dsh.compatibility.dshReleases`——并且有测试保证两个 README 的兼容性段落与它逐字一致、且落在 `peerDependencies` 声明的范围内。未列出的 DSH 版本**不会被宣称为兼容**。
|
|
94
|
+
- `peerDependencies` 声明的范围是 `>=0.1.6-0 <0.2.0`(`dsh-client-ui-layout` 与 `dsh-client-ui-conversation`):这是**允许加载**的范围,不等于已验证。
|
|
95
|
+
- DSH 升级快于插件时,插件本身不会因此报错:色块依赖 DSH 的行 DOM(见[限制](#限制)),所以 DSH 大改行结构时最坏的结果是**色块不再显示**,不会挡住点击。
|
|
96
|
+
|
|
97
|
+
## 跨设备与局域网
|
|
98
|
+
|
|
99
|
+
存储走插件**自己的** HTTP 路由(`GET`/`POST /plugins/dsh-session-colors/marks`),落盘到 profile 数据目录里的一个 JSON 文件。这是**有意为之**:
|
|
100
|
+
|
|
101
|
+
DSH 自带的用户设置服务**只对回环页面**做宿主持久化——
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
persistence = $host.isLoopback ? "host" : "memory"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
——所以用局域网地址或隧道打开的页面,设置 scope 会**永久不可用**,读不了也写不进。自有路由不受这条规则限制,这正是标记能跨设备的原因。局域网转发(`dsh-bridge`、`dsh-lan-proxy` 等)会把 `Host`/`Origin` 改写成回环并注入认证 cookie,所以经局域网进来的请求在 DSH 侧仍是回环,路由正常响应。
|
|
108
|
+
|
|
109
|
+
## 配置
|
|
110
|
+
|
|
111
|
+
| 字段 | 类型 | 含义 |
|
|
112
|
+
| --- | --- | --- |
|
|
113
|
+
| `dataDir` | 绝对路径 | `session-colors.json` 的写入位置。不填则标记只存在于进程内存。 |
|
|
114
|
+
|
|
115
|
+
标记是一个 JSON 文档:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"version": 1,
|
|
120
|
+
"marks": {
|
|
121
|
+
"session-0698599a-…": { "h": 211.3, "s": 1, "v": 1, "a": 1 }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
写入是**原子**的(先写临时文件,再 rename)。要清掉某个标记,用选择器里的**清除标记**,或直接从文件里删掉那一行。
|
|
127
|
+
|
|
128
|
+
## 故障排查
|
|
129
|
+
|
|
130
|
+
**手机上还是看不到颜色。**
|
|
131
|
+
先看设备跑的是哪个构建:
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
document.querySelector('.dsh-sc-layer').dataset
|
|
135
|
+
// { dshScBuild, dshScStatus, dshScWritable, dshScMarks, dshScError }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`dshScBuild` 不是 `host-routes+drawer-aware` 就是**客户端缓存**,刷新页面即可(客户端半边刷新即热重载,不需要重启 DSH)。`dshScStatus` 不是 `ready` 则是存储读不到,见下一条。
|
|
139
|
+
|
|
140
|
+
**头部控制显示 ⚠。**
|
|
141
|
+
表示读不到存储:`dshScError` 里有原因,`dshScWritable` 说明能不能写。宿主路由未注册(插件没被 profile 加载)或数据目录不可写时会这样。注意**这不是**"这个会话没有颜色"。
|
|
142
|
+
|
|
143
|
+
**局域网页面上功能不全。**
|
|
144
|
+
从 `0.1.0` 起本插件在局域网/隧道页面与回环页面行为一致(存储走自有路由)。如果你看到的是旧版那种"设置读不到"的表现,先确认装的是哪个版本。
|
|
145
|
+
|
|
146
|
+
**色块位置不对或消失。**
|
|
147
|
+
色块浮层靠 ARIA role 找会话行、靠 React fiber 取会话 ID。DSH 大改侧栏结构后可能找不到行;此时色块会消失,但**不会影响点击**,因为浮层是点击穿透的。
|
|
148
|
+
|
|
149
|
+
## 安全边界
|
|
150
|
+
|
|
151
|
+
- 标记只保存**会话 ID 与颜色**,不写会话日志、标题、历史、状态、归档记录或工作区归属。
|
|
152
|
+
- **不创建、不复制、不移动、不重排任何会话**;标记不是会话数据的一部分。
|
|
153
|
+
- 色块浮层**从不接收指针事件**,并且按侧栏滚动容器裁剪:最坏情况只是色块不显示。
|
|
154
|
+
- 宿主路由复用 DSH 自带的鉴权栅栏(`connection.requestRejection`),写入另加同源检查。
|
|
155
|
+
- 插件不注册模型 Tool、不启动子进程、不访问网络。
|
|
156
|
+
|
|
157
|
+
## 限制
|
|
158
|
+
|
|
159
|
+
- **色块依赖 DSH 的行 DOM。** 它靠 ARIA role 找行、靠 React 内部结构取会话 ID。DSH 未来改版可能让色块不再显示;但**不会影响点击**。
|
|
160
|
+
- **标记属于单个 DSH 实例。** 它存在某个 profile 的数据目录里,两个独立的 DSH 服务之间不共享。
|
|
161
|
+
- **没有权限模型。** 凡是能访问该 profile 已鉴权路由的人,都能读写标记。
|
|
162
|
+
- **只有颜色。** 没有文字标签、图标或 emoji。
|
|
163
|
+
|
|
164
|
+
## 卸载
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
dsh plugin --profile <profile> remove @idoall/dsh-session-colors
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
重启 DSH 并刷新 Web GUI。数据目录里的 `session-colors.json` 不会被自动删除;不需要就自行删除。
|
|
171
|
+
|
|
172
|
+
## 开发
|
|
173
|
+
|
|
174
|
+
```sh
|
|
175
|
+
npm test # 34 项:bundle 结构、存储、路由、跨设备、几何、文档一致性
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
浏览器半边是**手写的** `__ModuleLoader__` bundle——这是 DSH 客户端加载器接受的唯一格式。手写是刻意的:**没有构建步骤**,就不会有产物与目标 DSH 版本漂移的问题。
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
src/index.js 宿主半边:路由、JSON 存储、鉴权栅栏
|
|
182
|
+
src/client.js 浏览器半边:选择器、色块浮层、fetch 存储
|
|
183
|
+
tests/ 两个半边的单元测试,外加文档一致性检查
|
|
184
|
+
docs/ 设计记录(中文)与 README 截图
|
|
185
|
+
demos/ 独立的选择器 HTML Demo
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
设计取舍与实测记录见 [docs/plugin-design.zh.md](docs/plugin-design.zh.md);独立的选择器 Demo 见 [demos/session-color-mark-demo.html](demos/session-color-mark-demo.html)。
|
|
189
|
+
|
|
190
|
+
## 许可证
|
|
191
|
+
|
|
192
|
+
[MIT](LICENSE)
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Bundle mount for the Session-colours plugin: one Host-side entry.
|
|
2
|
+
#
|
|
3
|
+
# `name` is the Node-resolvable package name and must stay in sync with
|
|
4
|
+
# package.json; `id` is the local mount id, so profile config keys keep the
|
|
5
|
+
# short `dsh-session-colors` spelling.
|
|
6
|
+
#
|
|
7
|
+
# Durability needs a `dataDir` from the profile owner — see README.md. Without
|
|
8
|
+
# it the routes still answer and marks live for the process only.
|
|
9
|
+
- insert:
|
|
10
|
+
- id: dsh-session-colors
|
|
11
|
+
name: '@idoall/dsh-session-colors'
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@idoall/dsh-session-colors",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "DSH web plugin: give any Session a colour mark, shown as a chip in the sidebar and picked from the conversation header. Marks are stored on the Host, so a colour chosen on one device is visible on every other one — including over LAN and tunnels.",
|
|
6
|
+
"main": "./src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js",
|
|
9
|
+
"./client": "./src/client.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src",
|
|
14
|
+
"cordis.patch.yml",
|
|
15
|
+
"README.md",
|
|
16
|
+
"README.zh.md",
|
|
17
|
+
"CHANGELOG.md",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"docs/images"
|
|
20
|
+
],
|
|
21
|
+
"dsh": {
|
|
22
|
+
"manifestVersion": 1,
|
|
23
|
+
"compatibility": {
|
|
24
|
+
"dshReleases": {
|
|
25
|
+
"0.1.6-alpha.2": "compatible"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"bundle": {
|
|
29
|
+
"patch": "./cordis.patch.yml"
|
|
30
|
+
},
|
|
31
|
+
"client": {
|
|
32
|
+
"platform": "web",
|
|
33
|
+
"inject": [
|
|
34
|
+
"@deepseek-ai/dsh-client-ui-layout",
|
|
35
|
+
"@deepseek-ai/dsh-client-ui-conversation"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"test": "node --test tests/*.test.mjs"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.1.6-0 <0.2.0",
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.6-0 <0.2.0",
|
|
51
|
+
"react": "^18.2.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-conversation": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"@deepseek-ai/dsh-client-ui-layout": {
|
|
58
|
+
"optional": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"license": "MIT",
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=20"
|
|
64
|
+
},
|
|
65
|
+
"repository": {
|
|
66
|
+
"type": "git",
|
|
67
|
+
"url": "git+https://github.com/idoall/dsh-session-colors.git"
|
|
68
|
+
},
|
|
69
|
+
"homepage": "https://github.com/idoall/dsh-session-colors#readme",
|
|
70
|
+
"bugs": {
|
|
71
|
+
"url": "https://github.com/idoall/dsh-session-colors/issues"
|
|
72
|
+
},
|
|
73
|
+
"keywords": [
|
|
74
|
+
"dsh",
|
|
75
|
+
"dsh-plugin",
|
|
76
|
+
"deepseek",
|
|
77
|
+
"deepseek-harness",
|
|
78
|
+
"harness",
|
|
79
|
+
"cordis",
|
|
80
|
+
"plugin",
|
|
81
|
+
"session",
|
|
82
|
+
"colors",
|
|
83
|
+
"sidebar",
|
|
84
|
+
"web"
|
|
85
|
+
],
|
|
86
|
+
"packageManager": "pnpm@10.33.1"
|
|
87
|
+
}
|