Kilo JetBrains 插件 Context 设置页实现:基于共享 kilo.json 的压缩与文件监视配置 UI
【免费下载链接】kilocodeKilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kilocode
导读
本文完整讲解 Kilo 开源仓库中 JetBrains 插件新增Context 设置页(Settings -> Tools -> Kilo Code -> Context)的实现方案。该页面围绕共享配置kilo.json中的compaction(自动压缩)与watcher(文件监视忽略)两组键,为 JetBrains 端补齐与 VS Code 对齐的 UI 入口。读完本文,你将掌握:Context 四个配置项在共享 DTO、后端 CLI 解析器、前端草稿状态与 Swing 设置页之间的完整数据流,以及显式null清空、布尔false序列化、字符串数组编辑等易错细节的处理方式。
一、背景:JetBrains ↔ VS Code 设置对齐中的“轻松赢项”
Kilo 的双端(VS Code 与 JetBrains)客户端都通过 CLI 编辑同一份共享kilo.json。这意味着:只要某项设置的行为完全由 CLI 承担,JetBrains 端就只需要一个写配置键的 UI 行即可,无需改动 CLI,也无需新增运行时特性。源码层面,这一思路完整记录在 docs/jetbrains-vscode-settings-parity.md 中,其实现三件套是:
- 使用既有
settings/base/原语(BaseSettingsUi、SettingsRow、SettingsToggle、SettingsListPanel)新增一个Configurable页面,并在 kilo.jetbrains.frontend.xml 注册; - 扩展 KiloCliDataParser.kt 中
buildConfigPatch的键白名单(此前仅支持model、small_model、subagent_model、subagent_variant、default_agent五个字符串键),并补充布尔/数字的 JSON 序列化能力; - 在
KiloBundle.properties中补充本地化文案。
Context 页属于 parity 文档中的Tier 1(真正轻松)档位:CLI 已完成所有工作,JetBrains 只需加 UI 与配置键。parity 文档同时划清了边界——索引(indexing)、沙箱(sandboxing)等“隐含启用新特性”的项不属于 easy win;snapshot(检查点)按建议放独立的 Checkpoints 页;本页也不包含 VS Code Context 标签页中的 memory/indexing 控件,因为 JetBrains 尚无对应的 memory/indexing 设置服务。
二、目标与范围:四个配置项
本计划在Settings -> Tools -> Kilo Code -> Context下提供四个设置项:
| 设置项 | 配置键 | 类型 |
|---|---|---|
| 自动压缩 Auto-compaction | compaction.auto | boolean |
| 压缩阈值百分比 Compaction threshold percent | compaction.threshold_percent | number 或 null |
| 压缩时剪枝 Prune on compaction | compaction.prune | boolean |
| 文件监视忽略模式 Watcher ignore patterns | watcher.ignore | string array |
设计约束明确:首次实现只走全局配置写路径(复用既有 app 级设置写通道),不引入项目级配置;不为非字符串值重载ConfigPatchDto.values,而是新增类型化 DTO 字段;watcher.ignore使用共享列表原语而不是自造增删控件。
三、Part A:共享 DTO——类型化读取与补丁
配置文件:KiloAppStateDto.kt。该文件当前已包含计划中定义的读取与补丁 DTO(ConfigDto已在 60-74 行接入watcher/compaction字段)。
读取侧 DTO:
@Serializable data class WatcherConfigDto( val ignore: List<String> = emptyList(), ) @Serializable data class CompactionConfigDto( val auto: Boolean? = null, val threshold_percent: Double? = null, val prune: Boolean? = null, )补丁侧 DTO(ConfigPatchDto中对应字段为watcher: WatcherPatchDto? = null、compaction: CompactionPatchDto? = null):
@Serializable data class WatcherPatchDto( val ignore: List<String>? = null, ) @Serializable data class CompactionPatchDto( val clear: List<String> = emptyList(), val auto: Boolean? = null, val threshold_percent: Double? = null, val prune: Boolean? = null, )这套 DTO 形态背后是四个容易踩坑的语义约定,务必理解:
watcher.ignore = null表示不修改;watcher.ignore = emptyList()表示显式保存为空列表(删除最后一个模式时依赖此语义);compaction.threshold_percent = null单独出现表示不修改;compaction.clear = listOf("threshold_percent")才表示真正清空——因为Double?无法区分“未提供”与“显式 null”,所以必须用独立的clear列表来发射 JSON"threshold_percent": null;- 布尔
false必须被序列化,绝不能把false当作“未提供”而省略。
四、Part B:后端解析器与序列化器
配置文件:KiloCliDataParser.kt。
4.1 解析 parseConfig
parseConfig(raw)读取GET /global/config响应,现已解析watcher.ignore、compaction.auto、compaction.threshold_percent、compaction.prune。私有助手沿用既有风格(见 566-582 行):
- 字符串用
str(...); - 布尔用
flagOrNull(...)(并包一层runCatching容错); - 数字用
num(...); - 字符串数组用
arr()?.mapNotNull { it.jsonPrimitive.contentOrNull }。
parseConfig整体包在runCatching中,解析失败回退ConfigDto(),保证坏配置不会阻塞插件启动。
4.2 序列化 buildConfigPatch
buildConfigPatch(patch)生成PATCH /global/config请求体。Context 相关补丁的期望输出:
{ "watcher": { "ignore": ["**/node_modules/**"] }, "compaction": { "auto": true, "threshold_percent": 80, "prune": false } }显式清空阈值时的输出:
{ "compaction": { "threshold_percent": null } }实现要点:compaction块先按clear列表逐项写入JsonNull,再写入非空的新值;watcher块在ignore != null时整体发射数组。既有的values白名单继续只服务字符串模型键(model等五个),Context 值不经过values通道。
4.3 写路径调用链
Context 页的保存沿用的是既有全局配置写路径,从源码结构可以梳理出完整调用链:
- 前端:
KiloAppService.updateConfigAsync(...)(见 ContextSettingsUi.kt 第 79 行调用); - RPC:
KiloAppRpcApi.updateConfig(patch: ConfigPatchDto); - 后端:
KiloBackendAppService.updateConfig(...); - HTTP:
PATCH /global/config,随后GET /global/config刷新回读。
五、Part C:前端状态模型——字符串化阈值草稿
状态文件:ContextSettingsState.kt。
internal data class ContextDraft( val auto: Boolean = false, val threshold: String = "", val prune: Boolean = false, val editor: Boolean = KiloPluginSettings.getAutoEditorContext(), val ignore: List<String> = emptyList(), )关键设计:阈值在草稿中保持字符串,这样 UI 可以承载空串/非法中间输入而不丢失用户文本,只在构建补丁时才转换为数字。实际实现比计划多了一个本地editor字段(自动编辑器上下文),它走KiloPluginSettings本地持久化而非全局配置。
核心函数(均已实现):
contextDraft(config: ConfigDto?): ContextDraft——从回读配置生成基线草稿;formatThreshold会把整数 80.0 格式化为"80";patch(from, to): ConfigPatchDto?——只发射变化字段,阈值非法时返回null;savedMatches(base, draft): Boolean——通过normalizeThreshold归一化后比较;thresholdStatus(value)——空串合法;非数字、非有限数或超出0..100判为INVALID;compactionPatch(from, to)——内部按字段差异逐个生成补丁。
补丁行为约定(计划文档要求、实现已覆盖):
- 用户关闭自动压缩 → 发射
CompactionPatchDto(auto = false); - 用户关闭剪枝 → 发射
CompactionPatchDto(prune = false); - 输入合法的非空数字 → 发射
CompactionPatchDto(threshold_percent = 80.0); - 清空既有阈值 → 发射
CompactionPatchDto(clear = listOf("threshold_percent")); - 删除最后一个忽略模式 → 发射
WatcherPatchDto(ignore = emptyList()); - 所有字段与基线一致 → 页面不产生任何变更。
六、Part D:前端 UI 页面
6.1 Configurable 注册类
ContextConfigurable.kt 镜像ModelsConfigurable:
- 继承
DraftReadyConfigurable<JComponent>; ID = "ai.kilocode.jetbrains.settings.context";getDisplayName()返回KiloBundle.message("settings.context.displayName");create(cs)返回ContextSettingsUi(cs)。
6.2 设置 UI
ContextSettingsUi.kt 继承BaseSettingsUi<ContextSettingsContent, ContextDraft, ConfigPatchDto, KiloAppStateDto, Unit>,职责映射:
save(change, done)→app.updateConfigAsync(change, done),成功回调里同步写本地editor设置;base(result)/draft(state)→contextDraft(state.config);saved(base, draft)→savedMatches(...);pendingText()/failedText()→ 对应settings.context.save.pending/settings.context.save.failed;loadWorkspace(root)/applyWorkspace(result)→Unit;models(state)→Unit(本页不涉及工作区与模型状态);syncContent()→ 根据 app 状态READY与saving标志更新控件可用性、字段值、保存进度遮罩与校验提示。
页面布局:Compaction 分区(自动压缩开关、阈值数字行、剪枝开关)+ Watcher ignore patterns 分区(列表编辑器)。控件选择遵循 AGENTS.md 的 UI 规则:布尔用SettingsToggle,阈值用JBTextField(配合DocumentFilter限制输入),忽略模式列表用JBList+CollectionListModel+ScrollingUtil.installActions,全部是 IntelliJ 平台组件而非裸 Swing。页面在 app 状态为 ready 且无保存挂起时可编辑,保存期间禁用控件。
6.3 校验规则
- 空阈值合法,含义是“清空/复位该配置值”(若与基线不同则发射 clear);
- 非数字阈值非法,阻止
apply()发送补丁(patch()返回null); - 建议接受范围
0..100,与 CLI 行为保持一致; - 校验信息通过既有设置消息机制呈现,不引入临时标签。
七、Part E:设置注册与根页导航
7.1 XML 注册
kilo.jetbrains.frontend.xml 中已注册子配置项(76-80 行):
<applicationConfigurable parentId="ai.kilocode.jetbrains.settings" id="ai.kilocode.jetbrains.settings.context" groupWeight="-1" instance="ai.kilocode.client.settings.context.ContextConfigurable" bundle="messages.KiloBundle" key="settings.context.displayName"/>计划建议通过权重稳定顺序(User Profile=5、Models=4、Context=3、Providers=2、Agent Behavior=1);实际落地的 XML 以既有各页的groupWeight为准(Models=4、Providers=2、Agent Behavior=1,Context 取 -1,位于两者之间且紧随 Providers 之后)。若需调整显示顺序,改groupWeight即可。
7.2 根页导航
KiloSettingsConfigurable.kt 在根页 Models 与 Providers 之间新增指向ContextConfigurable.ID的ActionLink,文案使用settings.context.displayName。KiloSettingsSelection.kt无需改动,因为子页面 ID 已共享根前缀ai.kilocode.jetbrains.settings。
八、Part F:本地化字符串
基础文案位于 KiloBundle.properties:
settings.context.displayName=Context settings.context.description=Configure compaction and file-watcher context behavior. settings.context.save.pending=Saving context settings... settings.context.save.failed=Failed to save context settings settings.context.compaction.title=Compaction settings.context.compaction.description=Control when Kilo summarizes long sessions to reduce context usage. settings.context.compaction.auto.title=Auto-compaction settings.context.compaction.auto.description=Automatically compact long conversations before they exceed the model context window. settings.context.compaction.threshold.title=Compaction threshold settings.context.compaction.threshold.description=Percent of the context window to use before auto-compaction starts. Leave blank to use the default. settings.context.compaction.threshold.invalid=Enter a number from 0 to 100, or leave the field blank. settings.context.compaction.prune.title=Prune on compaction settings.context.compaction.prune.description=Drop older raw conversation details after compaction to keep the session context smaller. settings.context.watcher.title=Watcher ignore patterns settings.context.watcher.description=Glob patterns Kilo should ignore when watching repository file changes. settings.context.watcher.add=Add pattern settings.context.watcher.empty=No ignore patterns configured. settings.context.watcher.placeholder=e.g. **/dist/** settings.context.watcher.remove=Remove {0}当前仓库中这些键已同步复制进KiloBundle_zh_CN、KiloBundle_ja、KiloBundle_de等多语言 bundle(资源包检查要求每键在每语言包存在时,先复制英文值,翻译工作留给后续 i18n 批次)。用户可见字符串一律走*.properties,符合 AGENTS.md 的 UI 规则。
九、Part G:测试覆盖
计划与实现均强调“每个写设置的页面都需要 fake-RPC 前端测试 + MockCliServer 后端断言”这一仓库测试模式(见 packages/kilo-jetbrains/AGENTS.md 的 Settings Test Coverage Pattern)。
9.1 前端状态测试
ContextSettingsStateTest.kt 覆盖:草稿正确读取ConfigDto.watcher/compaction;未变更草稿不发射补丁;布尔变更正确发射false/true;设置阈值发射threshold_percent;清空阈值发射clear = listOf("threshold_percent");忽略列表增删发射完整新列表(含空列表);非法阈值在保存前被拒绝。
9.2 前端 UI 测试
ContextSettingsUiTest.kt 以ModelsSettingsUiTest为模板:BasePlatformTestCase+ 真实 EDT +FakeAppRpcApi+KiloAppService+flushUntil助手,断言交互后的rpc.configPatches、保存挂起期间控件禁用、保存失败后页面保持 modified 并显示settings.context.save.failed。配套 FakeAppRpcApi.kt 需要:应用patch.watcher/patch.compaction到假配置状态,保留显式空列表与布尔false,并按compaction.clear将对应字段置null。
9.3 后端解析器与 app 服务测试
KiloCliDataParserTest.kt 增加精确 JSON 断言:parseConfig读取 watcher/compaction 字段;buildConfigPatch发射 ignore 数组、auto=false、prune=false、数字threshold_percent、以及clear含该字段时的显式"threshold_percent": null。KiloBackendAppServiceTest.kt 则调用updateConfig(ConfigPatchDto(watcher = ..., compaction = ...)),断言MockCliServer.lastConfigPatchBody与期望嵌套 JSON 完全一致,且回读的ConfigDto包含已保存的 Context 值。
9.4 根页测试
KiloSettingsConfigurableTest.kt 断言ContextConfigurable.ID == "ai.kilocode.jetbrains.settings.context"、根页包含 Context 链接、链接顺序与 XML 顺序一致。
十、构建验证与手动验收
在packages/kilo-jetbrains/下运行:
./gradlew typecheck ./gradlew test迭代期间的聚焦检查:
./gradlew :shared:test --tests '*ContextSettingsStateTest' ./gradlew :frontend:test --tests '*ContextSettingsUiTest' ./gradlew :backend:test --tests '*KiloCliDataParserTest' ./gradlew :backend:test --tests '*KiloBackendAppServiceTest'手动验收流程:
- 在
packages/kilo-jetbrains/下运行./gradlew runIde启动沙箱 IDE; - 打开
Settings -> Tools -> Kilo Code -> Context; - 切换自动压缩与剪枝开关;
- 设置阈值数字 → Apply → 重开设置页,确认持久化;
- 清空阈值 → Apply → 重开设置页,确认复位;
- 增删 watcher 忽略模式 → Apply → 重开设置页,确认列表持久化;
- 必要时通过既有
Open: global ...动作直接检查全局 Kilo 配置文件内容。
十一、风险与后续事项
- 全局 vs 项目级配置:本方案复用全局配置写路径;若未来要做项目级 Context 设置,需要新增 workspace 配置 RPC 管道。
- 阈值 null 语义:必须实现显式 clear 处理,否则清空字段会静默无效。
- 字符串数组 UI:复用共享列表原语(即使需要小适配器类型),避免一次性列表控件。
- VS Code memory/indexing 对齐:延迟处理,因为它不是纯配置,且已被 easy-win 标准排除。
- Checkpoints 页:
snapshot单独实现,除非产品明确要求与 Context 合并。 - Changeset:作为用户可见的 JetBrains 设置特性落地时,需按仓库发布指引为
kilo-code/JetBrains 添加补丁 changeset。
小结
Context 设置页是“CLI 承担逻辑、客户端只补 UI”这一 parity 策略的典型落地:共享 DTO 提供类型化读写、后端解析器扩展布尔/数字/数组序列化、前端草稿状态用字符串兜住阈值输入、UI 复用BaseSettingsUi与平台组件,测试沿用 fake-RPC + MockCliServer 双端断言模式。对希望为 Kilo JetBrains 插件新增纯配置类设置页的开发者,.kilo/plans/jetbrains-context-settings-page.md 与上述实现文件构成了可直接照搬的七步参考流程。
【免费下载链接】kilocodeKilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kilocode
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考