compressed-context 0.1.0 → 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/README.md +59 -51
- package/package.json +64 -64
- package/src/compression/active-summary-cache.ts +50 -50
- package/src/compression/adopt.ts +57 -57
- package/src/compression/auto.ts +386 -372
- package/src/compression/babel.ts +85 -85
- package/src/compression/block.ts +25 -25
- package/src/compression/cache-history.ts +75 -75
- package/src/compression/compaction.ts +189 -189
- package/src/compression/decompress-tool.ts +74 -74
- package/src/compression/decompress.ts +292 -292
- package/src/compression/deleted-sessions.ts +24 -24
- package/src/compression/distill.ts +220 -220
- package/src/compression/events.ts +275 -275
- package/src/compression/markdown.ts +53 -53
- package/src/compression/normalize.ts +114 -114
- package/src/compression/render.ts +70 -70
- package/src/compression/schema.ts +131 -84
- package/src/compression/select.ts +123 -123
- package/src/compression/session-message.ts +112 -112
- package/src/compression/settings-rpc.ts +123 -111
- package/src/compression/settings.ts +175 -175
- package/src/compression/shape.ts +75 -0
- package/src/compression/state.ts +248 -248
- package/src/compression/summarize.ts +534 -595
- package/src/compression/summary.ts +73 -73
- package/src/compression/tool.ts +184 -142
- package/src/compression/transcript-store.ts +258 -258
- package/src/compression/transcript.ts +63 -63
- package/src/compression/validate.ts +81 -81
- package/src/i18n/en.ts +93 -93
- package/src/i18n/index.ts +28 -28
- package/src/i18n/types.ts +89 -89
- package/src/i18n/zh.ts +93 -93
- package/src/index.ts +116 -108
- package/src/shared/blocks.ts +17 -17
- package/src/shared/cache.ts +199 -199
- package/src/shared/format.ts +23 -23
- package/src/shared/media.ts +184 -184
- package/src/shared/parse.ts +25 -25
- package/src/shared/parts.ts +72 -72
- package/src/shared/rpc.ts +145 -145
- package/src/shared/scan.ts +32 -32
- package/src/shared/settings.ts +466 -471
- package/src/shared/stats.ts +142 -142
- package/src/shared/tokens.ts +259 -259
- package/src/tui/chart/cache-chart.ts +237 -237
- package/src/tui/chart/color.ts +58 -58
- package/src/tui/index.tsx +109 -111
- package/src/tui/panel/cache.tsx +203 -203
- package/src/tui/panel/data.ts +105 -105
- package/src/tui/panel/index.tsx +176 -176
- package/src/tui/panel/summaries.tsx +203 -192
- package/src/tui/settings/dialogs.tsx +215 -215
- package/src/tui/settings/options.ts +238 -238
- package/src/tui/settings.tsx +418 -418
- package/src/tui/types.ts +4 -4
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
import { isBabelSummary, isMarkdownSummary, type Summary } from "./schema.ts"
|
|
2
|
-
import { summaryChars } from "./summary.ts"
|
|
3
|
-
|
|
4
|
-
export const MIN_SUMMARY_CHARS = 200
|
|
5
|
-
export const MIN_MERGE_SUMMARY_CHARS = 80
|
|
6
|
-
export const MIN_ULTRA_SUMMARY_CHARS = 40
|
|
7
|
-
export const MAX_SUMMARY_CHARS = 20_000
|
|
8
|
-
|
|
9
|
-
/** 输入:层级;输出:该层允许的最短摘要字符数。 */
|
|
10
|
-
export function minSummaryChars(tier: 1 | 2 | 3): number {
|
|
11
|
-
if (tier === 3) return MIN_ULTRA_SUMMARY_CHARS
|
|
12
|
-
if (tier === 2) return MIN_MERGE_SUMMARY_CHARS
|
|
13
|
-
return MIN_SUMMARY_CHARS
|
|
14
|
-
}
|
|
15
|
-
/** 可压缩原文的最小字符数,低于它不生成块。 */
|
|
16
|
-
export const MIN_SOURCE_CHARS = 5_000
|
|
17
|
-
|
|
18
|
-
export interface ValidationResult {
|
|
19
|
-
readonly ok: boolean
|
|
20
|
-
readonly fields: readonly string[]
|
|
21
|
-
readonly message: string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 输入:结构化摘要或 Markdown 摘要 + 原文总字符数。
|
|
26
|
-
* 输出:校验结果。
|
|
27
|
-
* 预期:JSON 检查字段;Markdown 检查标题/正文/长度,且摘要必须比原文小。
|
|
28
|
-
*/
|
|
29
|
-
export function validateSummary(
|
|
30
|
-
summary: Summary,
|
|
31
|
-
sourceChars: number,
|
|
32
|
-
minChars: number = MIN_SUMMARY_CHARS,
|
|
33
|
-
maxChars: number = MAX_SUMMARY_CHARS,
|
|
34
|
-
): ValidationResult {
|
|
35
|
-
const fields: string[] = []
|
|
36
|
-
if (isBabelSummary(summary)) {
|
|
37
|
-
if (summary.title.trim().length === 0 || summary.title.length > 80) fields.push("title")
|
|
38
|
-
if (summary.goal.trim().length === 0) fields.push("goal")
|
|
39
|
-
const body = summary.text.split(/\r?\n/).slice(1).join("\n").trim()
|
|
40
|
-
if (body.length === 0) fields.push("text")
|
|
41
|
-
} else if (isMarkdownSummary(summary)) {
|
|
42
|
-
if (summary.title.trim().length === 0 || summary.title.length > 80) fields.push("title")
|
|
43
|
-
if (summary.text.trim().length === 0) fields.push("text")
|
|
44
|
-
} else {
|
|
45
|
-
if (summary.goal.trim().length === 0) fields.push("goal")
|
|
46
|
-
if (summary.title.trim().length === 0 || summary.title.length > 80) fields.push("title")
|
|
47
|
-
if (summary.constraints.some((item) => item.trim().length === 0)) fields.push("constraints")
|
|
48
|
-
if (summary.decisions.some((item) => item.trim().length === 0)) fields.push("decisions")
|
|
49
|
-
if (summary.open_items.some((item) => item.trim().length === 0)) fields.push("open_items")
|
|
50
|
-
if (summary.files.some((item) => item.trim().length === 0)) fields.push("files")
|
|
51
|
-
if (summary.facts.some((item) => item.trim().length === 0)) fields.push("facts")
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (fields.length > 0) {
|
|
55
|
-
return { ok: false, fields, message: `empty field: ${fields.join(", ")}` }
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const chars = summaryChars(summary)
|
|
59
|
-
if (chars < minChars) {
|
|
60
|
-
return {
|
|
61
|
-
ok: false,
|
|
62
|
-
fields: ["summary"],
|
|
63
|
-
message: `summary too short (${chars.toString()} chars, min ${minChars.toString()})`,
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (chars > maxChars) {
|
|
67
|
-
return {
|
|
68
|
-
ok: false,
|
|
69
|
-
fields: ["summary"],
|
|
70
|
-
message: `summary too long (${chars.toString()} chars, max ${maxChars.toString()})`,
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
if (sourceChars > 0 && chars >= sourceChars) {
|
|
74
|
-
return {
|
|
75
|
-
ok: false,
|
|
76
|
-
fields: ["summary"],
|
|
77
|
-
message: `summary (${chars.toString()} chars) is not smaller than the source (${sourceChars.toString()} chars)`,
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return { ok: true, fields: [], message: "ok" }
|
|
81
|
-
}
|
|
1
|
+
import { isBabelSummary, isMarkdownSummary, type Summary } from "./schema.ts"
|
|
2
|
+
import { summaryChars } from "./summary.ts"
|
|
3
|
+
|
|
4
|
+
export const MIN_SUMMARY_CHARS = 200
|
|
5
|
+
export const MIN_MERGE_SUMMARY_CHARS = 80
|
|
6
|
+
export const MIN_ULTRA_SUMMARY_CHARS = 40
|
|
7
|
+
export const MAX_SUMMARY_CHARS = 20_000
|
|
8
|
+
|
|
9
|
+
/** 输入:层级;输出:该层允许的最短摘要字符数。 */
|
|
10
|
+
export function minSummaryChars(tier: 1 | 2 | 3): number {
|
|
11
|
+
if (tier === 3) return MIN_ULTRA_SUMMARY_CHARS
|
|
12
|
+
if (tier === 2) return MIN_MERGE_SUMMARY_CHARS
|
|
13
|
+
return MIN_SUMMARY_CHARS
|
|
14
|
+
}
|
|
15
|
+
/** 可压缩原文的最小字符数,低于它不生成块。 */
|
|
16
|
+
export const MIN_SOURCE_CHARS = 5_000
|
|
17
|
+
|
|
18
|
+
export interface ValidationResult {
|
|
19
|
+
readonly ok: boolean
|
|
20
|
+
readonly fields: readonly string[]
|
|
21
|
+
readonly message: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 输入:结构化摘要或 Markdown 摘要 + 原文总字符数。
|
|
26
|
+
* 输出:校验结果。
|
|
27
|
+
* 预期:JSON 检查字段;Markdown 检查标题/正文/长度,且摘要必须比原文小。
|
|
28
|
+
*/
|
|
29
|
+
export function validateSummary(
|
|
30
|
+
summary: Summary,
|
|
31
|
+
sourceChars: number,
|
|
32
|
+
minChars: number = MIN_SUMMARY_CHARS,
|
|
33
|
+
maxChars: number = MAX_SUMMARY_CHARS,
|
|
34
|
+
): ValidationResult {
|
|
35
|
+
const fields: string[] = []
|
|
36
|
+
if (isBabelSummary(summary)) {
|
|
37
|
+
if (summary.title.trim().length === 0 || summary.title.length > 80) fields.push("title")
|
|
38
|
+
if (summary.goal.trim().length === 0) fields.push("goal")
|
|
39
|
+
const body = summary.text.split(/\r?\n/).slice(1).join("\n").trim()
|
|
40
|
+
if (body.length === 0) fields.push("text")
|
|
41
|
+
} else if (isMarkdownSummary(summary)) {
|
|
42
|
+
if (summary.title.trim().length === 0 || summary.title.length > 80) fields.push("title")
|
|
43
|
+
if (summary.text.trim().length === 0) fields.push("text")
|
|
44
|
+
} else {
|
|
45
|
+
if (summary.goal.trim().length === 0) fields.push("goal")
|
|
46
|
+
if (summary.title.trim().length === 0 || summary.title.length > 80) fields.push("title")
|
|
47
|
+
if (summary.constraints.some((item) => item.trim().length === 0)) fields.push("constraints")
|
|
48
|
+
if (summary.decisions.some((item) => item.trim().length === 0)) fields.push("decisions")
|
|
49
|
+
if (summary.open_items.some((item) => item.trim().length === 0)) fields.push("open_items")
|
|
50
|
+
if (summary.files.some((item) => item.trim().length === 0)) fields.push("files")
|
|
51
|
+
if (summary.facts.some((item) => item.trim().length === 0)) fields.push("facts")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (fields.length > 0) {
|
|
55
|
+
return { ok: false, fields, message: `empty field: ${fields.join(", ")}` }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const chars = summaryChars(summary)
|
|
59
|
+
if (chars < minChars) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
fields: ["summary"],
|
|
63
|
+
message: `summary too short (${chars.toString()} chars, min ${minChars.toString()})`,
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (chars > maxChars) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
fields: ["summary"],
|
|
70
|
+
message: `summary too long (${chars.toString()} chars, max ${maxChars.toString()})`,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (sourceChars > 0 && chars >= sourceChars) {
|
|
74
|
+
return {
|
|
75
|
+
ok: false,
|
|
76
|
+
fields: ["summary"],
|
|
77
|
+
message: `summary (${chars.toString()} chars) is not smaller than the source (${sourceChars.toString()} chars)`,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { ok: true, fields: [], message: "ok" }
|
|
81
|
+
}
|
package/src/i18n/en.ts
CHANGED
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
import type { Messages } from "./types.ts"
|
|
2
|
-
|
|
3
|
-
/** English copy. Labels stay short so they fit the narrow sidebar. */
|
|
4
|
-
export const en: Messages = {
|
|
5
|
-
title: "Context breakdown",
|
|
6
|
-
labels: {
|
|
7
|
-
system: "System",
|
|
8
|
-
tools: "Tool defs",
|
|
9
|
-
tool: "Tool I/O",
|
|
10
|
-
text: "Text",
|
|
11
|
-
recent: "Kept",
|
|
12
|
-
summaries: "Summary",
|
|
13
|
-
media: "Media",
|
|
14
|
-
},
|
|
15
|
-
approximate: "≈",
|
|
16
|
-
terminal: "Context cannot be compressed further; start a new session or use native compaction",
|
|
17
|
-
cacheTitle: "Cache",
|
|
18
|
-
cacheChart: "Chart",
|
|
19
|
-
cacheLog: "Log",
|
|
20
|
-
cacheInput: "In",
|
|
21
|
-
cacheOutput: "Out",
|
|
22
|
-
cacheCached: "Cached",
|
|
23
|
-
cacheHit: "Hit",
|
|
24
|
-
summariesTitle: "Summaries",
|
|
25
|
-
noData: "—",
|
|
26
|
-
command: {
|
|
27
|
-
title: "Compressed context settings",
|
|
28
|
-
description: "Open plugin settings",
|
|
29
|
-
group: "Plugins",
|
|
30
|
-
},
|
|
31
|
-
settings: {
|
|
32
|
-
title: "Compressed context plugin settings",
|
|
33
|
-
show: "Show panel",
|
|
34
|
-
limit: "Context limit",
|
|
35
|
-
limitAuto: "Model native",
|
|
36
|
-
limitCustom: "Custom limit…",
|
|
37
|
-
limitHint: "Upper bound; the effective window is the smaller of this value and the model's native window. Digits or a k/m suffix",
|
|
38
|
-
limitInvalid: "Enter a valid token count",
|
|
39
|
-
limitPlaceholder: "200k",
|
|
40
|
-
limitPreview: (value) => `= ${value} tokens`,
|
|
41
|
-
limitCapped: (requested, actual) => `${requested} (model max ${actual})`,
|
|
42
|
-
threshold: "Compression threshold",
|
|
43
|
-
thresholdHint: "Enter an integer between 60 and 95 (percent)",
|
|
44
|
-
thresholdInvalid: "Threshold must be between 60 and 95",
|
|
45
|
-
thresholdPreview: (value) => `= ${value}%`,
|
|
46
|
-
nudgeGrowth: "Compression reminder",
|
|
47
|
-
nudgeGrowthHint: "Remind the model after this much context growth; 0 disables it",
|
|
48
|
-
nudgeGrowthInvalid: "Enter 0, or 1k to 200k",
|
|
49
|
-
summaryBlockPercent: "Summary block limit",
|
|
50
|
-
summaryBlockPercentHint: "Max share of the window for one summary; enter 10% or 20k",
|
|
51
|
-
summaryTotalPercent: "Total summary limit",
|
|
52
|
-
summaryTotalPercentHint: "Max share of the window for all summaries; enter 50% or 100k",
|
|
53
|
-
summaryPercentInvalid: "Enter 1% to 90%, or a token count that fits the window",
|
|
54
|
-
windowKnown: (value) => `Current window: ${value}`,
|
|
55
|
-
windowUnknown: "Current window unknown (run one model request first)",
|
|
56
|
-
summaryLanguage: "Summary language",
|
|
57
|
-
summaryFormat: "Summary format",
|
|
58
|
-
summaryFormatJson: "JSON
|
|
59
|
-
summaryFormatMarkdown: "Markdown
|
|
60
|
-
summaryFormatBabel: "Babel
|
|
61
|
-
autoCompress: "Auto compression",
|
|
62
|
-
enableCompressTool: "compress tool",
|
|
63
|
-
enableDecompressTool: "decompress tool",
|
|
64
|
-
showTimeline: "Block timeline",
|
|
65
|
-
showBlockTokens: "Block token estimate",
|
|
66
|
-
showCacheChart: "Show cache chart",
|
|
67
|
-
showCacheLog: "Show cache log",
|
|
68
|
-
showSummaries: "Show summary blocks",
|
|
69
|
-
categories: {
|
|
70
|
-
compress: "Compression",
|
|
71
|
-
summary: "Summary",
|
|
72
|
-
panel: "Panel",
|
|
73
|
-
decompress: "Decompression",
|
|
74
|
-
interface: "Interface",
|
|
75
|
-
},
|
|
76
|
-
decompressInlineMax: "Decompress inline limit",
|
|
77
|
-
decompressInlineMaxHint: "Above this many characters the content goes to a temp file; digits or a k/m suffix",
|
|
78
|
-
decompressInlineMaxInvalid: "Enter a character limit between 1k and 1m",
|
|
79
|
-
decompressTempCap: "Decompress temp file cap",
|
|
80
|
-
decompressTempCapHint: "Maximum number of decompress temp files to keep",
|
|
81
|
-
decompressTempCapInvalid: "Enter an integer between 1 and 1000",
|
|
82
|
-
decompressShowTokens: "Decompress token estimate",
|
|
83
|
-
submit: "Submit",
|
|
84
|
-
language: "Language",
|
|
85
|
-
auto: "Auto",
|
|
86
|
-
on: "On",
|
|
87
|
-
off: "Off",
|
|
88
|
-
},
|
|
89
|
-
languages: {
|
|
90
|
-
zh: "中文",
|
|
91
|
-
en: "English",
|
|
92
|
-
},
|
|
93
|
-
}
|
|
1
|
+
import type { Messages } from "./types.ts"
|
|
2
|
+
|
|
3
|
+
/** English copy. Labels stay short so they fit the narrow sidebar. */
|
|
4
|
+
export const en: Messages = {
|
|
5
|
+
title: "Context breakdown",
|
|
6
|
+
labels: {
|
|
7
|
+
system: "System",
|
|
8
|
+
tools: "Tool defs",
|
|
9
|
+
tool: "Tool I/O",
|
|
10
|
+
text: "Text",
|
|
11
|
+
recent: "Kept",
|
|
12
|
+
summaries: "Summary",
|
|
13
|
+
media: "Media",
|
|
14
|
+
},
|
|
15
|
+
approximate: "≈",
|
|
16
|
+
terminal: "Context cannot be compressed further; start a new session or use native compaction",
|
|
17
|
+
cacheTitle: "Cache",
|
|
18
|
+
cacheChart: "Chart",
|
|
19
|
+
cacheLog: "Log",
|
|
20
|
+
cacheInput: "In",
|
|
21
|
+
cacheOutput: "Out",
|
|
22
|
+
cacheCached: "Cached",
|
|
23
|
+
cacheHit: "Hit",
|
|
24
|
+
summariesTitle: "Summaries",
|
|
25
|
+
noData: "—",
|
|
26
|
+
command: {
|
|
27
|
+
title: "Compressed context settings",
|
|
28
|
+
description: "Open plugin settings",
|
|
29
|
+
group: "Plugins",
|
|
30
|
+
},
|
|
31
|
+
settings: {
|
|
32
|
+
title: "Compressed context plugin settings",
|
|
33
|
+
show: "Show panel",
|
|
34
|
+
limit: "Context limit",
|
|
35
|
+
limitAuto: "Model native",
|
|
36
|
+
limitCustom: "Custom limit…",
|
|
37
|
+
limitHint: "Upper bound; the effective window is the smaller of this value and the model's native window. Digits or a k/m suffix",
|
|
38
|
+
limitInvalid: "Enter a valid token count",
|
|
39
|
+
limitPlaceholder: "200k",
|
|
40
|
+
limitPreview: (value) => `= ${value} tokens`,
|
|
41
|
+
limitCapped: (requested, actual) => `${requested} (model max ${actual})`,
|
|
42
|
+
threshold: "Compression threshold",
|
|
43
|
+
thresholdHint: "Enter an integer between 60 and 95 (percent)",
|
|
44
|
+
thresholdInvalid: "Threshold must be between 60 and 95",
|
|
45
|
+
thresholdPreview: (value) => `= ${value}%`,
|
|
46
|
+
nudgeGrowth: "Compression reminder",
|
|
47
|
+
nudgeGrowthHint: "Remind the model after this much context growth; 0 disables it",
|
|
48
|
+
nudgeGrowthInvalid: "Enter 0, or 1k to 200k",
|
|
49
|
+
summaryBlockPercent: "Summary block limit",
|
|
50
|
+
summaryBlockPercentHint: "Max share of the window for one summary; enter 10% or 20k",
|
|
51
|
+
summaryTotalPercent: "Total summary limit",
|
|
52
|
+
summaryTotalPercentHint: "Max share of the window for all summaries; enter 50% or 100k",
|
|
53
|
+
summaryPercentInvalid: "Enter 1% to 90%, or a token count that fits the window",
|
|
54
|
+
windowKnown: (value) => `Current window: ${value}`,
|
|
55
|
+
windowUnknown: "Current window unknown (run one model request first)",
|
|
56
|
+
summaryLanguage: "Summary language",
|
|
57
|
+
summaryFormat: "Summary format",
|
|
58
|
+
summaryFormatJson: "JSON",
|
|
59
|
+
summaryFormatMarkdown: "Markdown",
|
|
60
|
+
summaryFormatBabel: "Babel",
|
|
61
|
+
autoCompress: "Auto compression",
|
|
62
|
+
enableCompressTool: "compress tool",
|
|
63
|
+
enableDecompressTool: "decompress tool",
|
|
64
|
+
showTimeline: "Block timeline",
|
|
65
|
+
showBlockTokens: "Block token estimate",
|
|
66
|
+
showCacheChart: "Show cache chart",
|
|
67
|
+
showCacheLog: "Show cache log",
|
|
68
|
+
showSummaries: "Show summary blocks",
|
|
69
|
+
categories: {
|
|
70
|
+
compress: "Compression",
|
|
71
|
+
summary: "Summary",
|
|
72
|
+
panel: "Panel",
|
|
73
|
+
decompress: "Decompression",
|
|
74
|
+
interface: "Interface",
|
|
75
|
+
},
|
|
76
|
+
decompressInlineMax: "Decompress inline limit",
|
|
77
|
+
decompressInlineMaxHint: "Above this many characters the content goes to a temp file; digits or a k/m suffix",
|
|
78
|
+
decompressInlineMaxInvalid: "Enter a character limit between 1k and 1m",
|
|
79
|
+
decompressTempCap: "Decompress temp file cap",
|
|
80
|
+
decompressTempCapHint: "Maximum number of decompress temp files to keep",
|
|
81
|
+
decompressTempCapInvalid: "Enter an integer between 1 and 1000",
|
|
82
|
+
decompressShowTokens: "Decompress token estimate",
|
|
83
|
+
submit: "Submit",
|
|
84
|
+
language: "Language",
|
|
85
|
+
auto: "Auto",
|
|
86
|
+
on: "On",
|
|
87
|
+
off: "Off",
|
|
88
|
+
},
|
|
89
|
+
languages: {
|
|
90
|
+
zh: "中文",
|
|
91
|
+
en: "English",
|
|
92
|
+
},
|
|
93
|
+
}
|
package/src/i18n/index.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { en } from "./en.ts"
|
|
2
|
-
import type { Messages } from "./types.ts"
|
|
3
|
-
import { zh } from "./zh.ts"
|
|
4
|
-
|
|
5
|
-
export type { Messages }
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* 输入:locale 字符串(可为空)。
|
|
9
|
-
* 输出:对应语言的消息表。
|
|
10
|
-
* 预期:`zh*` 用中文,其余一律英文;空值回退到系统 locale。
|
|
11
|
-
*/
|
|
12
|
-
export function resolveMessages(locale: string | undefined): Messages {
|
|
13
|
-
const value = (locale ?? detectLocale()).toLowerCase()
|
|
14
|
-
return value.startsWith("zh") ? zh : en
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* 输入:无。
|
|
19
|
-
* 输出:系统 locale。
|
|
20
|
-
* 预期:运行时拿不到时回退 `en`,保证始终有文案。
|
|
21
|
-
*/
|
|
22
|
-
export function detectLocale(): string {
|
|
23
|
-
try {
|
|
24
|
-
return Intl.DateTimeFormat().resolvedOptions().locale
|
|
25
|
-
} catch {
|
|
26
|
-
return "en"
|
|
27
|
-
}
|
|
28
|
-
}
|
|
1
|
+
import { en } from "./en.ts"
|
|
2
|
+
import type { Messages } from "./types.ts"
|
|
3
|
+
import { zh } from "./zh.ts"
|
|
4
|
+
|
|
5
|
+
export type { Messages }
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 输入:locale 字符串(可为空)。
|
|
9
|
+
* 输出:对应语言的消息表。
|
|
10
|
+
* 预期:`zh*` 用中文,其余一律英文;空值回退到系统 locale。
|
|
11
|
+
*/
|
|
12
|
+
export function resolveMessages(locale: string | undefined): Messages {
|
|
13
|
+
const value = (locale ?? detectLocale()).toLowerCase()
|
|
14
|
+
return value.startsWith("zh") ? zh : en
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 输入:无。
|
|
19
|
+
* 输出:系统 locale。
|
|
20
|
+
* 预期:运行时拿不到时回退 `en`,保证始终有文案。
|
|
21
|
+
*/
|
|
22
|
+
export function detectLocale(): string {
|
|
23
|
+
try {
|
|
24
|
+
return Intl.DateTimeFormat().resolvedOptions().locale
|
|
25
|
+
} catch {
|
|
26
|
+
return "en"
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/i18n/types.ts
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import type { CategoryKey } from "../shared/stats.ts"
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 面板文案。
|
|
5
|
-
*
|
|
6
|
-
* 源码里只引用键名,所有用户可见文字都来自语言文件。
|
|
7
|
-
*/
|
|
8
|
-
export interface Messages {
|
|
9
|
-
readonly title: string
|
|
10
|
-
readonly labels: Readonly<Record<CategoryKey, string>>
|
|
11
|
-
readonly approximate: string
|
|
12
|
-
readonly terminal: string
|
|
13
|
-
readonly cacheTitle: string
|
|
14
|
-
readonly cacheChart: string
|
|
15
|
-
readonly cacheLog: string
|
|
16
|
-
readonly cacheInput: string
|
|
17
|
-
readonly cacheOutput: string
|
|
18
|
-
readonly cacheCached: string
|
|
19
|
-
readonly cacheHit: string
|
|
20
|
-
readonly summariesTitle: string
|
|
21
|
-
readonly noData: string
|
|
22
|
-
readonly command: {
|
|
23
|
-
readonly title: string
|
|
24
|
-
readonly description: string
|
|
25
|
-
readonly group: string
|
|
26
|
-
}
|
|
27
|
-
readonly settings: {
|
|
28
|
-
readonly title: string
|
|
29
|
-
readonly show: string
|
|
30
|
-
readonly limit: string
|
|
31
|
-
readonly limitAuto: string
|
|
32
|
-
readonly limitCustom: string
|
|
33
|
-
readonly limitHint: string
|
|
34
|
-
readonly limitInvalid: string
|
|
35
|
-
readonly limitPlaceholder: string
|
|
36
|
-
readonly limitPreview: (value: string) => string
|
|
37
|
-
readonly limitCapped: (requested: string, actual: string) => string
|
|
38
|
-
readonly threshold: string
|
|
39
|
-
readonly thresholdHint: string
|
|
40
|
-
readonly thresholdInvalid: string
|
|
41
|
-
readonly thresholdPreview: (value: string) => string
|
|
42
|
-
readonly nudgeGrowth: string
|
|
43
|
-
readonly nudgeGrowthHint: string
|
|
44
|
-
readonly nudgeGrowthInvalid: string
|
|
45
|
-
readonly summaryBlockPercent: string
|
|
46
|
-
readonly summaryBlockPercentHint: string
|
|
47
|
-
readonly summaryTotalPercent: string
|
|
48
|
-
readonly summaryTotalPercentHint: string
|
|
49
|
-
readonly summaryPercentInvalid: string
|
|
50
|
-
readonly windowKnown: (value: string) => string
|
|
51
|
-
readonly windowUnknown: string
|
|
52
|
-
readonly summaryLanguage: string
|
|
53
|
-
readonly summaryFormat: string
|
|
54
|
-
readonly summaryFormatJson: string
|
|
55
|
-
readonly summaryFormatMarkdown: string
|
|
56
|
-
readonly summaryFormatBabel: string
|
|
57
|
-
readonly autoCompress: string
|
|
58
|
-
readonly enableCompressTool: string
|
|
59
|
-
readonly enableDecompressTool: string
|
|
60
|
-
readonly showTimeline: string
|
|
61
|
-
readonly showBlockTokens: string
|
|
62
|
-
readonly showCacheChart: string
|
|
63
|
-
readonly showCacheLog: string
|
|
64
|
-
readonly showSummaries: string
|
|
65
|
-
readonly categories: {
|
|
66
|
-
readonly compress: string
|
|
67
|
-
readonly summary: string
|
|
68
|
-
readonly panel: string
|
|
69
|
-
readonly decompress: string
|
|
70
|
-
readonly interface: string
|
|
71
|
-
}
|
|
72
|
-
readonly decompressInlineMax: string
|
|
73
|
-
readonly decompressInlineMaxHint: string
|
|
74
|
-
readonly decompressInlineMaxInvalid: string
|
|
75
|
-
readonly decompressTempCap: string
|
|
76
|
-
readonly decompressTempCapHint: string
|
|
77
|
-
readonly decompressTempCapInvalid: string
|
|
78
|
-
readonly decompressShowTokens: string
|
|
79
|
-
readonly submit: string
|
|
80
|
-
readonly language: string
|
|
81
|
-
readonly auto: string
|
|
82
|
-
readonly on: string
|
|
83
|
-
readonly off: string
|
|
84
|
-
}
|
|
85
|
-
readonly languages: {
|
|
86
|
-
readonly zh: string
|
|
87
|
-
readonly en: string
|
|
88
|
-
}
|
|
89
|
-
}
|
|
1
|
+
import type { CategoryKey } from "../shared/stats.ts"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 面板文案。
|
|
5
|
+
*
|
|
6
|
+
* 源码里只引用键名,所有用户可见文字都来自语言文件。
|
|
7
|
+
*/
|
|
8
|
+
export interface Messages {
|
|
9
|
+
readonly title: string
|
|
10
|
+
readonly labels: Readonly<Record<CategoryKey, string>>
|
|
11
|
+
readonly approximate: string
|
|
12
|
+
readonly terminal: string
|
|
13
|
+
readonly cacheTitle: string
|
|
14
|
+
readonly cacheChart: string
|
|
15
|
+
readonly cacheLog: string
|
|
16
|
+
readonly cacheInput: string
|
|
17
|
+
readonly cacheOutput: string
|
|
18
|
+
readonly cacheCached: string
|
|
19
|
+
readonly cacheHit: string
|
|
20
|
+
readonly summariesTitle: string
|
|
21
|
+
readonly noData: string
|
|
22
|
+
readonly command: {
|
|
23
|
+
readonly title: string
|
|
24
|
+
readonly description: string
|
|
25
|
+
readonly group: string
|
|
26
|
+
}
|
|
27
|
+
readonly settings: {
|
|
28
|
+
readonly title: string
|
|
29
|
+
readonly show: string
|
|
30
|
+
readonly limit: string
|
|
31
|
+
readonly limitAuto: string
|
|
32
|
+
readonly limitCustom: string
|
|
33
|
+
readonly limitHint: string
|
|
34
|
+
readonly limitInvalid: string
|
|
35
|
+
readonly limitPlaceholder: string
|
|
36
|
+
readonly limitPreview: (value: string) => string
|
|
37
|
+
readonly limitCapped: (requested: string, actual: string) => string
|
|
38
|
+
readonly threshold: string
|
|
39
|
+
readonly thresholdHint: string
|
|
40
|
+
readonly thresholdInvalid: string
|
|
41
|
+
readonly thresholdPreview: (value: string) => string
|
|
42
|
+
readonly nudgeGrowth: string
|
|
43
|
+
readonly nudgeGrowthHint: string
|
|
44
|
+
readonly nudgeGrowthInvalid: string
|
|
45
|
+
readonly summaryBlockPercent: string
|
|
46
|
+
readonly summaryBlockPercentHint: string
|
|
47
|
+
readonly summaryTotalPercent: string
|
|
48
|
+
readonly summaryTotalPercentHint: string
|
|
49
|
+
readonly summaryPercentInvalid: string
|
|
50
|
+
readonly windowKnown: (value: string) => string
|
|
51
|
+
readonly windowUnknown: string
|
|
52
|
+
readonly summaryLanguage: string
|
|
53
|
+
readonly summaryFormat: string
|
|
54
|
+
readonly summaryFormatJson: string
|
|
55
|
+
readonly summaryFormatMarkdown: string
|
|
56
|
+
readonly summaryFormatBabel: string
|
|
57
|
+
readonly autoCompress: string
|
|
58
|
+
readonly enableCompressTool: string
|
|
59
|
+
readonly enableDecompressTool: string
|
|
60
|
+
readonly showTimeline: string
|
|
61
|
+
readonly showBlockTokens: string
|
|
62
|
+
readonly showCacheChart: string
|
|
63
|
+
readonly showCacheLog: string
|
|
64
|
+
readonly showSummaries: string
|
|
65
|
+
readonly categories: {
|
|
66
|
+
readonly compress: string
|
|
67
|
+
readonly summary: string
|
|
68
|
+
readonly panel: string
|
|
69
|
+
readonly decompress: string
|
|
70
|
+
readonly interface: string
|
|
71
|
+
}
|
|
72
|
+
readonly decompressInlineMax: string
|
|
73
|
+
readonly decompressInlineMaxHint: string
|
|
74
|
+
readonly decompressInlineMaxInvalid: string
|
|
75
|
+
readonly decompressTempCap: string
|
|
76
|
+
readonly decompressTempCapHint: string
|
|
77
|
+
readonly decompressTempCapInvalid: string
|
|
78
|
+
readonly decompressShowTokens: string
|
|
79
|
+
readonly submit: string
|
|
80
|
+
readonly language: string
|
|
81
|
+
readonly auto: string
|
|
82
|
+
readonly on: string
|
|
83
|
+
readonly off: string
|
|
84
|
+
}
|
|
85
|
+
readonly languages: {
|
|
86
|
+
readonly zh: string
|
|
87
|
+
readonly en: string
|
|
88
|
+
}
|
|
89
|
+
}
|