dsh-claude-desktop-theme 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -54
- package/lib/client.js +9392 -2579
- package/lib/index.js +387 -20
- package/lib/types/client/compat/account-menu.d.ts +4 -4
- package/lib/types/client/compat/account-more.d.ts +3 -0
- package/lib/types/client/compat/account-theme.d.ts +3 -0
- package/lib/types/client/compat/adapter.d.ts +22 -1
- package/lib/types/client/compat/browser-header.d.ts +57 -0
- package/lib/types/client/compat/browser-menu.d.ts +16 -0
- package/lib/types/client/compat/composer-menus.d.ts +6 -3
- package/lib/types/client/compat/context-panel.d.ts +47 -0
- package/lib/types/client/compat/empty-groups.d.ts +46 -0
- package/lib/types/client/compat/files-pane.d.ts +78 -0
- package/lib/types/client/compat/header-menu-actions.d.ts +14 -0
- package/lib/types/client/compat/header-menus.d.ts +4 -0
- package/lib/types/client/compat/host-dom.d.ts +180 -0
- package/lib/types/client/compat/pane-chrome.d.ts +29 -0
- package/lib/types/client/compat/pane-icons.d.ts +23 -0
- package/lib/types/client/compat/pane-tiles.d.ts +37 -0
- package/lib/types/client/compat/permission-menu.d.ts +88 -0
- package/lib/types/client/compat/relative-file-path.d.ts +2 -0
- package/lib/types/client/compat/right-panes.d.ts +16 -0
- package/lib/types/client/compat/scroll-pill.d.ts +70 -0
- package/lib/types/client/compat/sidebar-navigation.d.ts +11 -0
- package/lib/types/client/compat/stats-values.d.ts +18 -1
- package/lib/types/client/compat/view-options.d.ts +58 -0
- package/lib/types/client/compat/view-switch.d.ts +46 -5
- package/lib/types/client/contracts/ports.d.ts +176 -1
- package/lib/types/client/features/context-panel/ContextPanel.d.ts +12 -0
- package/lib/types/client/features/context-panel/mount.d.ts +20 -0
- package/lib/types/client/features/conversation/index.d.ts +5 -3
- package/lib/types/client/features/conversation/view-switch-icons.d.ts +13 -0
- package/lib/types/client/features/settings/locales.d.ts +7 -0
- package/lib/types/client/features/shell/index.d.ts +9 -3
- package/lib/types/client/features/sidebar/index.d.ts +1 -1
- package/lib/types/client/features/sidebar/navigation-icons.d.ts +6 -0
- package/lib/types/client/features/statistics/books.d.ts +1 -2
- package/lib/types/client/features/statistics/format.d.ts +4 -4
- package/lib/types/client/features/view-options/ViewOptionsCard.d.ts +30 -0
- package/lib/types/client/features/view-options/mount.d.ts +25 -0
- package/lib/types/client/theme/mount.d.ts +2 -2
- package/lib/types/client/theme/palette.d.ts +1 -1
- package/lib/types/host/context/compaction.d.ts +26 -0
- package/lib/types/host/context/pricing.d.ts +99 -0
- package/lib/types/host/context/service.d.ts +24 -0
- package/lib/types/host/context/unit.d.ts +136 -0
- package/lib/types/host/index.d.ts +18 -0
- package/lib/types/shared/config.d.ts +26 -1
- package/lib/types/shared/context.d.ts +243 -0
- package/package.json +6 -3
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Disposer } from '../contracts/ports.ts';
|
|
2
|
+
/** Names the preset a tagged row switches to; `theme/menus.css` keys the two-line cell off it. */
|
|
3
|
+
export declare const PERMISSION_MODE_ATTRIBUTE = "data-ccd-permission-mode";
|
|
4
|
+
/** Tags the card those rows sit in, so the stylesheet can reach the card itself. */
|
|
5
|
+
export declare const PERMISSION_MENU_ATTRIBUTE = "data-ccd-permission-menu";
|
|
6
|
+
/** One preset as the card draws it. */
|
|
7
|
+
export interface PermissionPresetCopy {
|
|
8
|
+
/** DSH's machine value for the preset (`read-only`, `auto`, …): the row's identity, never shown. */
|
|
9
|
+
readonly value: string;
|
|
10
|
+
/** The name DSH renders, which is what a row is recognised by. */
|
|
11
|
+
readonly name: string;
|
|
12
|
+
/** The name to draw — the same wording wherever the host's is already the one to use. */
|
|
13
|
+
readonly label: string;
|
|
14
|
+
/** The preset's trailing badge: the word DSH prints, and the word to print instead. */
|
|
15
|
+
readonly badge?: {
|
|
16
|
+
readonly host: string;
|
|
17
|
+
readonly text: string;
|
|
18
|
+
};
|
|
19
|
+
/** The row's second line, saying what the mode does. */
|
|
20
|
+
readonly description: string;
|
|
21
|
+
}
|
|
22
|
+
/** The card's copy in one language. */
|
|
23
|
+
export interface PermissionCopy {
|
|
24
|
+
/** The group's name, above the rows — the one thing the reference writes that the host does not. */
|
|
25
|
+
readonly heading: string;
|
|
26
|
+
readonly presets: readonly PermissionPresetCopy[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The card's copy for the document on screen.
|
|
30
|
+
*
|
|
31
|
+
* DSH localises its own strings through `ctx.locale`; a third-party plugin may
|
|
32
|
+
* not borrow another package's namespace, so the second line follows the
|
|
33
|
+
* document language instead — the same rule `compat/header-labels.ts` follows.
|
|
34
|
+
*
|
|
35
|
+
* @param document - renderer document whose language DSH sets from the locale.
|
|
36
|
+
* @returns Chinese copy for a Chinese document, English otherwise.
|
|
37
|
+
*/
|
|
38
|
+
export declare function permissionCopy(document: Document): PermissionCopy;
|
|
39
|
+
/**
|
|
40
|
+
* The permission picker's card, drawn the way the reference draws it.
|
|
41
|
+
*
|
|
42
|
+
* DSH's card is four flat rows of a preset's name — `仅可查看` / `工作区内修改`
|
|
43
|
+
* / `完全权限` / `Auto review` — one 20px line each, and the only thing that
|
|
44
|
+
* tells them apart is the name itself. The reference draws the same four
|
|
45
|
+
* choices as two-line cells: the mode's name over a sentence saying what the
|
|
46
|
+
* mode does, with the one flagged preset carrying a badge beside its name. The
|
|
47
|
+
* names are the host's and stay the host's; what this module adds is the second
|
|
48
|
+
* line, and its home is a node the host never renders — `optionDescription`
|
|
49
|
+
* exists in the permission catalog, but the picker passes it to the trigger's
|
|
50
|
+
* `title` and prints nothing in the row.
|
|
51
|
+
*
|
|
52
|
+
* So this is the one compat module that *writes* copy rather than rewriting
|
|
53
|
+
* what the host rendered, and the copy is this plugin's own: see
|
|
54
|
+
* `permissionCopy` above. It is kept in one table per document language, so a
|
|
55
|
+
* wording change is one edit in one place.
|
|
56
|
+
*
|
|
57
|
+
* Three facts decide how the rows are reached, and each is worth stating:
|
|
58
|
+
*
|
|
59
|
+
* - **A row is recognised by its name.** `Menu` rows carry no identity of their
|
|
60
|
+
* own — no id, no data attribute, and the preset's own glyph is a thing this
|
|
61
|
+
* plugin removes (`theme/menus.css` hides the icon seat) — so the name the
|
|
62
|
+
* host localised is the only handle there is. That is the same fact
|
|
63
|
+
* `compat/workspace-menu.ts` reads for its own row, and it fails safe: a
|
|
64
|
+
* deployment that configured its own preset names matches nothing, and its
|
|
65
|
+
* card keeps the host's single-line rows exactly as they are.
|
|
66
|
+
* - **The card is recognised by its rows.** The picker's trigger carries no
|
|
67
|
+
* `aria-expanded` (unlike the account trigger and the hero chips), so the
|
|
68
|
+
* portalled card cannot be tied back to the control that opened it; the card
|
|
69
|
+
* a recognised row sits in is therefore the card this module tags. A card
|
|
70
|
+
* none of whose rows is recognised is left whole — its heading with it, since
|
|
71
|
+
* a heading over four unrecognised rows names nothing.
|
|
72
|
+
* - **Nothing here reorders a row.** The second line is inserted as the label's
|
|
73
|
+
* next sibling and the heading as the row group's first child, so the
|
|
74
|
+
* primitive's own keyboard walk — which collects `button`s out of the group,
|
|
75
|
+
* not its children — steps over both, and every click target, focus order and
|
|
76
|
+
* accessible name the host built is left where it was. The row keeps its own
|
|
77
|
+
* name too: the inserted line widens what a screen reader reads out of the
|
|
78
|
+
* row, which is the point of the sentence.
|
|
79
|
+
*
|
|
80
|
+
* The host mounts the card afresh on every open, so every pass is idempotent
|
|
81
|
+
* and every write is undone on release: a disabled plugin leaves DSH's own card
|
|
82
|
+
* on screen.
|
|
83
|
+
*
|
|
84
|
+
* @param document - renderer document carrying the status bar and the portal.
|
|
85
|
+
* @param report - sink for observer failures; the native card stays untouched.
|
|
86
|
+
* @returns disposer that disconnects the observers and takes every write back.
|
|
87
|
+
*/
|
|
88
|
+
export declare function mountPermissionMenu(document: Document, report: (error: unknown) => void): Disposer;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { Disposer } from '../contracts/ports.ts';
|
|
3
|
+
/** DockLayout can only render two horizontal dock panes. Its floating leaves
|
|
4
|
+
* have no such limit: retain those host-rendered bodies and controls, and give
|
|
5
|
+
* them session-owned column geometry. No React-owned node is reparented. */
|
|
6
|
+
export declare const PANES_ATTRIBUTE = "data-ccd-panes";
|
|
7
|
+
export declare const PANE_ATTRIBUTE = "data-ccd-pane";
|
|
8
|
+
export declare const SEAM_ATTRIBUTE = "data-ccd-pane-seam";
|
|
9
|
+
export declare const SEAM_AXIS_ATTRIBUTE = "data-ccd-pane-axis";
|
|
10
|
+
export declare const SEAM_INDEX_ATTRIBUTE = "data-ccd-pane-seam-index";
|
|
11
|
+
export declare const DRAGGING_ATTRIBUTE = "data-ccd-pane-dragging";
|
|
12
|
+
export declare const PANE_LEFT_PROPERTY = "--ccd-pane-left";
|
|
13
|
+
export declare const PANE_TOP_PROPERTY = "--ccd-pane-top";
|
|
14
|
+
export declare const PANE_WIDTH_PROPERTY = "--ccd-pane-width";
|
|
15
|
+
export declare const PANE_HEIGHT_PROPERTY = "--ccd-pane-height";
|
|
16
|
+
export declare function mountRightPanes(ctx: Context, document: Document, report: (error: unknown) => void): Disposer;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Disposer } from '../contracts/ports.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The window's scrollbars: thin, dark, and there only while something moves
|
|
4
|
+
* (DESIGN.md §三).
|
|
5
|
+
*
|
|
6
|
+
* Two mechanisms, one look.
|
|
7
|
+
*
|
|
8
|
+
* **The ink.** Every scroller inside `theme/scrollbars.css`'s scope keeps the
|
|
9
|
+
* host's own track, thumb box and navigation, and this module publishes the
|
|
10
|
+
* moment one is moving as {@link SCROLLING_ATTRIBUTE}; the sheet keeps the ink
|
|
11
|
+
* switched off until it sees that attribute, so no surface in the window
|
|
12
|
+
* carries a bar at rest. A listener on the document's capture phase sees every
|
|
13
|
+
* element scroll in one place — scroll events do not bubble, but they do travel
|
|
14
|
+
* down — and clears the mark again once the surface has been still for
|
|
15
|
+
* {@link IDLE_MS}.
|
|
16
|
+
*
|
|
17
|
+
* **The pill.** The five page-level surfaces — the Conversation page, the
|
|
18
|
+
* transcript column, the sidebar's tree, the Files pane and the agent-team panel
|
|
19
|
+
* — go one step further and keep no ink at all: {@link PILL_SURFACE_ATTRIBUTE}
|
|
20
|
+
* takes their track's thumb out of the painting, and a floating pill
|
|
21
|
+
* ({@link PILL_ATTRIBUTE}, all of them in one fixed layer) follows the scroll
|
|
22
|
+
* position instead. That pill is the short capsule the reference draws. The
|
|
23
|
+
* painted thumb cannot be it: its length is the content's share of the track, so
|
|
24
|
+
* a surface that only just overflows — a short conversation, a panel with one
|
|
25
|
+
* page of content — paints a bar the height of its own viewport. The pill is
|
|
26
|
+
* capped at {@link PILL_MAX} instead, and never shorter than {@link PILL_MIN}.
|
|
27
|
+
*
|
|
28
|
+
* The pill is centred on the painted thumb it stands in for, and sits inside the
|
|
29
|
+
* track's own strip at the edge, so it is where the pointer expects: the host's
|
|
30
|
+
* thumb — invisible, but still laid out and still the thing that drags — is
|
|
31
|
+
* directly underneath it, and a drag that starts anywhere on the pill grabs
|
|
32
|
+
* that bar.
|
|
33
|
+
*
|
|
34
|
+
* Everything here is written on elements the host owns, so the disposer puts
|
|
35
|
+
* each mark back: attributes off, layer gone, listeners removed.
|
|
36
|
+
*/
|
|
37
|
+
/** Marks a surface whose bar is the floating pill rather than the track's ink. */
|
|
38
|
+
export declare const PILL_SURFACE_ATTRIBUTE = "data-ccd-scroll-pill";
|
|
39
|
+
/** Marks a surface in motion — and, on a pill, the pill that belongs to it. */
|
|
40
|
+
export declare const SCROLLING_ATTRIBUTE = "data-ccd-scrolling";
|
|
41
|
+
/** The one fixed layer every pill is painted in. */
|
|
42
|
+
export declare const PILL_LAYER_ATTRIBUTE = "data-ccd-scroll-layer";
|
|
43
|
+
/** Identifies one floating pill. */
|
|
44
|
+
export declare const PILL_ATTRIBUTE = "data-ccd-scroll-thumb";
|
|
45
|
+
/**
|
|
46
|
+
* How long a mark survives after the last scroll event. The reference's own
|
|
47
|
+
* overlay scroller fades out about this long after the wheel stops; long enough
|
|
48
|
+
* to read the position between two flicks, short enough that a resting window
|
|
49
|
+
* carries no ink.
|
|
50
|
+
*/
|
|
51
|
+
export declare const IDLE_MS = 800;
|
|
52
|
+
/**
|
|
53
|
+
* The surfaces the pill replaces the ink on. All five are page-level chrome the
|
|
54
|
+
* reader scrolls by the screenful; the host's popup cards and this plugin's own
|
|
55
|
+
* panels keep the painted bar (it appears while they scroll, like every other
|
|
56
|
+
* surface in the sheet's scope), because they are short-lived and their tracks
|
|
57
|
+
* are narrower.
|
|
58
|
+
* @param document - renderer document carrying the interface.
|
|
59
|
+
* @returns the selectors, resolved for the build on screen.
|
|
60
|
+
*/
|
|
61
|
+
export declare function pillSurfaces(document: Document): readonly string[];
|
|
62
|
+
/**
|
|
63
|
+
* Follow the interface's five page-level scrollers with a floating pill each,
|
|
64
|
+
* and mark every other scroller while it moves.
|
|
65
|
+
*
|
|
66
|
+
* @param document - renderer document carrying the interface.
|
|
67
|
+
* @param report - sink for observer failures; the host's own bars stay usable.
|
|
68
|
+
* @returns disposer that removes every pill, mark and listener.
|
|
69
|
+
*/
|
|
70
|
+
export declare function mountScrollPills(document: Document, report: (error: unknown) => void): Disposer;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Disposer } from '../contracts/ports.ts';
|
|
2
|
+
export interface SidebarNavigationIcons {
|
|
3
|
+
readonly newSession: string;
|
|
4
|
+
readonly plugins: string;
|
|
5
|
+
readonly routines: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const SIDEBAR_NAV_ATTRIBUTE = "data-ccd-nav";
|
|
8
|
+
/** Rename and decorate the native buttons without replacing React-owned nodes
|
|
9
|
+
* or handlers. Every write is conditional and reversible, including delayed
|
|
10
|
+
* mounts, locale changes, wide/rail rerenders and the native tooltip portals. */
|
|
11
|
+
export declare function mountSidebarNavigation(document: Document, icons: SidebarNavigationIcons, report: (error: unknown) => void): Disposer;
|
|
@@ -7,14 +7,31 @@ export declare const TRAILING_WIDTH_PROPERTY = "--ccd-trailing-width";
|
|
|
7
7
|
export declare const MODEL_MAX_WIDTH_PROPERTY = "--ccd-model-max-width";
|
|
8
8
|
/** The one gap the trailing cluster uses, read to budget the model button. */
|
|
9
9
|
export declare const CLUSTER_GAP_PROPERTY = "--ccd-cluster-gap";
|
|
10
|
+
/**
|
|
11
|
+
* Root attribute carrying whether the readouts are drawn, whose values are
|
|
12
|
+
* `on` and `off`.
|
|
13
|
+
*
|
|
14
|
+
* Both states are published rather than only the off one: the stylesheet that
|
|
15
|
+
* hides the cluster keys on `off`, so a document where this module never ran —
|
|
16
|
+
* a frame the observers could not attach to — keeps the host's own readouts
|
|
17
|
+
* instead of losing them to a stylesheet default it cannot correct.
|
|
18
|
+
*/
|
|
19
|
+
export declare const STATS_ATTRIBUTE = "data-ccd-composer-stats";
|
|
10
20
|
/**
|
|
11
21
|
* The responsive statistics cluster sits before the model selector. Its dock is
|
|
12
22
|
* a sibling of the card rather than a row child, so its wide-layout offset needs
|
|
13
23
|
* the trailing group's live width. Readouts and their detail dialogs stay owned
|
|
14
24
|
* by the host; wide columns mirror one short segment without changing the host label.
|
|
15
25
|
*
|
|
26
|
+
* The cluster is the configuration's to keep or drop (`features.composer-stats`,
|
|
27
|
+
* off by default): its state is published on the root for the stylesheet, which
|
|
28
|
+
* draws it only while the readouts are on. The width measurements below are
|
|
29
|
+
* outside that switch — they budget the row whether or not the readouts are
|
|
30
|
+
* drawn, and a hidden cluster simply hands its width back to the model button.
|
|
31
|
+
*
|
|
16
32
|
* @param document - renderer document carrying the Composer.
|
|
17
33
|
* @param report - sink for observer failures; the native readouts stay.
|
|
34
|
+
* @param readouts - whether the configuration asks for the plugin's readouts.
|
|
18
35
|
* @returns disposer that disconnects the observers and clears every property.
|
|
19
36
|
*/
|
|
20
|
-
export declare function mountComposerStats(document: Document, report: (error: unknown) => void): Disposer;
|
|
37
|
+
export declare function mountComposerStats(document: Document, report: (error: unknown) => void, readouts: boolean): Disposer;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { ViewOptionsPort, ViewOptionsSettingsPort } from '../contracts/ports.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The sidebar's view-options menu, driven instead of replaced.
|
|
4
|
+
*
|
|
5
|
+
* DSH's card is a `ui-primitives` `Menu` holding three labelled option groups —
|
|
6
|
+
* grouping mode, ordering, archived visibility — with the current option marked
|
|
7
|
+
* by the primitive's trailing check. The three values live in the workspace
|
|
8
|
+
* browser's own browser-local store, and nothing on the public face writes them:
|
|
9
|
+
* `UiWorkspace` (`dsh-client-ui-workspace/client` `navigation.d.ts`) publishes
|
|
10
|
+
* navigation, archive and directory operations only, and the store it keeps
|
|
11
|
+
* (`stores.d.ts`) exports its factory alone, so a second instance would hold a
|
|
12
|
+
* copy rather than the browser's state. The one handle that *does* write them is
|
|
13
|
+
* the host's own row: `WorkspaceBrowser`'s `onSelect` calls `setOpen(false)`
|
|
14
|
+
* after it applies the choice.
|
|
15
|
+
*
|
|
16
|
+
* So this module treats that card as the state API it effectively is. Opening
|
|
17
|
+
* the card reads it — the host's own menu is opened through the trigger's click
|
|
18
|
+
* with `DRIVING_ATTRIBUTE` keeping the sheet from drawing it — and choosing an
|
|
19
|
+
* option clicks the host's own row. Nothing is shown, nothing is synthesised
|
|
20
|
+
* beyond the clicks the host's control already answers, and the card the reader
|
|
21
|
+
* sees is the one `features/view-options` draws.
|
|
22
|
+
*
|
|
23
|
+
* Three details decide how the drive is written:
|
|
24
|
+
*
|
|
25
|
+
* - **The trigger's click is intercepted.** The host opens its card from the
|
|
26
|
+
* trigger's `onClick`; a listener on the button that stops propagation keeps
|
|
27
|
+
* React's delegated handler from running, so the card opens only when this
|
|
28
|
+
* module drives it. The one flag `driving` is what lets our own clicks
|
|
29
|
+
* through.
|
|
30
|
+
* - **React flushes a discrete event synchronously**, so the card is in the
|
|
31
|
+
* document by the time the driving click returns; `settle` still waits a
|
|
32
|
+
* microtask and then polls, because a build that mounts the card later must
|
|
33
|
+
* not turn into a failed read — the card is off screen either way.
|
|
34
|
+
* - **A card that is not the pinned shape hands the click back.** `readCard`
|
|
35
|
+
* refuses anything that is not three groups of at least two rows with exactly
|
|
36
|
+
* one check each, and the click that opened it is then passed to DSH so its
|
|
37
|
+
* own menu opens. A later build keeps its own interface instead of a card
|
|
38
|
+
* with nothing in it.
|
|
39
|
+
*/
|
|
40
|
+
/** Marks the host popup this module is driving; the sheet keeps it off screen. */
|
|
41
|
+
export declare const DRIVING_ATTRIBUTE = "data-ccd-view-options-driving";
|
|
42
|
+
/** Marks the trigger while this plugin's card is the one on screen. */
|
|
43
|
+
export declare const OPEN_ATTRIBUTE = "data-ccd-view-options-open";
|
|
44
|
+
/** The driver's own face, plus the release the mounting scope holds. */
|
|
45
|
+
export interface ViewOptionsDriver {
|
|
46
|
+
readonly port: ViewOptionsPort;
|
|
47
|
+
readonly settings: ViewOptionsSettingsPort;
|
|
48
|
+
/** Read persisted native preferences without showing either menu. */
|
|
49
|
+
inspect(): Promise<void>;
|
|
50
|
+
dispose(): void;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Watch the sidebar's view-options trigger and drive the host's card for it.
|
|
54
|
+
* @param document - renderer document carrying the sidebar and the portal.
|
|
55
|
+
* @param report - sink for observer failures; the native menu stays in charge.
|
|
56
|
+
* @returns the port the card reads through, and the release of every observer.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createViewOptionsDriver(document: Document, report: (error: unknown) => void): ViewOptionsDriver;
|
|
@@ -6,9 +6,50 @@ export declare const VIEW_WIDTH_PROPERTY = "--ccd-view-w";
|
|
|
6
6
|
/** Animate selection changes; layout corrections must be immediate. */
|
|
7
7
|
export declare const VIEW_DURATION_PROPERTY = "--ccd-view-duration";
|
|
8
8
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Marker on the tablist while it is parked in the sidebar's window-control row.
|
|
10
|
+
* `conversation.css` draws the fixed-position state from it; its absence means
|
|
11
|
+
* the host's own row (the header, or whatever the platform still offers) keeps
|
|
12
|
+
* the switcher.
|
|
13
13
|
*/
|
|
14
|
-
export declare
|
|
14
|
+
export declare const VIEW_DOCK_ATTRIBUTE = "data-ccd-view-dock";
|
|
15
|
+
/** Custom property carrying the parked tablist's inset from the window's right edge. */
|
|
16
|
+
export declare const VIEW_DOCK_RIGHT_PROPERTY = "--ccd-view-dock-right";
|
|
17
|
+
/** Marker on a tab whose label is drawn as artwork, naming the View it selects. */
|
|
18
|
+
export declare const VIEW_TAB_ATTRIBUTE = "data-ccd-view";
|
|
19
|
+
/** Marker on the artwork seat injected into a decorated tab. */
|
|
20
|
+
export declare const VIEW_GLYPH_ATTRIBUTE = "data-ccd-view-glyph";
|
|
21
|
+
/**
|
|
22
|
+
* The parked pill's inset from the sidebar column's right edge, in px. Measured
|
|
23
|
+
* at @2x on the reference: the column's divider sits 16 device px right of the
|
|
24
|
+
* pill's right edge (docs/issues/img/todo-sidebar-sessions-target.webp).
|
|
25
|
+
*/
|
|
26
|
+
export declare const VIEW_DOCK_INSET = 8;
|
|
27
|
+
/** Bundled artwork, one per shipped View; see features/conversation/view-switch-icons.ts. */
|
|
28
|
+
export interface ViewSwitchIcons {
|
|
29
|
+
readonly chat: string;
|
|
30
|
+
readonly trajectory: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Shape the host's View switcher, and park it where the reference has it.
|
|
34
|
+
*
|
|
35
|
+
* Three jobs, one observer:
|
|
36
|
+
* - Publish the selected segment's geometry for the sliding thumb
|
|
37
|
+
* (`--ccd-view-x` / `-w` / `-duration`), measured against the tablist.
|
|
38
|
+
* - Replace each shipped tab's text label with bundled artwork (the host draws
|
|
39
|
+
* the labels itself; a tab has no icon of its own), reversibly.
|
|
40
|
+
* - Park the tablist in the sidebar column's top-right corner — the reference
|
|
41
|
+
* keeps the View switcher on the window-control row — by measuring the
|
|
42
|
+
* column and publishing its inset (`data-ccd-view-dock` +
|
|
43
|
+
* `--ccd-view-dock-right`). The node stays where React put it: only CSS moves
|
|
44
|
+
* it, exactly as the macOS sidebar toggle is parked.
|
|
45
|
+
*
|
|
46
|
+
* The mutation observer covers tablist replacement, selection, frame drags
|
|
47
|
+
* (inline grid tracks) and the collapse flag, synchronously, including occluded
|
|
48
|
+
* windows where animation frames are throttled. A ResizeObserver on the sidebar
|
|
49
|
+
* column covers what no attribute says: the column's own width while the grid
|
|
50
|
+
* track animates between 0 and its settled value.
|
|
51
|
+
*
|
|
52
|
+
* @returns disposer that clears the observers, every injected node, every
|
|
53
|
+
* written attribute and every published property.
|
|
54
|
+
*/
|
|
55
|
+
export declare function mountViewSwitch(document: Document, icons: ViewSwitchIcons, report: (error: unknown) => void): Disposer;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import type { ThemePreference, ThemeRuntime } from '@deepseek-ai/dsh-client-ui-theme/client';
|
|
3
3
|
import type { UiWorkspace } from '@deepseek-ai/dsh-client-ui-workspace/client';
|
|
4
|
+
import type { ContextBreakdown, ContextBreakdownView, ContextEntry } from '../../shared/context.ts';
|
|
4
5
|
export type { ThemePreference };
|
|
5
6
|
export type Disposer = () => void;
|
|
6
7
|
/**
|
|
@@ -81,9 +82,16 @@ export interface SidebarRightPort {
|
|
|
81
82
|
}): void;
|
|
82
83
|
/** Focus a tab and the pane holding it; a missing tab is left alone. */
|
|
83
84
|
focus(tabId: string): void;
|
|
84
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* Open tab metadata across adopted Sessions — and, in the shipped face, the
|
|
87
|
+
* snapshot store behind it: the plugin's pane layer re-reads the layout
|
|
88
|
+
* whenever that list changes, which covers every way a tab opens, closes or
|
|
89
|
+
* changes pane. A build whose source cannot be observed is read once per
|
|
90
|
+
* mutation instead.
|
|
91
|
+
*/
|
|
85
92
|
readonly openTabs: {
|
|
86
93
|
getSnapshot(): readonly SidebarTabRecord[];
|
|
94
|
+
subscribe?(listener: () => void): Disposer;
|
|
87
95
|
};
|
|
88
96
|
/**
|
|
89
97
|
* Collapse the column, or expand it and focus its active dock pane.
|
|
@@ -94,6 +102,27 @@ export interface SidebarRightPort {
|
|
|
94
102
|
* keeps that row out rather than offering one that cannot act.
|
|
95
103
|
*/
|
|
96
104
|
toggleExpanded?(): void;
|
|
105
|
+
/**
|
|
106
|
+
* Take one docked tab out into a floating pane, and put one back.
|
|
107
|
+
*
|
|
108
|
+
* The panel's own renderer draws at most one pane or two horizontal panes —
|
|
109
|
+
* its layout component throws on anything else — so a vertical split or a
|
|
110
|
+
* third pane cannot be asked of it. A floating pane has no such limit (the
|
|
111
|
+
* layout stores a rectangle per float and the package allows any number), so
|
|
112
|
+
* `compat/right-panes.ts` builds the panel's panes out of these two calls and
|
|
113
|
+
* draws their boxes itself. A missing `float` means a build that cannot host
|
|
114
|
+
* panes at all: the panel keeps its tabs, exactly as it does today.
|
|
115
|
+
* Source: packages/client/ui-sidebar-right/src/client/controller.ts
|
|
116
|
+
* (`float(tabId, rect)`, `dock(paneId)`).
|
|
117
|
+
*/
|
|
118
|
+
float?(tabId: string, rect?: {
|
|
119
|
+
x: number;
|
|
120
|
+
y: number;
|
|
121
|
+
width: number;
|
|
122
|
+
height: number;
|
|
123
|
+
}): void;
|
|
124
|
+
/** Return one floating pane's tab to the panel's docked column. */
|
|
125
|
+
dock?(paneId: string): void;
|
|
97
126
|
}
|
|
98
127
|
/**
|
|
99
128
|
* The tab-type registry that face publishes as `ctx.sidebarRightTabs`. A header
|
|
@@ -124,6 +153,146 @@ export interface BlankSessionsPort {
|
|
|
124
153
|
/** Observe list replacements and row-state changes; returns the releaser. */
|
|
125
154
|
subscribe(listener: () => void): Disposer;
|
|
126
155
|
}
|
|
156
|
+
/** One group of the host's view-options menu, as the host drew it. */
|
|
157
|
+
export interface ViewOptionsGroupRead {
|
|
158
|
+
/** The heading the host drew above this group, in the document's language. */
|
|
159
|
+
readonly label: string;
|
|
160
|
+
/** Every row's own label, in the host's order. */
|
|
161
|
+
readonly labels: readonly string[];
|
|
162
|
+
/** Index of the row the host marks as current, or −1 when none is marked. */
|
|
163
|
+
readonly selected: number;
|
|
164
|
+
}
|
|
165
|
+
/** The host's view-options menu, read out of its own card. */
|
|
166
|
+
export interface ViewOptionsRead {
|
|
167
|
+
/** The three groups in the host's own order: group by, order by, archived filter. */
|
|
168
|
+
readonly groups: readonly ViewOptionsGroupRead[];
|
|
169
|
+
}
|
|
170
|
+
/** Which of the host's three groups a choice belongs to. */
|
|
171
|
+
export type ViewOptionsGroup = 0 | 1 | 2;
|
|
172
|
+
/** What the card is drawn from: whether it is up, what it hangs from, and the
|
|
173
|
+
host's three values as they were read when it opened. */
|
|
174
|
+
export interface ViewOptionsSnapshot {
|
|
175
|
+
readonly open: boolean;
|
|
176
|
+
readonly anchor: Element | null;
|
|
177
|
+
/** Null before the first open, and after the host's card could not be read. */
|
|
178
|
+
readonly values: ViewOptionsRead | null;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The sidebar's view-options menu, as this plugin's card needs it.
|
|
182
|
+
*
|
|
183
|
+
* DSH keeps the three view settings in the browser and publishes no way to read
|
|
184
|
+
* or write them, so the only handle is the host's own menu: opening this card
|
|
185
|
+
* reads it, and `choose` clicks one of its rows. `getSnapshot`/`subscribe`
|
|
186
|
+
* carry the whole of what the DOM side owns — the trigger, whether the card is
|
|
187
|
+
* up, and the values read for it.
|
|
188
|
+
*/
|
|
189
|
+
export interface ViewOptionsPort {
|
|
190
|
+
/** The current state; the object identity changes only when the state does. */
|
|
191
|
+
getSnapshot(): ViewOptionsSnapshot;
|
|
192
|
+
/** Observe opening, closing, and the trigger being replaced. */
|
|
193
|
+
subscribe(listener: () => void): Disposer;
|
|
194
|
+
/** Put the card away; the trigger's own state follows. */
|
|
195
|
+
close(): void;
|
|
196
|
+
/** Choose one option by driving the host's own row; false when it could not be reached. */
|
|
197
|
+
choose(group: ViewOptionsGroup, index: number): Promise<boolean>;
|
|
198
|
+
}
|
|
199
|
+
/** Native view preferences also used by the sidebar's empty-group policy. */
|
|
200
|
+
export interface ViewOptionsSettingsPort {
|
|
201
|
+
getSnapshot(): ViewOptionsRead | null;
|
|
202
|
+
subscribe(listener: () => void): Disposer;
|
|
203
|
+
}
|
|
204
|
+
/** Authoritative membership, including sessions omitted from collapsed DOM. */
|
|
205
|
+
export interface SidebarSessionsPort {
|
|
206
|
+
/** Durable history across all groups and filters; null while loading. */
|
|
207
|
+
hasHistory(): boolean | null;
|
|
208
|
+
/** Null while either catalog is still arriving; null filter keeps all history. */
|
|
209
|
+
populatedGroups(filter: number | null, nested: boolean): ReadonlySet<string> | null;
|
|
210
|
+
subscribe(listener: () => void): Disposer;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* One session's context readings, as the client session list holds them.
|
|
214
|
+
*
|
|
215
|
+
* The host computes all of this itself: `contextPressure` is the ring's own
|
|
216
|
+
* occupancy and `contextBreakdown` its three-way composition, and both travel
|
|
217
|
+
* to the browser as wire projections on the session list. The panel reads them
|
|
218
|
+
* rather than recomputing them, so its header can never disagree with the ring
|
|
219
|
+
* beside it.
|
|
220
|
+
*/
|
|
221
|
+
export interface ContextProjectionRead {
|
|
222
|
+
/** `contextPressure.contextWindow`. */
|
|
223
|
+
readonly window: number;
|
|
224
|
+
/** Occupancy: `projectedTokens ?? pressureTokens`. */
|
|
225
|
+
readonly used: number;
|
|
226
|
+
/** `contextBreakdown.systemTokens`. */
|
|
227
|
+
readonly systemTokens: number;
|
|
228
|
+
/** `contextBreakdown.toolsTokens`. */
|
|
229
|
+
readonly toolsTokens: number;
|
|
230
|
+
/** `contextBreakdown.messageTokens`. */
|
|
231
|
+
readonly messageTokens: number;
|
|
232
|
+
/** This plugin's own `ccdContext` value, or null while it is not there. */
|
|
233
|
+
readonly breakdown: ContextBreakdownView | null;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* The host's context projections, read off the client session list.
|
|
237
|
+
*
|
|
238
|
+
* `ctx.sessions.list` publishes every registered wire value per session
|
|
239
|
+
* (`SessionListState.projectionsBySession`) and carries rows for sessions that
|
|
240
|
+
* were never opened, so this is a plain snapshot read with no I/O. A build that
|
|
241
|
+
* does not publish the list yields null and the ring keeps DSH's own panel.
|
|
242
|
+
*/
|
|
243
|
+
export interface ContextProjectionPort {
|
|
244
|
+
/** One session's readings, or null when the list has nothing for it yet. */
|
|
245
|
+
read(sessionId: string): ContextProjectionRead | null;
|
|
246
|
+
/** Observe list replacements and live projection frames. */
|
|
247
|
+
subscribe(listener: () => void): Disposer;
|
|
248
|
+
}
|
|
249
|
+
/** One entry of a drill-down group, as the panel draws it. */
|
|
250
|
+
export interface ContextDetailGroup {
|
|
251
|
+
/** The group's own name, in the document's language. */
|
|
252
|
+
readonly label: string;
|
|
253
|
+
/** The group's total, which is the authoritative number above it. */
|
|
254
|
+
readonly tokens: number;
|
|
255
|
+
/** The rows, largest first. */
|
|
256
|
+
readonly rows: readonly ContextEntry[];
|
|
257
|
+
}
|
|
258
|
+
/** What the context panel is drawn from. */
|
|
259
|
+
export interface ContextPanelSnapshot {
|
|
260
|
+
readonly open: boolean;
|
|
261
|
+
/** The ring trigger the panel hangs from; null before the shell renders it. */
|
|
262
|
+
readonly anchor: Element | null;
|
|
263
|
+
/** The whole reading, or null while the ring has no numbers for this session. */
|
|
264
|
+
readonly breakdown: ContextBreakdown | null;
|
|
265
|
+
/** `mcp__` tools, largest first. */
|
|
266
|
+
readonly mcp: readonly ContextEntry[];
|
|
267
|
+
/** Built-in tools, largest first. */
|
|
268
|
+
readonly tools: readonly ContextEntry[];
|
|
269
|
+
/** Retained instruction files, largest first. */
|
|
270
|
+
readonly files: readonly ContextEntry[];
|
|
271
|
+
/** Retained skill-catalog entries, largest first. */
|
|
272
|
+
readonly skills: readonly ContextEntry[];
|
|
273
|
+
/** The panel's own expansion; it lives only while the panel is open. */
|
|
274
|
+
readonly expanded: boolean;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* The context ring's breakdown panel, as this plugin's card needs it.
|
|
278
|
+
*
|
|
279
|
+
* DSH opens its own 264px panel from the ring's click, and that panel is the
|
|
280
|
+
* whole of its own affordance — no public face reads or drives it. So this port
|
|
281
|
+
* owns the interaction instead: the driver intercepts the trigger's click
|
|
282
|
+
* (DSH's handler is React-delegated at the root, so stopping the event on the
|
|
283
|
+
* button keeps the host's panel from ever opening), holds the open and expanded
|
|
284
|
+
* state, and publishes the host's own numbers beside this plugin's rows.
|
|
285
|
+
*/
|
|
286
|
+
export interface ContextPanelPort {
|
|
287
|
+
/** The current state; the object identity changes only when the state does. */
|
|
288
|
+
getSnapshot(): ContextPanelSnapshot;
|
|
289
|
+
/** Observe opening, closing, expanding, and the trigger being replaced. */
|
|
290
|
+
subscribe(listener: () => void): Disposer;
|
|
291
|
+
/** Put the panel away; the trigger's own state follows. */
|
|
292
|
+
close(): void;
|
|
293
|
+
/** Flip the panel between its collapsed and expanded states. */
|
|
294
|
+
toggleExpanded(): void;
|
|
295
|
+
}
|
|
127
296
|
/** Actual SDK types, never a second definition of DSH component props. */
|
|
128
297
|
export interface HostServices {
|
|
129
298
|
readonly slots: Context['slots'];
|
|
@@ -142,6 +311,12 @@ export interface HostServices {
|
|
|
142
311
|
* session list; a null port leaves the native rows exactly as they are.
|
|
143
312
|
*/
|
|
144
313
|
readonly blankSessions: BlankSessionsPort | null;
|
|
314
|
+
readonly sidebarSessions: SidebarSessionsPort | null;
|
|
315
|
+
/**
|
|
316
|
+
* The host's context projections, or null on a build that does not publish
|
|
317
|
+
* the session list; a null port leaves the ring's own panel in charge.
|
|
318
|
+
*/
|
|
319
|
+
readonly contextProjections: ContextProjectionPort | null;
|
|
145
320
|
/** The settings transport carrying this plugin's own configuration section. */
|
|
146
321
|
readonly configForms: ConfigFormsPort;
|
|
147
322
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { ContextPanelPort } from '../../contracts/ports.ts';
|
|
3
|
+
export interface ContextPanelProps {
|
|
4
|
+
readonly port: ContextPanelPort;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The panel, in whichever of its two states the port says.
|
|
8
|
+
*
|
|
9
|
+
* @param props - the driver's port.
|
|
10
|
+
* @returns the card, or null while it is closed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function ContextPanel({ port }: ContextPanelProps): ReactElement | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { FeatureEnvironment } from '../../contracts/feature.ts';
|
|
3
|
+
import type { CleanupScope } from '../../core/cleanup.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Put the context ring's breakdown panel in the frame-wide overlay.
|
|
6
|
+
*
|
|
7
|
+
* The panel is this plugin's own surface, so it is registered like one: a React
|
|
8
|
+
* entry in `shell.overlay`, holding the driver that watches the ring's trigger
|
|
9
|
+
* and takes its click (`compat/context-panel.ts`). Nothing here writes session
|
|
10
|
+
* state — the numbers are the host's own projections, read off the session list
|
|
11
|
+
* — so a write can never re-mount the plugin behind the panel.
|
|
12
|
+
*
|
|
13
|
+
* A build that does not publish the session list yields no port, and the ring
|
|
14
|
+
* keeps DSH's own panel: the feature loses a richer reading, not the control.
|
|
15
|
+
*
|
|
16
|
+
* @param ctx - client root context carrying the slot service.
|
|
17
|
+
* @param environment - configuration, ports and logging for this activation.
|
|
18
|
+
* @param cleanup - scope owning the styles, the driver and the registration.
|
|
19
|
+
*/
|
|
20
|
+
export declare function mountContextPanel(ctx: Context, environment: FeatureEnvironment, cleanup: CleanupScope): void;
|
|
@@ -5,9 +5,11 @@ import type { ImplementedFeature } from '../../contracts/feature.ts';
|
|
|
5
5
|
* adapts the header chrome, the transcript column and the message surfaces.
|
|
6
6
|
*
|
|
7
7
|
* The header keeps DSH's own View switcher: the host still owns which View is
|
|
8
|
-
* selected and how it is rendered
|
|
9
|
-
*
|
|
10
|
-
* stylesheet can slide the thumb onto it
|
|
8
|
+
* selected and how it is rendered. This module swaps the two shipped Views'
|
|
9
|
+
* text labels for bundled artwork, publishes the selected segment's geometry so
|
|
10
|
+
* the stylesheet can slide the thumb onto it, and parks the tablist in the
|
|
11
|
+
* sidebar's window-control row while that column has a corner to hold it
|
|
12
|
+
* (`compat/view-switch.ts`).
|
|
11
13
|
*
|
|
12
14
|
* The transcript's own edge fade is published the same way: the host owns the
|
|
13
15
|
* scroll position, `compat/conversation-fade.ts` turns it into two attributes,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two View switcher glyphs, bundled as trusted static markup.
|
|
3
|
+
*
|
|
4
|
+
* Drawn to the reference's own segments (docs/issues/img/todo-sidebar-sessions-target.webp,
|
|
5
|
+
* @2x): a pair of speech bubbles for the chat View and the `</>` pair for the
|
|
6
|
+
* trajectory View, both on the CCD 16 grid — 1–1.2px stroke (each glyph's own
|
|
7
|
+
* weight read off the reference), round caps and joins, `currentColor` ink,
|
|
8
|
+
* ink box ≈ 12.5 × 11px inside the 16px artwork.
|
|
9
|
+
*/
|
|
10
|
+
export declare const VIEW_SWITCH_ICONS: Readonly<{
|
|
11
|
+
chat: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M10.4 8.3a2.6 2.6 0 0 1-2.6 2.6H5.7L3.3 12.5V5.9a2.6 2.6 0 0 1 2.6-2.6h1.9a2.6 2.6 0 0 1 2.6 2.6Z\"/>\n <path d=\"M10.3 5.9H12.1a2.1 2.1 0 0 1 2.1 2.1V10.4a2.1 2.1 0 0 1-2.1 2.1H10.25L9.1 13.1\"/>\n</svg>";
|
|
12
|
+
trajectory: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M5.3 5.8 3.05 8l2.25 2.2\"/>\n <path d=\"M9.1 3.8 6.9 12.2\"/>\n <path d=\"M10.7 5.8 12.95 8l-2.25 2.2\"/>\n</svg>";
|
|
13
|
+
}>;
|
|
@@ -14,6 +14,9 @@ export declare const zh: {
|
|
|
14
14
|
readonly 'section.features': '模块';
|
|
15
15
|
readonly 'section.appearance': '外观';
|
|
16
16
|
readonly 'section.fonts': '字体';
|
|
17
|
+
readonly 'section.view': '视图';
|
|
18
|
+
readonly 'field.showEmptyGroups': '显示空分组';
|
|
19
|
+
readonly 'hint.showEmptyGroups': '关掉时没有会话的工作区不再显示;视图选项菜单里的同一项';
|
|
17
20
|
readonly 'field.enabled': '启用 CCD 风格界面';
|
|
18
21
|
readonly 'field.theme': '主题';
|
|
19
22
|
readonly 'theme.system': '跟随系统';
|
|
@@ -49,6 +52,10 @@ export declare const zh: {
|
|
|
49
52
|
readonly 'feature.tool-calls': '工具调用展示';
|
|
50
53
|
readonly 'feature.statistics': '统计卡片';
|
|
51
54
|
readonly 'feature.composer-pet': '输入框小鲸鱼';
|
|
55
|
+
readonly 'feature.composer-stats': '状态栏统计读数';
|
|
56
|
+
readonly 'hint.composer-stats': '输出速度与缓存命中率,关掉时这两项不显示(默认)';
|
|
57
|
+
readonly 'feature.context-panel': '上下文分解面板';
|
|
58
|
+
readonly 'hint.context-panel': '点环打开的分段面板;关掉时环点开的是 DSH 原生面板';
|
|
52
59
|
};
|
|
53
60
|
export type SettingsKey = keyof typeof zh;
|
|
54
61
|
/** English dictionary; every Chinese key has a counterpart. */
|