目配置架構(gòu):不可變綁定與版本化寫入的設(shè)計(jì)實(shí)踐)
Kilo Agent Manager 多項(xiàng)目配置架構(gòu)不可變綁定與版本化寫入的設(shè)計(jì)實(shí)踐【免費(fèi)下載鏈接】kilocodeKilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/ki/kilocodeAgent Manager 為 Kilo 引入多項(xiàng)目管理后Settings 面板的讀寫目標(biāo)從當(dāng)前激活項(xiàng)目轉(zhuǎn)向顯式、不可變、帶版本的綁定契約避免 A 項(xiàng)目的草稿被錯(cuò)誤寫入 B 項(xiàng)目的配置文件。本文以倉(cāng)庫(kù)內(nèi)設(shè)計(jì)規(guī)范文檔 .kilo/plans/agent-manager-multi-project-configuration.md 為骨架結(jié)合 Kilo 源碼中的綁定實(shí)現(xiàn)config-bindings.ts、webview 保存流程config.tsx與后端 overlay 沖突測(cè)試config-overlay.test.ts完整講解四層配置存儲(chǔ)的所有權(quán)劃分、設(shè)置標(biāo)簽的目標(biāo)映射、不可變綁定契約、后端 SHA-256 版本校驗(yàn)與 CAS 寫入以及保證多項(xiàng)目發(fā)布的阻塞測(cè)試清單。讀完本文你將掌握 Kilo 多項(xiàng)目設(shè)置讀寫為何必須綁定目標(biāo)、校驗(yàn)版本以及這套契約在擴(kuò)展端與后端各層的落地方式。背景多項(xiàng)目時(shí)代的 Settings 讀寫困境Kilo 當(dāng)前維護(hù)著四個(gè)互不相同的配置存儲(chǔ)層存儲(chǔ)示例歸屬VS Code preferencesVS Codesettings.json當(dāng)前 VS Code 用戶/安裝Kilo user config~/.config/kilo/kilo.json跨項(xiàng)目、跨 Kilo 客戶端的用戶默認(rèn)值Kilo project configrepo/.kilo/kilo.jsonc倉(cāng)庫(kù)行為與覆蓋項(xiàng)Runtime/session state內(nèi)存中按目錄限定單個(gè)項(xiàng)目、worktree 或會(huì)話共享的 Settings 保存路徑目前調(diào)用splitConfigByScope()自動(dòng)切分草稿config-scope.tscommit_message寫入項(xiàng)目配置indexing.enabled寫入項(xiàng)目配置其余通用 Settings 字段寫入用戶配置。問題在于這類隱藏的自動(dòng)切分并不足以支撐多項(xiàng)目Indexing 標(biāo)簽雖然提供了顯式的 Global/Project 選擇器卻可以把整個(gè)indexing對(duì)象寫入任意一層導(dǎo)致 provider/model/vector-store 憑據(jù)和基礎(chǔ)設(shè)施設(shè)置可能被塞進(jìn)倉(cāng)庫(kù)內(nèi)的項(xiàng)目配置。而另一些控件autocomplete UI、browser automation、notifications、max auto-approve cost、commit-message 輸出語(yǔ)言、indexing 按鈕可見性則完全繞過 Kilo 配置屬于 VS Code preferences。確認(rèn)的阻塞缺陷讀有目錄、寫無(wú)目標(biāo)這是當(dāng)前協(xié)議最根本的失效模式——讀取按目錄限定寫入?yún)s沒有綁定到讀取目標(biāo)KiloProvider.fetchAndSendConfig()解析一個(gè)可變的當(dāng)前目錄發(fā)出不帶限定信息的configLoaded狀態(tài)KiloProvider.tswebview 持有唯一的 global/project/effective 草稿Agent Manager 把激活項(xiàng)目從 A 切換到 Bwebview 發(fā)出不帶限定信息的updateConfigKiloProvider.handleUpdateConfig()在保存時(shí)再次解析當(dāng)前目錄可能把 A 的草稿寫入 BKiloProvider.ts。后端同樣缺少預(yù)期目標(biāo)/版本前置條件外部編輯器或另一個(gè)窗口可以在讀取與保存之間覆蓋配置。這是多項(xiàng)目發(fā)布的 release blocker。配置所有權(quán)策略設(shè)計(jì)決策是保留用戶設(shè)置與項(xiàng)目設(shè)置的有用拆分但讓每次 Settings 讀寫的目標(biāo)顯式、不可變、帶版本并且完全獨(dú)立于 Agent Manager 的激活狀態(tài)。絕不允許Settings 為項(xiàng)目 A 加載草稿卻從可變的激活項(xiàng)目 B 解析保存目標(biāo)。VS Code preferences不參與項(xiàng)目配置以下項(xiàng)留在 VS Code settings 中擴(kuò)展語(yǔ)言與展示偏好autocomplete 的啟用、快捷鍵、provider、modelbrowser automation 的啟用、系統(tǒng) Chrome/headless 模式通知啟用與聲音最大自動(dòng)批準(zhǔn)成本max auto-approve costcommit-message 輸出語(yǔ)言indexing 禁用時(shí)的按鈕可見性多項(xiàng)目功能的啟用開關(guān)。Kilo user config個(gè)人默認(rèn)值或安全策略以下項(xiàng)屬于 User 范圍編輯default、small、subagent 模型及變體provider 啟用、自定義 provider、憑據(jù)與端點(diǎn)用戶/全局 agent 與默認(rèn) agent權(quán)限默認(rèn)值與用戶工具默認(rèn)值sandbox 策略、網(wǎng)絡(luò)訪問、可寫路徑、允許的主機(jī)compaction、checkpoint/snapshot、tool-output 默認(rèn)值用戶名與展示行為sharing、remote control、telemetry、實(shí)驗(yàn)性功能用戶/全局 formatter、LSP、MCP、skills、instructions、commands、workflowsindexing 的 provider、model、憑據(jù)、向量存儲(chǔ)與全局調(diào)優(yōu)默認(rèn)值。可信項(xiàng)目可以在運(yùn)行時(shí)覆蓋其中許多項(xiàng)但在 User 范圍編輯永遠(yuǎn)不會(huì)寫入這些覆蓋項(xiàng)。Kilo project config倉(cāng)庫(kù)行為以下項(xiàng)描述倉(cāng)庫(kù)行為屬于合法的項(xiàng)目設(shè)置commit-message prompt倉(cāng)庫(kù)索引的文件擴(kuò)展名、include/ignore 規(guī)則與有意的項(xiàng)目調(diào)優(yōu)覆蓋倉(cāng)庫(kù) instructions倉(cāng)庫(kù) skill 路徑倉(cāng)庫(kù) commands/workflows可信項(xiàng)目 agent可信項(xiàng)目 MCP servers倉(cāng)庫(kù) formatter/LSP 覆蓋倉(cāng)庫(kù) watcher ignores倉(cāng)庫(kù)特定的工具限制與權(quán)限請(qǐng)求。項(xiàng)目配置可以覆蓋用戶層的 model/agent/tool 默認(rèn)值但provider 憑據(jù)與削弱安全策略的內(nèi)容絕不能被靜默寫入倉(cāng)庫(kù)。機(jī)器本地的項(xiàng)目索引同意machine-local consent索引啟用本質(zhì)上是隱私同意consent不是倉(cāng)庫(kù)配置因此必須存到倉(cāng)庫(kù)之外以規(guī)范的ProjectId為鍵存入機(jī)器本地?cái)U(kuò)展?fàn)顟B(tài)新觀察到的項(xiàng)目默認(rèn)索引禁用用戶在本機(jī)針對(duì)單個(gè)項(xiàng)目顯式啟用索引倉(cāng)庫(kù)配置無(wú)法開啟索引倉(cāng)庫(kù)配置只能描述索引什么而同意consent決定是否啟動(dòng)索引規(guī)范的項(xiàng)目身份可以防止通過 symlink 或別名路徑繞過同意。有效索引需要同時(shí)滿足用戶全局索引配置有效 該項(xiàng)目的機(jī)器本地同意。設(shè)置標(biāo)簽與寫入目標(biāo)映射規(guī)范文檔給出了每個(gè) Settings 標(biāo)簽的正確可編輯目標(biāo)Settings 標(biāo)簽正確的可編輯目標(biāo)Models默認(rèn) User顯式 Project 范圍可覆蓋 models/agentsProviders憑據(jù)/端點(diǎn)僅 User項(xiàng)目提供的條目需標(biāo)記來源source-labelledAgent BehaviourUser 或顯式可信 Project 范圍Auto ApproveUser Kilo 配置max cost 仍是 VS Code preferenceBrowserVS Code preferencesCheckpointsUser 默認(rèn)或顯式 Project 覆蓋DisplayUser 配置AutocompleteVS Code preferencesNotificationsVS Code preferencesContextUser 默認(rèn)倉(cāng)庫(kù) watcher/instruction 規(guī)則在顯式 Project 范圍Commit MessagePrompt 在 Project 范圍語(yǔ)言仍是 VS Code preferenceIndexingProvider/model/憑據(jù)/存儲(chǔ) 在 User啟用走機(jī)器本地同意倉(cāng)庫(kù)規(guī)則在 ProjectExperimentalUser 配置多項(xiàng)目還鏡像到 VS Code preferenceSandboxing僅 User 配置LanguageVS Code preferenceMCP/Commands/SkillsUser 默認(rèn)或顯式可信 Project 范圍核心原則任何字段在保存時(shí)都不能靜默選擇文件UI 必須展示其 scope。Settings UX顯式范圍與項(xiàng)目選擇器UI 采用顯式 scope 與項(xiàng)目控件Scope: User | Project Project: backend Target: /projects/backend/.kilo/kilo.jsoncUser 范圍永遠(yuǎn)指向用戶配置Project 范圍要求顯式選擇可信項(xiàng)目Settings 的項(xiàng)目選擇器與 Agent Manager 的激活項(xiàng)目相互獨(dú)立打開 Settings 時(shí)可以用當(dāng)前項(xiàng)目初始化選擇器一次但之后 Agent Manager 的切換不會(huì)改變它臟的項(xiàng)目草稿不能遷移到另一個(gè)項(xiàng)目選擇器變更必須走 Save、Discard 或 Stay繼承值顯示來源徽標(biāo)如User、Project: backend、ManagedProject 范圍提供 Override 與 Reset to inherited項(xiàng)目來源的 provider 不能被 User 范圍靜默地從項(xiàng)目配置中刪除。需要特別注意運(yùn)行時(shí)配置與 Settings 目標(biāo)的分離runtime config 仍精確跟隨會(huì)話目錄而 Settings 的 Project 范圍指向注冊(cè)的項(xiàng)目根registered project root不是激活的 worktree。worktree 配置編輯屬于需要顯式WorktreeRef的未來獨(dú)立功能。不可變綁定契約Immutable Binding ContractSettings 讀取返回一個(gè)不透明綁定opaque binding擴(kuò)展端持有其權(quán)威副本interface SettingsBinding { id: string connectionGeneration: number scope: global | project project?: { projectId: string root: string generation: number } directory: string target: { scope: global | project path: string revision: string exists: boolean writable: boolean } }寫入只攜帶該不透明綁定與補(bǔ)丁interface WriteSettingsConfig { type: settingsConfig.write requestId: string bindingId: string set: Recordstring, unknown unset: string[][] }擴(kuò)展端在寫入時(shí)必須拒絕未知/過期的綁定校驗(yàn)項(xiàng)目存在性、generation 與信任狀態(tài)在第一個(gè) await 之前捕獲綁定使用綁定中存儲(chǔ)的 directory 與 scope絕不調(diào)用getWorkspaceDirectory()、contexts.active()或使用 worktree/session 回退只在匹配的{ requestId, bindingId }響應(yīng)中清除草稿。綁定在保存、重連、信任撤銷、項(xiàng)目移除或 context generation 變化后失效。這套契約在倉(cāng)庫(kù)中已經(jīng)有對(duì)應(yīng)的落地實(shí)現(xiàn)config-bindings.ts 中的ConfigBindings類以Mapstring, ConfigBinding保存綁定create()會(huì)給每個(gè)綁定生成randomUUID()作為 id并在同一 scopedirectory 下丟棄被取代的舊綁定避免只讀刷新導(dǎo)致綁定無(wú)限增長(zhǎng)get()校驗(yàn) id、connection代數(shù)以及項(xiàng)目合法性通過validConfigProject回調(diào)consume()在寫入成功后刪除綁定一次性語(yǔ)義clear()用于連接級(jí)清理。在 KiloProvider.ts 的handleUpdateConfig中擴(kuò)展端正是通過configBindings.get(globalBindingId / projectBindingId, this.connectionGeneration, ...)來拒絕未知或過期綁定失敗時(shí)直接回發(fā)configUpdateFailedSettings changed or expired. Reload before saving.。后端版本契約Backend Revision ContractGET /config/overlay必須返回精確的 global/project 目標(biāo)路徑、解析后的原始目標(biāo)配置、有效配置/來源元數(shù)據(jù)以及一個(gè)revision。revision 是對(duì)規(guī)范目標(biāo)路徑 存在標(biāo)記 文件精確字節(jié)的 SHA-256 指紋。它能捕獲三類變化內(nèi)容變化文件字節(jié)不同JSONC 僅注釋編輯字節(jié)不同 → revision 變化目標(biāo)路徑變化路徑參與指紋。PATCH /config/overlay只接受一個(gè) scope請(qǐng)求體{ scope: global | project set: Recordstring, unknown unset: string[][] expected: { path: string revision: string } }后端必須重新解析權(quán)威目標(biāo) → 在目標(biāo)鎖target lock下校驗(yàn) path/revision → 修補(bǔ)原始目標(biāo)層 → 校驗(yàn)配置 →原子替換文件→ 返回全新快照。后端絕不接受任意的客戶端路徑。預(yù)期失敗類型包括過期綁定、未知/不可信項(xiàng)目、目標(biāo)變化、版本沖突、非法配置、目標(biāo)不可寫、I/O 失敗——每次失敗都必須保留草稿draft 不丟失。源碼側(cè)可以驗(yàn)證這套契約已被擴(kuò)展端采用handleUpdateConfig對(duì) global/project 分別調(diào)用client.config.overlayUpdate(...)并攜帶directory: globalBinding!.directory與expected: { path, revision }寫入成功后再consume()綁定并回發(fā)configUpdatedKiloProvider.ts。版本沖突的測(cè)試證據(jù)config-overlay.test.ts 印證了 revision 契約的關(guān)鍵語(yǔ)義目標(biāo)請(qǐng)求會(huì)自動(dòng)回填expected: { path, revision }測(cè)試夾具層缺失文件具有穩(wěn)定的 revision對(duì)同一不存在的項(xiàng)目配置連續(xù)兩次取 targetrevision 相同保存后 revision 必然變化僅注釋的外部編輯會(huì)被判為版本沖突先讀取 overlay讓外部把文件改成僅注釋不同的內(nèi)容再用舊的expected提交 PATCH返回code: revision-conflict——這正是外部編輯器覆蓋讀-寫窗口這一阻塞缺陷的回歸防護(hù)項(xiàng)目 scope 支持按路徑unset如[[indexing, enabled]]并驗(yàn)證保存后該字段確實(shí)從原始層消失而其余字段provider、ollama baseUrl保留。實(shí)施清單從協(xié)議到代碼的九項(xiàng)改造規(guī)范文檔要求落地以下九項(xiàng)為 Kilo 配置 overlay API 增加帶版本的 target 描述符與 compare-and-swap 寫入把與激活綁定的 runtime config 狀態(tài)與按綁定鍵控的 Settings 編輯器狀態(tài)分離用攜帶 request/binding ID 的 settings 讀/寫消息替換不帶限定的configLoaded/updateConfig用每個(gè)可編輯控件上的顯式 scope 替換隱藏的splitConfigByScope保存把 Indexing 的 Project 范圍限制為倉(cāng)庫(kù)規(guī)則provider/model/憑據(jù)/存儲(chǔ)留在 User 范圍把索引啟用從項(xiàng)目配置遷移為按規(guī)范ProjectId鍵控的機(jī)器本地同意默認(rèn)關(guān)閉審計(jì)保存條之外的直接配置修改者provider disconnect、imports/resets、自定義 provider、work styles、權(quán)限規(guī)則、索引操作讓 Open Project Config 接受ProjectRef解析不可變的注冊(cè)根并校驗(yàn)信任按 scope、directory、target、revision 與 activation generation 分區(qū)配置緩存/事件。當(dāng)前倉(cāng)庫(kù)中第 13 項(xiàng)的擴(kuò)展端骨架已經(jīng)可見webview 端 config.tsx 維護(hù)bindings()global/project 兩個(gè) binding、globalDraft/projectDraft分區(qū)草稿、configBindingExpired處理項(xiàng)目變化時(shí)提示 Discard or reload before saving、configUpdateFailed的部分成功處理按completedScopes保留未完成部分的草稿saveConfig()已把globalBindingId/projectBindingId隨updateConfig消息發(fā)送但仍在使用splitConfigByScope做隱藏切分——這正是實(shí)施清單第 4 項(xiàng)要繼續(xù)消除的部分。config-scope.ts中PROJECT_SCOPED_KEYS目前只有commit_message一個(gè)頂層鍵也印證了自動(dòng)切分過于粗糙的現(xiàn)狀。阻塞測(cè)試清單Blocking Tests多項(xiàng)目配置可以發(fā)布的前提是以下測(cè)試全部通過為 A 加載 Settings切換到 B保存只有 A 綁定的目標(biāo)發(fā)生變化同一測(cè)試在 A/B 的 worktree 與會(huì)話選擇下成立User 范圍保存只改用戶配置Project 范圍保存要求顯式可信項(xiàng)目且只改其注冊(cè)根配置臟草稿在 Agent Manager 切換后存活且不能遷移到其他 Settings 項(xiàng)目亂序的讀/寫只更新匹配的 request/binding外部文件修改觸發(fā)版本沖突但不丟失草稿配置目標(biāo)路徑變化觸發(fā)目標(biāo)沖突項(xiàng)目移除、generation 變化或信任撤銷會(huì)使綁定過期表單中的 indexing provider/model/憑據(jù)/存儲(chǔ)永不進(jìn)入項(xiàng)目配置倉(cāng)庫(kù)文件中出現(xiàn)indexing.enabled: true不能授予索引同意新項(xiàng)目默認(rèn)索引禁用直到在本機(jī)顯式啟用同意跟隨規(guī)范項(xiàng)目身份跨越 symlink/路徑別名且絕不泄漏到另一項(xiàng)目commit_message.prompt與倉(cāng)庫(kù)索引規(guī)則仍支持顯式項(xiàng)目寫入runtime worktree 配置使用 worktree 目錄而 Project Settings 仍綁定注冊(cè)項(xiàng)目根。發(fā)布門檻Release Gate在多項(xiàng)目默認(rèn)關(guān)閉disabled by default之前必須完成不可變綁定/版本契約與上述阻塞測(cè)試。規(guī)范同時(shí)強(qiáng)調(diào)保留而非移除現(xiàn)有的項(xiàng)目本地行為——只是其寫入目標(biāo)必須變?yōu)轱@式且不可變。這既保護(hù)了現(xiàn)有用戶既有的repo/.kilo/kilo.jsonc工作流又為 Agent Manager 的多項(xiàng)目切換提供了確定性的讀寫語(yǔ)義讓Settings 草稿寫錯(cuò)項(xiàng)目這類數(shù)據(jù)污染問題從架構(gòu)上不再可能發(fā)生。小結(jié)Kilo 多項(xiàng)目配置架構(gòu)的核心是把 Settings 從面向當(dāng)前目錄的共享草稿重構(gòu)為綁定目標(biāo) 版本校驗(yàn)的 CAS 寫入所有權(quán)上嚴(yán)格區(qū)分 VS Code preferences、用戶配置、項(xiàng)目配置與機(jī)器本地索引同意四層讀寫協(xié)議上引入不透明綁定與 SHA-256 revision讓擴(kuò)展端無(wú)法在寫入時(shí)重新解析目標(biāo)讓后端在目標(biāo)鎖下原子替換文件并拒絕任何版本不一致的寫入測(cè)試上以跨項(xiàng)目切換不串寫、外部編輯觸發(fā)版本沖突、索引同意默認(rèn)關(guān)閉且不可由倉(cāng)庫(kù)授予等阻塞用例鎖死行為。這一契約在 .kilo/plans/agent-manager-multi-project-configuration.md 中定義在 config-bindings.ts、KiloProvider.ts、config.tsx 與 config-overlay.test.ts 中逐步落地感興趣的讀者可以沿著這條鏈路繼續(xù)深入?!久赓M(fèi)下載鏈接】kilocodeKilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.項(xiàng)目地址: https://gitcode.com/GitHub_Trending/ki/kilocode創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考