compressed-context 0.1.0 → 0.1.1

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 (55) hide show
  1. package/package.json +64 -64
  2. package/src/compression/active-summary-cache.ts +50 -50
  3. package/src/compression/adopt.ts +57 -57
  4. package/src/compression/auto.ts +372 -372
  5. package/src/compression/babel.ts +85 -85
  6. package/src/compression/block.ts +25 -25
  7. package/src/compression/cache-history.ts +75 -75
  8. package/src/compression/compaction.ts +189 -189
  9. package/src/compression/decompress-tool.ts +74 -74
  10. package/src/compression/decompress.ts +292 -292
  11. package/src/compression/deleted-sessions.ts +24 -24
  12. package/src/compression/distill.ts +220 -220
  13. package/src/compression/events.ts +275 -275
  14. package/src/compression/markdown.ts +53 -53
  15. package/src/compression/normalize.ts +114 -114
  16. package/src/compression/render.ts +70 -70
  17. package/src/compression/schema.ts +84 -84
  18. package/src/compression/select.ts +123 -123
  19. package/src/compression/session-message.ts +112 -112
  20. package/src/compression/settings-rpc.ts +111 -111
  21. package/src/compression/settings.ts +175 -175
  22. package/src/compression/state.ts +248 -248
  23. package/src/compression/summarize.ts +595 -595
  24. package/src/compression/summary.ts +73 -73
  25. package/src/compression/tool.ts +142 -142
  26. package/src/compression/transcript-store.ts +258 -258
  27. package/src/compression/transcript.ts +63 -63
  28. package/src/compression/validate.ts +81 -81
  29. package/src/i18n/en.ts +93 -93
  30. package/src/i18n/index.ts +28 -28
  31. package/src/i18n/types.ts +89 -89
  32. package/src/i18n/zh.ts +93 -93
  33. package/src/index.ts +108 -108
  34. package/src/shared/blocks.ts +17 -17
  35. package/src/shared/cache.ts +199 -199
  36. package/src/shared/format.ts +23 -23
  37. package/src/shared/media.ts +184 -184
  38. package/src/shared/parse.ts +25 -25
  39. package/src/shared/parts.ts +72 -72
  40. package/src/shared/rpc.ts +145 -145
  41. package/src/shared/scan.ts +32 -32
  42. package/src/shared/settings.ts +471 -471
  43. package/src/shared/stats.ts +142 -142
  44. package/src/shared/tokens.ts +259 -259
  45. package/src/tui/chart/cache-chart.ts +237 -237
  46. package/src/tui/chart/color.ts +58 -58
  47. package/src/tui/index.tsx +111 -111
  48. package/src/tui/panel/cache.tsx +203 -203
  49. package/src/tui/panel/data.ts +105 -105
  50. package/src/tui/panel/index.tsx +176 -176
  51. package/src/tui/panel/summaries.tsx +192 -192
  52. package/src/tui/settings/dialogs.tsx +215 -215
  53. package/src/tui/settings/options.ts +238 -238
  54. package/src/tui/settings.tsx +418 -418
  55. package/src/tui/types.ts +4 -4
@@ -1,142 +1,142 @@
1
- /**
2
- * 上下文统计的跨进程载体。
3
- *
4
- * 服务端插件把估算写进 session metadata,TUI 插件读出来按真实 usage 缩放。
5
- * 本模块只放纯函数:构造、校验、节流判断、metadata 合并、缩放。
6
- */
7
-
8
- import { totalCategories, type TokenCategories } from "./tokens.ts"
9
-
10
- /** metadata 里存放统计的键名,避免和其他插件撞车。 */
11
- export const STATS_KEY = "compressed-context"
12
-
13
- /** metadata 里存放终止原因的键名;TUI 面板据此显示警告。 */
14
- export const TERMINAL_KEY = "compressed-context-terminal"
15
-
16
- export const CATEGORY_KEYS = ["system", "tools", "tool", "text", "recent", "summaries", "media"] as const
17
-
18
- export type CategoryKey = (typeof CATEGORY_KEYS)[number]
19
-
20
- export interface ContextStats extends TokenCategories {
21
- readonly estimatedTotal: number
22
- readonly at: number
23
- }
24
-
25
- /** 两次写入之间至少要有这么多 token 的变化,避免 durable 事件被刷屏。 */
26
- export const PUBLISH_MIN_DELTA = 2_000
27
-
28
- /** 输入:分类估算 + 时间戳;输出:带合计的统计对象。 */
29
- export function createStats(categories: TokenCategories, now: number): ContextStats {
30
- return { ...categories, estimatedTotal: totalCategories(categories), at: now }
31
- }
32
-
33
- /** 输入:任意 metadata 值;输出:合法数字或 undefined。 */
34
- function readNumber(value: unknown): number | undefined {
35
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined
36
- }
37
-
38
- /**
39
- * 输入:metadata 里的原始 JSON。
40
- * 输出:校验通过的统计对象;缺字段、类型不对或负数返回 undefined。
41
- * 预期:metadata 可能被别的版本或别的插件改写,解析必须防御。
42
- */
43
- export function parseStats(value: unknown): ContextStats | undefined {
44
- if (typeof value !== "object" || value === null) return undefined
45
- const record = value as Record<string, unknown>
46
- const system = readNumber(record["system"])
47
- const tools = readNumber(record["tools"])
48
- const tool = readNumber(record["tool"])
49
- const text = readNumber(record["text"])
50
- // 旧版本没有 recent 字段;缺省按 0 处理,避免统计整块失效。
51
- const recent = record["recent"] === undefined ? 0 : readNumber(record["recent"])
52
- const summaries = readNumber(record["summaries"])
53
- const media = readNumber(record["media"])
54
- const estimatedTotal = readNumber(record["estimatedTotal"])
55
- const at = readNumber(record["at"])
56
- if (
57
- system === undefined ||
58
- tools === undefined ||
59
- tool === undefined ||
60
- text === undefined ||
61
- recent === undefined ||
62
- summaries === undefined ||
63
- media === undefined ||
64
- estimatedTotal === undefined ||
65
- at === undefined
66
- ) {
67
- return undefined
68
- }
69
- return { system, tools, tool, text, recent, summaries, media, estimatedTotal, at }
70
- }
71
-
72
- /**
73
- * 输入:上一次发布的统计(可能没有)+ 本次统计。
74
- * 输出:是否值得写一次 metadata。
75
- * 预期:合计或任一分类变化达到阈值才写,减少 durable 事件。
76
- */
77
- export function shouldPublish(previous: ContextStats | undefined, next: ContextStats): boolean {
78
- if (previous === undefined) return true
79
- if (Math.abs(next.estimatedTotal - previous.estimatedTotal) >= PUBLISH_MIN_DELTA) return true
80
- return CATEGORY_KEYS.some((key) => Math.abs(next[key] - previous[key]) >= PUBLISH_MIN_DELTA)
81
- }
82
-
83
- export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }
84
-
85
- /**
86
- * 输入:已有 metadata + 本次统计。
87
- * 输出:保留其他键、替换 STATS_KEY 的新对象。
88
- * 预期:metadata 是整体替换语义,必须先合并再写。
89
- */
90
- export function mergeMetadata(
91
- metadata: Readonly<Record<string, JsonValue>> | undefined,
92
- stats: ContextStats,
93
- ): Record<string, JsonValue> {
94
- return {
95
- ...(metadata ?? {}),
96
- [STATS_KEY]: {
97
- system: stats.system,
98
- tools: stats.tools,
99
- tool: stats.tool,
100
- text: stats.text,
101
- recent: stats.recent,
102
- summaries: stats.summaries,
103
- media: stats.media,
104
- estimatedTotal: stats.estimatedTotal,
105
- at: stats.at,
106
- },
107
- }
108
- }
109
-
110
- /**
111
- * 输入:已有 metadata + 终止原因。
112
- * 输出:保留其他键、写入终止原因的新对象。
113
- * 预期:TUI 面板读 TERMINAL_KEY 显示警告;写入失败不影响压缩状态。
114
- */
115
- export function mergeTerminalMetadata(
116
- metadata: Readonly<Record<string, JsonValue>> | undefined,
117
- message: string,
118
- ): Record<string, JsonValue> {
119
- return { ...(metadata ?? {}), [TERMINAL_KEY]: message }
120
- }
121
-
122
- export interface ScaledCategory {
123
- readonly key: CategoryKey
124
- readonly value: number
125
- readonly pct: number
126
- }
127
-
128
- /**
129
- * 输入:估算统计 + 真实总量(0 表示上游没给)。
130
- * 输出:按真实总量缩放后的各类数值与百分比。
131
- * 预期:真实总量缺失时按原值展示;百分比分母是缩放后的合计。
132
- */
133
- export function scaleCategories(stats: ContextStats, realTotal: number): readonly ScaledCategory[] {
134
- const scale = realTotal > 0 && stats.estimatedTotal > 0 ? realTotal / stats.estimatedTotal : 1
135
- const scaled = CATEGORY_KEYS.map((key) => ({ key, value: Math.round(stats[key] * scale) }))
136
- const total = scaled.reduce((sum, item) => sum + item.value, 0)
137
- return scaled.map((item) => ({
138
- key: item.key,
139
- value: item.value,
140
- pct: total > 0 ? Math.round((item.value / total) * 100) : 0,
141
- }))
142
- }
1
+ /**
2
+ * 上下文统计的跨进程载体。
3
+ *
4
+ * 服务端插件把估算写进 session metadata,TUI 插件读出来按真实 usage 缩放。
5
+ * 本模块只放纯函数:构造、校验、节流判断、metadata 合并、缩放。
6
+ */
7
+
8
+ import { totalCategories, type TokenCategories } from "./tokens.ts"
9
+
10
+ /** metadata 里存放统计的键名,避免和其他插件撞车。 */
11
+ export const STATS_KEY = "compressed-context"
12
+
13
+ /** metadata 里存放终止原因的键名;TUI 面板据此显示警告。 */
14
+ export const TERMINAL_KEY = "compressed-context-terminal"
15
+
16
+ export const CATEGORY_KEYS = ["system", "tools", "tool", "text", "recent", "summaries", "media"] as const
17
+
18
+ export type CategoryKey = (typeof CATEGORY_KEYS)[number]
19
+
20
+ export interface ContextStats extends TokenCategories {
21
+ readonly estimatedTotal: number
22
+ readonly at: number
23
+ }
24
+
25
+ /** 两次写入之间至少要有这么多 token 的变化,避免 durable 事件被刷屏。 */
26
+ export const PUBLISH_MIN_DELTA = 2_000
27
+
28
+ /** 输入:分类估算 + 时间戳;输出:带合计的统计对象。 */
29
+ export function createStats(categories: TokenCategories, now: number): ContextStats {
30
+ return { ...categories, estimatedTotal: totalCategories(categories), at: now }
31
+ }
32
+
33
+ /** 输入:任意 metadata 值;输出:合法数字或 undefined。 */
34
+ function readNumber(value: unknown): number | undefined {
35
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined
36
+ }
37
+
38
+ /**
39
+ * 输入:metadata 里的原始 JSON。
40
+ * 输出:校验通过的统计对象;缺字段、类型不对或负数返回 undefined。
41
+ * 预期:metadata 可能被别的版本或别的插件改写,解析必须防御。
42
+ */
43
+ export function parseStats(value: unknown): ContextStats | undefined {
44
+ if (typeof value !== "object" || value === null) return undefined
45
+ const record = value as Record<string, unknown>
46
+ const system = readNumber(record["system"])
47
+ const tools = readNumber(record["tools"])
48
+ const tool = readNumber(record["tool"])
49
+ const text = readNumber(record["text"])
50
+ // 旧版本没有 recent 字段;缺省按 0 处理,避免统计整块失效。
51
+ const recent = record["recent"] === undefined ? 0 : readNumber(record["recent"])
52
+ const summaries = readNumber(record["summaries"])
53
+ const media = readNumber(record["media"])
54
+ const estimatedTotal = readNumber(record["estimatedTotal"])
55
+ const at = readNumber(record["at"])
56
+ if (
57
+ system === undefined ||
58
+ tools === undefined ||
59
+ tool === undefined ||
60
+ text === undefined ||
61
+ recent === undefined ||
62
+ summaries === undefined ||
63
+ media === undefined ||
64
+ estimatedTotal === undefined ||
65
+ at === undefined
66
+ ) {
67
+ return undefined
68
+ }
69
+ return { system, tools, tool, text, recent, summaries, media, estimatedTotal, at }
70
+ }
71
+
72
+ /**
73
+ * 输入:上一次发布的统计(可能没有)+ 本次统计。
74
+ * 输出:是否值得写一次 metadata。
75
+ * 预期:合计或任一分类变化达到阈值才写,减少 durable 事件。
76
+ */
77
+ export function shouldPublish(previous: ContextStats | undefined, next: ContextStats): boolean {
78
+ if (previous === undefined) return true
79
+ if (Math.abs(next.estimatedTotal - previous.estimatedTotal) >= PUBLISH_MIN_DELTA) return true
80
+ return CATEGORY_KEYS.some((key) => Math.abs(next[key] - previous[key]) >= PUBLISH_MIN_DELTA)
81
+ }
82
+
83
+ export type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }
84
+
85
+ /**
86
+ * 输入:已有 metadata + 本次统计。
87
+ * 输出:保留其他键、替换 STATS_KEY 的新对象。
88
+ * 预期:metadata 是整体替换语义,必须先合并再写。
89
+ */
90
+ export function mergeMetadata(
91
+ metadata: Readonly<Record<string, JsonValue>> | undefined,
92
+ stats: ContextStats,
93
+ ): Record<string, JsonValue> {
94
+ return {
95
+ ...(metadata ?? {}),
96
+ [STATS_KEY]: {
97
+ system: stats.system,
98
+ tools: stats.tools,
99
+ tool: stats.tool,
100
+ text: stats.text,
101
+ recent: stats.recent,
102
+ summaries: stats.summaries,
103
+ media: stats.media,
104
+ estimatedTotal: stats.estimatedTotal,
105
+ at: stats.at,
106
+ },
107
+ }
108
+ }
109
+
110
+ /**
111
+ * 输入:已有 metadata + 终止原因。
112
+ * 输出:保留其他键、写入终止原因的新对象。
113
+ * 预期:TUI 面板读 TERMINAL_KEY 显示警告;写入失败不影响压缩状态。
114
+ */
115
+ export function mergeTerminalMetadata(
116
+ metadata: Readonly<Record<string, JsonValue>> | undefined,
117
+ message: string,
118
+ ): Record<string, JsonValue> {
119
+ return { ...(metadata ?? {}), [TERMINAL_KEY]: message }
120
+ }
121
+
122
+ export interface ScaledCategory {
123
+ readonly key: CategoryKey
124
+ readonly value: number
125
+ readonly pct: number
126
+ }
127
+
128
+ /**
129
+ * 输入:估算统计 + 真实总量(0 表示上游没给)。
130
+ * 输出:按真实总量缩放后的各类数值与百分比。
131
+ * 预期:真实总量缺失时按原值展示;百分比分母是缩放后的合计。
132
+ */
133
+ export function scaleCategories(stats: ContextStats, realTotal: number): readonly ScaledCategory[] {
134
+ const scale = realTotal > 0 && stats.estimatedTotal > 0 ? realTotal / stats.estimatedTotal : 1
135
+ const scaled = CATEGORY_KEYS.map((key) => ({ key, value: Math.round(stats[key] * scale) }))
136
+ const total = scaled.reduce((sum, item) => sum + item.value, 0)
137
+ return scaled.map((item) => ({
138
+ key: item.key,
139
+ value: item.value,
140
+ pct: total > 0 ? Math.round((item.value / total) * 100) : 0,
141
+ }))
142
+ }