Repository navigation
Releases: tcgbp/dock-flash
Release list
dock-flash v3.0.0 — the dock-base Workbench adapter
dock-flash 3.0.0 — the dock-base Workbench adapter
The panel core moved out to dsh-flash@1.0.0. This package is now the thin
adapter: a 470-line client half (the former //#region DockAdapter, promoted to
a package) plus a deliberately empty host half. It declares dsh-flash as a
real dependency and dock-base as a non-optional peer.
What it does: claims the dockFlashPanel service and registers the panel with
ctx.workbench — sidebar panel dock-flash:quick-control, the plugin entry, the
activity-bar ⚡, the editor view and the dock-flash:openQuickControl command.
Teardown calls releaseOne(); the whole-host release() is reserved for the
dock-hidden detach path (calling it from a per-mount disposer broke the
two-mount case).
Full bundle patch (two rows)
cordis.patch.yml inserts both rows, so an adapter-only install still composes
the core. A hoisted dependency is not a composed row:
- id: dock-flash # keep — the id IS the settings namespace
name: dsh-flash
- id: dock-flash-adapter
name: dock-flashThe name: key is an assertion. Old v2 profile patches read
- id: dock-flash / name: dock-flash; DSH drops the whole config: block
when it mismatches, silently losing panel order, skin and trigger settings.
Change name: to dsh-flash and keep id: dock-flash.
Failing loudly
inject is intentionally empty: declaring dockFlashPanel there would make
cordis silently skip apply(), so a missing core would look like "not
installed". Instead the adapter subscribes via ctx.inject(['dockFlashPanel'])
and prints an actionable error if the service has not arrived after 2000 ms.
Published alongside
dsh-flash@1.0.0— the panel coredsh-flash-ctx-mon@0.1.7,dsh-flash-mem-mon@0.1.5,dsh-flash-net-mon@0.1.4,dsh-flash-proxy@0.1.5
This release is marked pre-release to match npm's next dist-tag; it is
promoted (both here and on npm) after the isolated-profile boot acceptance.
v2.3.0
Internal refactor with nothing different on screen and no preference migration — the settings namespace stays dock-flash.
The mode used to be decided by probing ctx.get('workbench'). That pairing breaks as soon as the two halves can be installed independently: dock-base installed, no dock adapter rendered nothing at all — no sidebar panel, and no ⚡ to fall back on. Ownership is inverted instead.
ctx.provide('dockFlashPanel', …)publishes{ version: 1, Panel, ErrorBoundary, Header, icon, registry, i18n, host }— a frozen field set checked at startup. A host that finds no service, or one whoseversionit does not speak, logs the reason and leaves the ⚡ in place rather than drawing half a panel.host.claim()returns a lease bound to the host fiber; a 2 s watchdog undoes an unconfirmed claim, andrelease()remounts the ⚡. A duplicateapply()returns immediately, keyed on the service (not a module orwindowflag, which would make a legitimate disable→enable inert).createPanelHeader(registry)seals the seven symbols the dock header used to reach into, and accepts both{ wb }and dock-base's own ViewProps{ ctx, viewId, … }(dock-base never passeswb).- The dock half is now one closed
//#region DockAdapter; its dock-hidden ↔ ⚡ sync releases the claim instead of mounting its own trigger. - Fixed: the moved
mountWorkbenchstill closed overapply()'sctx— aReferenceError: ctx is not definedon the first boot with dock-base. - Fixed: the header's close-on-blur toggle had, since 2.2.0, written the preference through the workbench service where a registry was expected, so the header never repainted its own switch.
- Fixed: the claim was a single lease while dock-base mounts the panel twice — the sidebar pane and the floating window — so the first of the two to unmount pulled the panel out from under the instance still mounted. The lease now carries a holder count, whose one invariant is count non-zero ⇔ lease alive: each mount's disposer releases exactly one holder, and only a dock-hidden or a whole-host teardown releases the lease itself.
- Fixed: the panel service was read with
ctx.get('dockFlashPanel')in the same synchronous tick as theprovidethat publishes it, and cordis resolves services asynchronously (measured on cordis 4.0.4:undefinedin that tick, a value on the next), so the dock half registered nothing at all — the root cause of the report "dock-flash 没有出现在 dock-base 配置里". The adapter now receives the service as an explicit argument rather than looking it up, and a source-level pin asserts the call site passes it.
The adapter did not become a separate file: a client bundle's synchronous require cannot resolve a relative path, so the file boundary arrives in Phase 2, when the two halves are two packages.
check:overlay 272 → 295 assertions, 0 fail (the section drives the whole truth table against a fake workbench: claim, the five registrations, the ⚡ standing down, the dock-hidden round trip, dispose, the watchdog, a late workbench, both refusals, a pin that every dock-base-only API stays inside the region, the multi-mount holder count, and a ctx that cannot resolve the service at all — the production shape).
Full narrative: CHANGELOG.md.
v2.2.0 — the compact panel
The floating panel has a compact form. Double-click the standalone ⚡ and it becomes a 176px
strip: no borders, no scrollbar, no text chrome at all. Rows show each control's icon and the control
itself with the names in tooltips, the language row drops even its icon, two consecutive toggle-only
rows share one line (a pair, never three), a cluster whose master switch is off is dropped whole, the
Workbench page is drawn without a tab header, and there is no alert bar and no Changes page.
Standalone only, deliberately. The mode was briefly offered in dock-base's sidebar too and was
withdrawn: a panel's width there belongs to dock-base — its contract has no width field in
ViewDefinition and none in WorkbenchLayout, checked rather than assumed — so it could never make
that panel narrower, only strip chrome from somebody else's window.
Also in this release, every one of them measured rather than eyeballed:
- The theme and skin dropdowns drew over each other at the compact width (52px of overlap) because
each one sits in a shrink-to-fitinline-block. They now ellipsize inside their own box, and wrap
onto two lines only when they do not fit — short values still share one line. - A row's label sat 0px from its dropdown in a narrow panel:
justify-content: space-between
guarantees nothing when the two meet. AcolumnGapand an ellipsizing name fix it. - An icon-only column on
flex: 1(a basis of ZERO) gave up all its width before the control gave up
any, and the 12px glyph spilled onto the control. It isflex: nonenow. - The compact panel dropped its title, but with
visibility: hiddenrather thandisplay: none— the
title is the header'sflex: 1spacer, so removing it from the layout slid the close buttons 78px
left. - The close-on-blur switch row asked for the generic
eyewhile the header button drew a panel
with a pointer leaving it. One setting, two faces; now one glyph from one source.
check:overlay: 272 assertions, 0 fail. The narrative, with the measurements behind each fix, is in
CHANGELOG.md.
v2.1.0
Names the companion plugins that are not running and hands over the command that installs the ones genuinely absent — with installed, not running kept distinct from not installed, and state unknown instead of a guess when the profile's package list cannot be read. A ✕ dismisses it by writing the panel's existing hidden set, so the rows stay registered and come back from the ◉ visibility mode.
The Workbench tab now carries its own glyph (sliders) instead of a second lightning bolt, so the tab row reads as one system and the ⚡ stays the product mark.
Fixed: a collapsed tab header lost its bottom edge — a React style diff, not CSS. border was byte-identical across the two style objects so React skipped it, while borderBottom: 'none' vanished and React wrote '', clearing the longhands the shorthand had set. Measured in headless Chrome at 2x: fresh collapsed top=1px bottom=1px, open→collapsed top=1px bottom=0px.
Narrative and reasoning in CHANGELOG.md.
v2.0.2
A preference-load crash that made the plugin — and its companion monitors — silently disappear.
settings.describe() was called with .then(...) unconditionally, but that one name has
two implementations: the typert WIRE form returns a Promise, while the DIRECT form —
SettingsController.describe() in @deepseek-ai/dsh-api-settings-controller — is
synchronous and returns the view object itself, and can throw instead
(settings service is absent: mount @deepseek-ai/dsh-settings).
The resulting TypeError: settings.describe(...).then is not a function is raised
synchronously, so it escaped before the .catch at the end of the loader's chain.
Because it lands inside apply(), it aborted the rest of apply: ctx.provide('quickControl', …),
every switch registration and the panel mount all sit downstream of the preference load. The plugin
therefore still read as loaded while nothing of it was on screen — with only
[dock-flash] apply failed: TypeError: … in the console. That is the reported "the plugin was
registered and then silently disappeared".
Both call sites now normalize through _describeAsync(), which accepts a Promise, a plain view, or a
throw, so the loader's existing .catch records a named reason instead of killing the plugin. The same
defect was fixed in all four companions (dsh-flash-ctx-mon 0.1.3, dsh-flash-mem-mon 0.1.2,
dsh-flash-net-mon 0.1.1, dsh-flash-proxy 0.1.2), where apply() is async with no internal catch —
there the throw rejected apply and failed the Cordis fiber, so those plugins never activated at all.
pnpm run check:overlay section 23 exercises both shapes (a synchronous view and a throwing provider) and
asserts that apply() still reaches ctx.provide('quickControl', …), that the synchronous view is
parsed and adopted rather than merely tolerated, and that a refusal is recorded instead of swallowed.
All five assertions fail against the unfixed build, reproducing the reported error verbatim.
204 assertions pass, 0 fail.
Patch: no published surface changed — no switch added, renamed or removed, no field, type or route touched.
v2.0.1
Six UI defects in the floating panel and the alert surfaces — all of them "it was there but you could not use it".
Floating panel. It was placed by setting ONE edge and leaving its height to max-height: 70vh, so with the ⚡ anywhere but near the opposite edge it landed partly outside the window — measured at top: -186px for a mid-page button, which clips the panel's header, and -616px for a button near the top. It now tries the configured side, then the other, then turns the corner and sits beside the button, clamped into the window on both axes. Its height is never touched. The horizontal clamp was wrong in the same shape: a button near the right edge put the panel's right edge 80px past the window.
Alert surfaces. The toast, the alert dropdown and the alert detail modal carried fixed z-indices (1200/1200/2200) while the panel's level is the user-settable triggerLayer — so the shipped 2000 preset put the panel on top of the toast and of the dropdown anchored to the trigger. All three now derive from that one setting, floored at 1100.
Toast. It was pinned to the window's top-right, a screen away from the conversation it reports on; it is now anchored to the conversation viewport's content corner — inside the scrollbar gutter, giving way to the right-side turn rail — and kept there by a ResizeObserver on that viewport, because the sidebar opening or the sash moving changes the conversation's box without firing a window resize. With no conversation on screen it falls back to the window corner.
Toast, accessibility. Each card now carries role="alert" for critical/error and role="status" otherwise, and prefers-reduced-motion: reduce drops the exit slide and the progress animation while keeping the fade.
Toast switch. It was hidden while the panel was rendered by dock-base even though the toast keeps running there — a popup with no way to turn it off. Shown in both modes now.
Cluster fold control. Its hit area was the glyph plus padding: 2px 22px; it is now the whole bottom row of the card, with distinct static and hover colours, and it is not drawn when the cluster's master switch is off and the body would be empty.
No published surface changed: no switch added, renamed or removed, no field, type or route touched.
v2.0.0
Breaking: the context monitor has moved out of dock-flash into the dsh-flash-ctx-mon plugin.
Removed from the client half: SessionEventTokenSource, createSessionContextProvider, the dock-flash:context-alert provider, the dock-flash:monitor-context switch, the monitor config modal and model-window-map editor, their styles, and the context i18n keys. Removed from the host half: the ctxApproxWindow, ctxThresholdInfo/Warning/Error, ctxPollBase/Min, modelContextWindows and modelContextWindowSources settings fields — all of which now live in the dsh-flash-ctx-mon settings namespace.
What stays in dock-flash is the machinery an extracted monitor plugs into: the quickControl and dockFlashAlerts services, the dock-flash:ready event, the host-pushed alert queue, and the companion integration tables (_PROVIDER_SWITCH_MAP, _PROVIDER_LABELS, _COMPANION_PREFIXES) that label each monitor's alerts and link them back to its own config page.
Note for upgraders: values saved under the old dock-flash namespace are not migrated into the new one, so context thresholds and any manual model-window overrides return to their defaults — re-set them in the context monitor's config page.
Also included, carried over from the abandoned in-tree context-monitor rewrite: the alert-detail footer padding fix, and subtitleBlock support for toggle switches (so a monitor's status line can wrap onto its own row).
v1.6.5
Patch release: the skin switch worked on DSH Desktop and did nothing at all on DSH Web. (1) The host half FOUND the running profile by readdirSync order over $DSH_HOME/profiles instead of reading the launcher's profileContext — with two profiles both installing dock-flash, a dsh web process resolved the DESKTOP profile, so every toggle wrote profiles/desktop/cordis.patch.yml while the running loader watched profiles/web/cordis.patch.yml, reported application: "applied" and changed: true, and no skin ever came up. It now asks profileContext first (dir, then dirname(patchPath), then ctx.baseUrl) and keeps the walk only as a fallback for a boot with no launcher. (2) The patch row carried a name: that dsh-app-boot's applyEntryPatches skips on mismatch, so an ENABLE was silently discarded; the row is now written with the id alone, exactly as DSH's own writePluginEnabled does. Host half only, so dist/ is rebuilt in the same change and the fix needs a DSH restart. check:overlay: 189 assertions, 0 FAIL. Full narrative in CHANGELOG.md.
v1.6.4
Patch release: the skin switch now writes BOTH layers on every path. (1) The row branch wrote the loader ENTRY and never consulted dsh.profile.bundles, so a skin whose entry was ENABLED switched off in the loader and was composed straight back in on the next boot. (2) The ENABLE path - a CSS skin WITH a loader row - wrote the entry and never the roster, so a skin switched off in both layers could not be switched on again. Also realigns three harness assertions that had pinned the old contract. check:overlay: 189 assertions, 0 FAIL. Full narrative in CHANGELOG.md.