dsh-claude-desktop-theme 0.2.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/LICENSE +54 -0
- package/README.md +197 -0
- package/cordis.patch.yml +5 -0
- package/lib/client.js +5492 -0
- package/lib/index.js +666 -0
- package/lib/types/client/apply.d.ts +25 -0
- package/lib/types/client/compat/account-menu.d.ts +52 -0
- package/lib/types/client/compat/adapter.d.ts +17 -0
- package/lib/types/client/compat/blank-session-rows.d.ts +74 -0
- package/lib/types/client/compat/composer-menus.d.ts +11 -0
- package/lib/types/client/compat/composer-placeholder.d.ts +3 -0
- package/lib/types/client/compat/composer-status-order.d.ts +56 -0
- package/lib/types/client/compat/conversation-fade.d.ts +37 -0
- package/lib/types/client/compat/dom.d.ts +2 -0
- package/lib/types/client/compat/header-labels.d.ts +24 -0
- package/lib/types/client/compat/host-builds.d.ts +101 -0
- package/lib/types/client/compat/host-dom.d.ts +247 -0
- package/lib/types/client/compat/open-target.d.ts +9 -0
- package/lib/types/client/compat/pet-anchor.d.ts +30 -0
- package/lib/types/client/compat/plugin-manager.d.ts +32 -0
- package/lib/types/client/compat/session-menu.d.ts +47 -0
- package/lib/types/client/compat/slots.d.ts +21 -0
- package/lib/types/client/compat/stats-values.d.ts +20 -0
- package/lib/types/client/compat/view-switch.d.ts +14 -0
- package/lib/types/client/compat/workspace-menu.d.ts +15 -0
- package/lib/types/client/contracts/feature.d.ts +22 -0
- package/lib/types/client/contracts/ports.d.ts +169 -0
- package/lib/types/client/core/cleanup.d.ts +10 -0
- package/lib/types/client/core/mount-features.d.ts +3 -0
- package/lib/types/client/features/composer-pet/BlankPet.d.ts +17 -0
- package/lib/types/client/features/composer-pet/ComposerPet.d.ts +7 -0
- package/lib/types/client/features/composer-pet/Whale.d.ts +18 -0
- package/lib/types/client/features/composer-pet/mount.d.ts +9 -0
- package/lib/types/client/features/composer-pet/reactions.d.ts +15 -0
- package/lib/types/client/features/conversation/header-actions/HeaderActionButton.d.ts +25 -0
- package/lib/types/client/features/conversation/header-actions/entries.d.ts +101 -0
- package/lib/types/client/features/conversation/header-actions/mount.d.ts +28 -0
- package/lib/types/client/features/conversation/header-actions/sidebar-view.d.ts +21 -0
- package/lib/types/client/features/conversation/index.d.ts +16 -0
- package/lib/types/client/features/model-controls/EffortPanel.d.ts +14 -0
- package/lib/types/client/features/model-controls/ModelControls.d.ts +11 -0
- package/lib/types/client/features/model-controls/mount.d.ts +5 -0
- package/lib/types/client/features/model-controls/pixels.d.ts +4 -0
- package/lib/types/client/features/model-controls/popup.d.ts +10 -0
- package/lib/types/client/features/model-controls/selection.d.ts +66 -0
- package/lib/types/client/features/new-session/index.d.ts +8 -0
- package/lib/types/client/features/settings/ConfigPage.d.ts +28 -0
- package/lib/types/client/features/settings/FontMenu.d.ts +37 -0
- package/lib/types/client/features/settings/edits.d.ts +39 -0
- package/lib/types/client/features/settings/fields.d.ts +83 -0
- package/lib/types/client/features/settings/fonts.d.ts +40 -0
- package/lib/types/client/features/settings/locales.d.ts +61 -0
- package/lib/types/client/features/settings/mount.d.ts +17 -0
- package/lib/types/client/features/settings/register.d.ts +17 -0
- package/lib/types/client/features/shell/index.d.ts +8 -0
- package/lib/types/client/features/sidebar/index.d.ts +14 -0
- package/lib/types/client/features/statistics/books.d.ts +34 -0
- package/lib/types/client/features/statistics/card.d.ts +143 -0
- package/lib/types/client/features/statistics/format.d.ts +36 -0
- package/lib/types/client/features/statistics/index.d.ts +8 -0
- package/lib/types/client/features/statistics/mount.d.ts +12 -0
- package/lib/types/client/features/statistics/source.d.ts +35 -0
- package/lib/types/client/features/statistics/view.d.ts +95 -0
- package/lib/types/client/features/tool-calls/index.d.ts +2 -0
- package/lib/types/client/index.d.ts +1 -0
- package/lib/types/client/theme/mount.d.ts +15 -0
- package/lib/types/client/theme/palette.d.ts +80 -0
- package/lib/types/client/theme/tokens.d.ts +27 -0
- package/lib/types/host/index.d.ts +106 -0
- package/lib/types/host/stats/aggregate.d.ts +38 -0
- package/lib/types/host/stats/service.d.ts +18 -0
- package/lib/types/host/stats/unit.d.ts +115 -0
- package/lib/types/shared/config.d.ts +61 -0
- package/lib/types/shared/identity.d.ts +5 -0
- package/lib/types/shared/stats.d.ts +133 -0
- package/package.json +116 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* New-session statistics card, rebuilt as plain DOM.
|
|
3
|
+
*
|
|
4
|
+
* The reference panel (Claude Desktop's Code tab) is a 480px card: a header
|
|
5
|
+
* with two segmented controls (`Overview`/`Models`, `All`/`30d`/`7d`), then
|
|
6
|
+
* either a 3×2 grid of stat tiles with a 26×7 contribution heatmap and one
|
|
7
|
+
* footer sentence, or the `Models` view's stacked daily bar chart and its
|
|
8
|
+
* legend. It is drawn imperatively because the card lives in its own container
|
|
9
|
+
* next to the host's greeting, not in a slot the host renders — so there is no
|
|
10
|
+
* React root to render into and no shared-library dependency to declare.
|
|
11
|
+
*
|
|
12
|
+
* Geometry and colour come from the reference, measured against its own
|
|
13
|
+
* Tailwind classes and the @2x screenshots (see theme/tokens.css): a
|
|
14
|
+
* 20px segmented control with 6px padding, a 160px chart whose bars are 72% of
|
|
15
|
+
* their day column, an 8px legend swatch, and a dark tooltip placed 4px above
|
|
16
|
+
* its anchor. Everything visible is a theme variable (see
|
|
17
|
+
* `theme/tokens.css`).
|
|
18
|
+
*/
|
|
19
|
+
import type { StatsRangeId } from '../../../shared/stats.ts';
|
|
20
|
+
/** Marks the card container; the compatibility layer positions it. */
|
|
21
|
+
export declare const CARD_ATTRIBUTE = "data-ccd-stats-card";
|
|
22
|
+
/** Heatmap columns and rows. 26×7 = 182 days, as the reference draws it. */
|
|
23
|
+
export declare const HEAT_COLUMNS = 26;
|
|
24
|
+
export declare const HEAT_ROWS = 7;
|
|
25
|
+
/** Legend rows the reference shows before it offers "Show N more". */
|
|
26
|
+
export declare const LEGEND_LIMIT = 6;
|
|
27
|
+
/** Distance the reference leaves between an anchor and its tooltip. */
|
|
28
|
+
export declare const TIP_OFFSET_PX = 4;
|
|
29
|
+
/** Gap the chart's x-axis labels keep from each other when they are thinned. */
|
|
30
|
+
export declare const CHART_LABEL_GAP_PX = 8;
|
|
31
|
+
/** The card's two views. */
|
|
32
|
+
export type StatsTabId = 'overview' | 'models';
|
|
33
|
+
/** One segmented-control choice. */
|
|
34
|
+
export interface StatsOption<T extends string> {
|
|
35
|
+
readonly id: T;
|
|
36
|
+
readonly label: string;
|
|
37
|
+
}
|
|
38
|
+
/** One stat tile: a footnote label above a semibold value. */
|
|
39
|
+
export interface StatsTile {
|
|
40
|
+
readonly label: string;
|
|
41
|
+
readonly value: string;
|
|
42
|
+
/** The reference prints `Favorite model` one size down; long ids need it. */
|
|
43
|
+
readonly small?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** One heatmap cell: a day with its count, or a future cell left blank. */
|
|
46
|
+
export interface HeatCell {
|
|
47
|
+
readonly date: string;
|
|
48
|
+
readonly count: number;
|
|
49
|
+
/** 0 = no activity, 1-4 = the reference's four steps, null = after today. */
|
|
50
|
+
readonly level: number | null;
|
|
51
|
+
}
|
|
52
|
+
/** One model's slice of one chart bar. */
|
|
53
|
+
export interface ChartSegment {
|
|
54
|
+
readonly model: string;
|
|
55
|
+
readonly tokens: number;
|
|
56
|
+
/** Theme variable holding this model's colour. */
|
|
57
|
+
readonly color: string;
|
|
58
|
+
}
|
|
59
|
+
/** One bar: a day with tokens, its slices, and the tooltip it opens. */
|
|
60
|
+
export interface ChartDay {
|
|
61
|
+
readonly date: string;
|
|
62
|
+
readonly label: string;
|
|
63
|
+
readonly tokens: number;
|
|
64
|
+
readonly segments: readonly ChartSegment[];
|
|
65
|
+
}
|
|
66
|
+
/** One legend row, exactly as the reference composes it. */
|
|
67
|
+
export interface LegendRow {
|
|
68
|
+
readonly model: string;
|
|
69
|
+
readonly color: string;
|
|
70
|
+
/** `40.4M in · 3.6M out`, from the lifetime counters. */
|
|
71
|
+
readonly usage: string;
|
|
72
|
+
/** Share of the range's tokens, one decimal place. */
|
|
73
|
+
readonly percent: string;
|
|
74
|
+
}
|
|
75
|
+
/** Everything the `Overview` view draws. */
|
|
76
|
+
export interface StatsOverviewData {
|
|
77
|
+
readonly tiles: readonly StatsTile[];
|
|
78
|
+
/** One level per cell, column-major: `column * 7 + row`, Sunday first. */
|
|
79
|
+
readonly heat: readonly HeatCell[];
|
|
80
|
+
/** First index drawn after today; those cells stay transparent. */
|
|
81
|
+
readonly futureFrom: number;
|
|
82
|
+
/** Footer sentence, or null when the reference would draw none. */
|
|
83
|
+
readonly note: string | null;
|
|
84
|
+
}
|
|
85
|
+
/** Everything the `Models` view draws. */
|
|
86
|
+
export interface StatsModelsData {
|
|
87
|
+
/** Axis labels, lowest first; empty when the range saw no tokens. */
|
|
88
|
+
readonly ticks: readonly string[];
|
|
89
|
+
/** Top of the axis; bar heights are a share of it. */
|
|
90
|
+
readonly top: number;
|
|
91
|
+
/** One bar per day with usage in the range, oldest first. */
|
|
92
|
+
readonly days: readonly ChartDay[];
|
|
93
|
+
readonly legend: readonly LegendRow[];
|
|
94
|
+
/** Legend rows past {@link LEGEND_LIMIT}, behind "Show N more". */
|
|
95
|
+
readonly moreCount: number;
|
|
96
|
+
}
|
|
97
|
+
/** Everything the card needs to draw itself. */
|
|
98
|
+
export interface StatsCardData {
|
|
99
|
+
readonly tab: StatsTabId;
|
|
100
|
+
readonly tabs: readonly StatsOption<StatsTabId>[];
|
|
101
|
+
readonly ranges: readonly StatsOption<StatsRangeId>[];
|
|
102
|
+
readonly range: StatsRangeId;
|
|
103
|
+
/** Present when {@link tab} is `overview`. */
|
|
104
|
+
readonly overview: StatsOverviewData | null;
|
|
105
|
+
/** Present when {@link tab} is `models`. */
|
|
106
|
+
readonly models: StatsModelsData | null;
|
|
107
|
+
}
|
|
108
|
+
/** What the card reports back to its owner. */
|
|
109
|
+
export interface StatsCardHandlers {
|
|
110
|
+
readonly onTab: (id: StatsTabId) => void;
|
|
111
|
+
readonly onRange: (id: StatsRangeId) => void;
|
|
112
|
+
}
|
|
113
|
+
/** The mounted card. */
|
|
114
|
+
export interface StatsCard {
|
|
115
|
+
readonly element: HTMLElement;
|
|
116
|
+
/** Fit the chart's x-axis labels to the card's current width. */
|
|
117
|
+
layout(): void;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Level for one day: `ceil(day / busiest day * 4)` clamped to 0-4, which is the
|
|
121
|
+
* reference's own rule (`L = 80 - ceil(ratio * 4) * 8`).
|
|
122
|
+
*
|
|
123
|
+
* @param value - that day's count.
|
|
124
|
+
* @param peak - the busiest day in the window.
|
|
125
|
+
*/
|
|
126
|
+
export declare function heatLevel(value: number, peak: number): number;
|
|
127
|
+
/**
|
|
128
|
+
* The heatmap's tooltip line, exactly the reference's copy: `Sep 30 — 1,387`.
|
|
129
|
+
*
|
|
130
|
+
* @param date - local day key.
|
|
131
|
+
* @param count - that day's count.
|
|
132
|
+
* @returns the line the tooltip shows.
|
|
133
|
+
*/
|
|
134
|
+
export declare function heatTip(date: string, count: number): string;
|
|
135
|
+
/**
|
|
136
|
+
* Build the card.
|
|
137
|
+
*
|
|
138
|
+
* @param document - renderer document the card belongs to.
|
|
139
|
+
* @param data - header state plus the active view's content.
|
|
140
|
+
* @param handlers - tab and range selections.
|
|
141
|
+
* @returns the detached card and its layout hook.
|
|
142
|
+
*/
|
|
143
|
+
export declare function createStatsCard(document: Document, data: StatsCardData, handlers: StatsCardHandlers): StatsCard;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Number and date formatting for the statistics card.
|
|
3
|
+
*
|
|
4
|
+
* The card's copy is English, so its separators and its 12-hour clock are too:
|
|
5
|
+
* every formatter here is fixed to `en-US`, which is what the reference uses.
|
|
6
|
+
* They live in their own module because both the data layer (`view.ts`) and the
|
|
7
|
+
* DOM layer (`card.ts`) need them, and neither should import the other.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* One metric as the reference writes it: `1,556`.
|
|
11
|
+
*
|
|
12
|
+
* @param value - the raw count.
|
|
13
|
+
* @returns the display string.
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatCount(value: number): string;
|
|
16
|
+
/**
|
|
17
|
+
* Token totals, scaled the way the reference scales them.
|
|
18
|
+
*
|
|
19
|
+
* @param value - raw token total.
|
|
20
|
+
* @returns `493.1M`, `12k`, or a plain count below a thousand.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatTokens(value: number): string;
|
|
23
|
+
/**
|
|
24
|
+
* One hour of the day, as the reference labels it (`11 AM`).
|
|
25
|
+
*
|
|
26
|
+
* @param hour - local hour, 0-23.
|
|
27
|
+
* @returns the label.
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatHour(hour: number): string;
|
|
30
|
+
/**
|
|
31
|
+
* One `YYYY-MM-DD` key as the reference labels a chart day (`Sep 30`).
|
|
32
|
+
*
|
|
33
|
+
* @param date - local day key.
|
|
34
|
+
* @returns the short label.
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatDayLabel(date: string): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ImplementedFeature } from '../../contracts/feature.ts';
|
|
2
|
+
/**
|
|
3
|
+
* New-session statistics card. DSH sells no cross-session aggregate, so the
|
|
4
|
+
* host half folds the session logs through a projection unit of its own and
|
|
5
|
+
* serves one snapshot on `/api/ccd-stats`; the card renders that snapshot with
|
|
6
|
+
* the card's presentation rules.
|
|
7
|
+
*/
|
|
8
|
+
export declare const statisticsFeature: ImplementedFeature;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CleanupScope } from '../../core/cleanup.ts';
|
|
2
|
+
import type { Logger } from '../../contracts/ports.ts';
|
|
3
|
+
import type { StatsSource } from './source.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Keep one card mounted inside the hero stack.
|
|
6
|
+
*
|
|
7
|
+
* @param document - renderer document carrying the conversation page.
|
|
8
|
+
* @param scope - cleanup scope owning the observer, the subscription and the card node.
|
|
9
|
+
* @param logger - sink for observer failures; the native page stays without a card.
|
|
10
|
+
* @param source - snapshot reader the card redraws from.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mountStatisticsCard(document: Document, scope: CleanupScope, logger: Logger, source: StatsSource): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The card's data source: one host route, polled on a scope-owned timer.
|
|
3
|
+
*
|
|
4
|
+
* The host serves `/api/ccd-stats` on its authenticated channel, so the read
|
|
5
|
+
* is an ordinary same-origin fetch — the session cookie the page already holds
|
|
6
|
+
* is what authorizes it, and the host applies its own trust fence before the
|
|
7
|
+
* handler runs. Nothing here holds a socket or a second copy of the data.
|
|
8
|
+
*
|
|
9
|
+
* The poll cadence follows the host's progress counters: while cold sessions
|
|
10
|
+
* are still being folded (`pending > 0`) the card is genuinely incomplete, so
|
|
11
|
+
* it refreshes every couple of seconds; once the snapshot is complete it drops
|
|
12
|
+
* to a slow poll. A missing route (the host half is off) hides the card rather
|
|
13
|
+
* than failing the mount.
|
|
14
|
+
*/
|
|
15
|
+
import { type StatsSnapshot } from '../../../shared/stats.ts';
|
|
16
|
+
import type { Logger } from '../../contracts/ports.ts';
|
|
17
|
+
/** One snapshot reader the card subscribes to. */
|
|
18
|
+
export interface StatsSource {
|
|
19
|
+
/** The last accepted snapshot, or null while there is none. */
|
|
20
|
+
readonly current: StatsSnapshot | null;
|
|
21
|
+
/** Observe snapshots; returns the unsubscribe function. */
|
|
22
|
+
subscribe(listener: (snapshot: StatsSnapshot | null) => void): () => void;
|
|
23
|
+
/** Stop polling and abort any read in flight. */
|
|
24
|
+
dispose(): void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Start polling the host's statistics route.
|
|
28
|
+
*
|
|
29
|
+
* @param options - logger and an optional route override (tests).
|
|
30
|
+
* @returns the live source.
|
|
31
|
+
*/
|
|
32
|
+
export declare function createStatsSource(options: {
|
|
33
|
+
logger: Logger;
|
|
34
|
+
url?: string;
|
|
35
|
+
}): StatsSource;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snapshot → card data: the reference's own presentation rules.
|
|
3
|
+
*
|
|
4
|
+
* Two views share one snapshot. `Overview` draws 182 days (26 columns × 7 rows)
|
|
5
|
+
* ending on the Saturday of the current week, with the day rows running
|
|
6
|
+
* Sunday-first — the window the reference computes — and levels of
|
|
7
|
+
* `ceil(count / busiest day * 4)`; days after today are transparent rather than
|
|
8
|
+
* empty, which is why the card data marks them instead of giving them a level.
|
|
9
|
+
* `Models` draws one bar per day that produced tokens, stacked by model and
|
|
10
|
+
* scaled to the axis the reference derives from the busiest day.
|
|
11
|
+
*
|
|
12
|
+
* The range switch filters the tiles, the chart and the footer sentence, but
|
|
13
|
+
* not the heatmap or `Peak hour`: the reference feeds both from unfiltered
|
|
14
|
+
* statistics, and its heatmap is a fixed 182-day window.
|
|
15
|
+
*/
|
|
16
|
+
import { type StatsDay, type StatsRangeId, type StatsSnapshot } from '../../../shared/stats.ts';
|
|
17
|
+
import { type HeatCell, type StatsCardData, type StatsModelsData, type StatsOption, type StatsOverviewData, type StatsTabId } from './card.ts';
|
|
18
|
+
import { formatCount, formatDayLabel, formatHour, formatTokens } from './format.ts';
|
|
19
|
+
export { formatCount, formatDayLabel, formatHour, formatTokens };
|
|
20
|
+
/** Days the heatmap draws: 26 weeks. */
|
|
21
|
+
export declare const HEAT_DAYS: number;
|
|
22
|
+
/** The reference's own tabs, in its order. */
|
|
23
|
+
export declare const STATS_TABS: readonly StatsOption<StatsTabId>[];
|
|
24
|
+
/** The reference's own ranges, in its order. */
|
|
25
|
+
export declare const STATS_RANGE_OPTIONS: readonly StatsOption<StatsRangeId>[];
|
|
26
|
+
/** Which view and range the card is showing. */
|
|
27
|
+
export interface StatsViewState {
|
|
28
|
+
readonly tab: StatsTabId;
|
|
29
|
+
readonly range: StatsRangeId;
|
|
30
|
+
}
|
|
31
|
+
/** What a freshly mounted card shows, matching the reference's defaults. */
|
|
32
|
+
export declare const INITIAL_STATS_VIEW: StatsViewState;
|
|
33
|
+
/** What the card draws for the 182-day window. */
|
|
34
|
+
export interface HeatWindow {
|
|
35
|
+
/** One cell per day, column-major: `column * 7 + row`, Sunday first. */
|
|
36
|
+
readonly heat: readonly HeatCell[];
|
|
37
|
+
/** First index drawn after today; those cells stay transparent. */
|
|
38
|
+
readonly futureFrom: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Lay the host's sparse day counts out on the reference's 26-week grid.
|
|
42
|
+
*
|
|
43
|
+
* @param days - local day keys with their counts.
|
|
44
|
+
* @param now - the current instant (injectable for tests).
|
|
45
|
+
* @returns the cells and where "today" ends.
|
|
46
|
+
*/
|
|
47
|
+
export declare function heatWindow(days: readonly StatsDay[], now?: Date): HeatWindow;
|
|
48
|
+
/**
|
|
49
|
+
* The reference's y-axis steps: from `1/2/5/10/20/50` scaled to the magnitude
|
|
50
|
+
* of `max / 6`, keep the candidates that fit in six steps and take the one
|
|
51
|
+
* whose top is lowest, preferring four steps on a tie.
|
|
52
|
+
*
|
|
53
|
+
* @param max - the busiest day's tokens.
|
|
54
|
+
* @returns the tick values, lowest first; empty when there is nothing to scale.
|
|
55
|
+
*/
|
|
56
|
+
export declare function tokenTicks(max: number): number[];
|
|
57
|
+
/**
|
|
58
|
+
* The colour of the n-th busiest model.
|
|
59
|
+
*
|
|
60
|
+
* The reference computes `hsl(217 70% min(88, 58 + 7n)%)`, which flattens into
|
|
61
|
+
* six shades; the theme carries those six so both themes can express them.
|
|
62
|
+
*
|
|
63
|
+
* @param index - position in the range's model list.
|
|
64
|
+
* @returns a theme variable holding that shade.
|
|
65
|
+
*/
|
|
66
|
+
export declare function modelColor(index: number): string;
|
|
67
|
+
/**
|
|
68
|
+
* The `Overview` body for one range.
|
|
69
|
+
*
|
|
70
|
+
* @param snapshot - the host's aggregate.
|
|
71
|
+
* @param range - the selected range.
|
|
72
|
+
* @param random - stable draw for the footer's book choice.
|
|
73
|
+
* @param now - the current instant (injectable for tests).
|
|
74
|
+
* @returns tiles, heat cells and the footer sentence.
|
|
75
|
+
*/
|
|
76
|
+
export declare function buildOverview(snapshot: StatsSnapshot, range: StatsRangeId, random: () => number, now?: Date): StatsOverviewData;
|
|
77
|
+
/**
|
|
78
|
+
* The `Models` body for one range.
|
|
79
|
+
*
|
|
80
|
+
* @param snapshot - the host's aggregate.
|
|
81
|
+
* @param range - the selected range.
|
|
82
|
+
* @param now - the current instant (injectable for tests).
|
|
83
|
+
* @returns the chart and its legend.
|
|
84
|
+
*/
|
|
85
|
+
export declare function buildModels(snapshot: StatsSnapshot, range: StatsRangeId, now?: Date): StatsModelsData;
|
|
86
|
+
/**
|
|
87
|
+
* Build everything the card draws for one snapshot and view state.
|
|
88
|
+
*
|
|
89
|
+
* @param snapshot - the host's aggregate.
|
|
90
|
+
* @param state - the selected tab and range.
|
|
91
|
+
* @param random - stable draw for the footer's book choice.
|
|
92
|
+
* @param now - the current instant (injectable for tests).
|
|
93
|
+
* @returns the card data.
|
|
94
|
+
*/
|
|
95
|
+
export declare function buildCardData(snapshot: StatsSnapshot, state: StatsViewState, random: () => number, now?: Date): StatsCardData;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { apply, inject } from './apply.ts';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FeatureEnvironment } from '../contracts/feature.ts';
|
|
2
|
+
import type { CleanupScope } from '../core/cleanup.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Plugin-scoped presentation base: the root activation marker, the design
|
|
5
|
+
* variables, the shared Composer geometry two features depend on (siblings must
|
|
6
|
+
* not import each other), the host popup chrome (DESIGN.md §6.7) and the
|
|
7
|
+
* semantic token overrides.
|
|
8
|
+
*
|
|
9
|
+
* The override layer is recomputed on every mount, so a configuration change
|
|
10
|
+
* releases the previous layer through the same scope that owns the stylesheets
|
|
11
|
+
* and stacks the new one; `overrideTokens` replaces a source's layer wholesale.
|
|
12
|
+
* @param environment - activation services and configuration.
|
|
13
|
+
* @param scope - activation scope owning every resource mounted here.
|
|
14
|
+
*/
|
|
15
|
+
export declare function mountTheme(environment: FeatureEnvironment, scope: CleanupScope): void;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colour arithmetic behind the configurable surfaces.
|
|
3
|
+
*
|
|
4
|
+
* The plugin ships one light palette; a user-supplied background therefore has
|
|
5
|
+
* to bring its own hover, selection and line steps, or a dark canvas would keep
|
|
6
|
+
* light grey rows. Every value here is derived from the two configured colours
|
|
7
|
+
* with fixed ratios, so the result is deterministic and testable — and no other
|
|
8
|
+
* stylesheet gains a literal colour (see `scripts/check-architecture.mjs`).
|
|
9
|
+
*
|
|
10
|
+
* The dark palette is not derived: it is a fixed set of values measured for the
|
|
11
|
+
* dark canvas and mirrored by `theme/tokens.css`, because a colour the user
|
|
12
|
+
* picked for a light canvas says nothing about the dark one.
|
|
13
|
+
*/
|
|
14
|
+
export interface Rgb {
|
|
15
|
+
readonly r: number;
|
|
16
|
+
readonly g: number;
|
|
17
|
+
readonly b: number;
|
|
18
|
+
}
|
|
19
|
+
/** The surfaces a configured background produces. */
|
|
20
|
+
export interface Palette {
|
|
21
|
+
readonly canvas: string;
|
|
22
|
+
readonly sidebar: string;
|
|
23
|
+
readonly card: string;
|
|
24
|
+
readonly track: string;
|
|
25
|
+
readonly raised: string;
|
|
26
|
+
readonly hover: string;
|
|
27
|
+
readonly selected: string;
|
|
28
|
+
readonly border: string;
|
|
29
|
+
readonly borderStrong: string;
|
|
30
|
+
readonly borderSoft: string;
|
|
31
|
+
readonly tableHeadLine: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Built-in surfaces, byte-identical to the fallback declarations in
|
|
35
|
+
* `theme/tokens.css` (`--ccd-canvas`, `--ccd-sidebar`, `--ccd-border`); a local
|
|
36
|
+
* test parses that stylesheet and fails when the two drift apart.
|
|
37
|
+
*/
|
|
38
|
+
export declare const BUILT_IN_SURFACES: Readonly<{
|
|
39
|
+
canvas: "#fcfcfb";
|
|
40
|
+
sidebar: "#fbfbfa";
|
|
41
|
+
border: "#e3e3e1";
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Built-in dark palette, byte-identical to the dark block of
|
|
45
|
+
* `theme/tokens.css`; a local test parses that stylesheet and fails when the two
|
|
46
|
+
* drift apart. Configured backgrounds do not reach this mode (see the file
|
|
47
|
+
* comment), so the theme layer can publish these values as the `dark` side of
|
|
48
|
+
* every surface pair.
|
|
49
|
+
*/
|
|
50
|
+
export declare const BUILT_IN_DARK: Palette;
|
|
51
|
+
/**
|
|
52
|
+
* Parse one normalized `#rrggbb` colour.
|
|
53
|
+
* @param value - the colour to parse.
|
|
54
|
+
* @returns its channels, or undefined when it is not a six-digit hex colour.
|
|
55
|
+
*/
|
|
56
|
+
export declare function parseColour(value: string): Rgb | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Format channels as lowercase `#rrggbb`.
|
|
59
|
+
* @param rgb - channels to format.
|
|
60
|
+
* @returns the CSS colour.
|
|
61
|
+
*/
|
|
62
|
+
export declare function formatColour(rgb: Rgb): string;
|
|
63
|
+
/**
|
|
64
|
+
* Mix one colour toward another.
|
|
65
|
+
* @param base - the colour being adjusted.
|
|
66
|
+
* @param toward - the colour mixed in.
|
|
67
|
+
* @param ratio - share of `toward`, from 0 to 1.
|
|
68
|
+
* @returns the mixed colour.
|
|
69
|
+
*/
|
|
70
|
+
export declare function mixColour(base: Rgb, toward: Rgb, ratio: number): Rgb;
|
|
71
|
+
/**
|
|
72
|
+
* Derive every surface step from the two configured backgrounds.
|
|
73
|
+
*
|
|
74
|
+
* An empty or unusable value falls back to the built-in surface, so the theme
|
|
75
|
+
* layer can call this with raw configuration and still get usable colours.
|
|
76
|
+
* @param canvas - normalized conversation/canvas background, or empty.
|
|
77
|
+
* @param sidebar - normalized sidebar background, or empty.
|
|
78
|
+
* @returns the palette the theme layer publishes as tokens.
|
|
79
|
+
*/
|
|
80
|
+
export declare function derivePalette(canvas: string, sidebar: string): Palette;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ThemeTokenOverrides } from '@deepseek-ai/dsh-client-ui-theme/client';
|
|
2
|
+
import type { StyleConfig } from '../../shared/config.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Compose host semantic tokens and configured --ccd-* overrides as light/dark
|
|
5
|
+
* pairs. The theme presenter writes the active values onto body. Configured
|
|
6
|
+
* backgrounds affect light mode; dark mode uses the built-in palette. Font
|
|
7
|
+
* choices apply to both schemes. Other values come from theme/tokens.css.
|
|
8
|
+
*/
|
|
9
|
+
export declare const THEME_OVERRIDE_SOURCE = "dsh-ccd-style";
|
|
10
|
+
/** Host semantic surfaces the CCD canvas replaces. */
|
|
11
|
+
export declare const HOST_SURFACE_TOKENS: Readonly<{
|
|
12
|
+
base: "--dsw-alias-bg-base";
|
|
13
|
+
sidebar: "--dsw-specific-sidebar-fill";
|
|
14
|
+
border: "--dsw-alias-border-l3";
|
|
15
|
+
}>;
|
|
16
|
+
/** Host typography tokens; both drive app-wide stacks. */
|
|
17
|
+
export declare const HOST_FONT_TOKENS: Readonly<{
|
|
18
|
+
ui: "--dsw-font-family";
|
|
19
|
+
code: "--ds-font-family-code";
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the whole override layer for one configuration.
|
|
23
|
+
* @param config - the adopted configuration section.
|
|
24
|
+
* @returns token overrides keyed by custom-property name; never empty, because
|
|
25
|
+
* the host surface tokens always travel with the plugin's own canvas.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveThemeTokens(config: StyleConfig): ThemeTokenOverrides;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import z from '@deepseek-ai/schemastery';
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
/**
|
|
4
|
+
* Fields are marked `.volatile()` so the DSH settings layer projects them into
|
|
5
|
+
* a configuration form: only volatile paths are served to the client
|
|
6
|
+
* (`dsh-settings` `volatileForm`/`projectForm`), and the generated form is what
|
|
7
|
+
* the browser half reads through `ctx.configForms.get(entryId)`. Marking them
|
|
8
|
+
* also gives the plugin a real settings surface: the row configuration page
|
|
9
|
+
* registered by the browser half writes these paths back through the same
|
|
10
|
+
* transport, and the Host validates the whole candidate before touching disk.
|
|
11
|
+
*
|
|
12
|
+
* The `pattern` guards are the first of three: the settings boundary rejects an
|
|
13
|
+
* unusable candidate, the configuration page validates before it submits, and
|
|
14
|
+
* `adoptConfig` falls back to the defaults for a hand-edited patch file.
|
|
15
|
+
*/
|
|
16
|
+
export declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
17
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
18
|
+
debug: z<boolean, boolean, "volatile-defined">;
|
|
19
|
+
features: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
20
|
+
shell: z<boolean, boolean, "defined">;
|
|
21
|
+
sidebar: z<boolean, boolean, "defined">;
|
|
22
|
+
'new-session': z<boolean, boolean, "defined">;
|
|
23
|
+
conversation: z<boolean, boolean, "defined">;
|
|
24
|
+
'tool-calls': z<boolean, boolean, "defined">;
|
|
25
|
+
statistics: z<boolean, boolean, "defined">;
|
|
26
|
+
'composer-pet': z<boolean, boolean, "defined">;
|
|
27
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
28
|
+
shell: z<boolean, boolean, "defined">;
|
|
29
|
+
sidebar: z<boolean, boolean, "defined">;
|
|
30
|
+
'new-session': z<boolean, boolean, "defined">;
|
|
31
|
+
conversation: z<boolean, boolean, "defined">;
|
|
32
|
+
'tool-calls': z<boolean, boolean, "defined">;
|
|
33
|
+
statistics: z<boolean, boolean, "defined">;
|
|
34
|
+
'composer-pet': z<boolean, boolean, "defined">;
|
|
35
|
+
}>>>, "volatile-defined">;
|
|
36
|
+
appearance: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
37
|
+
canvas: z<string, string, "defined">;
|
|
38
|
+
sidebar: z<string, string, "defined">;
|
|
39
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
40
|
+
canvas: z<string, string, "defined">;
|
|
41
|
+
sidebar: z<string, string, "defined">;
|
|
42
|
+
}>>>, "volatile-defined">;
|
|
43
|
+
fonts: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
44
|
+
uiLatin: z<string, string, "defined">;
|
|
45
|
+
uiCjk: z<string, string, "defined">;
|
|
46
|
+
code: z<string, string, "defined">;
|
|
47
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
48
|
+
uiLatin: z<string, string, "defined">;
|
|
49
|
+
uiCjk: z<string, string, "defined">;
|
|
50
|
+
code: z<string, string, "defined">;
|
|
51
|
+
}>>>, "volatile-defined">;
|
|
52
|
+
}>>, Schemastery.ObjectT<NoInfer<{
|
|
53
|
+
enabled: z<boolean, boolean, "volatile-defined">;
|
|
54
|
+
debug: z<boolean, boolean, "volatile-defined">;
|
|
55
|
+
features: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
56
|
+
shell: z<boolean, boolean, "defined">;
|
|
57
|
+
sidebar: z<boolean, boolean, "defined">;
|
|
58
|
+
'new-session': z<boolean, boolean, "defined">;
|
|
59
|
+
conversation: z<boolean, boolean, "defined">;
|
|
60
|
+
'tool-calls': z<boolean, boolean, "defined">;
|
|
61
|
+
statistics: z<boolean, boolean, "defined">;
|
|
62
|
+
'composer-pet': z<boolean, boolean, "defined">;
|
|
63
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
64
|
+
shell: z<boolean, boolean, "defined">;
|
|
65
|
+
sidebar: z<boolean, boolean, "defined">;
|
|
66
|
+
'new-session': z<boolean, boolean, "defined">;
|
|
67
|
+
conversation: z<boolean, boolean, "defined">;
|
|
68
|
+
'tool-calls': z<boolean, boolean, "defined">;
|
|
69
|
+
statistics: z<boolean, boolean, "defined">;
|
|
70
|
+
'composer-pet': z<boolean, boolean, "defined">;
|
|
71
|
+
}>>>, "volatile-defined">;
|
|
72
|
+
appearance: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
73
|
+
canvas: z<string, string, "defined">;
|
|
74
|
+
sidebar: z<string, string, "defined">;
|
|
75
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
76
|
+
canvas: z<string, string, "defined">;
|
|
77
|
+
sidebar: z<string, string, "defined">;
|
|
78
|
+
}>>>, "volatile-defined">;
|
|
79
|
+
fonts: z<NoInfer<Schemastery.ObjectS<NoInfer<{
|
|
80
|
+
uiLatin: z<string, string, "defined">;
|
|
81
|
+
uiCjk: z<string, string, "defined">;
|
|
82
|
+
code: z<string, string, "defined">;
|
|
83
|
+
}>>>, NoInfer<Schemastery.ObjectT<NoInfer<{
|
|
84
|
+
uiLatin: z<string, string, "defined">;
|
|
85
|
+
uiCjk: z<string, string, "defined">;
|
|
86
|
+
code: z<string, string, "defined">;
|
|
87
|
+
}>>>, "volatile-defined">;
|
|
88
|
+
}>>, "plain">;
|
|
89
|
+
/**
|
|
90
|
+
* Host half: the configuration surface the interface reads, plus the read-only
|
|
91
|
+
* session-log fold behind the statistics card.
|
|
92
|
+
*
|
|
93
|
+
* The card's numbers come from a projection unit of the host's own session
|
|
94
|
+
* projection seam (see `stats/unit.ts`) and are served over the host's
|
|
95
|
+
* authenticated fetch registry; nothing is written back to a profile, a
|
|
96
|
+
* session log, or any second state store.
|
|
97
|
+
*
|
|
98
|
+
* Registration follows the plugin switch alone: while the plugin is on, the
|
|
99
|
+
* fold and the route are live, so turning the statistics *feature* on in the
|
|
100
|
+
* settings page shows the card without a restart. Turning the plugin itself
|
|
101
|
+
* off costs the host nothing, because nothing is registered at all.
|
|
102
|
+
*
|
|
103
|
+
* @param ctx - host plugin context.
|
|
104
|
+
* @param config - resolved Host configuration cells (validated by the loader).
|
|
105
|
+
*/
|
|
106
|
+
export declare function apply(ctx: Context, config: unknown): void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-session aggregation: many per-session fold results → one card snapshot.
|
|
3
|
+
*
|
|
4
|
+
* Pure and synchronous, so the numbers the card shows are testable without a
|
|
5
|
+
* host: the service layer owns the session listing, the cold reads and the
|
|
6
|
+
* transport, this file owns only the arithmetic.
|
|
7
|
+
*
|
|
8
|
+
* The card offers the reference's three ranges, and the reference computes all
|
|
9
|
+
* of them from the same per-day tables: a range is a lower date bound
|
|
10
|
+
* (`start = today - (days - 1)`) over days, messages and per-day model tokens,
|
|
11
|
+
* while each session is counted once when any of its active days falls inside
|
|
12
|
+
* the range. `Peak hour` is the one tile the reference leaves unfiltered — it
|
|
13
|
+
* reads that value from its unfiltered statistics — so the hour histogram here
|
|
14
|
+
* is all-time as well.
|
|
15
|
+
*
|
|
16
|
+
* The one bounded output is the shipped day list: the ranges count every
|
|
17
|
+
* active day, while `days` and `modelDays` carry only the most recent
|
|
18
|
+
* {@link STATS_DAY_LIMIT} days so a long-lived install cannot grow the
|
|
19
|
+
* response without limit.
|
|
20
|
+
*/
|
|
21
|
+
import { type StatsSessionUsage, type StatsSnapshot } from '../../shared/stats.ts';
|
|
22
|
+
/** Counters the aggregate needs from outside the fold. */
|
|
23
|
+
export interface AggregateOptions {
|
|
24
|
+
/** Computation time, epoch ms. */
|
|
25
|
+
readonly now: number;
|
|
26
|
+
/** Sessions still being folded. */
|
|
27
|
+
readonly pending: number;
|
|
28
|
+
/** Sessions whose logs could not be read. */
|
|
29
|
+
readonly missed: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Aggregate every session's fold result into the card's snapshot.
|
|
33
|
+
*
|
|
34
|
+
* @param values - one view per visible stored session.
|
|
35
|
+
* @param options - computation time and the service's progress counters.
|
|
36
|
+
* @returns the snapshot the route serves.
|
|
37
|
+
*/
|
|
38
|
+
export declare function aggregateUsage(values: Iterable<StatsSessionUsage>, options: AggregateOptions): StatsSnapshot;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read live session projections first, then durable checkpoints, then cold-fold
|
|
3
|
+
* missing checkpoints in the background. Failed sessions retry after cooldown.
|
|
4
|
+
* Aggregates are served through the host's authenticated connection.fetch route.
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
7
|
+
/**
|
|
8
|
+
* Mount the aggregation and its route, once the host services it needs exist.
|
|
9
|
+
*
|
|
10
|
+
* A plugin's `apply` runs as soon as its own fiber starts, which can be before
|
|
11
|
+
* the session projection registry and the connection carrier: the optional
|
|
12
|
+
* injection below waits for both, and a deployment that mounts neither simply
|
|
13
|
+
* never gets the card.
|
|
14
|
+
*
|
|
15
|
+
* @param ctx - host plugin context.
|
|
16
|
+
* @param isEnabled - current plugin switch, read at mount time.
|
|
17
|
+
*/
|
|
18
|
+
export declare function mountStatistics(ctx: Context, isEnabled: () => boolean): void;
|