dsh-claude-desktop-theme 0.4.4 → 0.4.6

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.
Files changed (59) hide show
  1. package/README.md +89 -69
  2. package/lib/client.js +18357 -7848
  3. package/lib/index.js +251 -14
  4. package/lib/types/client/compat/account-balance.d.ts +8 -0
  5. package/lib/types/client/compat/browser-header.d.ts +1 -2
  6. package/lib/types/client/compat/changed-files.d.ts +7 -0
  7. package/lib/types/client/compat/composer-status-order.d.ts +1 -54
  8. package/lib/types/client/compat/hero-greeting.d.ts +6 -0
  9. package/lib/types/client/compat/host-dom.d.ts +16 -0
  10. package/lib/types/client/compat/mutation-scope.d.ts +18 -14
  11. package/lib/types/client/compat/pane-chrome.d.ts +5 -0
  12. package/lib/types/client/compat/pane-icons.d.ts +2 -0
  13. package/lib/types/client/compat/pane-labels.d.ts +2 -0
  14. package/lib/types/client/compat/permission-confirmation.d.ts +5 -0
  15. package/lib/types/client/compat/permission-menu.d.ts +4 -1
  16. package/lib/types/client/compat/pet-anchor.d.ts +5 -1
  17. package/lib/types/client/compat/plugin-feedback.d.ts +28 -0
  18. package/lib/types/client/compat/reply-signature.d.ts +3 -2
  19. package/lib/types/client/compat/running-status.d.ts +8 -0
  20. package/lib/types/client/compat/scroll-pill.d.ts +4 -64
  21. package/lib/types/client/compat/sidebar-search.d.ts +18 -0
  22. package/lib/types/client/compat/status-groups.d.ts +1 -1
  23. package/lib/types/client/compat/tool-call-details.d.ts +10 -0
  24. package/lib/types/client/compat/tool-call-groups.d.ts +22 -0
  25. package/lib/types/client/compat/tool-call-labels.d.ts +5 -0
  26. package/lib/types/client/compat/tool-file-summary.d.ts +13 -0
  27. package/lib/types/client/compat/voice-waveform.d.ts +12 -0
  28. package/lib/types/client/compat/workspace-branch.d.ts +62 -0
  29. package/lib/types/client/compat/workspace-menu.d.ts +10 -1
  30. package/lib/types/client/compat/workspace-picker-port.d.ts +9 -0
  31. package/lib/types/client/contracts/ports.d.ts +1 -0
  32. package/lib/types/client/features/composer-pet/BlankPet.d.ts +4 -1
  33. package/lib/types/client/features/composer-pet/ClaudePet.d.ts +7 -0
  34. package/lib/types/client/features/composer-pet/ComposerPet.d.ts +1 -1
  35. package/lib/types/client/features/composer-pet/claude-frames.d.ts +12 -0
  36. package/lib/types/client/features/composer-pet/claude-motion.d.ts +3 -0
  37. package/lib/types/client/features/conversation/header-actions/BlankHeaderActions.d.ts +10 -0
  38. package/lib/types/client/features/conversation/header-actions/HeaderActionButton.d.ts +3 -2
  39. package/lib/types/client/features/conversation/header-actions/entries.d.ts +4 -5
  40. package/lib/types/client/features/conversation/header-actions/mount.d.ts +4 -5
  41. package/lib/types/client/features/model-controls/EffortPanel.d.ts +2 -1
  42. package/lib/types/client/features/model-controls/ModelControls.d.ts +11 -1
  43. package/lib/types/client/features/model-controls/PricingHint.d.ts +19 -0
  44. package/lib/types/client/features/model-controls/model-icon-data.d.ts +31 -0
  45. package/lib/types/client/features/model-controls/model-icon-match.d.ts +20 -0
  46. package/lib/types/client/features/model-controls/model-icons.d.ts +13 -0
  47. package/lib/types/client/features/model-controls/pricing.d.ts +18 -0
  48. package/lib/types/client/features/model-controls/selection.d.ts +2 -0
  49. package/lib/types/client/features/settings/ChoiceMenu.d.ts +15 -0
  50. package/lib/types/client/features/settings/fields.d.ts +18 -0
  51. package/lib/types/client/features/settings/locales.d.ts +22 -1
  52. package/lib/types/client/features/tool-calls/index.d.ts +2 -2
  53. package/lib/types/host/balance.d.ts +5 -0
  54. package/lib/types/host/git.d.ts +37 -0
  55. package/lib/types/host/index.d.ts +38 -0
  56. package/lib/types/shared/balance.d.ts +8 -0
  57. package/lib/types/shared/config.d.ts +14 -3
  58. package/lib/types/shared/git.d.ts +30 -0
  59. package/package.json +2 -1
@@ -1,70 +1,10 @@
1
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. */
2
+ /** Native scrollbars reveal their ink while scrolling, then return to idle. */
40
3
  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
4
  export declare const IDLE_MS = 800;
52
5
  /**
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.
6
+ * Keep the existing entry-point name for assembly compatibility. Geometry and
7
+ * dragging now belong entirely to native scrollbars; no overlay or per-surface
8
+ * observers are needed. Capture also reaches dynamically inserted scrollers.
69
9
  */
70
10
  export declare function mountScrollPills(document: Document, report: (error: unknown) => void): Disposer;
@@ -0,0 +1,18 @@
1
+ import type { Disposer } from '../contracts/ports.ts';
2
+ /** Marks the sidebar column whose field is currently parked above New Session. */
3
+ export declare const SIDEBAR_SEARCH_PLACED_ATTRIBUTE = "data-ccd-sidebar-search-placed";
4
+ /**
5
+ * Park the browsing region's search field above New Session.
6
+ *
7
+ * The field belongs to `ui-workspace`'s `WorkspaceBrowser`, and React removes
8
+ * it from the section header whenever the sidebar collapses to its rail.
9
+ * Moving the React-owned node would make that removal target the wrong parent,
10
+ * so the node stays where React put it and is positioned over the gap that New
11
+ * Session opens above itself. That gap sits after the brand row when the brand
12
+ * is visible and directly below the window strip when it is not.
13
+ *
14
+ * The section header keeps its own row. With the search slot out of flow, its
15
+ * label takes the leading edge and the native View options trigger stays on the
16
+ * trailing edge.
17
+ */
18
+ export declare function mountSidebarSearch(document: Document, report: (error: unknown) => void): Disposer;
@@ -16,4 +16,4 @@ export declare function sessionGroup(status: SessionStatus | undefined, running:
16
16
  * uiSession.sessionStatus is the root observable provided by ui-session in the
17
17
  * pinned app.asar; it does not acquire or activate any listed Session.
18
18
  */
19
- export declare function mountStatusGroups(document: Document, ctx: Context, showEmpty: boolean, report: (error: unknown) => void): Disposer;
19
+ export declare function mountStatusGroups(document: Document, ctx: Context, report: (error: unknown) => void): Disposer;
@@ -0,0 +1,10 @@
1
+ import type { Disposer } from '../contracts/ports.ts';
2
+ export interface CommandSegment {
3
+ readonly text: string;
4
+ readonly tone: 'command' | 'argument' | 'plain';
5
+ }
6
+ export declare function writeCommandClipboard(document: Document, text: string): Promise<void>;
7
+ /** Presentation tokens only: preserve every character, including shell quotes. */
8
+ export declare function commandSegments(command: string): CommandSegment[];
9
+ /** Add a highlighted sibling; never rewrite React's command text or handlers. */
10
+ export declare function mountToolCallDetails(document: Document, report: (error: unknown) => void, copyText?: (text: string) => Promise<void>): Disposer;
@@ -0,0 +1,22 @@
1
+ import type { Disposer } from '../contracts/ports.ts';
2
+ import { type ToolFileSummary } from './tool-file-summary.ts';
3
+ export type ToolGroupKind = 'read' | 'command' | 'tool' | 'reasoning';
4
+ export interface ToolGroupEntry<T> {
5
+ readonly value: T;
6
+ readonly kind: ToolGroupKind | 'barrier';
7
+ readonly turn: string | null;
8
+ readonly settled: boolean;
9
+ readonly file?: ToolFileSummary | undefined;
10
+ readonly live?: boolean;
11
+ readonly description?: string;
12
+ readonly failed: boolean;
13
+ }
14
+ /** A visible reply, live activity, or turn boundary ends a run. */
15
+ export declare function consecutiveToolGroups<T>(entries: readonly ToolGroupEntry<T>[], includeLive?: boolean): ToolGroupEntry<T>[][];
16
+ export declare function toolGroupLabel(kinds: readonly ToolGroupKind[]): string;
17
+ /**
18
+ * Inject only a sibling disclosure. Native calls keep their original React
19
+ * parents, identities, handlers and independent detail state. Adjacent borders
20
+ * paint the expanded list without wrapping or moving host nodes.
21
+ */
22
+ export declare function mountToolCallGroups(document: Document, report: (error: unknown) => void): Disposer;
@@ -0,0 +1,5 @@
1
+ import type { Disposer } from '../contracts/ports.ts';
2
+ /** Exact UI labels only: never translate model descriptions, paths or output. */
3
+ export declare function englishToolLabel(text: string, running?: boolean): string | undefined;
4
+ /** Keep React's title nodes intact and add English presentation siblings. */
5
+ export declare function mountToolCallLabels(document: Document, report: (error: unknown) => void): Disposer;
@@ -0,0 +1,13 @@
1
+ /** Read only the native row header; expanded diffs and nested calls are not metadata. */
2
+ export interface ToolFileSummary {
3
+ readonly action: 'write' | 'edit';
4
+ readonly name: string;
5
+ readonly added?: number | undefined;
6
+ readonly removed?: number | undefined;
7
+ }
8
+ export interface FileSummaryPart {
9
+ readonly text: string;
10
+ readonly tone: 'plain' | 'file' | 'added' | 'removed';
11
+ }
12
+ export declare function toolFileSummary(row: Element): ToolFileSummary | null;
13
+ export declare function fileSummaryParts(files: readonly ToolFileSummary[], others: readonly string[]): FileSummaryPart[];
@@ -0,0 +1,12 @@
1
+ import type { Disposer } from '../contracts/ports.ts';
2
+ export interface VoiceWaveformHistory {
3
+ heights: number[];
4
+ sampledAt: number | null;
5
+ }
6
+ /** Sample each bar once, then translate the history continuously. A bar's
7
+ * height stays fixed for its entire trip from the right edge to the left. */
8
+ export declare function advanceVoiceWaveform(history: VoiceWaveformHistory, now: number, level: number): number;
9
+ /** Render reference geometry from the host's real audio samples. Keep its SVG
10
+ * mounted and untouched: its recording effect owns those original line nodes.
11
+ * The separate presentation SVG cannot enter the host's line-node snapshot. */
12
+ export declare function mountVoiceWaveform(document: Document, report: (error: unknown) => void): Disposer;
@@ -0,0 +1,62 @@
1
+ import { type GitBranchView, type GitCheckoutResult } from '../../shared/git.ts';
2
+ import type { Disposer } from '../contracts/ports.ts';
3
+ /** Marks the plugin's own groups in the picker card, which no host pass may count. */
4
+ export declare const WORKSPACE_EXTRA_ATTRIBUTE = "data-ccd-workspace-extra";
5
+ /** The plugin's branch card, nested in the host card so its pointer guard keeps both open. */
6
+ export declare const BRANCH_MENU_ATTRIBUTE = "data-ccd-branch-menu";
7
+ /** Search field shared by the picker card and the branch card. */
8
+ export declare const MENU_SEARCH_ATTRIBUTE = "data-ccd-menu-search";
9
+ /** A row the current query hides. */
10
+ export declare const FILTERED_ATTRIBUTE = "data-ccd-filtered";
11
+ /** Last listing per Workspace, so a reopened card shows its branch at once. */
12
+ export type BranchCache = Map<string, GitBranchView>;
13
+ interface Copy {
14
+ readonly branch: string;
15
+ readonly search: string;
16
+ readonly empty: string;
17
+ readonly loading: string;
18
+ /** The Host half predates this row: the route is registered only at Host start. */
19
+ readonly restart: string;
20
+ readonly detached: string;
21
+ readonly truncated: string;
22
+ readonly states: Readonly<Record<Exclude<GitBranchView['state'], 'ready'>, string>>;
23
+ readonly switching: (branch: string) => string;
24
+ readonly carried: (count: number) => string;
25
+ readonly busy: string;
26
+ readonly outcomes: Readonly<Record<Exclude<GitCheckoutResult['state'], 'switched'>, string>>;
27
+ }
28
+ /** Host-language copy, following the `<html lang>` the rest of the picker reads. */
29
+ export declare function menuCopy(document: Document): {
30
+ readonly zh: boolean;
31
+ readonly copy: Copy;
32
+ };
33
+ /** One bare search line, as the model card draws it. */
34
+ export declare function createMenuSearch(document: Document, placeholder: string): HTMLInputElement;
35
+ /**
36
+ * The picker card's branch row and its side card.
37
+ *
38
+ * The row names the selected Workspace's current branch; the side card lists
39
+ * the repository's local branches with the current one checked, and choosing
40
+ * another one checks it out through the Host (`host/git.ts`). The picker only
41
+ * opens on the new-session page, so no conversation of this session is under
42
+ * way; another session of the same Workspace may be, and while one runs or waits
43
+ * for input the switch is refused, since it would change the files under that
44
+ * agent. There is no confirmation: git itself refuses a switch that would
45
+ * overwrite local changes, and changes it carries over are reported in one line
46
+ * at the foot of the card.
47
+ *
48
+ * Both are the plugin's own nodes: the row in a group after the host's pinned
49
+ * footer, the side card nested in the host card as a manual popover, so the
50
+ * primitive's outside-pointer guard (`card.contains(target)`) keeps the card open
51
+ * while the pointer is in the side card and the top layer lifts it out of the
52
+ * card's clipping.
53
+ *
54
+ * @param card - the open picker card (the portalled host `Menu`).
55
+ * @param workspaceId - selected Workspace; the Host resolves its directory.
56
+ * @param cache - listings retained across openings.
57
+ * @param busy - whether another session of this Workspace is running or waiting.
58
+ * @param report - sink for unexpected failures.
59
+ * @returns disposer that aborts the read and removes every node.
60
+ */
61
+ export declare function mountWorkspaceBranch(card: HTMLElement, workspaceId: string, cache: BranchCache, busy: () => boolean, report: (error: unknown) => void): Disposer;
62
+ export {};
@@ -1,4 +1,12 @@
1
1
  import type { Disposer } from '../contracts/ports.ts';
2
+ import type { WorkspacePickerPort } from './workspace-picker-port.ts';
3
+ /**
4
+ * The add row's label in the reference's words.
5
+ * @param text - one label run, as the host rendered it.
6
+ * @param zh - whether the interface is Chinese.
7
+ * @returns the rewritten run, or null when it carries no trailing ellipsis.
8
+ */
9
+ export declare function openFolderLabel(text: string, zh: boolean): string | null;
2
10
  /**
3
11
  * Print the workspace picker's "add workspace" row with spaced dots.
4
12
  *
@@ -9,7 +17,8 @@ import type { Disposer } from '../contracts/ports.ts';
9
17
  * commit that mounts it and never shows the host's glyph first.
10
18
  *
11
19
  * @param document - renderer document carrying the hero chip and the portal.
20
+ * @param port - Workspace order and per-Workspace session activity.
12
21
  * @param report - sink for observer failures; the native label stays untouched.
13
22
  * @returns disposer that disconnects every observer and restores each label.
14
23
  */
15
- export declare function mountWorkspaceMenu(document: Document, report: (error: unknown) => void): Disposer;
24
+ export declare function mountWorkspaceMenu(document: Document, port: WorkspacePickerPort, report: (error: unknown) => void): Disposer;
@@ -0,0 +1,9 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ /** What the workspace picker reads from the host's authoritative snapshots. */
3
+ export interface WorkspacePickerPort {
4
+ /** Workspace ids in the order the picker renders its rows. */
5
+ workspaceIds(): readonly string[];
6
+ /** Whether any session of the Workspace is running or waiting for input. */
7
+ busy(workspaceId: string): boolean;
8
+ }
9
+ export declare function workspacePickerPort(ctx: Context): WorkspacePickerPort;
@@ -79,6 +79,7 @@ export interface SidebarRightPort {
79
79
  /** Open one page kind for the on-screen Session; an unregistered kind throws. */
80
80
  openTab(kind: string, options?: {
81
81
  readonly params?: Record<string, string>;
82
+ readonly revealIfOpened?: boolean;
82
83
  }): void;
83
84
  /** Focus a tab and the pane holding it; a missing tab is left alone. */
84
85
  focus(tabId: string): void;
@@ -1,7 +1,10 @@
1
1
  import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { PersonalizationConfig } from '../../../shared/config.ts';
2
3
  import type { PetAnchor } from '../../compat/pet-anchor.ts';
3
4
  /** Business face the frame overlay injects: the measured new-session corner. */
4
5
  export interface BlankPetFace {
6
+ /** Visual variant chosen in settings. */
7
+ readonly petStyle: PersonalizationConfig['petStyle'];
5
8
  /** Selector hook over the compat layer's measurement. */
6
9
  readonly useAnchor: () => PetAnchor | null;
7
10
  }
@@ -14,4 +17,4 @@ export type BlankPetProps = PropsRuntime<'shell.overlay'> & BlankPetFace;
14
17
  * @param props - injected measurement.
15
18
  * @returns the positioned whale, or null.
16
19
  */
17
- export declare function BlankPet({ useAnchor }: BlankPetProps): import("react/jsx-runtime").JSX.Element | null;
20
+ export declare function BlankPet({ useAnchor, petStyle }: BlankPetProps): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,7 @@
1
+ /** On appearing or clicking, take out a laptop, type, then return to standing. */
2
+ export declare function ClaudePet(): import("react/jsx-runtime").JSX.Element;
3
+ /** One shared drawing path for idle and recorded poses, also used by previews. */
4
+ export declare function ClaudeArt({ elapsed, reducedMotion }: {
5
+ readonly elapsed?: number | null;
6
+ readonly reducedMotion?: boolean;
7
+ }): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The hero-page whale. Accepted clicks choose one of three local reactions;
2
+ * The hero-page whale. Appearing or clicking chooses one of three local reactions;
3
3
  * busy clicks do nothing, and hiding or unmounting cancels all active frames.
4
4
  * It reads no session state and does not trigger any Composer action.
5
5
  * @returns the whale mark.
@@ -0,0 +1,12 @@
1
+ /** Geometric reconstruction of the original click sequence, sampled at 20fps.
2
+ * Recording antialiasing/compression fringes are not artwork: there is no outline
3
+ * layer. All feet have a constant 3px width; their roots follow the belly while
4
+ * their toes share a ground line. Only the projected feet have a deliberate bend.
5
+ */
6
+ export type ClaudeFrame = readonly [body: string, shade: string, eyes: string, laptop: string];
7
+ export declare const CLAUDE_GROUND_Y = 23.5;
8
+ export declare const CLAUDE_IDLE: ClaudeFrame;
9
+ /** Pose order and hold times follow the recording; identical clean silhouettes
10
+ * are reused so compression noise cannot animate otherwise stationary edges. */
11
+ export declare const CLAUDE_FRAMES: readonly ClaudeFrame[];
12
+ export declare const CLAUDE_TRACK: readonly number[];
@@ -0,0 +1,3 @@
1
+ export declare const CLAUDE_REACTION_MS: number;
2
+ /** Each recorded pose lasts 50ms; null restores the static mark after playback. */
3
+ export declare function claudePose(elapsed: number, reducedMotion?: boolean): readonly string[] | null;
@@ -0,0 +1,10 @@
1
+ import type { VIEWS } from './entries.ts';
2
+ type View = (typeof VIEWS)[number];
3
+ export interface BlankHeaderActionsProps {
4
+ readonly labels: Record<View['kind'], string>;
5
+ readonly useAvailableViews: () => readonly View[];
6
+ readonly open: (kind: View['kind']) => void;
7
+ }
8
+ /** The blank header keeps its corner seat even while it omits Session utilities. */
9
+ export declare function BlankHeaderActions({ labels, useAvailableViews, open }: BlankHeaderActionsProps): import("react/jsx-runtime").JSX.Element | null;
10
+ export {};
@@ -12,8 +12,9 @@ export interface HeaderActionProps {
12
12
  * One view button for the conversation header.
13
13
  *
14
14
  * All three sit in the utilities group beside the native actions, in terminal,
15
- * browser, project folder order; the corner seat past them holds nothing (the panel's shipped
16
- * expand control is retired there and its action moves into the Session menu).
15
+ * browser, project folder order. Blank Sessions use the corner seat instead,
16
+ * because the host omits their utilities group. The panel's shipped expand
17
+ * control is retired and its action moves into the Session menu.
17
18
  * All three are the same control: the box size, hover surface and spacing
18
19
  * belong to the seat's own stylesheet
19
20
  * (`features/conversation/conversation.css`) so every control in the row shares
@@ -64,16 +64,15 @@ export declare function utilitiesEntry(view: (typeof VIEWS)[number], labels: Rec
64
64
  inject: (sessionId: string) => HeaderActionProps;
65
65
  };
66
66
  /**
67
- * The corner seat's retirement: the cell the reference leaves empty.
67
+ * Retire the corner seat's shipped expand control.
68
68
  *
69
69
  * That seat's shipped occupant is `ui-sidebar-right`'s collapsed-panel expand
70
70
  * control, and this interface does not want it: hovering it drew a control the
71
71
  * reference has no room for, and the action it carries lives in the Session menu
72
72
  * instead ({@link sidebarExpandRow}). Registering below the occupant's rank
73
- * ({@link OVERRIDE_PRIORITY}) takes the cell, and the entry's component renders
74
- * nothing — a structural retirement rather than a control hidden in place, so
75
- * nothing of the displaced button stays behind: no hover surface, no tooltip and
76
- * no hit area.
73
+ * ({@link OVERRIDE_PRIORITY}) takes the cell. The replacement holds the three
74
+ * view buttons on blank Sessions, where the host omits utilities; on active
75
+ * Sessions the corner is hidden and utilities hold those same actions.
77
76
  *
78
77
  * @returns the options the registry is called with.
79
78
  */
@@ -2,8 +2,7 @@ import type { Context } from '@deepseek-ai/cordis';
2
2
  import type { FeatureEnvironment } from '../../../contracts/feature.ts';
3
3
  import type { CleanupScope } from '../../../core/cleanup.ts';
4
4
  /**
5
- * Add the right panel's views to the conversation header — the project folder
6
- * first, then terminal and browser, all in the utilities group — and move the
5
+ * Add terminal, browser and project folder to the conversation header, and move the
7
6
  * collapsed panel's re-entry action into the Session menu.
8
7
  *
9
8
  * The header's trailing group is a native list slot — `ui-open-in-app`,
@@ -15,9 +14,9 @@ import type { CleanupScope } from '../../../core/cleanup.ts';
15
14
  *
16
15
  * The corner seat is different, and deliberately so. It is a *single* cell whose
17
16
  * shipped occupant is `ui-sidebar-right`'s collapsed-panel expand control; the
18
- * reference draws nothing there, so the plugin shadows that occupant with an
19
- * entry that renders nothing and puts the expand action into the Session menu's
20
- * own ⋮ list (`compat/session-menu.ts`), where it appears only while the panel
17
+ * plugin shadows that occupant with the blank page's three view buttons,
18
+ * visible only under the host's headerBlank state, and puts the expand action
19
+ * into the Session menu's ⋮ list (`compat/session-menu.ts`), only while the panel
21
20
  * is collapsed. Nothing about the panel's own state changes hands: the menu row
22
21
  * calls the panel's own service method.
23
22
  *
@@ -4,6 +4,7 @@ export interface EffortPanelProps {
4
4
  readonly anchor: RefObject<HTMLButtonElement>;
5
5
  readonly choices: readonly EffortChoice[];
6
6
  readonly selected: number;
7
+ readonly defaultIndex: number;
7
8
  readonly disabled: boolean;
8
9
  readonly busy: boolean;
9
10
  readonly error: string | null;
@@ -11,4 +12,4 @@ export interface EffortPanelProps {
11
12
  readonly onClose: () => void;
12
13
  }
13
14
  /** Presentation-only slider: continuous local preview, one supported choice on release. */
14
- export declare function EffortPanel({ anchor, choices, selected, disabled, busy, error, onCommit, onClose }: EffortPanelProps): import("react/jsx-runtime").JSX.Element | null;
15
+ export declare function EffortPanel({ anchor, choices, selected, defaultIndex, disabled, busy, error, onCommit, onClose }: EffortPanelProps): import("react/jsx-runtime").JSX.Element | null;
@@ -3,9 +3,19 @@ import type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selec
3
3
  import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
4
4
  import type { ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types';
5
5
  export type ModelControlsProps = Omit<ModelSelectInjected, 'directory'> & PropsLocale<'model'> & {
6
+ readonly showModelIcons: boolean;
6
7
  readonly locked: boolean;
7
8
  readonly useDirectory: () => ModelDirectoryState;
8
9
  readonly selectEffort: (route: ModelSelection, effort: string | undefined) => void;
9
10
  };
10
11
  /** SDK-derived values/hooks and callbacks only; DSH retains all business state. */
11
- export declare function ModelControls({ locked, available, useDirectory, load, select, selectEffort, t }: ModelControlsProps): import("react/jsx-runtime").JSX.Element | null;
12
+ export declare function ModelControls({ showModelIcons, locked, available, useDirectory, load, select, selectEffort, t }: ModelControlsProps): import("react/jsx-runtime").JSX.Element | null;
13
+ export declare function ModelPanel({ showModelIcons, anchor, state, disabled, load, t, onClose, onSelect }: PropsLocale<'model'> & {
14
+ readonly showModelIcons: boolean;
15
+ readonly anchor: React.RefObject<HTMLButtonElement>;
16
+ readonly state: ModelDirectoryState;
17
+ readonly disabled: boolean;
18
+ readonly load: () => void;
19
+ readonly onClose: () => void;
20
+ readonly onSelect: (selection: ModelSelection) => void;
21
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import type { ReactElement } from 'react';
2
+ /** Menu badges spell out the period; the Composer keeps its compact trend glyph. */
3
+ export declare function PriceMark({ provider, model, compact, badge }: {
4
+ provider: string | undefined;
5
+ model: string | undefined;
6
+ compact?: boolean;
7
+ badge?: boolean;
8
+ }): import("react/jsx-runtime").JSX.Element | null;
9
+ /** Native top layer avoids clipping inside the model list and Composer. */
10
+ export declare function PricingHint({ provider, model, compact, enabled, ignoreFocus, children }: {
11
+ provider: string | undefined;
12
+ model: string | undefined;
13
+ compact?: boolean;
14
+ enabled?: boolean;
15
+ ignoreFocus?: () => boolean;
16
+ children: ReactElement<{
17
+ 'aria-describedby'?: string | undefined;
18
+ }>;
19
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,31 @@
1
+ export interface ModelIconShape {
2
+ readonly kind: 'path' | 'circle' | 'ellipse' | 'rect';
3
+ readonly d?: string;
4
+ readonly cx?: string;
5
+ readonly cy?: string;
6
+ readonly r?: string;
7
+ readonly rx?: string;
8
+ readonly ry?: string;
9
+ readonly x?: string;
10
+ readonly y?: string;
11
+ readonly width?: string;
12
+ readonly height?: string;
13
+ readonly fillOpacity?: string;
14
+ readonly fillRule?: string;
15
+ readonly clipRule?: string;
16
+ readonly opacity?: string;
17
+ readonly transform?: string;
18
+ }
19
+ export interface ModelIconMark {
20
+ readonly title: string;
21
+ readonly viewBox: string;
22
+ readonly shapes: readonly ModelIconShape[];
23
+ readonly color?: ModelIconColor;
24
+ }
25
+ export interface ModelIconColor {
26
+ readonly viewBox: string;
27
+ readonly fill?: string;
28
+ readonly fillRule?: string;
29
+ readonly markup: string;
30
+ }
31
+ export declare const MODEL_ICONS: Readonly<Record<string, ModelIconMark>>;
@@ -0,0 +1,20 @@
1
+ import type { ModelIconMark } from './model-icon-data.ts';
2
+ export interface ModelIconTarget {
3
+ readonly id: string;
4
+ readonly name: string;
5
+ }
6
+ export interface ModelIconMatch {
7
+ readonly slug: string;
8
+ readonly mark: ModelIconMark;
9
+ }
10
+ /**
11
+ * Resolve one row's mark, preferring the model over its routing group.
12
+ *
13
+ * The provider is a fallback because a group such as `Magpie` can carry
14
+ * several brands; matching the group first made every row in it share one
15
+ * initial. The model row is the closest statement of which family a route
16
+ * actually serves.
17
+ */
18
+ export declare function resolveModelIcon(provider: ModelIconTarget, model: ModelIconTarget): ModelIconMatch | null;
19
+ /** The fallback seat: the model's own initial, not its routing group's. */
20
+ export declare function modelIconInitial(provider: ModelIconTarget, model: ModelIconTarget): string;
@@ -0,0 +1,13 @@
1
+ interface ModelIconTarget {
2
+ readonly id: string;
3
+ readonly name: string;
4
+ }
5
+ /**
6
+ * One row's leading glyph: the model family's mark when the index knows it,
7
+ * otherwise the model's initial. The seat is always drawn so rows align.
8
+ */
9
+ export declare function ModelIcon({ provider, model }: {
10
+ readonly provider: ModelIconTarget;
11
+ readonly model: ModelIconTarget;
12
+ }): import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -0,0 +1,18 @@
1
+ /** Official reference prices, CNY / million tokens; checked 2026-10-20.
2
+ * https://api-docs.deepseek.com/zh-cn/quick_start/pricing/
3
+ * The directory exposes route ids, not endpoints. Only the built-in DeepSeek
4
+ * route is eligible; these are reference prices, never a billing estimate.
5
+ */
6
+ export interface ModelPrice {
7
+ readonly hit: number;
8
+ readonly input: number;
9
+ readonly output: number;
10
+ }
11
+ export declare function officialPrice(provider: string | undefined, model: string | undefined): ModelPrice | null;
12
+ export interface PricingPeriod {
13
+ readonly peak: boolean;
14
+ readonly next: number | null;
15
+ }
16
+ /** Use absolute wall time, including after sleep; never decrement a counter. */
17
+ export declare function pricingPeriod(time: number): PricingPeriod | null;
18
+ export declare function pricingCountdown(remaining: number, zh: boolean): string;
@@ -36,6 +36,8 @@ export interface EffortViewCopy {
36
36
  * @returns every id a commit may carry, in provider order.
37
37
  */
38
38
  export declare function effortChoices(model: ModelCatalogModel | undefined, defaultName: string): EffortChoice[];
39
+ /** Default marker: a valid provider default wins; otherwise mark High if offered. */
40
+ export declare function effortDefaultIndex(model: ModelCatalogModel | undefined): number;
39
41
  /**
40
42
  * Lay out the card's stops, the resting thumb, and the trigger caption.
41
43
  *
@@ -0,0 +1,15 @@
1
+ import type { ReactElement } from 'react';
2
+ export declare function MenuCheck(): ReactElement;
3
+ /** A small choice list with native-style focus, dismissal and keyboard navigation. */
4
+ export declare function ChoiceMenu({ id, labelId, anchor, value, options, onSelect, onClose }: {
5
+ readonly id: string;
6
+ readonly labelId: string;
7
+ readonly anchor: HTMLElement;
8
+ readonly value: string;
9
+ readonly options: readonly {
10
+ readonly value: string;
11
+ readonly label: string;
12
+ }[];
13
+ readonly onSelect: (value: string) => void;
14
+ readonly onClose: () => void;
15
+ }): ReactElement;
@@ -81,3 +81,21 @@ export interface FontRowProps {
81
81
  * @returns The row and, when open, its menu.
82
82
  */
83
83
  export declare function FontRow(props: FontRowProps): ReactElement;
84
+ /** Styled choice control for named visual variants. */
85
+ export declare function ChoiceRow({ id, label, value, options, onChange }: {
86
+ readonly id: string;
87
+ readonly label: string;
88
+ readonly value: string;
89
+ readonly options: readonly {
90
+ readonly value: string;
91
+ readonly label: string;
92
+ }[];
93
+ readonly onChange: (value: string) => void;
94
+ }): ReactElement;
95
+ export declare function NameRow({ id, label, value, onChange, onCommit }: {
96
+ readonly id: string;
97
+ readonly label: string;
98
+ readonly value: string;
99
+ readonly onChange: (value: string) => void;
100
+ readonly onCommit: () => void;
101
+ }): ReactElement;