chore(lint): enforce one object property per line

Add @stylistic/object-property-newline to the src stylistic block, so an
object that already spans multiple lines cannot pack several properties
onto one line. Objects written entirely on one line stay compact, which
keeps small inline props objects untouched.

The autofix split 199 packed properties across i18n.ts, statsTiming.tsx,
fileActivity.ts, index.ts, fold.ts and imageTokens.ts. Note that this
rule's fixer only inserts the newlines, so @stylistic/indent repairs the
resulting indentation on a second lint:fix pass.
This commit is contained in:
bowenliang123 committed 2026-09-29 01:57:52 +08:00
1 parent f099cd9c88
commit d61d014a19
7 files changed
+320 -109

No files matched your search

+6
View File
@@ -194,6 +194,12 @@
"error", "error",
"always" "always"
], ],
"@stylistic/object-property-newline": [
"error",
{
"allowAllPropertiesOnSameLine": true
}
],
"@stylistic/arrow-parens": [ "@stylistic/arrow-parens": [
"error", "error",
"as-needed", "as-needed",
+8 -2
View File
@@ -145,7 +145,10 @@ export function makeStatsTiming(kit: ViewKit, Donut: (props: DonutProps) => Reac
key: slice.key, color: slice.color, value: share(modelRings[index]), key: slice.key, color: slice.color, value: share(modelRings[index]),
})) }))
const toolSlice: Slice = { const toolSlice: Slice = {
key: 'tools', color: COLOR.tools, label: t('timing.tools'), ms: timing.toolsMs, key: 'tools',
color: COLOR.tools,
label: t('timing.tools'),
ms: timing.toolsMs,
times: t('timing.toolTimes', { n: fmt(timing.toolCalls) }), times: t('timing.toolTimes', { n: fmt(timing.toolCalls) }),
} }
const otherSlice: Slice = { key: 'other', color: COLOR.other, label: t('timing.other'), ms: other } const otherSlice: Slice = { key: 'other', color: COLOR.other, label: t('timing.other'), ms: other }
@@ -155,7 +158,10 @@ export function makeStatsTiming(kit: ViewKit, Donut: (props: DonutProps) => Reac
{ key: 'other', color: COLOR.other, value: share(other) }, { key: 'other', color: COLOR.other, value: share(other) },
] ]
const toRow = (slice: Slice): SliceRow => ({ const toRow = (slice: Slice): SliceRow => ({
key: slice.key, color: slice.color, label: slice.label, dim: slice.ms === 0, key: slice.key,
color: slice.color,
label: slice.label,
dim: slice.ms === 0,
pct: fmtShare(slice.ms, wall), pct: fmtShare(slice.ms, wall),
count: countOf(slice.ms, slice.times), count: countOf(slice.ms, slice.times),
}) })
+6 -2
View File
@@ -274,8 +274,12 @@ function aggregateOps(ops: readonly FileOp[], before: number | null): FileActivi
entry = { entry = {
path: op.path, path: op.path,
form: formOf(op.tool, op.path), form: formOf(op.tool, op.path),
reads: 0, writes: 0, searches: 0, reads: 0,
added: 0, removed: 0, errs: 0, writes: 0,
searches: 0,
added: 0,
removed: 0,
errs: 0,
ops: [], ops: [],
...(op.pattern === true ? { pattern: true as const } : {}), ...(op.pattern === true ? { pattern: true as const } : {}),
} }
+284 -100
View File
@@ -8,8 +8,13 @@ export type Translate = (key: string, params?: Record<string, string | number>)
export const DICT_ZH: Record<string, string> = { export const DICT_ZH: Record<string, string> = {
'tab': '上下文', 'tab': '上下文',
'sidebar.guideDescription': '查看上下文的构成、统计、演变。', 'sidebar.guideDescription': '查看上下文的构成、统计、演变。',
'cat.system': '系统提示词', 'cat.tools': '工具定义', 'cat.user': '用户消息', 'cat.system': '系统提示词',
'cat.inject': '注入内容', 'cat.skill': '技能注入', 'cat.assistant': '助手消息', 'cat.tool': '工具结果', 'cat.tools': '工具定义',
'cat.user': '用户消息',
'cat.inject': '注入内容',
'cat.skill': '技能注入',
'cat.assistant': '助手消息',
'cat.tool': '工具结果',
'overview.title': '当前上下文', 'overview.title': '当前上下文',
'overview.estimate': 'tokens(估算)', 'overview.estimate': 'tokens(估算)',
'overview.free': '剩余窗口', 'overview.free': '剩余窗口',
@@ -17,7 +22,8 @@ export const DICT_ZH: Record<string, string> = {
'overview.ofUsed': '占已用上下文', 'overview.ofUsed': '占已用上下文',
'overview.compactReserve': '自动压缩预留:占用达 {pct}% 窗口时触发压缩,此区域一般不实际占用', 'overview.compactReserve': '自动压缩预留:占用达 {pct}% 窗口时触发压缩,此区域一般不实际占用',
'stats.title': '上下文统计', 'stats.title': '上下文统计',
'stats.turns': '轮次', 'stats.steps': '步数', 'stats.turns': '轮次',
'stats.steps': '步数',
'stats.humanInputs': '用户输入', 'stats.humanInputs': '用户输入',
'stats.humanInputsTip': '当前会话中的用户消息与问题回答次数。', 'stats.humanInputsTip': '当前会话中的用户消息与问题回答次数。',
'stats.toolCalls': '工具调用', 'stats.toolCalls': '工具调用',
@@ -31,7 +37,10 @@ export const DICT_ZH: Record<string, string> = {
'stats.subCostTip': '所有子 Agent 会话各自累计费用(同口径估算)的合计,不含当前 Agent 自身。', 'stats.subCostTip': '所有子 Agent 会话各自累计费用(同口径估算)的合计,不含当前 Agent 自身。',
'stats.costPriceHead': '每百万 Token 价格:', 'stats.costPriceHead': '每百万 Token 价格:',
'stats.costPriceBy': '按 {p} · {m} 在 models.dev 的刊登价格如上。', 'stats.costPriceBy': '按 {p} · {m} 在 models.dev 的刊登价格如上。',
'stats.costHit': '缓存输入', 'stats.costMiss': '未缓存输入', 'stats.costWrite': '缓存写入', 'stats.costOut': '输出', 'stats.costHit': '缓存输入',
'stats.costMiss': '未缓存输入',
'stats.costWrite': '缓存写入',
'stats.costOut': '输出',
'stats.costUnavailable': '模型价格暂不可用(自动重试中),费用暂无法估算。', 'stats.costUnavailable': '模型价格暂不可用(自动重试中),费用暂无法估算。',
'timing.title': '耗时统计', 'timing.title': '耗时统计',
'timing.total': '活跃时长', 'timing.total': '活跃时长',
@@ -42,7 +51,9 @@ export const DICT_ZH: Record<string, string> = {
'timing.toolArgs': '工具参数', 'timing.toolArgs': '工具参数',
'timing.tools': '工具执行', 'timing.tools': '工具执行',
'timing.other': '其他开销', 'timing.other': '其他开销',
'timing.callTimes': '{n}次', 'timing.toolTimes': '{n}次', 'timing.blockTimes': '{n}次', 'timing.callTimes': '{n}次',
'timing.toolTimes': '{n}次',
'timing.blockTimes': '{n}次',
'timing.empty': '暂无耗时数据 · 对话开始后这里会显示时长分布', 'timing.empty': '暂无耗时数据 · 对话开始后这里会显示时长分布',
'timing.tps': '{tps} tok/s', 'timing.tps': '{tps} tok/s',
'timing.tpsTip': '输出速度(TPS):累计解码输出 tokens ÷ 累计解码时长,与 DeepSeek Harness 会话统计同口径。', 'timing.tpsTip': '输出速度(TPS):累计解码输出 tokens ÷ 累计解码时长,与 DeepSeek Harness 会话统计同口径。',
@@ -57,19 +68,26 @@ export const DICT_ZH: Record<string, string> = {
'plugin.settings': '设置', 'plugin.settings': '设置',
'plugin.settingsOpen': '打开插件设置', 'plugin.settingsOpen': '打开插件设置',
'trend.title': '上下文趋势', 'trend.title': '上下文趋势',
'gran.step': '步骤', 'gran.turn': '轮次', 'gran.step': '步骤',
'settings.title': '上下文', 'settings.desc': 'dsh-context 插件中上下文面板的偏好设置', 'gran.turn': '轮次',
'settings.title': '上下文',
'settings.desc': 'dsh-context 插件中上下文面板的偏好设置',
'settings.placement': '入口位置', 'settings.placement': '入口位置',
'placement.tab': '标签页', 'placement.sidebar': '侧边栏', 'placement.all': '全部', 'placement.tab': '标签页',
'placement.sidebar': '侧边栏',
'placement.all': '全部',
'settings.insightsEntry': '上下文洞察入口', 'settings.insightsEntry': '上下文洞察入口',
'insightsEntry.show': '显示', 'insightsEntry.hide': '隐藏', 'insightsEntry.show': '显示',
'insightsEntry.hide': '隐藏',
'settings.gran': '趋势图 · 默认粒度', 'settings.gran': '趋势图 · 默认粒度',
'settings.mode': '趋势图 · 默认展示方式', 'settings.mode': '趋势图 · 默认展示方式',
'settings.toolSort': '工具定义 · 默认排序', 'settings.toolSort': '工具定义 · 默认排序',
'settings.fileSort': '文件活动 · 默认排序', 'settings.fileSort': '文件活动 · 默认排序',
'settings.expand': '展开', 'settings.collapse': '收起', 'settings.expand': '展开',
'settings.collapse': '收起',
'settings.readOnly': '当前环境的设置为只读', 'settings.readOnly': '当前环境的设置为只读',
'gran.total': '全量', 'gran.delta': '增量', 'gran.total': '全量',
'gran.delta': '增量',
'gran.modeHint': '全量:累计构成;增量:相对上一条请求的变化量', 'gran.modeHint': '全量:累计构成;增量:相对上一条请求的变化量',
'trend.focus': '仅展示 {cat}', 'trend.focus': '仅展示 {cat}',
'trend.adaptive': '自适应', 'trend.adaptive': '自适应',
@@ -97,14 +115,23 @@ export const DICT_ZH: Record<string, string> = {
'events.at': '第 {t} 轮 · 第 {s} 步', 'events.at': '第 {t} 轮 · 第 {s} 步',
'events.range': '第 {t} 轮 · 第 {a}→{b} 步', 'events.range': '第 {t} 轮 · 第 {a}→{b} 步',
'events.rangeTo': '第 {a} 轮 · 第 {as} 步 → 第 {b} 轮 · 第 {bs} 步', 'events.rangeTo': '第 {a} 轮 · 第 {as} 步 → 第 {b} 轮 · 第 {bs} 步',
'kind.inject': '注入', 'kind.compaction': '压缩', 'kind.prune': '剪枝', 'kind.model': '切换', 'kind.mode': '模式', 'kind.inject': '注入',
'kind.compaction': '压缩',
'kind.prune': '剪枝',
'kind.model': '切换',
'kind.mode': '模式',
'files.title': '文件活动', 'files.title': '文件活动',
'files.scopeLatest': '截至最新 · 跟随趋势图的选择', 'files.scopeLatest': '截至最新 · 跟随趋势图的选择',
'files.kind.all': '全部', 'files.kind.read': '读取', 'files.kind.write': '写入', 'files.kind.all': '全部',
'files.kind.search': '搜索', 'files.kind.image': '图片', 'files.kind.read': '读取',
'files.kind.write': '写入',
'files.kind.search': '搜索',
'files.kind.image': '图片',
'files.chipTip': '{files} 个文件 · {ops} 次操作', 'files.chipTip': '{files} 个文件 · {ops} 次操作',
'files.search': '按路径过滤…', 'files.search': '按路径过滤…',
'files.sort.count': '按次数', 'files.sort.latest': '按最新', 'files.sort.path': '按路径', 'files.sort.count': '按次数',
'files.sort.latest': '按最新',
'files.sort.path': '按路径',
'files.sortTip': '文件排序:按操作次数(选中分类时按该分类的次数)、最近操作时间或路径', 'files.sortTip': '文件排序:按操作次数(选中分类时按该分类的次数)、最近操作时间或路径',
'files.files': '{n} 个文件', 'files.files': '{n} 个文件',
'files.deltaTip': '按 edit/write 调用参数估算的累计行数变化:+ 新增 / − 删除', 'files.deltaTip': '按 edit/write 调用参数估算的累计行数变化:+ 新增 / − 删除',
@@ -117,23 +144,53 @@ export const DICT_ZH: Record<string, string> = {
'files.preview': '在侧边栏预览', 'files.preview': '在侧边栏预览',
'files.readEst': '按调用参数 limit 估算的读取行数', 'files.readEst': '按调用参数 limit 估算的读取行数',
'files.errs': '{n} 次失败', 'files.errs': '{n} 次失败',
'files.form.image': '图片', 'files.form.dir': '目录', 'files.form.text': '文件', 'files.form.image': '图片',
'files.glyph.root': '工作区根', 'files.glyph.tests': '测试', 'files.glyph.docs': '文档目录', 'files.form.dir': '目录',
'files.glyph.deps': '依赖', 'files.glyph.build': '构建产物', 'files.glyph.scripts': '脚本', 'files.form.text': '文件',
'files.glyph.config': '配置', 'files.glyph.assets': '静态资源', 'files.glyph.hidden': '元数据目录', 'files.glyph.root': '工作区根',
'files.glyph.lock': '锁文件', 'files.glyph.docker': 'Docker', 'files.glyph.ignore': '忽略规则', 'files.glyph.tests': '测试',
'files.glyph.license': '许可证', 'files.glyph.python': 'Python', 'files.glyph.notebook': 'Notebook', 'files.glyph.docs': '文档目录',
'files.glyph.shell': 'Shell', 'files.glyph.style': '样式', 'files.glyph.deps': '依赖',
'files.glyph.database': '数据库', 'files.glyph.data': '数据清单', 'files.glyph.build': '构建产物',
'files.glyph.markdown': '标记文档', 'files.glyph.log': '日志', 'files.glyph.sheet': '表格', 'files.glyph.scripts': '脚本',
'files.glyph.document': '文档', 'files.glyph.archive': '压缩包', 'files.glyph.font': '字体', 'files.glyph.config': '配置',
'files.glyph.assets': '静态资源',
'files.glyph.hidden': '元数据目录',
'files.glyph.lock': '锁文件',
'files.glyph.docker': 'Docker',
'files.glyph.ignore': '忽略规则',
'files.glyph.license': '许可证',
'files.glyph.python': 'Python',
'files.glyph.notebook': 'Notebook',
'files.glyph.shell': 'Shell',
'files.glyph.style': '样式',
'files.glyph.database': '数据库',
'files.glyph.data': '数据清单',
'files.glyph.markdown': '标记文档',
'files.glyph.log': '日志',
'files.glyph.sheet': '表格',
'files.glyph.document': '文档',
'files.glyph.archive': '压缩包',
'files.glyph.font': '字体',
'files.glyph.media': '媒体', 'files.glyph.media': '媒体',
'files.glyph.lang.ts': 'TypeScript', 'files.glyph.lang.js': 'JavaScript', 'files.glyph.lang.go': 'Go', 'files.glyph.lang.ts': 'TypeScript',
'files.glyph.lang.rust': 'Rust', 'files.glyph.lang.java': 'Java', 'files.glyph.lang.kotlin': 'Kotlin', 'files.glyph.lang.js': 'JavaScript',
'files.glyph.lang.ruby': 'Ruby', 'files.glyph.lang.php': 'PHP', 'files.glyph.lang.c': 'C', 'files.glyph.lang.go': 'Go',
'files.glyph.lang.cpp': 'C++', 'files.glyph.lang.csharp': 'C#', 'files.glyph.lang.scala': 'Scala', 'files.glyph.lang.rust': 'Rust',
'files.glyph.lang.lua': 'Lua', 'files.glyph.lang.dart': 'Dart', 'files.glyph.lang.swift': 'Swift', 'files.glyph.lang.java': 'Java',
'files.glyph.lang.vue': 'Vue', 'files.glyph.lang.svelte': 'Svelte', 'files.glyph.lang.html': 'HTML', 'files.glyph.lang.kotlin': 'Kotlin',
'files.glyph.lang.ruby': 'Ruby',
'files.glyph.lang.php': 'PHP',
'files.glyph.lang.c': 'C',
'files.glyph.lang.cpp': 'C++',
'files.glyph.lang.csharp': 'C#',
'files.glyph.lang.scala': 'Scala',
'files.glyph.lang.lua': 'Lua',
'files.glyph.lang.dart': 'Dart',
'files.glyph.lang.swift': 'Swift',
'files.glyph.lang.vue': 'Vue',
'files.glyph.lang.svelte': 'Svelte',
'files.glyph.lang.html': 'HTML',
'agents.title': 'Agent 网络', 'agents.title': 'Agent 网络',
'agents.sub': '当前 Agent 与子 Agent 的实时上下文 · 点击节点跳转会话', 'agents.sub': '当前 Agent 与子 Agent 的实时上下文 · 点击节点跳转会话',
'agents.chip.count': '{n} 个 Agent', 'agents.chip.count': '{n} 个 Agent',
@@ -171,9 +228,15 @@ export const DICT_ZH: Record<string, string> = {
'ev.prune': '剪枝工具输出', 'ev.prune': '剪枝工具输出',
'ev.skill': 'Skill 注入({name})', 'ev.skill': 'Skill 注入({name})',
'ev.model': '模型切换:{a} → {b}', 'ev.model': '模型切换:{a} → {b}',
'ev.mode.plan.on': '进入计划模式', 'ev.mode.plan.off': '退出计划模式', 'ev.mode.plan.on': '进入计划模式',
'form.instructions': '指令注入', 'form.catalog': '目录更新', 'form.snapshot': '状态快照', 'ev.mode.plan.off': '退出计划模式',
'form.notice': '通知', 'form.relay': '代理转发', 'form.recall': '历史召回', 'form.context': '上下文注入', 'form.instructions': '指令注入',
'form.catalog': '目录更新',
'form.snapshot': '状态快照',
'form.notice': '通知',
'form.relay': '代理转发',
'form.recall': '历史召回',
'form.context': '上下文注入',
'node.toolResult': '工具结果', 'node.toolResult': '工具结果',
'node.calls': '调用 ', 'node.calls': '调用 ',
'node.empty': '(空回复)', 'node.empty': '(空回复)',
@@ -203,7 +266,9 @@ export const DICT_ZH: Record<string, string> = {
'browser.search.skill': '按技能过滤…', 'browser.search.skill': '按技能过滤…',
'browser.search.assistant': '按回复或调用过滤…', 'browser.search.assistant': '按回复或调用过滤…',
'browser.search.tool': '按工具或参数过滤…', 'browser.search.tool': '按工具或参数过滤…',
'browser.kind.think': '思考', 'browser.kind.tool': '工具', 'browser.kind.answer': '回答', 'browser.kind.think': '思考',
'browser.kind.tool': '工具',
'browser.kind.answer': '回答',
'browser.kindTip': '按内容种类过滤回复:思考、工具调用、回答文本', 'browser.kindTip': '按内容种类过滤回复:思考、工具调用、回答文本',
'browser.rowNoMatch': '没有匹配当前过滤条件的行', 'browser.rowNoMatch': '没有匹配当前过滤条件的行',
'browser.loading': '正在从更早的会话历史加载完整内容…', 'browser.loading': '正在从更早的会话历史加载完整内容…',
@@ -218,7 +283,9 @@ export const DICT_ZH: Record<string, string> = {
'tool.jsonToggle': '查看原始 JSON', 'tool.jsonToggle': '查看原始 JSON',
'tool.jsonHide': '收起', 'tool.jsonHide': '收起',
'tool.search': '按名称、描述或参数过滤…', 'tool.search': '按名称、描述或参数过滤…',
'tool.sort.size': '按大小', 'tool.sort.count': '按次数', 'tool.sort.name': '按名称', 'tool.sort.size': '按大小',
'tool.sort.count': '按次数',
'tool.sort.name': '按名称',
'tool.sortTip': '工具排序:按当前步骤中的调用次数(默认)、token 大小或名称', 'tool.sortTip': '工具排序:按当前步骤中的调用次数(默认)、token 大小或名称',
'tool.hitsTip': '当前展示步骤的上下文中,该工具被调用并返回结果的次数', 'tool.hitsTip': '当前展示步骤的上下文中,该工具被调用并返回结果的次数',
'tool.noMatch': '没有匹配当前过滤条件的工具', 'tool.noMatch': '没有匹配当前过滤条件的工具',
@@ -226,16 +293,23 @@ export const DICT_ZH: Record<string, string> = {
'rich.md': 'Markdown', 'rich.md': 'Markdown',
'rich.toMd': '按 Markdown 渲染查看', 'rich.toMd': '按 Markdown 渲染查看',
'rich.toRaw': '查看原始文本', 'rich.toRaw': '查看原始文本',
'rich.copy': '复制原文', 'rich.copied': '已复制', 'rich.copy': '复制原文',
'rich.md.copy': '复制', 'rich.md.copied': '已复制', 'rich.copied': '已复制',
'rich.md.copy': '复制',
'rich.md.copied': '已复制',
'rich.md.footnotes': '脚注', 'rich.md.footnotes': '脚注',
'block.thinking': '思考', 'block.thinking': '思考',
'block.answer': '回答', 'block.answer': '回答',
'block.content': '内容', 'block.result': '结果', 'block.summary': '摘要', 'block.content': '内容',
'block.result': '结果',
'block.summary': '摘要',
// Line-count chip on a tool-result's payload card (the singular/plural // Line-count chip on a tool-result's payload card (the singular/plural
// split is a no-op in zh, where the measure word never inflects). // split is a no-op in zh, where the measure word never inflects).
'block.line': '{n} 行', 'block.lines': '{n} 行', 'block.line': '{n} 行',
'call.ok': '正常', 'call.fail': '失败', 'call.exit': 'exit {n}', 'block.lines': '{n} 行',
'call.ok': '正常',
'call.fail': '失败',
'call.exit': 'exit {n}',
'node.failed': '工具执行失败', 'node.failed': '工具执行失败',
'attach.images': '图片附件', 'attach.images': '图片附件',
'attach.other': '其他内容', 'attach.other': '其他内容',
@@ -253,7 +327,10 @@ export const DICT_ZH: Record<string, string> = {
'ov.title': '上下文洞察', 'ov.title': '上下文洞察',
'ov.unavailable': '会话列表暂不可用', 'ov.unavailable': '会话列表暂不可用',
'ov.range.label': '统计范围', 'ov.range.label': '统计范围',
'ov.range.24h': '近 24 小时', 'ov.range.7d': '近 7 天', 'ov.range.30d': '近 30 天', 'ov.range.all': '全部', 'ov.range.24h': '近 24 小时',
'ov.range.7d': '近 7 天',
'ov.range.30d': '近 30 天',
'ov.range.all': '全部',
'ov.kpi.sessions': '活跃会话', 'ov.kpi.sessions': '活跃会话',
'ov.kpi.ofTotal': '共 {n} 个', 'ov.kpi.ofTotal': '共 {n} 个',
'ov.kpi.tokens': '累计消耗', 'ov.kpi.tokens': '累计消耗',
@@ -274,18 +351,33 @@ export const DICT_ZH: Record<string, string> = {
'ov.heat.sub': '按日期筛选', 'ov.heat.sub': '按日期筛选',
'ov.heat.empty': '暂无活跃数据 — 会话产生模型请求后,这里会显示每日用量', 'ov.heat.empty': '暂无活跃数据 — 会话产生模型请求后,这里会显示每日用量',
'ov.heat.sessions': '{n} 个活跃会话', 'ov.heat.sessions': '{n} 个活跃会话',
'ov.heat.less': '少', 'ov.heat.more': '多', 'ov.heat.less': '少',
'ov.heat.metric': '指标', 'ov.heat.metric.sessions': '会话', 'ov.heat.metric.steps': '步数', 'ov.heat.more': '多',
'ov.heat.metric': '指标',
'ov.heat.metric.sessions': '会话',
'ov.heat.metric.steps': '步数',
'ov.heat.steps': '{n} 步', 'ov.heat.steps': '{n} 步',
'ov.heat.wd.1': '星期一', 'ov.heat.wd.3': '星期三', 'ov.heat.wd.5': '星期五', 'ov.heat.wd.1': '星期一',
'ov.heat.mon.01': '1月', 'ov.heat.mon.02': '2月', 'ov.heat.mon.03': '3月', 'ov.heat.wd.3': '星期三',
'ov.heat.mon.04': '4月', 'ov.heat.mon.05': '5月', 'ov.heat.mon.06': '6月', 'ov.heat.wd.5': '星期五',
'ov.heat.mon.07': '7月', 'ov.heat.mon.08': '8月', 'ov.heat.mon.09': '9月', 'ov.heat.mon.01': '1月',
'ov.heat.mon.10': '10月', 'ov.heat.mon.11': '11月', 'ov.heat.mon.12': '12月', 'ov.heat.mon.02': '2月',
'ov.heat.mon.03': '3月',
'ov.heat.mon.04': '4月',
'ov.heat.mon.05': '5月',
'ov.heat.mon.06': '6月',
'ov.heat.mon.07': '7月',
'ov.heat.mon.08': '8月',
'ov.heat.mon.09': '9月',
'ov.heat.mon.10': '10月',
'ov.heat.mon.11': '11月',
'ov.heat.mon.12': '12月',
'ov.list.title': '会话', 'ov.list.title': '会话',
'ov.list.search': '搜索标题 / 目录 / 最后消息…', 'ov.list.search': '搜索标题 / 目录 / 最后消息…',
'ov.list.sortLabel': '排序', 'ov.list.sortLabel': '排序',
'ov.list.sort.recent': '最近更新', 'ov.list.sort.tokens': 'Token 总用量', 'ov.list.sort.context': '当前 Context', 'ov.list.sort.recent': '最近更新',
'ov.list.sort.tokens': 'Token 总用量',
'ov.list.sort.context': '当前 Context',
'ov.list.empty': '还没有会话 — 发起一轮对话后,这里会列出每个会话的上下文画像', 'ov.list.empty': '还没有会话 — 发起一轮对话后,这里会列出每个会话的上下文画像',
'ov.list.noMatch': '没有匹配当前筛选条件的会话', 'ov.list.noMatch': '没有匹配当前筛选条件的会话',
'ov.list.noData': '暂无上下文数据 — 该会话产生模型请求后才会统计', 'ov.list.noData': '暂无上下文数据 — 该会话产生模型请求后才会统计',
@@ -310,8 +402,13 @@ export const DICT_ZH: Record<string, string> = {
export const DICT_EN: Record<string, string> = { export const DICT_EN: Record<string, string> = {
'tab': 'Context', 'tab': 'Context',
'sidebar.guideDescription': 'Inspect context composition, stats, and evolution.', 'sidebar.guideDescription': 'Inspect context composition, stats, and evolution.',
'cat.system': 'System Prompt', 'cat.tools': 'Tool Schemas', 'cat.user': 'User Messages', 'cat.system': 'System Prompt',
'cat.inject': 'Injected Context', 'cat.skill': 'Skill Injections', 'cat.assistant': 'Assistant Messages', 'cat.tool': 'Tool Results', 'cat.tools': 'Tool Schemas',
'cat.user': 'User Messages',
'cat.inject': 'Injected Context',
'cat.skill': 'Skill Injections',
'cat.assistant': 'Assistant Messages',
'cat.tool': 'Tool Results',
'overview.title': 'Current Context', 'overview.title': 'Current Context',
'overview.estimate': 'tokens (estimated)', 'overview.estimate': 'tokens (estimated)',
'overview.free': 'Free Window', 'overview.free': 'Free Window',
@@ -319,7 +416,8 @@ export const DICT_EN: Record<string, string> = {
'overview.ofUsed': 'of used context', 'overview.ofUsed': 'of used context',
'overview.compactReserve': 'Auto-compaction reserve: auto-compaction triggers at {pct}% of the window — this area is normally kept as headroom, not actually used', 'overview.compactReserve': 'Auto-compaction reserve: auto-compaction triggers at {pct}% of the window — this area is normally kept as headroom, not actually used',
'stats.title': 'Context Stats', 'stats.title': 'Context Stats',
'stats.turns': 'Turns', 'stats.steps': 'Steps', 'stats.turns': 'Turns',
'stats.steps': 'Steps',
'stats.humanInputs': 'Human Inputs', 'stats.humanInputs': 'Human Inputs',
'stats.humanInputsTip': 'User messages and question answerings in current session.', 'stats.humanInputsTip': 'User messages and question answerings in current session.',
'stats.toolCalls': 'Tool Calls', 'stats.toolCalls': 'Tool Calls',
@@ -333,7 +431,10 @@ export const DICT_EN: Record<string, string> = {
'stats.subCostTip': 'Summed estimates of every subagent session’s own cumulative cost (same basis); the current agent is not included.', 'stats.subCostTip': 'Summed estimates of every subagent session’s own cumulative cost (same basis); the current agent is not included.',
'stats.costPriceHead': 'Per-1M-token rates:', 'stats.costPriceHead': 'Per-1M-token rates:',
'stats.costPriceBy': 'Priced as listed on models.dev for {p} · {m}.', 'stats.costPriceBy': 'Priced as listed on models.dev for {p} · {m}.',
'stats.costHit': 'Cache input', 'stats.costMiss': 'Uncached input', 'stats.costWrite': 'Cache write', 'stats.costOut': 'Output', 'stats.costHit': 'Cache input',
'stats.costMiss': 'Uncached input',
'stats.costWrite': 'Cache write',
'stats.costOut': 'Output',
'stats.costUnavailable': 'Model prices are unavailable (retrying automatically) — the cost cannot be estimated yet.', 'stats.costUnavailable': 'Model prices are unavailable (retrying automatically) — the cost cannot be estimated yet.',
'timing.title': 'Timing Stats', 'timing.title': 'Timing Stats',
'timing.total': 'Active Time', 'timing.total': 'Active Time',
@@ -344,7 +445,9 @@ export const DICT_EN: Record<string, string> = {
'timing.toolArgs': 'Tool args', 'timing.toolArgs': 'Tool args',
'timing.tools': 'Tool runs', 'timing.tools': 'Tool runs',
'timing.other': 'Overhead', 'timing.other': 'Overhead',
'timing.callTimes': '{n} calls', 'timing.toolTimes': '{n} runs', 'timing.blockTimes': '{n} blocks', 'timing.callTimes': '{n} calls',
'timing.toolTimes': '{n} runs',
'timing.blockTimes': '{n} blocks',
'timing.empty': 'No timing data yet — durations appear as the conversation runs', 'timing.empty': 'No timing data yet — durations appear as the conversation runs',
'timing.tps': '{tps} tok/s', 'timing.tps': '{tps} tok/s',
'timing.tpsTip': 'Output speed (TPS): summed decoded output tokens over summed decode time — the same pairing as the harness session stats.', 'timing.tpsTip': 'Output speed (TPS): summed decoded output tokens over summed decode time — the same pairing as the harness session stats.',
@@ -359,19 +462,26 @@ export const DICT_EN: Record<string, string> = {
'plugin.settings': 'Settings', 'plugin.settings': 'Settings',
'plugin.settingsOpen': 'Open plugin settings', 'plugin.settingsOpen': 'Open plugin settings',
'trend.title': 'Context Trend', 'trend.title': 'Context Trend',
'gran.step': 'Step', 'gran.turn': 'Turn', 'gran.step': 'Step',
'settings.title': 'Context', 'settings.desc': 'Preferences for Context panel in dsh-context plugin', 'gran.turn': 'Turn',
'settings.title': 'Context',
'settings.desc': 'Preferences for Context panel in dsh-context plugin',
'settings.placement': 'Entry Options', 'settings.placement': 'Entry Options',
'placement.tab': 'Tab', 'placement.sidebar': 'Sidebar', 'placement.all': 'All', 'placement.tab': 'Tab',
'placement.sidebar': 'Sidebar',
'placement.all': 'All',
'settings.insightsEntry': 'Context Insights entry', 'settings.insightsEntry': 'Context Insights entry',
'insightsEntry.show': 'Show', 'insightsEntry.hide': 'Hide', 'insightsEntry.show': 'Show',
'insightsEntry.hide': 'Hide',
'settings.gran': 'Trend Chart · Default granularity', 'settings.gran': 'Trend Chart · Default granularity',
'settings.mode': 'Trend Chart · Default display', 'settings.mode': 'Trend Chart · Default display',
'settings.toolSort': 'Tool Schemas · Default sort', 'settings.toolSort': 'Tool Schemas · Default sort',
'settings.fileSort': 'File Activity · Default sort', 'settings.fileSort': 'File Activity · Default sort',
'settings.expand': 'Expand', 'settings.collapse': 'Collapse', 'settings.expand': 'Expand',
'settings.collapse': 'Collapse',
'settings.readOnly': 'Settings are read-only in this environment', 'settings.readOnly': 'Settings are read-only in this environment',
'gran.total': 'Total', 'gran.delta': 'Delta', 'gran.total': 'Total',
'gran.delta': 'Delta',
'gran.modeHint': 'Total: cumulative makeup; Delta: change vs the previous request', 'gran.modeHint': 'Total: cumulative makeup; Delta: change vs the previous request',
'trend.focus': 'Showing {cat} only', 'trend.focus': 'Showing {cat} only',
'trend.adaptive': 'Adaptive', 'trend.adaptive': 'Adaptive',
@@ -399,14 +509,23 @@ export const DICT_EN: Record<string, string> = {
'events.at': 'Turn {t} · Step {s}', 'events.at': 'Turn {t} · Step {s}',
'events.range': 'Turn {t} · Step {a}→{b}', 'events.range': 'Turn {t} · Step {a}→{b}',
'events.rangeTo': 'Turn {a} · Step {as} → Turn {b} · Step {bs}', 'events.rangeTo': 'Turn {a} · Step {as} → Turn {b} · Step {bs}',
'kind.inject': 'Inject', 'kind.compaction': 'Compact', 'kind.prune': 'Prune', 'kind.model': 'Switch', 'kind.mode': 'Mode', 'kind.inject': 'Inject',
'kind.compaction': 'Compact',
'kind.prune': 'Prune',
'kind.model': 'Switch',
'kind.mode': 'Mode',
'files.title': 'File Activity', 'files.title': 'File Activity',
'files.scopeLatest': 'Up to latest · follows the trend chart pick', 'files.scopeLatest': 'Up to latest · follows the trend chart pick',
'files.kind.all': 'All', 'files.kind.read': 'Read', 'files.kind.write': 'Written', 'files.kind.all': 'All',
'files.kind.search': 'Searched', 'files.kind.image': 'Images', 'files.kind.read': 'Read',
'files.kind.write': 'Written',
'files.kind.search': 'Searched',
'files.kind.image': 'Images',
'files.chipTip': '{files} files · {ops} ops', 'files.chipTip': '{files} files · {ops} ops',
'files.search': 'Filter by path…', 'files.search': 'Filter by path…',
'files.sort.count': 'Most active', 'files.sort.latest': 'Latest', 'files.sort.path': 'By path', 'files.sort.count': 'Most active',
'files.sort.latest': 'Latest',
'files.sort.path': 'By path',
'files.sortTip': 'Sort files by operation counts (of the selected kind when a kind chip is active), most recent activity, or path', 'files.sortTip': 'Sort files by operation counts (of the selected kind when a kind chip is active), most recent activity, or path',
'files.files': '{n} files', 'files.files': '{n} files',
'files.deltaTip': 'Cumulative line change estimated from edit/write call arguments: + added / − removed', 'files.deltaTip': 'Cumulative line change estimated from edit/write call arguments: + added / − removed',
@@ -419,23 +538,53 @@ export const DICT_EN: Record<string, string> = {
'files.preview': 'Preview in the sidebar', 'files.preview': 'Preview in the sidebar',
'files.readEst': 'Lines read, estimated from the limit argument', 'files.readEst': 'Lines read, estimated from the limit argument',
'files.errs': '{n} failed', 'files.errs': '{n} failed',
'files.form.image': 'Image', 'files.form.dir': 'Directory', 'files.form.text': 'File', 'files.form.image': 'Image',
'files.glyph.root': 'Workspace root', 'files.glyph.tests': 'Tests', 'files.glyph.docs': 'Docs', 'files.form.dir': 'Directory',
'files.glyph.deps': 'Dependencies', 'files.glyph.build': 'Build output', 'files.glyph.scripts': 'Scripts', 'files.form.text': 'File',
'files.glyph.config': 'Config', 'files.glyph.assets': 'Assets', 'files.glyph.hidden': 'Metadata directory', 'files.glyph.root': 'Workspace root',
'files.glyph.lock': 'Lockfile', 'files.glyph.docker': 'Docker', 'files.glyph.ignore': 'Ignore rules', 'files.glyph.tests': 'Tests',
'files.glyph.license': 'License', 'files.glyph.python': 'Python', 'files.glyph.notebook': 'Notebook', 'files.glyph.docs': 'Docs',
'files.glyph.shell': 'Shell', 'files.glyph.style': 'Styles', 'files.glyph.deps': 'Dependencies',
'files.glyph.database': 'Database', 'files.glyph.data': 'Data / manifest', 'files.glyph.build': 'Build output',
'files.glyph.markdown': 'Markup document', 'files.glyph.log': 'Log', 'files.glyph.sheet': 'Spreadsheet', 'files.glyph.scripts': 'Scripts',
'files.glyph.document': 'Document', 'files.glyph.archive': 'Archive', 'files.glyph.font': 'Font', 'files.glyph.config': 'Config',
'files.glyph.assets': 'Assets',
'files.glyph.hidden': 'Metadata directory',
'files.glyph.lock': 'Lockfile',
'files.glyph.docker': 'Docker',
'files.glyph.ignore': 'Ignore rules',
'files.glyph.license': 'License',
'files.glyph.python': 'Python',
'files.glyph.notebook': 'Notebook',
'files.glyph.shell': 'Shell',
'files.glyph.style': 'Styles',
'files.glyph.database': 'Database',
'files.glyph.data': 'Data / manifest',
'files.glyph.markdown': 'Markup document',
'files.glyph.log': 'Log',
'files.glyph.sheet': 'Spreadsheet',
'files.glyph.document': 'Document',
'files.glyph.archive': 'Archive',
'files.glyph.font': 'Font',
'files.glyph.media': 'Media', 'files.glyph.media': 'Media',
'files.glyph.lang.ts': 'TypeScript', 'files.glyph.lang.js': 'JavaScript', 'files.glyph.lang.go': 'Go', 'files.glyph.lang.ts': 'TypeScript',
'files.glyph.lang.rust': 'Rust', 'files.glyph.lang.java': 'Java', 'files.glyph.lang.kotlin': 'Kotlin', 'files.glyph.lang.js': 'JavaScript',
'files.glyph.lang.ruby': 'Ruby', 'files.glyph.lang.php': 'PHP', 'files.glyph.lang.c': 'C', 'files.glyph.lang.go': 'Go',
'files.glyph.lang.cpp': 'C++', 'files.glyph.lang.csharp': 'C#', 'files.glyph.lang.scala': 'Scala', 'files.glyph.lang.rust': 'Rust',
'files.glyph.lang.lua': 'Lua', 'files.glyph.lang.dart': 'Dart', 'files.glyph.lang.swift': 'Swift', 'files.glyph.lang.java': 'Java',
'files.glyph.lang.vue': 'Vue', 'files.glyph.lang.svelte': 'Svelte', 'files.glyph.lang.html': 'HTML', 'files.glyph.lang.kotlin': 'Kotlin',
'files.glyph.lang.ruby': 'Ruby',
'files.glyph.lang.php': 'PHP',
'files.glyph.lang.c': 'C',
'files.glyph.lang.cpp': 'C++',
'files.glyph.lang.csharp': 'C#',
'files.glyph.lang.scala': 'Scala',
'files.glyph.lang.lua': 'Lua',
'files.glyph.lang.dart': 'Dart',
'files.glyph.lang.swift': 'Swift',
'files.glyph.lang.vue': 'Vue',
'files.glyph.lang.svelte': 'Svelte',
'files.glyph.lang.html': 'HTML',
'agents.title': 'Agent Network', 'agents.title': 'Agent Network',
'agents.sub': 'Live context of this agent and its subagents · click a node to open its session', 'agents.sub': 'Live context of this agent and its subagents · click a node to open its session',
'agents.chip.count': '{n} agents', 'agents.chip.count': '{n} agents',
@@ -473,9 +622,15 @@ export const DICT_EN: Record<string, string> = {
'ev.prune': 'Tool output pruned', 'ev.prune': 'Tool output pruned',
'ev.skill': 'Skill injected ({name})', 'ev.skill': 'Skill injected ({name})',
'ev.model': 'Model switched: {a} → {b}', 'ev.model': 'Model switched: {a} → {b}',
'ev.mode.plan.on': 'Plan mode on', 'ev.mode.plan.off': 'Plan mode off', 'ev.mode.plan.on': 'Plan mode on',
'form.instructions': 'Instructions', 'form.catalog': 'Catalog Update', 'form.snapshot': 'State Snapshot', 'ev.mode.plan.off': 'Plan mode off',
'form.notice': 'Notice', 'form.relay': 'Agent Relay', 'form.recall': 'Recall', 'form.context': 'Context Injection', 'form.instructions': 'Instructions',
'form.catalog': 'Catalog Update',
'form.snapshot': 'State Snapshot',
'form.notice': 'Notice',
'form.relay': 'Agent Relay',
'form.recall': 'Recall',
'form.context': 'Context Injection',
'node.toolResult': 'Tool Result', 'node.toolResult': 'Tool Result',
'node.calls': 'Calls ', 'node.calls': 'Calls ',
'node.empty': '(empty reply)', 'node.empty': '(empty reply)',
@@ -505,7 +660,9 @@ export const DICT_EN: Record<string, string> = {
'browser.search.skill': 'Filter skills…', 'browser.search.skill': 'Filter skills…',
'browser.search.assistant': 'Filter by reply or calls…', 'browser.search.assistant': 'Filter by reply or calls…',
'browser.search.tool': 'Filter by tool or arguments…', 'browser.search.tool': 'Filter by tool or arguments…',
'browser.kind.think': 'Thinking', 'browser.kind.tool': 'Tools', 'browser.kind.answer': 'Answer', 'browser.kind.think': 'Thinking',
'browser.kind.tool': 'Tools',
'browser.kind.answer': 'Answer',
'browser.kindTip': 'Filter replies by content kind: thinking, tool calls, or answer text', 'browser.kindTip': 'Filter replies by content kind: thinking, tool calls, or answer text',
'browser.rowNoMatch': 'No rows match the current filter', 'browser.rowNoMatch': 'No rows match the current filter',
'browser.loading': 'Loading full content from older session history…', 'browser.loading': 'Loading full content from older session history…',
@@ -520,7 +677,9 @@ export const DICT_EN: Record<string, string> = {
'tool.jsonToggle': 'View Raw JSON', 'tool.jsonToggle': 'View Raw JSON',
'tool.jsonHide': 'Collapse', 'tool.jsonHide': 'Collapse',
'tool.search': 'Filter by name, description, or parameters…', 'tool.search': 'Filter by name, description, or parameters…',
'tool.sort.size': 'By size', 'tool.sort.count': 'By calls', 'tool.sort.name': 'By name', 'tool.sort.size': 'By size',
'tool.sort.count': 'By calls',
'tool.sort.name': 'By name',
'tool.sortTip': 'Sort tools by call count in the shown step (default), token size, or name', 'tool.sortTip': 'Sort tools by call count in the shown step (default), token size, or name',
'tool.hitsTip': 'Times this tool was called and answered within the shown step’s context', 'tool.hitsTip': 'Times this tool was called and answered within the shown step’s context',
'tool.noMatch': 'No tools match the current filter', 'tool.noMatch': 'No tools match the current filter',
@@ -528,14 +687,21 @@ export const DICT_EN: Record<string, string> = {
'rich.md': 'Markdown', 'rich.md': 'Markdown',
'rich.toMd': 'View as Markdown', 'rich.toMd': 'View as Markdown',
'rich.toRaw': 'View Raw Text', 'rich.toRaw': 'View Raw Text',
'rich.copy': 'Copy Raw Text', 'rich.copied': 'Copied', 'rich.copy': 'Copy Raw Text',
'rich.md.copy': 'Copy', 'rich.md.copied': 'Copied', 'rich.copied': 'Copied',
'rich.md.copy': 'Copy',
'rich.md.copied': 'Copied',
'rich.md.footnotes': 'Footnotes', 'rich.md.footnotes': 'Footnotes',
'block.thinking': 'Reasoning', 'block.thinking': 'Reasoning',
'block.answer': 'Response', 'block.answer': 'Response',
'block.content': 'Content', 'block.result': 'Result', 'block.summary': 'Summary', 'block.content': 'Content',
'block.line': '1 line', 'block.lines': '{n} lines', 'block.result': 'Result',
'call.ok': 'OK', 'call.fail': 'Failed', 'call.exit': 'exit {n}', 'block.summary': 'Summary',
'block.line': '1 line',
'block.lines': '{n} lines',
'call.ok': 'OK',
'call.fail': 'Failed',
'call.exit': 'exit {n}',
'node.failed': 'Tool execution failed', 'node.failed': 'Tool execution failed',
'attach.images': 'Images', 'attach.images': 'Images',
'attach.other': 'Other content', 'attach.other': 'Other content',
@@ -553,7 +719,10 @@ export const DICT_EN: Record<string, string> = {
'ov.title': 'Context Insights', 'ov.title': 'Context Insights',
'ov.unavailable': 'The session list is unavailable', 'ov.unavailable': 'The session list is unavailable',
'ov.range.label': 'Range', 'ov.range.label': 'Range',
'ov.range.24h': 'Last 24 hours', 'ov.range.7d': 'Last 7 days', 'ov.range.30d': 'Last 30 days', 'ov.range.all': 'All', 'ov.range.24h': 'Last 24 hours',
'ov.range.7d': 'Last 7 days',
'ov.range.30d': 'Last 30 days',
'ov.range.all': 'All',
'ov.kpi.sessions': 'Active Sessions', 'ov.kpi.sessions': 'Active Sessions',
'ov.kpi.ofTotal': 'of {n} total', 'ov.kpi.ofTotal': 'of {n} total',
'ov.kpi.tokens': 'Tokens Used', 'ov.kpi.tokens': 'Tokens Used',
@@ -574,18 +743,33 @@ export const DICT_EN: Record<string, string> = {
'ov.heat.sub': 'Filter by date', 'ov.heat.sub': 'Filter by date',
'ov.heat.empty': 'No activity yet — daily usage appears once sessions make model requests', 'ov.heat.empty': 'No activity yet — daily usage appears once sessions make model requests',
'ov.heat.sessions': '{n} active sessions', 'ov.heat.sessions': '{n} active sessions',
'ov.heat.less': 'Less', 'ov.heat.more': 'More', 'ov.heat.less': 'Less',
'ov.heat.metric': 'Metric', 'ov.heat.metric.sessions': 'Sessions', 'ov.heat.metric.steps': 'Steps', 'ov.heat.more': 'More',
'ov.heat.metric': 'Metric',
'ov.heat.metric.sessions': 'Sessions',
'ov.heat.metric.steps': 'Steps',
'ov.heat.steps': '{n} steps', 'ov.heat.steps': '{n} steps',
'ov.heat.wd.1': 'Mon', 'ov.heat.wd.3': 'Wed', 'ov.heat.wd.5': 'Fri', 'ov.heat.wd.1': 'Mon',
'ov.heat.mon.01': 'Jan', 'ov.heat.mon.02': 'Feb', 'ov.heat.mon.03': 'Mar', 'ov.heat.wd.3': 'Wed',
'ov.heat.mon.04': 'Apr', 'ov.heat.mon.05': 'May', 'ov.heat.mon.06': 'Jun', 'ov.heat.wd.5': 'Fri',
'ov.heat.mon.07': 'Jul', 'ov.heat.mon.08': 'Aug', 'ov.heat.mon.09': 'Sep', 'ov.heat.mon.01': 'Jan',
'ov.heat.mon.10': 'Oct', 'ov.heat.mon.11': 'Nov', 'ov.heat.mon.12': 'Dec', 'ov.heat.mon.02': 'Feb',
'ov.heat.mon.03': 'Mar',
'ov.heat.mon.04': 'Apr',
'ov.heat.mon.05': 'May',
'ov.heat.mon.06': 'Jun',
'ov.heat.mon.07': 'Jul',
'ov.heat.mon.08': 'Aug',
'ov.heat.mon.09': 'Sep',
'ov.heat.mon.10': 'Oct',
'ov.heat.mon.11': 'Nov',
'ov.heat.mon.12': 'Dec',
'ov.list.title': 'Sessions', 'ov.list.title': 'Sessions',
'ov.list.search': 'Search title / path / last message…', 'ov.list.search': 'Search title / path / last message…',
'ov.list.sortLabel': 'Sort', 'ov.list.sortLabel': 'Sort',
'ov.list.sort.recent': 'Last updated', 'ov.list.sort.tokens': 'Total Tokens', 'ov.list.sort.context': 'Current Context', 'ov.list.sort.recent': 'Last updated',
'ov.list.sort.tokens': 'Total Tokens',
'ov.list.sort.context': 'Current Context',
'ov.list.empty': 'No sessions yet — each session’s context profile appears here once you start one', 'ov.list.empty': 'No sessions yet — each session’s context profile appears here once you start one',
'ov.list.noMatch': 'No sessions match the current filters', 'ov.list.noMatch': 'No sessions match the current filters',
'ov.list.noData': 'No context data yet — stats appear once the session makes model requests', 'ov.list.noData': 'No context data yet — stats appear once the session makes model requests',
+4 -1
View File
@@ -122,7 +122,10 @@ function apply(ctx: ClientCtx): void {
const ContextModal = makeContextModal(ctx, kit, settings) const ContextModal = makeContextModal(ctx, kit, settings)
ctx.slots.inject('conversation.input.overlay', () => { ctx.slots.inject('conversation.input.overlay', () => {
return ctx.slots.register( return ctx.slots.register(
{ name: 'conversation.input.overlay', id: 'context-modal', order: 10, locale: NS, { name: 'conversation.input.overlay',
id: 'context-modal',
order: 10,
locale: NS,
inject: (sessionId = '') => ({ hooks: { contextModal: modalStoreOf(sessionId) } }) }, inject: (sessionId = '') => ({ hooks: { contextModal: modalStoreOf(sessionId) } }) },
props => h(ContextModal, props), props => h(ContextModal, props),
) )
+8 -3
View File
@@ -1028,7 +1028,9 @@ export function applyTimeline(state: TimelineState, event: TimelineEvent, bounds
const source = msg?.source const source = msg?.source
if (isInjection(source)) { if (isInjection(source)) {
const rec: ContextEventRecord = { const rec: ContextEventRecord = {
seq: event.seq, time: event.time, kind: 'inject', seq: event.seq,
time: event.time,
kind: 'inject',
// Re-proved: the harness validates a source's `kind` but not its // Re-proved: the harness validates a source's `kind` but not its
// `form`, so a hostile form must degrade to the default instead of // `form`, so a hostile form must degrade to the default instead of
// failing the record's strict wire/state schemas on every delivery // failing the record's strict wire/state schemas on every delivery
@@ -1153,7 +1155,8 @@ export function applyTimeline(state: TimelineState, event: TimelineEvent, bounds
bumpDetailRev(s) bumpDetailRev(s)
const total = s.systemTokens + s.toolsTokens + s.sums.user + s.sums.inject + s.sums.skill + s.sums.assistant + s.sums.tool const total = s.systemTokens + s.toolsTokens + s.sums.user + s.sums.inject + s.sums.skill + s.sums.assistant + s.sums.tool
const record: RequestRecord = { const record: RequestRecord = {
time: event.time, seq: event.seq, time: event.time,
seq: event.seq,
system: s.systemTokens, system: s.systemTokens,
tools: s.toolsTokens, tools: s.toolsTokens,
user: s.sums.user, user: s.sums.user,
@@ -1294,7 +1297,9 @@ export function applyTimeline(state: TimelineState, event: TimelineEvent, bounds
s.pendingShadowEventSeq = event.seq s.pendingShadowEventSeq = event.seq
} }
s.events.push({ s.events.push({
seq: event.seq, time: event.time, kind: event.type === 'compaction/summary' ? 'compaction' : 'prune', seq: event.seq,
time: event.time,
kind: event.type === 'compaction/summary' ? 'compaction' : 'prune',
tokens: data && typeof data.shadowedTokenCount === 'number' ? data.shadowedTokenCount : 0, tokens: data && typeof data.shadowedTokenCount === 'number' ? data.shadowedTokenCount : 0,
...(event.type === 'compaction/summary' && data && Array.isArray(data.shadowedSeqs) ...(event.type === 'compaction/summary' && data && Array.isArray(data.shadowedSeqs)
? { count: data.shadowedSeqs.length } ? { count: data.shadowedSeqs.length }
+4 -1
View File
@@ -94,7 +94,10 @@ function safeResize(height: number, width: number, paddedHeight: number, paddedW
const pad = COMPRESS_PAD_TO - 1 const pad = COMPRESS_PAD_TO - 1
const budget = MAX_TOKENS - pad const budget = MAX_TOKENS - pad
let result: ResizeSolution = { let result: ResizeSolution = {
nLlmH, nLlmW, bestHeight: paddedHeight, bestWidth: paddedWidth, nLlmH,
nLlmW,
bestHeight: paddedHeight,
bestWidth: paddedWidth,
numTokens: gridTokens(nLlmH, nLlmW), numTokens: gridTokens(nLlmH, nLlmW),
} }
if (result.numTokens > budget) { if (result.numTokens > budget) {