dsh-claude-desktop-theme 0.2.0 → 0.3.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 +69 -51
- package/lib/client.js +2342 -270
- package/lib/index.js +387 -20
- package/lib/types/client/compat/adapter.d.ts +22 -1
- 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/host-dom.d.ts +64 -0
- package/lib/types/client/compat/permission-menu.d.ts +88 -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/contracts/ports.d.ts +147 -0
- 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/settings/locales.d.ts +7 -0
- package/lib/types/client/features/sidebar/navigation-icons.d.ts +6 -0
- 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/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
|
@@ -56,6 +56,7 @@ export declare const HOST: Readonly<{
|
|
|
56
56
|
/** SidebarRoot.module.css: expanded macOS window-chrome toggle. */
|
|
57
57
|
readonly sidebarToggle: '._3WPZCG_toggle';
|
|
58
58
|
readonly sidebarNewSession: '._3WPZCG_newSession';
|
|
59
|
+
readonly sidebarNewSessionContent: '._3WPZCG_newSessionContent';
|
|
59
60
|
readonly sidebarNewSessionLabel: '._3WPZCG_newSessionLabel';
|
|
60
61
|
readonly sidebarNewSessionShortcut: '._3WPZCG_newSessionShortcut';
|
|
61
62
|
readonly sidebarPanelList: '._3WPZCG_panelList';
|
|
@@ -70,6 +71,22 @@ export declare const HOST: Readonly<{
|
|
|
70
71
|
readonly browserSectionHeader: '._7514NG_sectionHeader';
|
|
71
72
|
readonly browserSectionLabel: '._7514NG_sectionLabel';
|
|
72
73
|
readonly browserListArea: '._7514NG_listArea';
|
|
74
|
+
/**
|
|
75
|
+
* WorkspaceBrowser.module.css: the section header's view-options trigger —
|
|
76
|
+
* the one control there that is an `iconButton` *and* carries `wide` (its
|
|
77
|
+
* neighbours are `searchButton` and a plain `iconButton`), and the list class
|
|
78
|
+
* its card puts on the `Menu` surface. `compat/view-options.ts` reads the
|
|
79
|
+
* values out of that card and clicks its rows; the card itself is kept off
|
|
80
|
+
* screen while it does.
|
|
81
|
+
*/
|
|
82
|
+
readonly viewOptionsTrigger: '._7514NG_sectionHeader ._7514NG_iconButton._7514NG_wide';
|
|
83
|
+
readonly viewOptionsMenu: '._7514NG_viewOptionsMenu';
|
|
84
|
+
/**
|
|
85
|
+
* WorkspaceBrowser.module.css: one Workspace's row container — the box that
|
|
86
|
+
* holds its Workspace row, its nested groups and its Session rows, and the
|
|
87
|
+
* box `compat/empty-groups.ts` hides when the group has nothing to show.
|
|
88
|
+
*/
|
|
89
|
+
readonly workspaceGroup: '._7514NG_groupSection';
|
|
73
90
|
readonly settingsTrigger: '.Dws9Sa_trigger';
|
|
74
91
|
readonly settingsTriggerRow: '.Dws9Sa_triggerRow';
|
|
75
92
|
readonly accountTrigger: '.ZogL4G_trigger';
|
|
@@ -104,6 +121,12 @@ export declare const HOST: Readonly<{
|
|
|
104
121
|
readonly assistantMarkdown: '.gKv1-q_root';
|
|
105
122
|
readonly markdownBody: '._markdown_1ypvv_5:not([data-markdown-variant="compact"])';
|
|
106
123
|
readonly markdownFileMention: '._fileMention_1ypvv_85';
|
|
124
|
+
/**
|
|
125
|
+
* MarkdownText.module.css: the category glyph the host seats inside a URL
|
|
126
|
+
* anchor (and inside file mentions and URL-promoted inline code). `conversation.css`
|
|
127
|
+
* hides the anchor's copy; the reference draws link text alone.
|
|
128
|
+
*/
|
|
129
|
+
readonly markdownLinkIcon: '._linkIcon_1ypvv_94';
|
|
107
130
|
readonly conversationScroll: '.ST7X_W_scrollBody';
|
|
108
131
|
/** ChatView.module.css: the transcript's own scroll column, inside the page's
|
|
109
132
|
scroll viewport, and the two shells of the floating jump-to-bottom control
|
|
@@ -156,6 +179,17 @@ export declare const HOST: Readonly<{
|
|
|
156
179
|
readonly modelSelectEffort: '.cl2Rlq_triggerEffort';
|
|
157
180
|
/** PermissionSelect.module.css: compact permission text, keeping its button. */
|
|
158
181
|
readonly permissionSelectLabel: '.wXeviG_triggerLabel';
|
|
182
|
+
/** PermissionSelect.module.css: the control itself, in the status bar and in
|
|
183
|
+
the new-session card alike — `compat/permission-menu.ts` reads the mode's
|
|
184
|
+
name off it, and writes the card's own wording back. */
|
|
185
|
+
readonly permissionSelectTrigger: '.wXeviG_trigger';
|
|
186
|
+
/** PermissionSelect.module.css: the one preset badge DSH marks (`EXP`), on
|
|
187
|
+
the trigger as well as on the option row it belongs to. */
|
|
188
|
+
readonly permissionSelectBadge: '.wXeviG_badge';
|
|
189
|
+
/** PermissionSelect.module.css: the badge row's own name, told apart from the
|
|
190
|
+
badge beside it — the row label carries both, and only this one is the
|
|
191
|
+
preset's name. */
|
|
192
|
+
readonly permissionSelectOptionLabelText: '.wXeviG_optionLabelText';
|
|
159
193
|
/** TeamAction.module.css: native team dialog entry, retaining its label at every width. */
|
|
160
194
|
readonly teamActionTrigger: '._2tNPVa_trigger';
|
|
161
195
|
readonly teamActionLabel: '._2tNPVa_triggerLabel';
|
|
@@ -169,6 +203,15 @@ export declare const HOST: Readonly<{
|
|
|
169
203
|
readonly statsSeparator: '.OpZ85W_sep';
|
|
170
204
|
readonly statsPill: '.OpZ85W_pill';
|
|
171
205
|
readonly contextMeterTrigger: '.y0jqnG_trigger';
|
|
206
|
+
/**
|
|
207
|
+
* ContextMeter.module.css: the host's own click-open breakdown panel. It is a
|
|
208
|
+
* `position: fixed` portal on `document.body` at `z-index: 1100` rather than a
|
|
209
|
+
* native popover, so this plugin's panel — a top-layer popover — paints over
|
|
210
|
+
* it; the marker the driver writes is the belt to that braces, and it keeps
|
|
211
|
+
* the host's panel out of the paint if a click ever reaches DSH's own
|
|
212
|
+
* handler. `compat/context-panel.ts` is the only reader.
|
|
213
|
+
*/
|
|
214
|
+
readonly contextMeterPanel: '.y0jqnG_panel';
|
|
172
215
|
readonly heroRoot: '.bocITq_root';
|
|
173
216
|
readonly heroHeadline: '.bocITq_headline';
|
|
174
217
|
readonly heroWorkspaceChip: '.bocITq_workspace';
|
|
@@ -180,6 +223,20 @@ export declare const HOST: Readonly<{
|
|
|
180
223
|
/** Every menu surface the `Menu` primitive renders, portal or in place. */
|
|
181
224
|
readonly menu: '[role="menu"]';
|
|
182
225
|
readonly menuItem: '[role="menuitem"]';
|
|
226
|
+
/** Menu.module.css: the row's own label seat, the one box this plugin puts a
|
|
227
|
+
second line after (`compat/permission-menu.ts`). The `_4ub78_` prefix is
|
|
228
|
+
the static web frontend's bundle, identical in both installers, so it needs
|
|
229
|
+
no entry in `host-builds.ts` — the same fact `tokens.css` records for the
|
|
230
|
+
primitive's check mark. */
|
|
231
|
+
readonly menuItemLabel: '._itemLabel_4ub78_190';
|
|
232
|
+
/** Menu.module.css: the trailing mark a *selected* row draws — `Menu` renders
|
|
233
|
+
it only for the row whose id is in `selectedIds`, so its presence is how
|
|
234
|
+
`compat/view-options.ts` reads which option is current. */
|
|
235
|
+
readonly menuItemCheck: '._check_4ub78_179';
|
|
236
|
+
/** Menu.module.css: the scrolling row group inside the card — where the
|
|
237
|
+
permission card's heading is written, above the rows and outside the
|
|
238
|
+
keyboard's walk (that walk collects `button`s only). */
|
|
239
|
+
readonly menuViewport: '._viewport_4ub78_19';
|
|
183
240
|
}>;
|
|
184
241
|
/**
|
|
185
242
|
* Anchors that must exist before a feature may touch the host DOM. They are
|
|
@@ -220,6 +277,13 @@ export declare const ANCHOR: Readonly<{
|
|
|
220
277
|
* with a Session, so this is the seat the no-session pet is measured from.
|
|
221
278
|
*/
|
|
222
279
|
readonly composerCardHero: ".ST7X_W_root[data-phase=\"hero\"] [data-composer-card]";
|
|
280
|
+
/**
|
|
281
|
+
* ConversationRoot.tsx: the conversation body, carrying the Session identity
|
|
282
|
+
* the context panel reads its projections by. The Composer seat — and so the
|
|
283
|
+
* context ring — is a descendant, which is what makes `closest()` from the
|
|
284
|
+
* trigger enough. The host's own stable hook rather than the hashed class.
|
|
285
|
+
*/
|
|
286
|
+
readonly conversationSession: '[data-conversation-session]';
|
|
223
287
|
}>;
|
|
224
288
|
/** One document's selector table, resolved for the build that document runs. */
|
|
225
289
|
export type HostSelectors = Readonly<Record<keyof typeof HOST, string>>;
|
|
@@ -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,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;
|
|
@@ -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
|
/**
|
|
@@ -124,6 +125,146 @@ export interface BlankSessionsPort {
|
|
|
124
125
|
/** Observe list replacements and row-state changes; returns the releaser. */
|
|
125
126
|
subscribe(listener: () => void): Disposer;
|
|
126
127
|
}
|
|
128
|
+
/** One group of the host's view-options menu, as the host drew it. */
|
|
129
|
+
export interface ViewOptionsGroupRead {
|
|
130
|
+
/** The heading the host drew above this group, in the document's language. */
|
|
131
|
+
readonly label: string;
|
|
132
|
+
/** Every row's own label, in the host's order. */
|
|
133
|
+
readonly labels: readonly string[];
|
|
134
|
+
/** Index of the row the host marks as current, or −1 when none is marked. */
|
|
135
|
+
readonly selected: number;
|
|
136
|
+
}
|
|
137
|
+
/** The host's view-options menu, read out of its own card. */
|
|
138
|
+
export interface ViewOptionsRead {
|
|
139
|
+
/** The three groups in the host's own order: group by, order by, archived filter. */
|
|
140
|
+
readonly groups: readonly ViewOptionsGroupRead[];
|
|
141
|
+
}
|
|
142
|
+
/** Which of the host's three groups a choice belongs to. */
|
|
143
|
+
export type ViewOptionsGroup = 0 | 1 | 2;
|
|
144
|
+
/** What the card is drawn from: whether it is up, what it hangs from, and the
|
|
145
|
+
host's three values as they were read when it opened. */
|
|
146
|
+
export interface ViewOptionsSnapshot {
|
|
147
|
+
readonly open: boolean;
|
|
148
|
+
readonly anchor: Element | null;
|
|
149
|
+
/** Null before the first open, and after the host's card could not be read. */
|
|
150
|
+
readonly values: ViewOptionsRead | null;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The sidebar's view-options menu, as this plugin's card needs it.
|
|
154
|
+
*
|
|
155
|
+
* DSH keeps the three view settings in the browser and publishes no way to read
|
|
156
|
+
* or write them, so the only handle is the host's own menu: opening this card
|
|
157
|
+
* reads it, and `choose` clicks one of its rows. `getSnapshot`/`subscribe`
|
|
158
|
+
* carry the whole of what the DOM side owns — the trigger, whether the card is
|
|
159
|
+
* up, and the values read for it.
|
|
160
|
+
*/
|
|
161
|
+
export interface ViewOptionsPort {
|
|
162
|
+
/** The current state; the object identity changes only when the state does. */
|
|
163
|
+
getSnapshot(): ViewOptionsSnapshot;
|
|
164
|
+
/** Observe opening, closing, and the trigger being replaced. */
|
|
165
|
+
subscribe(listener: () => void): Disposer;
|
|
166
|
+
/** Put the card away; the trigger's own state follows. */
|
|
167
|
+
close(): void;
|
|
168
|
+
/** Choose one option by driving the host's own row; false when it could not be reached. */
|
|
169
|
+
choose(group: ViewOptionsGroup, index: number): Promise<boolean>;
|
|
170
|
+
}
|
|
171
|
+
/** Native view preferences also used by the sidebar's empty-group policy. */
|
|
172
|
+
export interface ViewOptionsSettingsPort {
|
|
173
|
+
getSnapshot(): ViewOptionsRead | null;
|
|
174
|
+
subscribe(listener: () => void): Disposer;
|
|
175
|
+
}
|
|
176
|
+
/** Authoritative membership, including sessions omitted from collapsed DOM. */
|
|
177
|
+
export interface SidebarSessionsPort {
|
|
178
|
+
/** Durable history across all groups and filters; null while loading. */
|
|
179
|
+
hasHistory(): boolean | null;
|
|
180
|
+
/** Null while either catalog is still arriving; null filter keeps all history. */
|
|
181
|
+
populatedGroups(filter: number | null, nested: boolean): ReadonlySet<string> | null;
|
|
182
|
+
subscribe(listener: () => void): Disposer;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* One session's context readings, as the client session list holds them.
|
|
186
|
+
*
|
|
187
|
+
* The host computes all of this itself: `contextPressure` is the ring's own
|
|
188
|
+
* occupancy and `contextBreakdown` its three-way composition, and both travel
|
|
189
|
+
* to the browser as wire projections on the session list. The panel reads them
|
|
190
|
+
* rather than recomputing them, so its header can never disagree with the ring
|
|
191
|
+
* beside it.
|
|
192
|
+
*/
|
|
193
|
+
export interface ContextProjectionRead {
|
|
194
|
+
/** `contextPressure.contextWindow`. */
|
|
195
|
+
readonly window: number;
|
|
196
|
+
/** Occupancy: `projectedTokens ?? pressureTokens`. */
|
|
197
|
+
readonly used: number;
|
|
198
|
+
/** `contextBreakdown.systemTokens`. */
|
|
199
|
+
readonly systemTokens: number;
|
|
200
|
+
/** `contextBreakdown.toolsTokens`. */
|
|
201
|
+
readonly toolsTokens: number;
|
|
202
|
+
/** `contextBreakdown.messageTokens`. */
|
|
203
|
+
readonly messageTokens: number;
|
|
204
|
+
/** This plugin's own `ccdContext` value, or null while it is not there. */
|
|
205
|
+
readonly breakdown: ContextBreakdownView | null;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The host's context projections, read off the client session list.
|
|
209
|
+
*
|
|
210
|
+
* `ctx.sessions.list` publishes every registered wire value per session
|
|
211
|
+
* (`SessionListState.projectionsBySession`) and carries rows for sessions that
|
|
212
|
+
* were never opened, so this is a plain snapshot read with no I/O. A build that
|
|
213
|
+
* does not publish the list yields null and the ring keeps DSH's own panel.
|
|
214
|
+
*/
|
|
215
|
+
export interface ContextProjectionPort {
|
|
216
|
+
/** One session's readings, or null when the list has nothing for it yet. */
|
|
217
|
+
read(sessionId: string): ContextProjectionRead | null;
|
|
218
|
+
/** Observe list replacements and live projection frames. */
|
|
219
|
+
subscribe(listener: () => void): Disposer;
|
|
220
|
+
}
|
|
221
|
+
/** One entry of a drill-down group, as the panel draws it. */
|
|
222
|
+
export interface ContextDetailGroup {
|
|
223
|
+
/** The group's own name, in the document's language. */
|
|
224
|
+
readonly label: string;
|
|
225
|
+
/** The group's total, which is the authoritative number above it. */
|
|
226
|
+
readonly tokens: number;
|
|
227
|
+
/** The rows, largest first. */
|
|
228
|
+
readonly rows: readonly ContextEntry[];
|
|
229
|
+
}
|
|
230
|
+
/** What the context panel is drawn from. */
|
|
231
|
+
export interface ContextPanelSnapshot {
|
|
232
|
+
readonly open: boolean;
|
|
233
|
+
/** The ring trigger the panel hangs from; null before the shell renders it. */
|
|
234
|
+
readonly anchor: Element | null;
|
|
235
|
+
/** The whole reading, or null while the ring has no numbers for this session. */
|
|
236
|
+
readonly breakdown: ContextBreakdown | null;
|
|
237
|
+
/** `mcp__` tools, largest first. */
|
|
238
|
+
readonly mcp: readonly ContextEntry[];
|
|
239
|
+
/** Built-in tools, largest first. */
|
|
240
|
+
readonly tools: readonly ContextEntry[];
|
|
241
|
+
/** Retained instruction files, largest first. */
|
|
242
|
+
readonly files: readonly ContextEntry[];
|
|
243
|
+
/** Retained skill-catalog entries, largest first. */
|
|
244
|
+
readonly skills: readonly ContextEntry[];
|
|
245
|
+
/** The panel's own expansion; it lives only while the panel is open. */
|
|
246
|
+
readonly expanded: boolean;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* The context ring's breakdown panel, as this plugin's card needs it.
|
|
250
|
+
*
|
|
251
|
+
* DSH opens its own 264px panel from the ring's click, and that panel is the
|
|
252
|
+
* whole of its own affordance — no public face reads or drives it. So this port
|
|
253
|
+
* owns the interaction instead: the driver intercepts the trigger's click
|
|
254
|
+
* (DSH's handler is React-delegated at the root, so stopping the event on the
|
|
255
|
+
* button keeps the host's panel from ever opening), holds the open and expanded
|
|
256
|
+
* state, and publishes the host's own numbers beside this plugin's rows.
|
|
257
|
+
*/
|
|
258
|
+
export interface ContextPanelPort {
|
|
259
|
+
/** The current state; the object identity changes only when the state does. */
|
|
260
|
+
getSnapshot(): ContextPanelSnapshot;
|
|
261
|
+
/** Observe opening, closing, expanding, and the trigger being replaced. */
|
|
262
|
+
subscribe(listener: () => void): Disposer;
|
|
263
|
+
/** Put the panel away; the trigger's own state follows. */
|
|
264
|
+
close(): void;
|
|
265
|
+
/** Flip the panel between its collapsed and expanded states. */
|
|
266
|
+
toggleExpanded(): void;
|
|
267
|
+
}
|
|
127
268
|
/** Actual SDK types, never a second definition of DSH component props. */
|
|
128
269
|
export interface HostServices {
|
|
129
270
|
readonly slots: Context['slots'];
|
|
@@ -142,6 +283,12 @@ export interface HostServices {
|
|
|
142
283
|
* session list; a null port leaves the native rows exactly as they are.
|
|
143
284
|
*/
|
|
144
285
|
readonly blankSessions: BlankSessionsPort | null;
|
|
286
|
+
readonly sidebarSessions: SidebarSessionsPort | null;
|
|
287
|
+
/**
|
|
288
|
+
* The host's context projections, or null on a build that does not publish
|
|
289
|
+
* the session list; a null port leaves the ring's own panel in charge.
|
|
290
|
+
*/
|
|
291
|
+
readonly contextProjections: ContextProjectionPort | null;
|
|
145
292
|
/** The settings transport carrying this plugin's own configuration section. */
|
|
146
293
|
readonly configForms: ConfigFormsPort;
|
|
147
294
|
}
|
|
@@ -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;
|
|
@@ -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. */
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Approved Claude sidebar SVG artwork, bundled as trusted static markup. */
|
|
2
|
+
export declare const SIDEBAR_NAVIGATION_ICONS: Readonly<{
|
|
3
|
+
newSession: "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"claude-sidebar-icon\" data-icon=\"new\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <circle class=\"icon-disc\" cx=\"12\" cy=\"12\" r=\"12\" fill=\"currentColor\" fill-opacity=\"0.09\"/>\n <path d=\"M12 7V17M7 12H17\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\"/>\n</svg>";
|
|
4
|
+
plugins: "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"claude-sidebar-icon\" data-icon=\"customize\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <g class=\"customize-case\" stroke=\"currentColor\" stroke-width=\"1.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M8 7V5.2C8 4.54 8.54 4 9.2 4H14.8C15.46 4 16 4.54 16 5.2V7\"/>\n <rect x=\"3\" y=\"7\" width=\"18\" height=\"12.5\" rx=\"1.5\"/>\n <path d=\"M3 13.5H7M9.5 13.5H14.5M17 13.5H21\"/>\n </g>\n</svg>";
|
|
5
|
+
routines: "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"claude-sidebar-icon\" data-icon=\"routines\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <g stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <path class=\"routine-long-hand\" d=\"M12 12V7.4\"/>\n <path d=\"M12 12L14.8 13.75\"/>\n </g>\n</svg>";
|
|
6
|
+
}>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ReactElement } from 'react';
|
|
2
|
+
import type { ViewOptionsPort } from '../../contracts/ports.ts';
|
|
3
|
+
export interface ViewOptionsCardProps {
|
|
4
|
+
readonly port: ViewOptionsPort;
|
|
5
|
+
/** `view.showEmptyGroups`: whether empty Workspaces are kept on screen. */
|
|
6
|
+
readonly showEmptyGroups: boolean;
|
|
7
|
+
/** Write the switch back through the settings transport. */
|
|
8
|
+
readonly setShowEmptyGroups: (value: boolean) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The sidebar's view-options card, drawn in this plugin's own words and geometry.
|
|
12
|
+
*
|
|
13
|
+
* DSH's own menu is a flat list of eight options under three grey headings. The
|
|
14
|
+
* reference draws the same settings as *value rows* — the dimension on the left,
|
|
15
|
+
* the current choice on the right, a disclosure mark at the end — with the
|
|
16
|
+
* options one level down in a card of their own, and the switch and the action
|
|
17
|
+
* that belong to the family at the bottom. So this card is that shape, and the
|
|
18
|
+
* host's menu is only ever read (`port.read`) and clicked (`port.choose`): the
|
|
19
|
+
* three values are the host's, its rows are what writes them, and the words of
|
|
20
|
+
* two of the three rows are the host's own — the card borrows the labels it read
|
|
21
|
+
* out of the host's card and renames only the archived-visibility triple, which
|
|
22
|
+
* is the one set the reference names differently (活跃 / 已归档 / 全部).
|
|
23
|
+
*
|
|
24
|
+
* Only `显示空分组` is this plugin's own state: it writes
|
|
25
|
+
* `view.showEmptyGroups` through the settings transport, and a write re-mounts
|
|
26
|
+
* the plugin, so the card closes behind it. `清除筛选` puts the filter rows back
|
|
27
|
+
* to their defaults and exists only while one of them is off its default, which
|
|
28
|
+
* is what the reference does with `Clear filters`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function ViewOptionsCard({ port, showEmptyGroups, setShowEmptyGroups, }: ViewOptionsCardProps): ReactElement | null;
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
import type { ViewOptionsSettingsPort } from '../../contracts/ports.ts';
|
|
5
|
+
/**
|
|
6
|
+
* Put the sidebar's view-options card in the frame-wide overlay.
|
|
7
|
+
*
|
|
8
|
+
* The card is this plugin's own surface, so it is registered like one: a React
|
|
9
|
+
* entry in `shell.overlay`, holding the driver that watches the host's trigger
|
|
10
|
+
* and drives the host's own menu (`compat/view-options.ts`). The one value the
|
|
11
|
+
* card writes is `view.showEmptyGroups`, and it goes through the settings
|
|
12
|
+
* transport the same way the configuration page writes its fields — a write
|
|
13
|
+
* re-mounts the plugin, which is why the card closes behind the switch.
|
|
14
|
+
*
|
|
15
|
+
* Nothing here fails the interface if the trigger is missing: the driver reports
|
|
16
|
+
* a card it cannot read and hands the click back to DSH, whose own menu opens.
|
|
17
|
+
*
|
|
18
|
+
* @param ctx - client root context carrying the slot service.
|
|
19
|
+
* @param environment - configuration, ports and logging for this activation.
|
|
20
|
+
* @param cleanup - scope owning the styles, the driver and the registration.
|
|
21
|
+
*/
|
|
22
|
+
export declare function mountViewOptions(ctx: Context, environment: FeatureEnvironment, cleanup: CleanupScope): {
|
|
23
|
+
settings: ViewOptionsSettingsPort;
|
|
24
|
+
showAllSessions(): void;
|
|
25
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The autocompaction policy this deployment actually runs.
|
|
3
|
+
*
|
|
4
|
+
* The panel's last row says how much of the window the compaction policy is
|
|
5
|
+
* holding back, and that number belongs to another plugin's configuration. DSH
|
|
6
|
+
* publishes no read face for it, so the loader's own entry tree is the source:
|
|
7
|
+
* an entry that is enabled *and* declares the policy's own fields
|
|
8
|
+
* (`thresholdRatio` / `headroomTokens`) is the backend that will compact this
|
|
9
|
+
* session, and an enabled `compaction-basic` with an empty config is that
|
|
10
|
+
* backend running on its defaults.
|
|
11
|
+
*
|
|
12
|
+
* A deployment with no such entry — which is this plugin's own machine, where
|
|
13
|
+
* `compaction-basic` is `disabled: true` — yields null, and the panel leaves
|
|
14
|
+
* the row out rather than drawing a threshold nobody enforces.
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
19
|
+
import type { CompactionPolicy } from './unit.ts';
|
|
20
|
+
/**
|
|
21
|
+
* The policy that will compact a session on this deployment.
|
|
22
|
+
*
|
|
23
|
+
* @param ctx - host plugin context carrying the loader.
|
|
24
|
+
* @returns the policy, or null when no enabled backend declares one.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readCompactionPolicy(ctx: Context): CompactionPolicy | null;
|