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.
Files changed (50) hide show
  1. package/README.md +76 -54
  2. package/lib/client.js +9392 -2579
  3. package/lib/index.js +387 -20
  4. package/lib/types/client/compat/account-menu.d.ts +4 -4
  5. package/lib/types/client/compat/account-more.d.ts +3 -0
  6. package/lib/types/client/compat/account-theme.d.ts +3 -0
  7. package/lib/types/client/compat/adapter.d.ts +22 -1
  8. package/lib/types/client/compat/browser-header.d.ts +57 -0
  9. package/lib/types/client/compat/browser-menu.d.ts +16 -0
  10. package/lib/types/client/compat/composer-menus.d.ts +6 -3
  11. package/lib/types/client/compat/context-panel.d.ts +47 -0
  12. package/lib/types/client/compat/empty-groups.d.ts +46 -0
  13. package/lib/types/client/compat/files-pane.d.ts +78 -0
  14. package/lib/types/client/compat/header-menu-actions.d.ts +14 -0
  15. package/lib/types/client/compat/header-menus.d.ts +4 -0
  16. package/lib/types/client/compat/host-dom.d.ts +180 -0
  17. package/lib/types/client/compat/pane-chrome.d.ts +29 -0
  18. package/lib/types/client/compat/pane-icons.d.ts +23 -0
  19. package/lib/types/client/compat/pane-tiles.d.ts +37 -0
  20. package/lib/types/client/compat/permission-menu.d.ts +88 -0
  21. package/lib/types/client/compat/relative-file-path.d.ts +2 -0
  22. package/lib/types/client/compat/right-panes.d.ts +16 -0
  23. package/lib/types/client/compat/scroll-pill.d.ts +70 -0
  24. package/lib/types/client/compat/sidebar-navigation.d.ts +11 -0
  25. package/lib/types/client/compat/stats-values.d.ts +18 -1
  26. package/lib/types/client/compat/view-options.d.ts +58 -0
  27. package/lib/types/client/compat/view-switch.d.ts +46 -5
  28. package/lib/types/client/contracts/ports.d.ts +176 -1
  29. package/lib/types/client/features/context-panel/ContextPanel.d.ts +12 -0
  30. package/lib/types/client/features/context-panel/mount.d.ts +20 -0
  31. package/lib/types/client/features/conversation/index.d.ts +5 -3
  32. package/lib/types/client/features/conversation/view-switch-icons.d.ts +13 -0
  33. package/lib/types/client/features/settings/locales.d.ts +7 -0
  34. package/lib/types/client/features/shell/index.d.ts +9 -3
  35. package/lib/types/client/features/sidebar/index.d.ts +1 -1
  36. package/lib/types/client/features/sidebar/navigation-icons.d.ts +6 -0
  37. package/lib/types/client/features/statistics/books.d.ts +1 -2
  38. package/lib/types/client/features/statistics/format.d.ts +4 -4
  39. package/lib/types/client/features/view-options/ViewOptionsCard.d.ts +30 -0
  40. package/lib/types/client/features/view-options/mount.d.ts +25 -0
  41. package/lib/types/client/theme/mount.d.ts +2 -2
  42. package/lib/types/client/theme/palette.d.ts +1 -1
  43. package/lib/types/host/context/compaction.d.ts +26 -0
  44. package/lib/types/host/context/pricing.d.ts +99 -0
  45. package/lib/types/host/context/service.d.ts +24 -0
  46. package/lib/types/host/context/unit.d.ts +136 -0
  47. package/lib/types/host/index.d.ts +18 -0
  48. package/lib/types/shared/config.d.ts +26 -1
  49. package/lib/types/shared/context.d.ts +243 -0
  50. package/package.json +6 -3
@@ -0,0 +1,243 @@
1
+ /**
2
+ * The context-breakdown contract both halves share.
3
+ *
4
+ * The host half re-derives what the host's own three-number breakdown cannot
5
+ * say — per-tool rows, per-file rows, per-skill rows, the autocompaction
6
+ * threshold — and ships it as the `ccdContext` projection; the browser half
7
+ * reads the host's authoritative `contextPressure` / `contextBreakdown` beside
8
+ * it and turns all of it into the panel's rows and bar with the pure functions
9
+ * below. Keeping the arithmetic here is what lets the card be a pure function
10
+ * of its inputs and lets the tests price a real session log without a browser.
11
+ *
12
+ * The pricing constants are the host's own (`@deepseek-ai/dsh-token-meter`
13
+ * `estimate.ts`): four characters per token, four tokens of structural overhead
14
+ * per content block and per message. They are restated rather than imported —
15
+ * that package is not part of this plugin's runtime baseline — and every number
16
+ * they produce is a re-derivation of a value the host also computed, never a
17
+ * second authority beside it.
18
+ */
19
+ /** Projection key this plugin owns; it must not collide with a host key. */
20
+ export declare const CONTEXT_KEY = "ccdContext";
21
+ /** Persisted-cache invalidation version for the fold state. */
22
+ export declare const CONTEXT_STATE_VERSION = 1;
23
+ /** Characters per token in the host's density heuristic. */
24
+ export declare const CHARS_PER_TOKEN = 4;
25
+ /** Structural overhead the host adds per content block and per message. */
26
+ export declare const BLOCK_OVERHEAD = 4;
27
+ /** Default autocompaction threshold ratio (`compaction-basic`). */
28
+ export declare const DEFAULT_THRESHOLD_RATIO = 0.8;
29
+ /** Default autocompaction headroom, in tokens (`compaction-basic`). */
30
+ export declare const DEFAULT_HEADROOM_TOKENS = 65536;
31
+ /** The public-name prefix DSH gives every MCP tool. */
32
+ export declare const MCP_PREFIX = "mcp__";
33
+ /** Distinct entries one fold group keeps before it drops the smallest. */
34
+ export declare const CONTEXT_ENTRY_LIMIT = 200;
35
+ /** Detail rows a group renders before its list scrolls. */
36
+ export declare const DETAIL_ROW_LIMIT = 200;
37
+ /** The narrowest segment the bar draws; anything under this is left out. */
38
+ export declare const MIN_SEGMENT_PX = 2;
39
+ /** One priced row, as it travels on the wire: `[name, tokens]`. */
40
+ export type ContextEntry = readonly [name: string, tokens: number];
41
+ /** The `ccdContext` projection's client-visible value. */
42
+ export interface ContextBreakdownView {
43
+ /** Every assembled tool schema, largest first. */
44
+ readonly tools: readonly ContextEntry[];
45
+ /** Every retained instruction file, largest first. */
46
+ readonly files: readonly ContextEntry[];
47
+ /** Every retained skill-catalog entry, largest first. */
48
+ readonly skills: readonly ContextEntry[];
49
+ /** Tokens every retained skill catalog contributes to the surface. */
50
+ readonly skillTokens: number;
51
+ /** Tokens every retained instruction message contributes to the surface. */
52
+ readonly fileTokens: number;
53
+ /** Effective autocompaction threshold, or null when no policy is readable. */
54
+ readonly compaction: number | null;
55
+ }
56
+ /** One row of the panel, and one segment of the bar, in the reference's order. */
57
+ export type ContextSliceKey = 'mcp' | 'tools' | 'system' | 'skills' | 'memory' | 'messages' | 'autocompact' | 'free';
58
+ /** One priced slice of the context window. */
59
+ export interface ContextSlice {
60
+ readonly key: ContextSliceKey;
61
+ /** Tokens this slice holds; never negative. */
62
+ readonly tokens: number;
63
+ }
64
+ /**
65
+ * Everything the panel draws from: the host's two authoritative projections,
66
+ * this plugin's re-derived rows, and the session's capacity.
67
+ */
68
+ export interface ContextSource {
69
+ /** `contextPressure.contextWindow`. */
70
+ readonly window: number;
71
+ /** Occupancy: `projectedTokens ?? pressureTokens` — the ring's own number. */
72
+ readonly used: number;
73
+ /** `contextBreakdown.systemTokens`. */
74
+ readonly systemTokens: number;
75
+ /** `contextBreakdown.toolsTokens`. */
76
+ readonly toolsTokens: number;
77
+ /** Per-tool rows, used only to split the authoritative total in two. */
78
+ readonly tools?: readonly ContextEntry[];
79
+ /** `contextBreakdown.messageTokens`. */
80
+ readonly messageTokens: number;
81
+ /** Tokens in every retained skill catalog, re-derived. */
82
+ readonly skillTokens: number;
83
+ /** Tokens in every retained instruction message, re-derived. */
84
+ readonly fileTokens: number;
85
+ /** Effective autocompaction threshold, or null when it is not readable. */
86
+ readonly compaction: number | null;
87
+ }
88
+ /** The panel's whole reading, ready to draw. */
89
+ export interface ContextBreakdown {
90
+ /** The session's capacity. */
91
+ readonly window: number;
92
+ /** Occupancy, exactly as the ring reads it. */
93
+ readonly used: number;
94
+ /** The ring's own integer percentage. */
95
+ readonly percent: number;
96
+ /** Every row, in the bar's own order; `free` is last. */
97
+ readonly slices: readonly ContextSlice[];
98
+ /** The slices the bar draws, without `free` — the track is the remainder. */
99
+ readonly segments: readonly ContextSlice[];
100
+ /** `used − Σ rows`: the sampled reading's distance from the heuristic tree. */
101
+ readonly residual: number;
102
+ }
103
+ /** Read a non-negative integer, or null when the value is not one. */
104
+ export declare function readCount(value: unknown): number | null;
105
+ /** Read one `[name, tokens]` list, dropping everything else. */
106
+ export declare function readEntries(value: unknown): readonly ContextEntry[];
107
+ /**
108
+ * Read one `ccdContext` value, from the wire or from a hand-written fixture.
109
+ *
110
+ * Deliberately lenient — a build that carries no such key, or a value from a
111
+ * later state version, must read as "this plugin's rows are not here" rather
112
+ * than throw into a render — and deliberately strict about *that*: a value that
113
+ * is not an object is null, so the panel can tell "no rows" from "zero rows".
114
+ *
115
+ * @param value - the raw projection value.
116
+ * @returns a usable view, or null when there is nothing to read.
117
+ */
118
+ export declare function readContextView(value: unknown): ContextBreakdownView | null;
119
+ /** The empty view, for a build or a state version that carries no rows. */
120
+ export declare function emptyContextView(): ContextBreakdownView;
121
+ /**
122
+ * Split the authoritative tool total across the MCP and built-in groups.
123
+ *
124
+ * The host prices the assembled tool array whole (`ceil(JSON.length / 4) + 4`),
125
+ * so per-tool prices cannot be summed back to it — 37 real tools came to 7657
126
+ * against the array's 7492. The authoritative total is therefore split in the
127
+ * ratio the per-tool prices report, which keeps the two rows summing to the
128
+ * host's own number with the rounding difference absorbed here.
129
+ *
130
+ * @param tools - per-tool rows, `[name, tokens]`.
131
+ * @param total - the host's authoritative `toolsTokens`.
132
+ * @returns the MCP share and the built-in share, summing to `total`.
133
+ */
134
+ export declare function splitTools(tools: readonly ContextEntry[], total: number): {
135
+ readonly mcp: number;
136
+ readonly tools: number;
137
+ };
138
+ /**
139
+ * The panel's rows, bar segments and residual.
140
+ *
141
+ * @param source - the host's projections plus this plugin's re-derived rows.
142
+ * @returns the whole reading; rows that price at zero are left out.
143
+ */
144
+ export declare function contextBreakdown(source: ContextSource): ContextBreakdown;
145
+ /**
146
+ * The autocompaction segment's own height: what the policy holds back.
147
+ *
148
+ * `compaction-basic` resolves `floor(min(window × ratio, window − reserved −
149
+ * headroom))`; the segment is the distance from that threshold to the window,
150
+ * which is the room the window keeps for the summary it will write. A session
151
+ * with no readable policy, or one already past its threshold, draws nothing.
152
+ *
153
+ * @param window - the session's capacity.
154
+ * @param compaction - the resolved threshold, or null when unreadable.
155
+ * @param used - current occupancy, which the segment never overstates.
156
+ * @returns the segment's token height; 0 when it is not drawn.
157
+ */
158
+ export declare function autocompactTokens(window: number, compaction: number | null, used: number): number;
159
+ /**
160
+ * The autocompaction threshold a request envelope implies.
161
+ *
162
+ * `reservedCompletionTokens` is the request's own output cap; a route that
163
+ * advertises none leaves the reservation unknown, and the row is then left out
164
+ * rather than guessed at.
165
+ *
166
+ * @param window - the session's capacity.
167
+ * @param reserved - the request's `maxTokens`, or null when it declares none.
168
+ * @param ratio - the policy's threshold ratio.
169
+ * @param headroom - the policy's headroom, in tokens.
170
+ * @returns the threshold, or null when it cannot be resolved.
171
+ */
172
+ export declare function compactionThreshold(window: number, reserved: number | null, ratio?: number, headroom?: number): number | null;
173
+ /**
174
+ * The bar's segments and the free weight beside them, all in tokens.
175
+ *
176
+ * The reference drops a category whose share is under 2px instead of drawing a
177
+ * hairline. The bar's weights have to add up to the window for a segment's
178
+ * share to be its share of the window — and the rows deliberately do not, since
179
+ * the sampled reading and the heuristic tree differ — so the remainder is
180
+ * measured against the window rather than summed from the rows.
181
+ *
182
+ * @param breakdown - the panel's reading.
183
+ * @param barWidth - the bar's measured width in CSS pixels.
184
+ * @returns the drawn segments and the free weight, all in tokens.
185
+ */
186
+ export declare function barSegments(breakdown: ContextBreakdown, barWidth: number): {
187
+ readonly drawn: readonly ContextSlice[];
188
+ readonly free: number;
189
+ };
190
+ /**
191
+ * The reference's compact token count: `342`, `4.6k`, `216.7k`, `1M`.
192
+ *
193
+ * One decimal place, with a trailing `.0` dropped — which is what the
194
+ * reference's own readings show (`48k`, `32.5k`, `216.7k`, `878k`, `1M`). The
195
+ * host's own formatter rounds to a whole number above 100 and would print
196
+ * `217k` where the reference prints `216.7k`; the panel follows the reference,
197
+ * and the header still agrees with the ring because both read the same
198
+ * `contextPressure` value.
199
+ *
200
+ * @param value - token count.
201
+ * @returns the compact reading.
202
+ */
203
+ export declare function formatTokens(value: number): string;
204
+ /**
205
+ * One row's share of the window, at the reference's one decimal.
206
+ *
207
+ * @param tokens - the row's tokens.
208
+ * @param window - the session's capacity.
209
+ * @returns e.g. `4.8%`.
210
+ */
211
+ export declare function formatPercent(tokens: number, window: number): string;
212
+ /**
213
+ * An MCP tool's two names, as the reference writes them.
214
+ *
215
+ * DSH gives every MCP tool the public name `mcp__<server>__<tool>`; the panel
216
+ * shows `<server> · <tool>`. A name that does not follow the convention is
217
+ * returned unchanged, so a build that renames the prefix loses the split and
218
+ * nothing else.
219
+ *
220
+ * @param name - the tool's public name.
221
+ * @returns the display label.
222
+ */
223
+ export declare function toolLabel(name: string): string;
224
+ /** The MCP server one tool name belongs to, or null for a built-in tool. */
225
+ export declare function mcpServer(name: string): string | null;
226
+ /**
227
+ * Shorten a path from the middle, keeping its own file name.
228
+ *
229
+ * The reference writes `/Users/zoukai/code/dsh-ccd-…AGENTS.md`: the tail is what
230
+ * identifies the file, so the head gives way first. A path that already fits is
231
+ * returned unchanged.
232
+ *
233
+ * The budget is the panel's own label column: a fixed 360px card leaves about
234
+ * 208px for a detail row's name, which is this many characters of a path at
235
+ * 13px with room to spare. It is deliberately conservative — the row carries
236
+ * the full path in its `title`, and CSS's own ellipsis would eat the tail this
237
+ * function exists to keep.
238
+ *
239
+ * @param path - the path as the instruction message named it.
240
+ * @param budget - characters to keep, the ellipsis included.
241
+ * @returns the shortened path.
242
+ */
243
+ export declare function shortenPath(path: string, budget?: number): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-claude-desktop-theme",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "license": "MIT",
5
5
  "description": "Claude Code Desktop-style theme for DeepSeek Harness (DSH) Desktop on macOS and Windows, with light/dark themes, model/effort pickers and an interactive pixel whale",
6
6
  "author": "zkforge",
@@ -81,10 +81,12 @@
81
81
  "typecheck": "tsc --noEmit",
82
82
  "check:architecture": "node scripts/check-architecture.mjs",
83
83
  "check:package": "node scripts/check-package.mjs",
84
- "test": "node --test tests/*.test.ts",
84
+ "test": "node --test tests/*.test.ts tests/*.test.mjs",
85
85
  "check": "npm run typecheck && npm run check:architecture && npm test && npm run build && npm run check:package",
86
86
  "prepack": "npm run check",
87
- "pack:local": "npm pack --pack-destination artifacts"
87
+ "pack:local": "npm pack --pack-destination artifacts",
88
+ "pet:gifs": "node scripts/pet-gifs.mjs",
89
+ "effort:gifs": "node scripts/effort-gif.mjs"
88
90
  },
89
91
  "dependencies": {
90
92
  "@deepseek-ai/schemastery": "3.18.4"
@@ -110,6 +112,7 @@
110
112
  "@types/react": "18.3.1",
111
113
  "esbuild": "0.28.2",
112
114
  "react": "18.3.1",
115
+ "react-dom": "18.3.1",
113
116
  "typescript": "7.0.2",
114
117
  "yaml": "2.9.1"
115
118
  }