dsh-todo-float-ball 0.8.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 ADDED
@@ -0,0 +1,431 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
+
6
+ ## [0.8.0] - 2026-09-08
7
+
8
+ ### Added
9
+
10
+ - **Nebula triple-variant** (user: 都保留 — keep all three texture
11
+ proposals): the 🎨 picker now offers SIX skins —
12
+ 🌌 星云·流光 (A, current), 🌟 星云·宝石 (B, gemstone depth),
13
+ 🌙 星云·顶弧 (C, crescent top-glow), 💎 石墨版, 🔵 蓝宝石版,
14
+ 🧊 玻璃版. B/C keep the opaque-dark base (background-independent),
15
+ rim flow, breathing, amber in-progress and per-status tints.
16
+
17
+ ### Reverted
18
+
19
+ - Glass-panel experiment (user: text hard to read) — the expanded panel
20
+ stays on the original dark translucent style.
21
+
22
+ ## [0.7.7] - 2026-09-08
23
+
24
+ ### Changed
25
+
26
+ - **Nebula skin now uses an OPAQUE dark base** (user request: 深浅背景观感
27
+ 一致): all four status gradients were semi-transparent and looked
28
+ different on light vs dark backgrounds — they are now fully opaque
29
+ (black base + teal/amber/mint/ice nebula tints), rendering identically
30
+ on any background. The rim flow + breathing animations are unchanged.
31
+
32
+ ## [0.7.6] - 2026-09-08
33
+
34
+ ### Changed
35
+
36
+ - **Panel is now frosted-glass translucent** (user request: 字体背景透明):
37
+ background 68% opacity + 28px backdrop blur with saturate boost — the
38
+ DSH interface shows through softly in both dark and light themes.
39
+ - **Balls get a subtle outline** (1px translucent white): clean silhouette
40
+ on any background; on dark it reads as a gem edge, on light it keeps
41
+ the dark balls from looking like flat blobs.
42
+
43
+ ## [0.7.5] - 2026-09-08
44
+
45
+ ### Fixed (ecosystem compatibility hardening)
46
+
47
+ - **悬浮球导航 shows the SAME interface no matter which balls are
48
+ installed** (ecosystem spec): the three visibility toggles are ALWAYS
49
+ displayed; a ball that is not installed shows its toggle grayed-out
50
+ with "(未安装)" instead of disappearing — installing a sibling later
51
+ makes its toggle active automatically.
52
+ - **Uninstall safety net**: if dsh-skill-browser (the section provider)
53
+ is removed while the Todo ball was hidden, the ball would be stuck
54
+ invisible with no way back — `applyBallVisibility` now detects the
55
+ provider is gone and shows the ball again.
56
+ - The shared section's 🎯 reset and rec-badge detection tolerate any
57
+ install combination (null-guarded DOM probes; todo ball resets through
58
+ its Shadow DOM).
59
+
60
+ ## [0.7.4] - 2026-09-08
61
+
62
+ ### Fixed
63
+
64
+ - **Ball size parity, take two**: the progress ring now uses the same
65
+ 1px outer overhang as the skill orb's rim (was 2px), so the visual
66
+ diameter matches the skill-browser ball exactly at 46px+1.
67
+
68
+ ### Changed (dsh-skill-browser shared section)
69
+
70
+ - 🎯 button text: "所有悬浮球回到右下角" (was 双球 wording).
71
+ - Usage notes updated: three-ball visibility control (skill / font /
72
+ todo, all shown by default on fresh install); Todo skin switching
73
+ happens inside the todo panel via 🎨 (星云 / 石墨 / 蓝宝石); reset
74
+ returns ALL balls to the bottom-right.
75
+
76
+ ## [0.7.3] - 2026-09-08
77
+
78
+ ### Fixed
79
+
80
+ - **Ball visual size now matches the skill-browser orb**: the progress
81
+ ring's `inset:-4px` overhang made the ball look ~54px despite the 46px
82
+ body — ring now hugs the ball edge (inset:-2px).
83
+
84
+ ### Added
85
+
86
+ - **Collapse refreshes the whole plugin UI** (font-enhancer pattern):
87
+ folding the panel rebuilds the UI after 120ms, so theme/structure
88
+ changes apply immediately on collapse — same behavior as the font
89
+ plugin's reload-on-collapse.
90
+ - **Three-ball reset**: the shared settings section's 🎯 reset button now
91
+ also returns the TODO ball to the bottom-right default (clears its
92
+ position memory + DOM reposition, no restart) — skill + font + todo
93
+ balls all reset together.
94
+
95
+ ## [0.7.2] - 2026-09-08
96
+
97
+ ### Changed
98
+
99
+ - **Ball size unified with the skill-browser orb**: 46px on all skins
100
+ (was 52px nebula / 56px others).
101
+ - **Nebula skin motion fix** (user: the up/down flowing band covered the
102
+ text): the band layer is removed; the rim light now circles the OUTER
103
+ edge only (skill-orb style rimSpin, faster while in progress) — text
104
+ stays clear. In-progress nebula tint is amber, matching the other
105
+ skins.
106
+
107
+ ### Added
108
+
109
+ - **🎯 一键归位** button in the panel footer: instantly moves the ball
110
+ back to the bottom-right default corner and clears the saved position
111
+ (no restart needed) — mirrors the skill-browser's reset button.
112
+
113
+ ## [0.7.1] - 2026-09-08
114
+
115
+ ### Changed
116
+
117
+ - **Ring skin removed** (user: it looked the same as graphite): the picker
118
+ now offers three skins — 🌌 星云版 / 💎 石墨版 / 🔵 蓝宝石版; any
119
+ previously-saved "ring" value falls back to graphite.
120
+
121
+ ## [0.7.0] - 2026-09-08
122
+
123
+ ### Added
124
+
125
+ - **Fourth skin: 🔵 蓝宝石版 (blue)** — deep-blue gem base with a blue
126
+ glow and blue progress ring, the early blue version brought back as a
127
+ first-class option. The 🎨 picker now lists four skins:
128
+ 🌌 星云版 / 💫 环版(粗环) / 💎 石墨版 / 🔵 蓝宝石版.
129
+
130
+ ### Changed
131
+
132
+ - **Ring skin visually distinct from graphite** (user: they looked the
133
+ same): the ring skin now shows a THICK (9px) glowing progress ring with
134
+ a stronger drop-shadow, clearly different from the thin graphite ring.
135
+ The skin renderer was refactored into per-skin rule blocks (kept the
136
+ same public behavior; status variants + ring/band/rim per skin).
137
+ - **Open/close triggers a theme refresh** (mirrors the font plugin):
138
+ expanding AND folding the panel re-applies the current skin, so any
139
+ theme change is picked up on open/close instead of only on the 2s poll.
140
+
141
+ ## [0.6.9] - 2026-09-07
142
+
143
+ ### Changed
144
+
145
+ - **Skin picker is now an explicit menu** (user request instead of the
146
+ invisible cycling): clicking 🎨 in the panel header opens a dropdown with
147
+ the three skins (🌌 星云版 / 💫 环版 / 💎 石墨版), the current one marked
148
+ with a ✓ highlight; picking one switches instantly and updates the
149
+ highlight. Clear, visible feedback on every click.
150
+
151
+ ## [0.6.8] - 2026-09-07
152
+
153
+ ### Changed
154
+
155
+ - **Round ball shows only progress** (user requirement): the ball face is
156
+ just `done/total` (or ✓ when all done) — the task-content sub-line is
157
+ no longer rendered in round mode, since it never fit.
158
+ - **Capsule text scrolls**: overflowing task names in capsule mode
159
+ ping-pong horizontally (measured marquee — the shift distance is
160
+ computed from the actual overflow, capped by animation, static when it
161
+ fits).
162
+
163
+ ## [0.6.7] - 2026-09-07
164
+
165
+ ### Changed
166
+
167
+ - **Skin switching moved into the ball's own panel** (user decision after
168
+ the settings-slot buttons proved unreliable): the panel header now has a
169
+ 🎨 button between 📌 (pin) and ✕ (close) that cycles
170
+ 🌌 nebula → 💫 ring → 💎 graphite → 🌌, rebuilding the shadow stylesheet
171
+ in place — 100% native events inside our own Shadow DOM, nothing can
172
+ break it. The choice persists via the same `dsh-tfb-theme` key.
173
+ - The settings section keeps only the Todo promotion row in the shared
174
+ "推荐插件" list (the unreliable in-settings skin buttons are removed).
175
+
176
+ ## [0.6.6] - 2026-09-07
177
+
178
+ ### Fixed
179
+
180
+ - **Skin switcher buttons now actually clickable** (second attempt, root
181
+ cause confirmed): React synthetic events AND ref callbacks are both
182
+ unreliable inside the settings section slot. The three skin buttons are
183
+ now plain `data-tfb-theme` attribute buttons; the plugin delegates at
184
+ the DOCUMENT capture phase (`installThemeDelegation`) — immune to any
185
+ re-render, fires before anything can stopPropagation.
186
+
187
+ ### Changed
188
+
189
+ - The Todo promotion + skin switcher moved INTO the shared "推荐插件"
190
+ list (all four sibling plugins now listed together: font / skill
191
+ browser / lightbox / todo ball) instead of a floating block.
192
+
193
+ ## [0.6.5] - 2026-09-07
194
+
195
+ ### Added
196
+
197
+ - **Third skin: 💫 环版 (ring)** — the 0.6.0 style restored as a first-class
198
+ option: dark-gem base with a THICK glowing conic progress ring around the
199
+ ball (done/total arc, amber while active, mint with strong glow when all
200
+ done, ice-blue when pending-only). The switcher in the shared "悬浮球
201
+ 导航" section now offers all three skins:
202
+ - 🌌 星云版 (nebula) — skill-orb clone, flowing bands + rotating rim;
203
+ - 💫 环版 (ring) — dark gem + thick progress ring;
204
+ - 💎 石墨版 (graphite) — v0.5.1 dark gem + thin progress ring.
205
+
206
+ ## [0.6.4] - 2026-09-07
207
+
208
+ ### Fixed
209
+
210
+ - **CRITICAL: newly assigned plans were silently rejected** (user bug
211
+ report: "todo 显示均已完成,没有我安排的新增任务"):
212
+ - the v0.6.1 monotonic guard compared raw completed counts, so a genuine
213
+ NEW plan (whole-list replacement starting at 0 done) was misjudged as
214
+ a stale snapshot and dropped — the ball stayed stuck on the old
215
+ "all done" list;
216
+ - the guard is now **plan-aware**: it only applies within the SAME plan
217
+ (identical content set — progress within one plan must not regress);
218
+ a different content set is a new/edited plan and is always accepted;
219
+ - the persisted-record restore applies the same plan-aware rule (a
220
+ different plan on disk never overrides the live one).
221
+
222
+ ### Changed
223
+
224
+ - Skin buttons in the shared settings section now bind native click
225
+ listeners via React refs (the slot's synthetic events were unreliable —
226
+ user-reported "切换按钮点击不了").
227
+
228
+ ## [0.6.3] - 2026-09-07
229
+
230
+ ### Fixed
231
+
232
+ - **Skin switching now works reliably** (user-reported: buttons had no
233
+ effect):
234
+ - root cause 1: the visibility/theme watcher self-expired after ~20
235
+ minutes (tries cap), so after that the localStorage key was written
236
+ but never read again — the watcher is now permanent;
237
+ - root cause 2: polling alone meant up to 2s latency; the plugin now
238
+ exposes `window.__dshtfbApplyTheme()` and the shared settings buttons
239
+ call it synchronously on click — the skin swaps instantly.
240
+
241
+ ### Added
242
+
243
+ - **Dual skin with a switcher in the shared settings section** (user
244
+ request: keep the previous skin too):
245
+ - 🌌 **星云版 (nebula)** — the skill-orb clone from 0.6.2 (default);
246
+ - 💎 **石墨版 (graphite)** — the v0.5.1 dark-gem style with the thin
247
+ progress ring, preserved as a first-class option;
248
+ - the switcher lives in the shared "悬浮球导航" section next to the Todo
249
+ toggle (provided by dsh-skill-browser); picking a skin writes
250
+ `dsh-tfb-theme` to localStorage and the ball hot-swaps within ~2s —
251
+ the shadow stylesheet is rebuilt in place, no reload needed;
252
+ - both skins keep the four status tints (teal idle / amber active /
253
+ mint done / ice pending) and the per-status list text colors.
254
+
255
+ ## [0.6.2] - 2026-09-07
256
+
257
+ ### Changed
258
+
259
+ - **Orb visuals cloned from the skill-browser ball, hue-shifted to the
260
+ todo teal identity** (user request: "和他一样呢换个颜色"):
261
+ - nebula-body radial gradient (bright highlight → teal nebula → deep
262
+ space rim) exactly mirroring the skill orb's structure;
263
+ - flowing nebula bands (bandFlow) + rotating conic rim light (rimSpin,
264
+ 7s; amber status spins faster at 2.6s) + breathing pulse (orbBreathe)
265
+ + glowing face text (dsbGlow-style keyframes) — the full five-piece
266
+ skill-orb motion stack, now on the todo ball;
267
+ - status variants are full nebula re-tints, not overlays: amber nebula
268
+ + fast rim while work is in progress, mint nebula + extra glow when
269
+ everything is done, ice-blue nebula for pending-only, teal at idle;
270
+ - hover scale-up (1.08) like the sibling orbs. The thin progress ring
271
+ from 0.6.0 is kept underneath the rim (done/total arc).
272
+
273
+ ## [0.6.1] - 2026-09-07
274
+
275
+ ### Fixed
276
+
277
+ - **Durable cross-update record survival (user clarification on "跨轮次")**:
278
+ the checklist and its COMPLETED history now survive every kind of update,
279
+ not just turn resets:
280
+ - every accepted snapshot is persisted to localStorage per session
281
+ (debounced 400ms);
282
+ - on startup / page refresh the persisted record is restored, taking
283
+ whichever side is strictly further along (progress score: done count →
284
+ total → recency) — a page reload can no longer drop completed items;
285
+ - a monotonic guard rejects incoming snapshots that would drag the
286
+ record backward (fewer completed items with an equal-or-larger total,
287
+ e.g. a stale polling snapshot), while still accepting genuine plan
288
+ rewrites (tasks added or total shrunk).
289
+
290
+ ## [0.6.0] - 2026-09-07
291
+
292
+ ### Fixed
293
+
294
+ - **Sticky checklist (requirements 1/2/5)**: the host resets the todos
295
+ projection to `null` at every `turn/start`, which previously wiped the
296
+ ball the moment a new reply began. The last known list is now kept
297
+ per-session until a real `todo_write` snapshot overwrites it — the
298
+ checklist and progress never blink away mid-conversation, across turns,
299
+ and completed items stay visible the whole time.
300
+
301
+ ### Added
302
+
303
+ - **Progress ring + flow effects (requirement 7, skill-orb style)**:
304
+ - a conic-gradient ring around the ball visualizing done/total (e.g.
305
+ 1/5 → 20% arc), rotating amber flow while work is in progress and a
306
+ full mint ring with glow when everything is done;
307
+ - the face label (1/5 or ✓) now carries a matching glow;
308
+ - when items remain, the panel shows a hint pointing to
309
+ `dsh-client-auto-continue` as the driver for continuous thinking (this
310
+ plugin is a read-only monitor and never sends messages itself).
311
+
312
+ ## [0.5.1] - 2026-09-07
313
+
314
+ ### Changed
315
+
316
+ - **Settings centralized into the shared "悬浮球导航" section** (per user
317
+ request): the ball's show/hide toggle now lives in the
318
+ dsh-skill-browser-provided settings section (which already controlled the
319
+ font ball the same way), alongside a promoted entry for this plugin with
320
+ a Star link. This plugin no longer registers its own settings section;
321
+ `exports.inject` is back to `["sessions"]` and `dsh.client.inject` back
322
+ to just `@deepseek-ai/dsh-client-runtime` — **no host restart needed**
323
+ when upgrading to 0.5.1 (a page refresh suffices).
324
+
325
+ ### Fixed
326
+
327
+ - **Theme aligned with the sibling balls** (user request): the ball base is
328
+ back to the same dark-gem gradient as font-enhancer / skill-browser;
329
+ only the accent glow + ball-face text color differ (teal), with status
330
+ colors amber (in progress, pulsing) / mint (done) / ice blue (pending).
331
+ Per-status list TEXT colors are kept: amber semibold for in-progress,
332
+ gray-green strikethrough for completed, light gray-blue for pending.
333
+
334
+ ## [0.5.0] - 2026-09-07
335
+
336
+ ### Added
337
+
338
+ - **DSH settings-page section (悬浮球设置)** — same official
339
+ `settings.section` slot mechanism as the skill-browser and
340
+ font-enhancer balls:
341
+ - show/hide toggle for the ball (persists in localStorage; the panel can
342
+ be re-enabled from settings if hidden);
343
+ - a "floating-ball family" list promoting the four sibling plugins
344
+ (font-enhancer / skill-browser / chat-image-lightbox / this one) with
345
+ Star links;
346
+ - registration follows the four verified requirements: official client
347
+ dependencies declared in `dsh.client.inject` (requires a host restart
348
+ when upgrading), pure-array `exports.inject`, no effect-wrapping, and
349
+ a hooks-free React component.
350
+ - **New teal-gem theme** — distinct from the skill browser's blue-purple
351
+ nebula orb and font-enhancer's graphite gem, same radial-gradient glass
352
+ language:
353
+ - ball states: teal (idle) / amber pulsing (in progress) / mint (all
354
+ done) / ice blue (pending only), each with matching glow;
355
+ - per-status TEXT colors in the list: in-progress = bright amber
356
+ (semibold), completed = gray-green strikethrough, pending = light
357
+ gray-blue — no more uniform white;
358
+ - panel border/header rule tinted teal to match the ball.
359
+
360
+ ## [0.4.0] - 2026-09-07
361
+
362
+ ### Added
363
+
364
+ - **Inline conversation rename from the ball**:
365
+ - click the conversation title in the panel header (or the ✏️ button on a
366
+ pinned row) to edit its name in place — Enter commits, Esc cancels;
367
+ - goes through the official session rename API (`session.rename` from
368
+ `dsh-client-runtime`), so the change is the same as renaming the
369
+ conversation in DSH itself: the sidebar, the projection store and the
370
+ ball all update together;
371
+ - works on the current session and on pinned sessions.
372
+
373
+ ## [0.3.0] - 2026-09-07
374
+
375
+ ### Fixed
376
+
377
+ - **Data layer rebuilt on the official `sessions` service** (the root fix):
378
+ - previous versions tapped `window.fetch`/`WebSocket`, but DSH Desktop's
379
+ connection runs through the shell's `__DSH_TRANSPORT__` (Electron
380
+ `net.fetch` + renderer access header) — page-level taps never saw a
381
+ single frame, so the ball only ever showed collapsed-panel skeleton
382
+ placeholders and never followed session switches;
383
+ - now the plugin injects the official `sessions` service (provided by
384
+ `dsh-client-runtime`) and reads its list snapshot directly: every
385
+ session's `projectionValues.todos` and `displayTitle`, plus the current
386
+ session id and a subscribe() — zero interception, host-computed data;
387
+ - session switching now follows instantly (the snapshot's `current` field
388
+ is the authoritative active-session signal);
389
+ - pinned conversations read real per-session projection data instead of
390
+ guesses;
391
+ - the DOM observer remains as a fallback only when the sessions service
392
+ is unavailable; collapsed-count skeletons are now clearly marked and
393
+ never overwrite real data.
394
+ - Requires `dsh.client.inject: ["@deepseek-ai/dsh-client-runtime"]` — a
395
+ host restart is needed when upgrading from <= 0.2.0.
396
+
397
+ ## [0.2.0] - 2026-09-07
398
+
399
+ ### Added
400
+
401
+ - **Multi-session monitoring**:
402
+ - the ball now follows the active conversation automatically — every
403
+ projection frame carries `sessionId`, and the most recently seen session
404
+ wins (title frames update session awareness too, so even conversations
405
+ without todos reset the ball correctly);
406
+ - conversations can be **pinned** from the panel (📌 button): pinned lists
407
+ keep monitoring across session switches, are listed in a "pinned"
408
+ section with live status dots (orange pulse = in progress, green = all
409
+ done), expand inline to show the full list, and can be unpinned;
410
+ - the pinned list persists in `localStorage`; conversation titles come
411
+ from the `title` projection frames;
412
+ - when the current session has no todos but a pinned one is running, the
413
+ ball surfaces a "📌 in progress" hint instead of going fully idle.
414
+ - Panel header now shows the current conversation's title.
415
+
416
+ ## [0.1.0] - 2026-09-06
417
+
418
+ ### Added
419
+
420
+ - Persistent draggable floating ball showing the current session's `todo_write`
421
+ progress (`done/total` + active task content).
422
+ - Click-to-toggle task panel with per-status colored items
423
+ (✓ completed / ▶ in progress / ○ pending) and `Esc` to fold.
424
+ - Dual-channel data sync:
425
+ - `MutationObserver` over the official todo panel (`[data-testid="todo-panel"]`),
426
+ including localized count-label parsing for the collapsed state;
427
+ - passive projection-frame inspection via wrapped `window.fetch` and
428
+ `WebSocket.prototype.onmessage`.
429
+ - Shadow DOM style isolation (`all:initial`).
430
+ - Position persistence with viewport clamping; Electron-safe mount on `<html>`.
431
+ - Loopback-only host health route `/dsh-todo-float-ball/health`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
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,92 @@
1
+ # dsh-todo-float-ball
2
+
3
+ **Keep your AI agent's task checklist always on screen — a floating progress ball for DeepSeek Harness (DSH).**
4
+
5
+ English | [简体中文](README.zh.md)
6
+
7
+ ## What is this?
8
+
9
+ When an AI agent in DSH works on a multi-step task, it records its plan with the built-in `todo_write` tool. The official UI shows this plan in a small strip above the input box — but the strip is easy to miss, disappears into the conversation flow, and collapses while the agent is still working.
10
+
11
+ **dsh-todo-float-ball** mirrors that checklist onto a small, persistent, draggable floating ball:
12
+
13
+ - The ball sits in a corner of the window at all times (default: bottom-right).
14
+ - Its face shows live progress: `done/total`, with the active task's name underneath.
15
+ - Click it to expand a full task panel; click again (or press `Esc`) to fold it back.
16
+ - Color tells you the state at a glance: pulsing orange = work in progress, green = all done, blue = pending only, gray = no list yet.
17
+
18
+ It is a pure, read-only companion: the plugin never modifies the official panel, the conversation, or any other plugin.
19
+
20
+ ## Features
21
+
22
+ | Feature | Detail |
23
+ |---|---|
24
+ | Persistent floating ball | Always visible in the viewport, draggable anywhere, position saved to `localStorage` and restored across restarts (off-screen stale positions are clamped back) |
25
+ | Live progress | `done/total` on the ball face plus the first active task's content (truncated), updated in real time |
26
+ | Fold / expand | Click the ball to toggle the task panel; the panel opens next to the ball and flips sides when near the screen edge |
27
+ | Status colors | Per-item icons and colors: ✓ completed (green, strikethrough), ▶ in progress (orange), ○ pending (dashed gray); ball itself: orange pulse / green / blue / idle gray |
28
+ | Dual-channel data sync | Channel A: `MutationObserver` over the official todo panel DOM. Channel B: passively inspects session projection frames (`{type:"projection", key:"todos", ...}`) via wrapped `fetch` and `WebSocket.onmessage`, so the full list is available even when the official strip is collapsed |
29
+ | Shadow DOM isolation | All UI lives inside an open Shadow DOM with `all:initial` — no style leaks in or out, immune to theme/skin plugins |
30
+ | Dual-end support | Works in DSH Desktop (Electron window) and the web UI (browser) with the same code, because both render the same page; the UI mounts on `<html>` to dodge `transform`-related `position:fixed` breakage |
31
+ | Privacy-friendly | Zero telemetry, zero data upload. The only host-side surface is a loopback-only health route (`/dsh-todo-float-ball/health`) |
32
+
33
+ ## Install
34
+
35
+ The plugin is a standard DSH npm package (`dsh.bundle` self-declared). Two ways:
36
+
37
+ ### From npm (when published)
38
+
39
+ ```bash
40
+ npm install dsh-todo-float-ball
41
+ ```
42
+
43
+ Then add `"dsh-todo-float-ball"` to both `dependencies` and `dsh.profile.bundles` in your profile's `package.json` (e.g. `%USERPROFILE%\.dsh\profiles\desktop\package.json`), and restart DSH.
44
+
45
+ ### Manual
46
+
47
+ Copy this package folder into your profile's `node_modules` (a real copy — do **not** use `link:` / `file:` dependencies, they can trigger DSH's install-recovery loop), then register it the same way and restart.
48
+
49
+ After the restart you should see the ball in the bottom-right corner. Verify the host half with:
50
+
51
+ ```
52
+ http://127.0.0.1:43120/dsh-todo-float-ball/health
53
+ → {"ok":true,"plugin":"dsh-todo-float-ball","version":"0.1.0"}
54
+ ```
55
+
56
+ ## How it works
57
+
58
+ The official todo data is a **session projection**:
59
+
60
+ 1. `@deepseek-ai/dsh-tool-todo` registers the `todo_write` tool and a `todos` projection unit on `sessionProjections`; every call appends a `todo/write` snapshot to the session log.
61
+ 2. `@deepseek-ai/dsh-client-connection` broadcasts the current value as a control frame: `{type:"projection", sessionId, key:"todos", value:[{content,status}...]}`.
62
+ 3. `@deepseek-ai/dsh-client-ui-conversation` renders it as the plan strip above the input box (`[data-testid="todo-panel"]`).
63
+
64
+ This plugin attaches to both ends without touching either:
65
+
66
+ - **Channel A (DOM)**: a debounced `MutationObserver` watches for `[data-testid="todo-panel"]`, reads `li[data-status]` items when the strip is expanded, and parses the localized count label (e.g. "1 完成 · 2 进行中") when it is collapsed.
67
+ - **Channel B (transport)**: a one-time, defensive wrapper around `window.fetch` (cloning responses, text/json only) and `WebSocket.prototype.onmessage` (text frames) feeds every payload through a strict extractor that only reacts to objects shaped like projection frames, `todo/write` events, or `{todos:[...]}` snapshots. Malformed payloads are ignored; nothing is ever written back.
68
+
69
+ All channels funnel into one normalizer: items are filtered to the three known statuses, blank contents are dropped, and unchanged lists are no-ops (cheap signature comparison).
70
+
71
+ ## FAQ
72
+
73
+ **The ball doesn't show up.**
74
+ Check the health URL above; if it responds, the host half is fine — the client bundle may have been blocked (look for `loaded without registering` in DSH logs; the bundle id must equal the package name). If it doesn't respond, the plugin isn't in your profile's bundles list.
75
+
76
+ **Can I move the ball?**
77
+ Yes — drag it anywhere. The position persists per browser/renderer profile. If a saved position somehow lands off-screen, the plugin clamps it back into the viewport on startup.
78
+
79
+ **Does it work while the official strip is collapsed?**
80
+ Yes. That is exactly why channel B exists: the official strip renders only a counts label when collapsed, while projection frames always carry the full list.
81
+
82
+ **Does it slow the UI down?**
83
+ No. The observer is debounced (200 ms), the transport tap only string-scans for `"todos"` before parsing, and the periodic re-render watchdog stops after ~10 minutes.
84
+
85
+ ## Compatibility
86
+
87
+ - DSH Desktop 2.x (desktop profile) and DSH web (web profile)
88
+ - No `peerDependencies` — the plugin is self-contained and talks to DSH only through public DOM/HTTP surfaces
89
+
90
+ ## License
91
+
92
+ MIT
package/README.zh.md ADDED
@@ -0,0 +1,92 @@
1
+ # dsh-todo-float-ball
2
+
3
+ **把 AI 干活的任务清单常驻挂在一个悬浮球上 —— DeepSeek Harness(DSH)进度悬浮球插件。**
4
+
5
+ [English](README.md) | 简体中文
6
+
7
+ ## 这是什么?
8
+
9
+ DSH 里的 AI 在推进多步骤任务时,会用内置的 `todo_write` 工具记录任务清单。官方界面把这份清单渲染成输入框上方的一条进度条——但它很容易被忽略、会随着对话滚动走远、而且 AI 还在干活时它默认是折叠的。
10
+
11
+ **dsh-todo-float-ball** 把这份清单镜像到一个小的、常驻的、可拖动的悬浮球上:
12
+
13
+ - 悬浮球始终固定在窗口角落(默认右下角);
14
+ - 球面实时显示进度:`完成数/总数`,下方滚动显示当前进行中的任务名;
15
+ - 点击展开完整任务面板,再点一下(或按 `Esc`)收起;
16
+ - 颜色一眼看状态:橙色脉动 = 正在干活,绿色 = 全部完成,蓝色 = 只有待办,灰色 = 暂无清单。
17
+
18
+ 它是一个纯只读的伴生插件:不修改官方面板、不改对话流、不碰任何其他插件的实现。
19
+
20
+ ## 功能清单
21
+
22
+ | 功能 | 说明 |
23
+ |---|---|
24
+ | 常驻悬浮球 | 始终在视口内可见,可拖到任意位置,位置存 `localStorage` 重启后恢复(保存了越界旧位置会自动拉回视口内,防"球丢了") |
25
+ | 实时进度 | 球面显示 `完成数/总数` + 当前第一个进行中任务的内容(超长截断),随 `todo_write` 实时刷新 |
26
+ | 折叠/展开 | 点球切换任务面板;面板在球旁边弹出,靠边时自动翻到另一侧 |
27
+ | 状态颜色 | 每项带状态图标与配色:✓ 已完成(绿色+删除线)、▶ 进行中(橙色)、○ 待办(灰色虚线圈);球本身:橙色脉动/绿/蓝/灰 |
28
+ | 数据双路同步 | 主路:`MutationObserver` 监听官方 todo 面板 DOM;辅路:包装 `fetch` 与 `WebSocket.onmessage`,被动捕获会话投影帧 `{type:"projection", key:"todos", ...}`——**官方面板折叠时也能拿到完整清单** |
29
+ | Shadow DOM 样式隔离 | 全部 UI 在 open Shadow DOM 内并加 `all:initial`——样式不进不出,主题/皮肤插件互不干扰 |
30
+ | 双端可用 | DSH Desktop 桌面端(Electron 窗口)与网页端(浏览器)同一份代码通用;UI 挂载在 `<html>` 根节点,规避 `transform` 导致的 `position:fixed` 失效 |
31
+ | 隐私友好 | 零遥测、零数据上传。宿主端只注册一个仅限本机回环访问的健康检查路由(`/dsh-todo-float-ball/health`) |
32
+
33
+ ## 安装
34
+
35
+ 本插件是标准 DSH npm 包(自带 `dsh.bundle` 声明)。两种方式:
36
+
37
+ ### 从 npm 安装(发布后)
38
+
39
+ ```bash
40
+ npm install dsh-todo-float-ball
41
+ ```
42
+
43
+ 然后在你所用 profile 的 `package.json`(如 `%USERPROFILE%\.dsh\profiles\desktop\package.json`)里,把 `"dsh-todo-float-ball"` 同时加进 `dependencies` 和 `dsh.profile.bundles`,重启 DSH 生效。
44
+
45
+ ### 手动安装
46
+
47
+ 把本包目录整体复制进 profile 的 `node_modules`(必须是真实目录复制——**不要**用 `link:` / `file:` 依赖,会触发 DSH 安装恢复死循环),按上面同样方式注册后重启。
48
+
49
+ 重启后右下角应出现悬浮球。可用下面的地址验证宿主端已挂载:
50
+
51
+ ```
52
+ http://127.0.0.1:43120/dsh-todo-float-ball/health
53
+ → {"ok":true,"plugin":"dsh-todo-float-ball","version":"0.1.0"}
54
+ ```
55
+
56
+ ## 实现原理
57
+
58
+ 官方的 todo 数据是一条**会话投影(session projection)**:
59
+
60
+ 1. `@deepseek-ai/dsh-tool-todo` 注册 `todo_write` 工具,并在 `sessionProjections` 上登记 `todos` 投影单元;每次调用向会话日志追加一条 `todo/write` 快照;
61
+ 2. `@deepseek-ai/dsh-client-connection` 把当前值以控制帧广播:`{type:"projection", sessionId, key:"todos", value:[{content,status}...]}`;
62
+ 3. `@deepseek-ai/dsh-client-ui-conversation` 把它渲染成输入框上方的任务条(`[data-testid="todo-panel"]`)。
63
+
64
+ 本插件在两端各挂一个只读探针,不碰任何一端:
65
+
66
+ - **主路(DOM)**:一个带 200ms 防抖的 `MutationObserver` 盯着 `[data-testid="todo-panel"]`——面板展开时读 `li[data-status]` 全量清单;折叠时解析本地化的计数文案(如"1 完成 · 2 进行中",含中文数字解析)。
67
+ - **辅路(传输层)**:一次性、防御式的 `window.fetch` 包装(clone 响应、只处理文本/JSON)与 `WebSocket.prototype.onmessage` 包装(文本帧),把每个载荷送进严格的提取器——只对形如投影帧、`todo/write` 事件、`{todos:[...]}` 快照的对象起反应,其余一律忽略,绝不回写。
68
+
69
+ 所有通道汇入同一个归一化器:过滤出三种合法状态、丢弃空内容、列表无变化时零开销跳过(签名比对)。
70
+
71
+ ## 常见问题
72
+
73
+ **悬浮球不出现?**
74
+ 先开上面的 health 地址:能返回说明宿主端正常,是客户端 bundle 没加载(查 DSH 日志有无 `loaded without registering`,bundle id 必须与包名一致);不能返回说明插件没进 profile 的 bundles 列表。
75
+
76
+ **能移动悬浮球吗?**
77
+ 能,拖到哪都行。位置按浏览器/渲染进程分别记忆;万一保存的位置跑到屏幕外,启动时会自动拉回视口内。
78
+
79
+ **官方面板折叠时也能同步吗?**
80
+ 能。这正是辅路存在的意义:官方面板折叠时只渲染计数文案,而投影帧始终携带完整清单。
81
+
82
+ **会拖慢界面吗?**
83
+ 不会。观察器 200ms 防抖;传输层窃听先做 `"todos"` 字符串预筛再解析;兜底看门狗跑约 10 分钟后自动停止。
84
+
85
+ ## 兼容性
86
+
87
+ - DSH Desktop 2.x(desktop profile)与 DSH web(web profile)
88
+ - 无 `peerDependencies`——插件自包含,只通过公开 DOM/HTTP 面与 DSH 交互
89
+
90
+ ## License
91
+
92
+ MIT
@@ -0,0 +1,8 @@
1
+ # dsh-todo-float-ball — floating ball showing live todo_write progress.
2
+ # Pure client-side plugin: the visual work lives in lib/client.js (mounted by
3
+ # the client-modules system once the host activates). The host half only
4
+ # registers a loopback-only health route so the bundle has a real cordis
5
+ # activate. No host services are required at runtime.
6
+ - insert:
7
+ - id: dsh-todo-float-ball
8
+ name: dsh-todo-float-ball