dsh-context 0.57.0 → 0.59.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 +2 -1
- package/lib/client.js +743 -400
- package/lib/index.d.ts +16 -0
- package/lib/index.js +158 -53
- package/package.json +15 -14
package/lib/index.d.ts
CHANGED
|
@@ -8,7 +8,13 @@ interface ActivityState {
|
|
|
8
8
|
days: Record<string, {
|
|
9
9
|
tokens: number;
|
|
10
10
|
requests: number;
|
|
11
|
+
cost?: SessionCostUsage;
|
|
11
12
|
}>;
|
|
13
|
+
/** The route in force (last `request/header`'s config wins) — prices each settlement. */
|
|
14
|
+
model?: string;
|
|
15
|
+
provider?: string;
|
|
16
|
+
/** The open step's start instant (armed by `step/start`, cleared by `step/end`). */
|
|
17
|
+
stepStart?: number;
|
|
12
18
|
}
|
|
13
19
|
//#endregion
|
|
14
20
|
//#region src/host/headers.d.ts
|
|
@@ -299,6 +305,16 @@ interface ActivityDay {
|
|
|
299
305
|
tokens: number;
|
|
300
306
|
/** Completed model calls (assistant settlements) that day. */
|
|
301
307
|
requests: number;
|
|
308
|
+
/**
|
|
309
|
+
* The day's billed buckets keyed provider → model → pricing period — the
|
|
310
|
+
* same SessionCostUsage raw material the timeline's session-cost totals
|
|
311
|
+
* carry, scoped to the day the requests INITIATED in, so the client prices
|
|
312
|
+
* each day off the same model-price book as the KPI band. ADDITIVE-OPTIONAL:
|
|
313
|
+
* absent on rows folded before the field existed (older plugin builds), on
|
|
314
|
+
* days whose settlements predate any model header, and on settlements the
|
|
315
|
+
* provider left unmetered — the usage chart degrades to tokens-only bars.
|
|
316
|
+
*/
|
|
317
|
+
cost?: SessionCostUsage;
|
|
302
318
|
}
|
|
303
319
|
/**
|
|
304
320
|
* The per-session daily activity ledger (`contextActivity` wire value):
|
package/lib/index.js
CHANGED
|
@@ -11,11 +11,14 @@ import { randomUUID } from "node:crypto";
|
|
|
11
11
|
* The provider-id seam between dsh request envelopes and the models.dev
|
|
12
12
|
* registry: client/cost.ts resolves price-book branches through it, and
|
|
13
13
|
* host/fold.ts uses the DeepSeek resolution to split the session-cost totals
|
|
14
|
-
* into peak/off-peak periods. Only the renames live here —
|
|
15
|
-
*
|
|
14
|
+
* into peak/off-peak periods. Only the renames live here — a dsh route key
|
|
15
|
+
* that is not a registry id (user-declared gateways, `claude`/`codex`
|
|
16
|
+
* subscriptions, org-prefixed catalogs) passes through and prices through
|
|
17
|
+
* the model-side resolution index instead (client/cost.ts).
|
|
16
18
|
*/
|
|
17
19
|
const MODELS_DEV_PROVIDER_IDS = {
|
|
18
20
|
"deepseek-official": "deepseek",
|
|
21
|
+
"deepseek-account": "deepseek",
|
|
19
22
|
"kimi-coding": "moonshotai",
|
|
20
23
|
"minimax-cn": "minimax",
|
|
21
24
|
"zai-coding-cn": "zhipuai"
|
|
@@ -1053,6 +1056,10 @@ function tokenCountOf(value) {
|
|
|
1053
1056
|
* DeepSeek's peak windows (the official list: UTC 01:00–04:00 and 06:00–10:00,
|
|
1054
1057
|
* Monday through Friday — Beijing Time 09:00–12:00 and 14:00–18:00). All other
|
|
1055
1058
|
* hours, plus entire weekends, bill at the half-price off-peak rate.
|
|
1059
|
+
*
|
|
1060
|
+
* Exported for the activity unit (host/activity.ts): the daily ledger prices
|
|
1061
|
+
* each day's buckets with the same split, so its per-day fees sum to the
|
|
1062
|
+
* session-cost totals the timeline fold books.
|
|
1056
1063
|
*/
|
|
1057
1064
|
function isPeakUtc(time) {
|
|
1058
1065
|
const at = new Date(time);
|
|
@@ -1741,7 +1748,8 @@ function dayKeyOf(time) {
|
|
|
1741
1748
|
//#region src/host/activity.ts
|
|
1742
1749
|
/**
|
|
1743
1750
|
* The `contextActivity` session projection unit — the per-day activity
|
|
1744
|
-
* ledger behind the Context Dashboard's heatmap
|
|
1751
|
+
* ledger behind the Context Dashboard's heatmap and its last-7-days usage
|
|
1752
|
+
* chart.
|
|
1745
1753
|
*
|
|
1746
1754
|
* The timeline unit (fold.ts) is a "current snapshot" fold: it prices the
|
|
1747
1755
|
* context as it stands NOW, which cannot draw a per-day chart. This unit
|
|
@@ -1750,75 +1758,165 @@ function dayKeyOf(time) {
|
|
|
1750
1758
|
* completed request to its day and, when the provider reported a usage
|
|
1751
1759
|
* object, the day's billed-token figure grows by the disjoint buckets
|
|
1752
1760
|
* (uncached input + cache read + cache write + output — the same semantics
|
|
1753
|
-
* the timeline's request records and the official token meter use).
|
|
1754
|
-
*
|
|
1755
|
-
*
|
|
1761
|
+
* the timeline's request records and the official token meter use). Each
|
|
1762
|
+
* metered settlement also books its buckets into the day's per-(provider,
|
|
1763
|
+
* model, period) pricing record — the same raw material the timeline's
|
|
1764
|
+
* session-cost totals carry (SessionCostUsage), so the client prices every
|
|
1765
|
+
* day off the SAME model-price book and estimator it prices the KPI band
|
|
1766
|
+
* with. Buckets attribute to the day the open STEP STARTED (the turn's
|
|
1767
|
+
* initiation, armed by `step/start` and cleared by `step/end` — the
|
|
1768
|
+
* timeline fold's own pending-slot protocol), falling back to the
|
|
1769
|
+
* settlement instant when no stamp is armed; the peak/off split prices the
|
|
1770
|
+
* same instant, so a fee always lands on one day at one rate.
|
|
1756
1771
|
*
|
|
1757
|
-
* One wire contract, one small state: a day entry is two integers
|
|
1758
|
-
*
|
|
1759
|
-
*
|
|
1760
|
-
*
|
|
1761
|
-
*
|
|
1762
|
-
*
|
|
1763
|
-
* state
|
|
1772
|
+
* One wire contract, one small state: a day entry is two integers plus the
|
|
1773
|
+
* optional pricing record, the route in force rides the state (last
|
|
1774
|
+
* `request/header` wins), and the retention cap keeps at most
|
|
1775
|
+
* {@link MAX_KEPT_DAYS} keys, so the value riding every session-list row
|
|
1776
|
+
* stays trivial next to the timeline head. Same projection contract as the
|
|
1777
|
+
* sibling units: pure init/apply/view, unknown or malformed events return
|
|
1778
|
+
* the state unchanged, and no `undefined`-valued property ever materializes
|
|
1779
|
+
* (the plain-JSON persisted-state precondition).
|
|
1764
1780
|
*/
|
|
1765
1781
|
/**
|
|
1766
1782
|
* Retention cap on ledger days. A little over a year of daily-active
|
|
1767
1783
|
* sessions; the oldest keys drop first (key order IS chronological order).
|
|
1768
1784
|
*/
|
|
1769
1785
|
const MAX_KEPT_DAYS = 400;
|
|
1786
|
+
const costBucketSchema = z.object({
|
|
1787
|
+
uncached: z.number().int().nonnegative(),
|
|
1788
|
+
cacheRead: z.number().int().nonnegative(),
|
|
1789
|
+
cacheWrite: z.number().int().nonnegative(),
|
|
1790
|
+
output: z.number().int().nonnegative()
|
|
1791
|
+
}).strict();
|
|
1792
|
+
const costModelSchema$1 = z.object({
|
|
1793
|
+
peak: costBucketSchema.optional(),
|
|
1794
|
+
off: costBucketSchema.optional()
|
|
1795
|
+
}).strict();
|
|
1796
|
+
const costUsageSchema$1 = z.record(z.string(), z.record(z.string(), costModelSchema$1));
|
|
1770
1797
|
const activityDaySchema = z.object({
|
|
1771
1798
|
tokens: z.number().int().nonnegative(),
|
|
1772
|
-
requests: z.number().int().nonnegative()
|
|
1799
|
+
requests: z.number().int().nonnegative(),
|
|
1800
|
+
cost: costUsageSchema$1.optional()
|
|
1773
1801
|
}).strict();
|
|
1774
1802
|
/** Validate the wire payload before it leaves the host (strict: no drift). */
|
|
1775
1803
|
const contextActivitySchema = z.object({ days: z.record(z.string(), activityDaySchema) }).strict();
|
|
1776
|
-
/** The persisted fold-state schema —
|
|
1777
|
-
const activityStateSchema = z.object({
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
*
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1804
|
+
/** The persisted fold-state schema — validated before a checkpoint row seeds a fold. */
|
|
1805
|
+
const activityStateSchema = z.object({
|
|
1806
|
+
days: z.record(z.string(), activityDaySchema),
|
|
1807
|
+
model: z.string().optional(),
|
|
1808
|
+
provider: z.string().optional(),
|
|
1809
|
+
stepStart: z.number().optional()
|
|
1810
|
+
});
|
|
1811
|
+
/**
|
|
1812
|
+
* One durable usage object's billed buckets, or null when NO bucket is
|
|
1813
|
+
* readable (the same rule the timeline fold bills by: a settlement that
|
|
1814
|
+
* carried no usage still counts its request without fabricating tokens).
|
|
1815
|
+
* Every bucket passes the shared per-bucket sanitizer ({@link tokenCountOf}
|
|
1816
|
+
* — fractions round, negatives clamp, garbage reads absent).
|
|
1817
|
+
*/
|
|
1818
|
+
function billedBucketsOf(value) {
|
|
1819
|
+
if (value === null || typeof value !== "object") return null;
|
|
1788
1820
|
const usage = value;
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1821
|
+
const input = tokenCountOf(usage.inputTokens);
|
|
1822
|
+
const cacheRead = tokenCountOf(usage.cacheReadTokens);
|
|
1823
|
+
const cacheWrite = tokenCountOf(usage.cacheWriteTokens);
|
|
1824
|
+
const output = tokenCountOf(usage.outputTokens);
|
|
1825
|
+
if (input === null && cacheRead === null && cacheWrite === null && output === null) return null;
|
|
1826
|
+
return {
|
|
1827
|
+
input: input ?? 0,
|
|
1828
|
+
cacheRead: cacheRead ?? 0,
|
|
1829
|
+
cacheWrite: cacheWrite ?? 0,
|
|
1830
|
+
output: output ?? 0
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
/**
|
|
1834
|
+
* Add one settlement's billed buckets to a day's pricing record — the same
|
|
1835
|
+
* clone-along-the-mutated-path walk the timeline fold's accumulateCost
|
|
1836
|
+
* prices by, so the two folds' records share one shape and one semantics.
|
|
1837
|
+
* The pricing period splits off the SAME instant the day bucket does: a fee
|
|
1838
|
+
* can never land on one day at the neighbouring window's rate.
|
|
1839
|
+
*/
|
|
1840
|
+
function pricedDayOf(prev, provider, model, period, usage) {
|
|
1841
|
+
const models = prev?.[provider] ?? {};
|
|
1842
|
+
const periods = models[model] ?? {};
|
|
1843
|
+
const b = periods[period] ?? {
|
|
1844
|
+
uncached: 0,
|
|
1845
|
+
cacheRead: 0,
|
|
1846
|
+
cacheWrite: 0,
|
|
1847
|
+
output: 0
|
|
1848
|
+
};
|
|
1849
|
+
return {
|
|
1850
|
+
...prev,
|
|
1851
|
+
[provider]: {
|
|
1852
|
+
...models,
|
|
1853
|
+
[model]: {
|
|
1854
|
+
...periods,
|
|
1855
|
+
[period]: {
|
|
1856
|
+
uncached: b.uncached + usage.input,
|
|
1857
|
+
cacheRead: b.cacheRead + usage.cacheRead,
|
|
1858
|
+
cacheWrite: b.cacheWrite + usage.cacheWrite,
|
|
1859
|
+
output: b.output + usage.output
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1801
1862
|
}
|
|
1802
|
-
}
|
|
1803
|
-
return any ? total : 0;
|
|
1863
|
+
};
|
|
1804
1864
|
}
|
|
1805
1865
|
/**
|
|
1806
|
-
* Fold one committed event into the ledger.
|
|
1807
|
-
*
|
|
1808
|
-
*
|
|
1809
|
-
*
|
|
1810
|
-
*
|
|
1866
|
+
* Fold one committed event into the ledger. Four event types advance it:
|
|
1867
|
+
* `request/header` tracks the route in force (the timeline fold's rule —
|
|
1868
|
+
* last header wins), `step/start`/`step/end` maintain the initiation stamp,
|
|
1869
|
+
* and `assistant/message` (the step settlement — both supported log
|
|
1870
|
+
* generations) books the day. Everything else returns the state reference
|
|
1871
|
+
* unchanged, as does a settlement with no attributable instant. The next
|
|
1872
|
+
* state is a copy along the mutated path only — the persisted previous
|
|
1873
|
+
* state is never mutated in place.
|
|
1811
1874
|
*/
|
|
1812
1875
|
function applyActivity(state, event) {
|
|
1876
|
+
if (event.type === "request/header") {
|
|
1877
|
+
const config = event.data?.header?.config;
|
|
1878
|
+
if (config === null || typeof config !== "object") return state;
|
|
1879
|
+
const model = typeof config.model === "string" ? config.model : void 0;
|
|
1880
|
+
const provider = typeof config.provider === "string" ? config.provider : void 0;
|
|
1881
|
+
const nextModel = model !== void 0 ? model : state.model;
|
|
1882
|
+
const nextProvider = provider !== void 0 ? provider : state.provider;
|
|
1883
|
+
if (nextModel === state.model && nextProvider === state.provider) return state;
|
|
1884
|
+
return {
|
|
1885
|
+
...state,
|
|
1886
|
+
...nextModel !== void 0 ? { model: nextModel } : {},
|
|
1887
|
+
...nextProvider !== void 0 ? { provider: nextProvider } : {}
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
if (event.type === "step/start") {
|
|
1891
|
+
if (!Number.isFinite(event.time)) return state;
|
|
1892
|
+
return state.stepStart === event.time ? state : {
|
|
1893
|
+
...state,
|
|
1894
|
+
stepStart: event.time
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
if (event.type === "step/end") {
|
|
1898
|
+
if (state.stepStart === void 0) return state;
|
|
1899
|
+
const next = { ...state };
|
|
1900
|
+
delete next.stepStart;
|
|
1901
|
+
return next;
|
|
1902
|
+
}
|
|
1813
1903
|
if (event.type !== "assistant/message") return state;
|
|
1814
|
-
const
|
|
1904
|
+
const initiated = state.stepStart !== void 0 ? state.stepStart : event.time;
|
|
1905
|
+
const key = dayKeyOf(initiated);
|
|
1815
1906
|
if (key === null) return state;
|
|
1816
1907
|
const data = event.data;
|
|
1817
|
-
const
|
|
1908
|
+
const buckets = billedBucketsOf(data?.usage);
|
|
1818
1909
|
const prev = state.days[key];
|
|
1910
|
+
let cost = prev?.cost;
|
|
1911
|
+
if (buckets !== null && state.model !== void 0) {
|
|
1912
|
+
const provider = state.provider ?? "";
|
|
1913
|
+
const period = isDeepSeekProvider(provider) && !isPeakUtc(initiated) ? "off" : "peak";
|
|
1914
|
+
cost = pricedDayOf(cost, provider, state.model, period, buckets);
|
|
1915
|
+
}
|
|
1819
1916
|
const entry = {
|
|
1820
|
-
tokens: prev === void 0 ?
|
|
1821
|
-
requests: prev === void 0 ?
|
|
1917
|
+
tokens: (prev === void 0 ? 0 : prev.tokens) + (buckets === null ? 0 : buckets.input + buckets.cacheRead + buckets.cacheWrite + buckets.output),
|
|
1918
|
+
requests: (prev === void 0 ? 0 : prev.requests) + 1,
|
|
1919
|
+
...cost !== void 0 ? { cost } : {}
|
|
1822
1920
|
};
|
|
1823
1921
|
let days = {
|
|
1824
1922
|
...state.days,
|
|
@@ -1830,12 +1928,19 @@ function applyActivity(state, event) {
|
|
|
1830
1928
|
const drop = new Set(keys.slice(0, keys.length - MAX_KEPT_DAYS));
|
|
1831
1929
|
days = Object.fromEntries(Object.entries(days).filter(([k]) => !drop.has(k)));
|
|
1832
1930
|
}
|
|
1833
|
-
return {
|
|
1931
|
+
return {
|
|
1932
|
+
...state,
|
|
1933
|
+
days
|
|
1934
|
+
};
|
|
1834
1935
|
}
|
|
1835
1936
|
/**
|
|
1836
1937
|
* The daily-activity projection unit, registered alongside the timeline and
|
|
1837
1938
|
* headers units (host/index.ts); the overview reads it through the session
|
|
1838
|
-
* list's projection column. `stateVersion`
|
|
1939
|
+
* list's projection column. `stateVersion` 2: the ledger gained the per-day
|
|
1940
|
+
* pricing records (and the fold the route/step-start tracking behind them),
|
|
1941
|
+
* so on upgrade every cached row reads version-stale — the dashboard's
|
|
1942
|
+
* warm-up cold-refolds it from the durable log, rebuilding the fees for the
|
|
1943
|
+
* whole corpus exactly.
|
|
1839
1944
|
*/
|
|
1840
1945
|
function createContextActivityDefinition() {
|
|
1841
1946
|
return {
|
|
@@ -1847,7 +1952,7 @@ function createContextActivityDefinition() {
|
|
|
1847
1952
|
viewSchema: contextActivitySchema,
|
|
1848
1953
|
view: (state) => ({ days: Object.fromEntries(Object.entries(state.days).map(([k, v]) => [k, { ...v }])) })
|
|
1849
1954
|
},
|
|
1850
|
-
stateVersion:
|
|
1955
|
+
stateVersion: 2
|
|
1851
1956
|
};
|
|
1852
1957
|
}
|
|
1853
1958
|
/**
|
|
@@ -3176,7 +3281,7 @@ function createContextTimelineDefinition(config, slim) {
|
|
|
3176
3281
|
},
|
|
3177
3282
|
init: () => createTimelineState(),
|
|
3178
3283
|
apply: (state, event) => applyTimeline(state, event, bounds),
|
|
3179
|
-
stateVersion:
|
|
3284
|
+
stateVersion: 21
|
|
3180
3285
|
};
|
|
3181
3286
|
}
|
|
3182
3287
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-context",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.0",
|
|
4
4
|
"description": "A DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.",
|
|
5
5
|
"icon": "icon.svg",
|
|
6
6
|
"author": "bowenliang123",
|
|
@@ -92,7 +92,8 @@
|
|
|
92
92
|
"@deepseek-ai/dsh-session": ">=0.1.5-rc.1",
|
|
93
93
|
"@deepseek-ai/dsh-settings": ">=0.1.5-rc.1",
|
|
94
94
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
95
|
-
"react": "^18.3.1"
|
|
95
|
+
"react": "^18.3.1",
|
|
96
|
+
"react-dom": "^18.3.1"
|
|
96
97
|
},
|
|
97
98
|
"peerDependenciesMeta": {
|
|
98
99
|
"@deepseek-ai/dsh-client-ui-primitives": {
|
|
@@ -100,32 +101,33 @@
|
|
|
100
101
|
},
|
|
101
102
|
"react": {
|
|
102
103
|
"optional": true
|
|
104
|
+
},
|
|
105
|
+
"react-dom": {
|
|
106
|
+
"optional": true
|
|
103
107
|
}
|
|
104
108
|
},
|
|
105
109
|
"devDependencies": {
|
|
106
110
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
107
111
|
"@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.1",
|
|
108
|
-
"@deepseek-ai/dsh-invariants": "0.1.5-rc.1",
|
|
109
|
-
"@deepseek-ai/dsh-scope": "0.1.5-rc.1",
|
|
110
112
|
"@deepseek-ai/dsh-session": "0.1.5-rc.1",
|
|
111
113
|
"@deepseek-ai/dsh-session-projection": "0.1.5-rc.1",
|
|
112
114
|
"@deepseek-ai/dsh-settings": "0.1.5-rc.1",
|
|
113
115
|
"@deepseek-ai/dsh-util-workspace-path": "0.1.5-rc.1",
|
|
114
116
|
"@deepseek-ai/schemastery": "^3.18.4",
|
|
115
|
-
"@opencode-ai/models": "^0.0.
|
|
117
|
+
"@opencode-ai/models": "^0.0.87",
|
|
116
118
|
"@shikijs/langs": "^4.3.1",
|
|
117
119
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
118
120
|
"@tailwindcss/node": "4.3.3",
|
|
119
121
|
"@tailwindcss/oxide": "4.3.3",
|
|
120
|
-
"@types/node": "^26.
|
|
122
|
+
"@types/node": "^26.6.3",
|
|
121
123
|
"@types/react": "^18.3.31",
|
|
122
124
|
"@types/react-dom": "^18.3.7",
|
|
123
125
|
"@vitest/coverage-v8": "^4.1.11",
|
|
124
126
|
"anser": "^2.3.5",
|
|
125
127
|
"clsx": "^2.0.0",
|
|
126
|
-
"eslint-plugin-sonarjs": "^4.2.
|
|
128
|
+
"eslint-plugin-sonarjs": "^4.2.1",
|
|
127
129
|
"husky": "^9.1.7",
|
|
128
|
-
"jsdom": "^30.
|
|
130
|
+
"jsdom": "^30.1.1",
|
|
129
131
|
"katex": "^0.16.47",
|
|
130
132
|
"lightningcss": "1.32.0",
|
|
131
133
|
"mdast-util-from-markdown": "^2.0.3",
|
|
@@ -139,17 +141,16 @@
|
|
|
139
141
|
"micromark-util-classify-character": "^2.0.1",
|
|
140
142
|
"micromark-util-sanitize-uri": "^2.0.1",
|
|
141
143
|
"micromark-util-symbol": "^2.0.1",
|
|
142
|
-
"oxlint": "1.
|
|
143
|
-
"oxlint-tsgolint": "7.0.
|
|
144
|
-
"playwright-core": "^1.
|
|
144
|
+
"oxlint": "1.85.0",
|
|
145
|
+
"oxlint-tsgolint": "7.0.2003",
|
|
146
|
+
"playwright-core": "^1.63.0",
|
|
145
147
|
"react": "^18.3.1",
|
|
146
148
|
"react-dom": "^18.3.1",
|
|
147
149
|
"shiki": "^4.3.1",
|
|
148
|
-
"simple-icons": "16.
|
|
150
|
+
"simple-icons": "16.32.0",
|
|
149
151
|
"tailwindcss": "4.3.3",
|
|
150
152
|
"tsdown": "^0.23.0",
|
|
151
153
|
"typescript": "^7.0.2",
|
|
152
|
-
"vitest": "^4.1.11"
|
|
153
|
-
"zod": "^4.4.3"
|
|
154
|
+
"vitest": "^4.1.11"
|
|
154
155
|
}
|
|
155
156
|
}
|