dsh-layered-memory 0.8.7 → 0.8.8

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.
@@ -9,45 +9,10 @@ export interface StoreCapabilities {
9
9
  ftsSearch: boolean;
10
10
  vectorSearch: boolean;
11
11
  }
12
- /** token_cost 单窗口成本聚合(成本看板用)。 */
13
- export interface CostAggregate {
14
- calls: number;
15
- inputChars: number;
16
- outputTokens: number;
17
- reasoningTokens: number;
18
- /** 单次调用输出 token 均值(无数据为 0)。 */
19
- avgOutputTokens: number;
20
- /** 单次调用输出 token 中位数(无数据为 0)。 */
21
- medianOutputTokens: number;
22
- }
23
- /** 按 model 分组的成本行(成本看板用)。 */
24
- export interface CostByModel {
25
- provider: string;
26
- model: string;
27
- calls: number;
28
- inputChars: number;
29
- outputTokens: number;
30
- reasoningTokens: number;
31
- }
32
- /** 按层级(l1/l2/l3 归并)分组的成本行。 */
33
- export interface CostByLayer {
34
- layer: string;
35
- calls: number;
36
- inputChars: number;
37
- outputTokens: number;
38
- reasoningTokens: number;
39
- avgOutputTokens: number;
40
- medianOutputTokens: number;
41
- }
42
- /** 按时间桶 + provider/model 聚合的扁平行(趋势图与日均/周均/月均 + 中位数统计共用)。 */
43
- export interface BucketRow {
44
- bucket: number;
45
- provider: string;
46
- model: string;
47
- calls: number;
48
- outputTokens: number;
49
- reasoningTokens: number;
50
- }
12
+ import { CostLedger } from './cost-ledger.js';
13
+ import type { BucketRow, CostAggregate, CostByLayer } from './cost-ledger.js';
14
+ export type { BucketRow, CostAggregate, CostByLayer } from './cost-ledger.js';
15
+ import type { CostByModel } from '../contract.js';
51
16
  /** L1 检索命中(含 BM25/余弦归一分数)。 */
52
17
  export interface L1SearchHit {
53
18
  id: string;
@@ -62,6 +27,7 @@ export interface L1SearchHit {
62
27
  export interface L0SearchHit extends L0MessageRecord {
63
28
  score: number;
64
29
  }
30
+ /** 已排序序列的中位数(偶数个取中间两者平均;空返回 0)。 */
65
31
  export declare class MemoryDb {
66
32
  private db;
67
33
  private degraded;
@@ -83,9 +49,8 @@ export declare class MemoryDb {
83
49
  private stmtL1FtsDelete;
84
50
  private stmtL1FtsSearch;
85
51
  private stmtL1FtsSearchFamily;
86
- /** token_cost 明细写入 / 滚动清理语句(构造期 prepare 缓存)。 */
87
- private stmtInsertCost;
88
- private stmtDeleteCost;
52
+ /** 成本账本(token_cost 表族;init 内初始化,未就绪时方法返回零值)。 */
53
+ readonly costLedger: CostLedger;
89
54
  private stmtUpsertL0;
90
55
  private stmtGetL0;
91
56
  /** 主表存在性点查(同 L1:防御性 FTS 删除的前置判断)。 */
@@ -187,31 +152,16 @@ export declare class MemoryDb {
187
152
  searchL1Vector(embedding: Float32Array, topK: number, family?: string): L1SearchHit[];
188
153
  /** 批量 upsert L0 消息(元数据 + FTS;embeddings 与 records 等长,可省略)。 */
189
154
  upsertL0Batch(records: L0MessageRecord[], embeddings?: Array<Float32Array | undefined>): boolean;
190
- /**
191
- * 记录一次蒸馏调用成本(明细表,写入时按 retentionDays 滚动清理;0 = 永久保留)。
192
- * 失败/成功都记(token 照烧);记账失败记 warn 但不阻断蒸馏(成本看板是增强能力)。
193
- */
155
+ /** 记录一次蒸馏调用成本(委托 cost-ledger;语义见 CostLedger.insertCostCall)。 */
194
156
  insertCostCall(provider: string, model: string, layer: string, inputChars: number, outputTokens: number, reasoningTokens: number, retentionDays: number): void;
195
- /**
196
- * 查询 token_cost 单窗口聚合(成本看板用;since 为毫秒起点,0 = 全量)。
197
- * 输入口径:inputChars 是字符(llm 流拿不到输入 token,沿用 llm-usage 的字符折算口径)。
198
- * 成本看板是增强能力:降级态/查询异常一律返回零值,不向上抛错。
199
- * median 需取 output_tokens 序列在 JS 侧算(SQLite 无内置 median 函数)。
200
- */
157
+ /** 查询 token_cost 单窗口聚合(委托 cost-ledger;降级/异常返回零值)。 */
201
158
  aggregateCost(since: number): {
202
159
  total: CostAggregate;
203
160
  byModel: CostByModel[];
204
161
  };
205
- /**
206
- * 按层级归并聚合(l1 = l1-extract + l1-dedup;成本看板层级表格用)。
207
- * 降级/异常返回空数组,不抛错。
208
- */
162
+ /** 按层级归并聚合(委托 cost-ledger;降级/异常返回空数组)。 */
209
163
  aggregateCostByLayer(since: number): CostByLayer[];
210
- /**
211
- * 按时间桶(bucketMs 毫秒)+ model 聚合,返回扁平行。
212
- * offsetMs 把桶边界对齐本地时区;layer 为空=全部,'l1' 归并 extract/dedup,其余精确匹配。
213
- * 趋势图与「日均/周均/月均 + 中位数」统计共用:JS 侧按不同 bucketMs 调三次再聚合。
214
- */
164
+ /** 按时间桶 + model 聚合(委托 cost-ledger;趋势图与日均/周均/月均共用)。 */
215
165
  aggregateByBucket(bucketMs: number, offsetMs: number, since: number, layer: string): BucketRow[];
216
166
  countL0(): number;
217
167
  /** 统计 recorded_at >= iso 的消息数(状态面板"今日捕获"用)。 */
@@ -22,6 +22,9 @@ import { bm25RankToScore, buildFtsQuery, tokenizeForFts } from './search-utils.j
22
22
  import { describeTokenizer, ensureTokenizer, tokenizerStamp } from '../util/tokenizer.js';
23
23
  const require = createRequire(import.meta.url);
24
24
  const TAG = '[memory][sqlite]';
25
+ // 成本账本(token_cost 表族:类型 + 实现)已整体迁出到 ./cost-ledger.ts——与检索引擎
26
+ // 零关系的独立职责;此处 re-export 不断裂既有引用,MemoryDb 四个公开方法改为一行委托。
27
+ import { CostLedger } from './cost-ledger.js';
25
28
  /** vec0 KNN 对遗留零向量的补偿缓冲(官方同款)。 */
26
29
  const ZERO_VEC_BUFFER = 10;
27
30
  /** IN 查询/删除的分块大小(保守避开 SQLite 变量数上限:现代构建 32766,老版 999)。 */
@@ -39,13 +42,6 @@ function emptyCostAggregate() {
39
42
  return { calls: 0, inputChars: 0, outputTokens: 0, reasoningTokens: 0, avgOutputTokens: 0, medianOutputTokens: 0 };
40
43
  }
41
44
  /** 已排序序列的中位数(偶数个取中间两者平均;空返回 0)。 */
42
- function medianOf(sorted) {
43
- const n = sorted.length;
44
- if (n === 0)
45
- return 0;
46
- const mid = Math.floor(n / 2);
47
- return n % 2 === 1 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
48
- }
49
45
  export class MemoryDb {
50
46
  db;
51
47
  degraded = false;
@@ -67,9 +63,8 @@ export class MemoryDb {
67
63
  stmtL1FtsDelete;
68
64
  stmtL1FtsSearch;
69
65
  stmtL1FtsSearchFamily;
70
- /** token_cost 明细写入 / 滚动清理语句(构造期 prepare 缓存)。 */
71
- stmtInsertCost;
72
- stmtDeleteCost;
66
+ /** 成本账本(token_cost 表族;init 内初始化,未就绪时方法返回零值)。 */
67
+ costLedger = new CostLedger();
73
68
  stmtUpsertL0;
74
69
  stmtGetL0;
75
70
  /** 主表存在性点查(同 L1:防御性 FTS 删除的前置判断)。 */
@@ -339,25 +334,8 @@ export class MemoryDb {
339
334
  this.stmtGetL0 = this.db.prepare('SELECT session_id, role, message_text, recorded_at, timestamp FROM l0_conversations WHERE record_id = ?');
340
335
  this.stmtL0Exists = this.db.prepare('SELECT 1 FROM l0_conversations WHERE record_id = ?');
341
336
  this.prepareL0VecStatements();
342
- // ── token_cost:蒸馏成本明细表(成本看板用;保留期经 retentionDays 滚动清理) ──
343
- this.db.exec(`
344
- CREATE TABLE IF NOT EXISTS token_cost (
345
- ts INTEGER NOT NULL,
346
- provider TEXT NOT NULL,
347
- model TEXT NOT NULL,
348
- layer TEXT NOT NULL,
349
- input_chars INTEGER NOT NULL DEFAULT 0,
350
- output_tokens INTEGER NOT NULL DEFAULT 0,
351
- reasoning_tokens INTEGER NOT NULL DEFAULT 0
352
- )
353
- `);
354
- // 迁移:provider/model 复合键引入前的旧表补 provider 列(历史行回填 unknown)
355
- if (this.tableExists('token_cost') && !this.hasColumn('token_cost', 'provider')) {
356
- this.db.exec("ALTER TABLE token_cost ADD COLUMN provider TEXT NOT NULL DEFAULT 'unknown'");
357
- }
358
- this.db.exec('CREATE INDEX IF NOT EXISTS idx_token_cost_ts ON token_cost(ts)');
359
- this.stmtInsertCost = this.db.prepare('INSERT INTO token_cost (ts, provider, model, layer, input_chars, output_tokens, reasoning_tokens) VALUES (?, ?, ?, ?, ?, ?, ?)');
360
- this.stmtDeleteCost = this.db.prepare('DELETE FROM token_cost WHERE ts < ?');
337
+ // ── token_cost:蒸馏成本明细表(成本账本自治;见 cost-ledger.ts) ──
338
+ this.costLedger.init(this.db, this.logger);
361
339
  // ── FTS5 全文索引(建表失败仅停用 FTS,不降级整个库) ──
362
340
  try {
363
341
  // 索引重建判据(FTS5 无法 ALTER,只能 drop 后从源表全量回灌):
@@ -1011,134 +989,21 @@ export class MemoryDb {
1011
989
  return false;
1012
990
  }
1013
991
  }
1014
- /**
1015
- * 记录一次蒸馏调用成本(明细表,写入时按 retentionDays 滚动清理;0 = 永久保留)。
1016
- * 失败/成功都记(token 照烧);记账失败记 warn 但不阻断蒸馏(成本看板是增强能力)。
1017
- */
992
+ /** 记录一次蒸馏调用成本(委托 cost-ledger;语义见 CostLedger.insertCostCall)。 */
1018
993
  insertCostCall(provider, model, layer, inputChars, outputTokens, reasoningTokens, retentionDays) {
1019
- if (this.degraded)
1020
- return;
1021
- try {
1022
- this.stmtInsertCost.run(Date.now(), provider, model, layer, Math.max(0, Math.round(inputChars)), Math.max(0, Math.round(outputTokens)), Math.max(0, Math.round(reasoningTokens)));
1023
- if (retentionDays > 0)
1024
- this.stmtDeleteCost.run(Date.now() - retentionDays * 24 * 3600_000);
1025
- }
1026
- catch (err) {
1027
- this.logger?.warn(`${TAG} token_cost 记账失败: ${err instanceof Error ? err.message : String(err)}`);
1028
- }
994
+ this.costLedger.insertCostCall(provider, model, layer, inputChars, outputTokens, reasoningTokens, retentionDays);
1029
995
  }
1030
- /**
1031
- * 查询 token_cost 单窗口聚合(成本看板用;since 为毫秒起点,0 = 全量)。
1032
- * 输入口径:inputChars 是字符(llm 流拿不到输入 token,沿用 llm-usage 的字符折算口径)。
1033
- * 成本看板是增强能力:降级态/查询异常一律返回零值,不向上抛错。
1034
- * median 需取 output_tokens 序列在 JS 侧算(SQLite 无内置 median 函数)。
1035
- */
996
+ /** 查询 token_cost 单窗口聚合(委托 cost-ledger;降级/异常返回零值)。 */
1036
997
  aggregateCost(since) {
1037
- if (this.degraded)
1038
- return { total: emptyCostAggregate(), byModel: [] };
1039
- try {
1040
- const total = this.db
1041
- .prepare(`SELECT COUNT(*) AS calls,
1042
- COALESCE(SUM(input_chars), 0) AS inputChars,
1043
- COALESCE(SUM(output_tokens), 0) AS outputTokens,
1044
- COALESCE(SUM(reasoning_tokens), 0) AS reasoningTokens,
1045
- COALESCE(AVG(output_tokens), 0) AS avgOutputTokens
1046
- FROM token_cost WHERE ts >= ?`)
1047
- .get(since);
1048
- const tokenRows = this.db
1049
- .prepare('SELECT output_tokens FROM token_cost WHERE ts >= ? ORDER BY output_tokens')
1050
- .all(since);
1051
- const byModel = this.db
1052
- .prepare(`SELECT provider, model, COUNT(*) AS calls,
1053
- COALESCE(SUM(input_chars), 0) AS inputChars,
1054
- COALESCE(SUM(output_tokens), 0) AS outputTokens,
1055
- COALESCE(SUM(reasoning_tokens), 0) AS reasoningTokens
1056
- FROM token_cost WHERE ts >= ? GROUP BY provider, model ORDER BY outputTokens DESC`)
1057
- .all(since);
1058
- return {
1059
- total: {
1060
- calls: total.calls,
1061
- inputChars: total.inputChars,
1062
- outputTokens: total.outputTokens,
1063
- reasoningTokens: total.reasoningTokens,
1064
- avgOutputTokens: total.avgOutputTokens,
1065
- medianOutputTokens: medianOf(tokenRows.map((r) => r.output_tokens)),
1066
- },
1067
- byModel,
1068
- };
1069
- }
1070
- catch {
1071
- return { total: emptyCostAggregate(), byModel: [] };
1072
- }
998
+ return this.costLedger.aggregateCost(since);
1073
999
  }
1074
- /**
1075
- * 按层级归并聚合(l1 = l1-extract + l1-dedup;成本看板层级表格用)。
1076
- * 降级/异常返回空数组,不抛错。
1077
- */
1000
+ /** 按层级归并聚合(委托 cost-ledger;降级/异常返回空数组)。 */
1078
1001
  aggregateCostByLayer(since) {
1079
- if (this.degraded)
1080
- return [];
1081
- try {
1082
- const rows = this.db
1083
- .prepare(`SELECT CASE WHEN layer IN ('l1-extract','l1-dedup') THEN 'l1' ELSE layer END AS layer,
1084
- COUNT(*) AS calls,
1085
- COALESCE(SUM(input_chars), 0) AS inputChars,
1086
- COALESCE(SUM(output_tokens), 0) AS outputTokens,
1087
- COALESCE(SUM(reasoning_tokens), 0) AS reasoningTokens,
1088
- COALESCE(AVG(output_tokens), 0) AS avgOutputTokens
1089
- FROM token_cost WHERE ts >= ? GROUP BY layer ORDER BY layer`)
1090
- .all(since);
1091
- // 中位数需取 output_tokens 序列在 JS 侧算(SQLite 无内置 median)
1092
- const tokenRows = this.db
1093
- .prepare(`SELECT CASE WHEN layer IN ('l1-extract','l1-dedup') THEN 'l1' ELSE layer END AS layer,
1094
- output_tokens
1095
- FROM token_cost WHERE ts >= ? ORDER BY layer, output_tokens`)
1096
- .all(since);
1097
- const medianByLayer = new Map();
1098
- for (const r of tokenRows) {
1099
- const arr = medianByLayer.get(r.layer);
1100
- if (arr)
1101
- arr.push(r.output_tokens);
1102
- else
1103
- medianByLayer.set(r.layer, [r.output_tokens]);
1104
- }
1105
- return rows.map((r) => ({
1106
- ...r,
1107
- medianOutputTokens: medianOf(medianByLayer.get(r.layer) ?? []),
1108
- }));
1109
- }
1110
- catch {
1111
- return [];
1112
- }
1002
+ return this.costLedger.aggregateCostByLayer(since);
1113
1003
  }
1114
- /**
1115
- * 按时间桶(bucketMs 毫秒)+ model 聚合,返回扁平行。
1116
- * offsetMs 把桶边界对齐本地时区;layer 为空=全部,'l1' 归并 extract/dedup,其余精确匹配。
1117
- * 趋势图与「日均/周均/月均 + 中位数」统计共用:JS 侧按不同 bucketMs 调三次再聚合。
1118
- */
1004
+ /** 按时间桶 + model 聚合(委托 cost-ledger;趋势图与日均/周均/月均共用)。 */
1119
1005
  aggregateByBucket(bucketMs, offsetMs, since, layer) {
1120
- if (this.degraded)
1121
- return [];
1122
- try {
1123
- let sql = `SELECT CAST((ts + ?) / ? AS INTEGER) AS bucket, provider, model,
1124
- COUNT(*) AS calls,
1125
- COALESCE(SUM(output_tokens), 0) AS outputTokens,
1126
- COALESCE(SUM(reasoning_tokens), 0) AS reasoningTokens
1127
- FROM token_cost WHERE ts >= ?`;
1128
- const params = [offsetMs, bucketMs, since];
1129
- if (layer === 'l1') {
1130
- sql += ` AND layer IN ('l1-extract','l1-dedup')`;
1131
- }
1132
- else if (layer) {
1133
- sql += ` AND layer = ?`;
1134
- params.push(layer);
1135
- }
1136
- sql += ` GROUP BY bucket, provider, model ORDER BY bucket, provider, model`;
1137
- return this.db.prepare(sql).all(...params);
1138
- }
1139
- catch {
1140
- return [];
1141
- }
1006
+ return this.costLedger.aggregateByBucket(bucketMs, offsetMs, since, layer);
1142
1007
  }
1143
1008
  countL0() {
1144
1009
  if (this.degraded)
@@ -7,84 +7,15 @@
7
7
  * 与作者 llm-usage.ts 的关系:作者是"按 layer 累计的纯内存计数器"(给 bench 用);
8
8
  * 本模块补上三个缺口——按 model 分组、持久化(保留期可配置,默认 365 天)、面向 UI 成本看板。
9
9
  */
10
+ import type { CostSnapshot, Granularity } from './contract.js';
10
11
  import type { DistillLayer } from './llm-usage.js';
11
- import type { CostByModel, MemoryDb } from './store/sqlite.js';
12
+ import type { MemoryDb } from './store/sqlite.js';
13
+ export type { CostWindow, Granularity, ModelMetrics, LayerMetrics, LayerWindow, LayerCost, TrendBucket, TrendSnapshot, CostSnapshot, } from './contract.js';
12
14
  /** 插件启动时注入 db 与明细保留期(index.ts 调用;retentionDays 0 = 永久保留)。 */
13
15
  export declare function initTokenCost(d: MemoryDb, retention: number): void;
14
16
  /** 插件卸载时清空 db 引用(index.ts 的 ctx.effect 清理里调用,防悬空引用)。 */
15
17
  export declare function resetTokenCost(): void;
16
18
  /** 记录一次蒸馏调用成本(callLLM 出口调用;provider/model 由调用方传入)。 */
17
19
  export declare function recordCostCall(provider: string, model: string, layer: DistillLayer, inputChars: number, outputTokens: number, reasoningTokens: number): void;
18
- /** 成本看板单个时间窗口(day/week/month/all)。 */
19
- export interface CostWindow {
20
- range: 'day' | 'week' | 'month' | 'all';
21
- /** 窗口起点(毫秒;all 为 0)。 */
22
- since: number;
23
- calls: number;
24
- inputChars: number;
25
- outputTokens: number;
26
- reasoningTokens: number;
27
- avgOutputTokens: number;
28
- medianOutputTokens: number;
29
- }
30
- /** 成本看板时间粒度(趋势图 + 统计口径共用)。 */
31
- export type Granularity = 'day' | 'week' | 'month';
32
- /** 每模型统计指标(层级表格行;均值/中位数按 since=0 全量历史的活跃桶口径,非「最近窗口」)。 */
33
- export interface ModelMetrics {
34
- model: string;
35
- dayCalls: number;
36
- weekCalls: number;
37
- monthCalls: number;
38
- dayOutput: number;
39
- dayMedian: number;
40
- weekOutput: number;
41
- weekMedian: number;
42
- monthOutput: number;
43
- monthMedian: number;
44
- }
45
- /** 每层级(l1/l2/l3)的模型统计(层级表格)。 */
46
- export interface LayerMetrics {
47
- layer: 'l1' | 'l2' | 'l3';
48
- models: ModelMetrics[];
49
- }
50
- /** 层级 × 窗口矩阵里的单个窗口格子。 */
51
- export interface LayerWindow {
52
- range: 'day' | 'week' | 'month' | 'all';
53
- calls: number;
54
- inputChars: number;
55
- outputTokens: number;
56
- reasoningTokens: number;
57
- avgOutputTokens: number;
58
- medianOutputTokens: number;
59
- }
60
- /** 单个层级在四个窗口的聚合(层级×窗口表格行)。 */
61
- export interface LayerCost {
62
- layer: 'l1' | 'l2' | 'l3';
63
- windows: LayerWindow[];
64
- }
65
- /** 趋势单桶。 */
66
- export interface TrendBucket {
67
- ts: number;
68
- total: number;
69
- byModel: Record<string, number>;
70
- }
71
- /** 趋势快照:三个层级各一份连续桶序列。 */
72
- export interface TrendSnapshot {
73
- granularity: Granularity;
74
- byLayer: Record<'l1' | 'l2' | 'l3', TrendBucket[]>;
75
- }
76
- /** 成本看板快照(dsh-memory/token-cost 端点返回值)。 */
77
- export interface CostSnapshot {
78
- /** day/week/month/all 四窗口聚合。 */
79
- windows: CostWindow[];
80
- /** 全量窗口(all)按 model 分组。 */
81
- byModel: CostByModel[];
82
- /** 按层级(l1/l2/l3 归并)在四个窗口的聚合(层级×窗口表格)。 */
83
- byLayer: LayerCost[];
84
- /** 每层级的模型统计指标(层级表格)。 */
85
- byLayerStats: LayerMetrics[];
86
- /** 趋势图数据。 */
87
- trend: TrendSnapshot;
88
- }
89
20
  /** 读成本看板快照(db 未注入/降级时返回全零结构,不抛错;rangeDays>0 = 趋势展示近 N 天)。 */
90
21
  export declare function snapshotTokenCost(granularity: Granularity, rangeDays: number): CostSnapshot;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-layered-memory",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
4
4
  "description": "L0~L3 分层蒸馏记忆插件 for DeepSeek Harness:自动捕获对话(L0)、抽取原子记忆(L1)、整合场景块(L2)、蒸馏核心画像/团队方法论(L3),并在模型步骤前自动召回注入。移植自 MemoryCore (TencentDB Agent Memory) 的管线设计。",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,9 +31,11 @@
31
31
  "cordis.patch.yml"
32
32
  ],
33
33
  "scripts": {
34
- "build": "tsc -p tsconfig.json && node scripts/copy-client.mjs",
35
- "smoke": "node dist-smoke/smoke.js",
36
- "verify-catalog": "npm run build && node scripts/verify-catalog.mjs"
34
+ "build": "tsc -p tsconfig.json && node scripts/build-client.mjs && node scripts/copy-client.mjs",
35
+ "smoke": "npm run build:smoke && node dist-smoke/smoke.js",
36
+ "verify-catalog": "npm run build && node scripts/verify-catalog.mjs",
37
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
38
+ "build:smoke": "tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop"
37
39
  },
38
40
  "engines": {
39
41
  "node": ">=22.16.0"
@@ -78,6 +80,8 @@
78
80
  "@deepseek-ai/dsh-system-prompt": "0.1.1-rc.2",
79
81
  "@deepseek-ai/dsh-tools": "0.1.1-rc.2",
80
82
  "@types/node": "^22.0.0",
83
+ "@types/react": "^19.2.18",
84
+ "esbuild": "^0.28.2",
81
85
  "typescript": "^5.6.0"
82
86
  }
83
87
  }