数据截至 (上游 commit 0004b748b71c)
运行骨架:一个 instance、一张 Effect 服务图、一份 SQLite
30 秒导读: Kilo Code 看起来是“VS Code 插件 / JetBrains 插件 / CLI 三个产品”,物理上只有一套东西——那张 Effect HttpApi 路由图。所有界面都是壳:IDE 插件 spawn 一个
kilo serve子进程用 HTTP 连上去,终端 TUI 干脆在进程内直接调同一套路由。本章讲清这套东西内部的三根骨头:instance(按目录切的实例上下文)、Effect 服务图(每个模块长得一模一样的那套模板)、一份 SQLite(所有实例共享的落盘)。
本章是后面所有章节的舞台。会话循环(02)、工具与权限(03)、编辑与快照(04)都跑在这个骨架上——先知道“戏台子长什么样”,再看戏。
1. 一句话骨架
先把结论摆出来,后面每节都是在展开这一句:
一个进程 = N 个 instance;一个 instance = 一个目录 + 一张惰性建起来的 Effect 服务图;所有 instance 共写同一个
kilo.db。
三个数量关系值得先记住:
| 东西 | 数量 | 谁决定的 |
|---|---|---|
| 后端进程 | 每个 IDE 窗口一个;TUI 不另起进 程,后端跑在同进程的 worker 里 | 前端 spawn(server-manager.ts:118)/worker 直调(cli/tui/worker.ts:75) |
| instance | 进程内每个目录一个 | 请求里的 directory(instance-store.ts:126 的 FSUtil.resolve 归一后当缓存键) |
| SQLite 文件 | 每台机器每个安装通道一份 | Database.Client 模块级单例(storage/db.ts:100) |
注意第二行:缓存键是目录,不是 project。同一个 git 仓库的主工作区和一个 worktree 是两个 instance,但它们指向同一条 project 行。
2. monorepo 布局:谁是内核、谁是壳
仓库是 bun workspaces,packages/* 全量纳管(根 package.json:22-26 的 workspaces.packages,另单列了 packages/sdk/js)。packages/ 下 24 个目录、21 个带 package.json 的真包,真正需要认识的是这几个:
| package | 定位 | 关键入口 |
|---|---|---|
packages/opencode | 内核 + CLI,发布名 @kilocode/cli | src/index.ts;bin 是 kilo / kilocode(package.json:21-23) |
packages/core | 共享 schema 与工具(@opencode-ai/core) | src/session-event.ts、src/model.ts、src/permission.ts |
packages/llm | 自研模型客户端 | src/llm.ts、src/providers/、src/protocols/ |
packages/sdk | 生成的 HTTP 客户端 + OpenAPI 快照 | js/src/v2/、openapi.json |
packages/kilo-vscode | VS Code 前端(薄壳) | src/services/cli-backend/server-manager.ts |
packages/kilo-jetbrains | JetBrains 前端(Kotlin 薄壳) | backend/src/main/kotlin/ai/kilocode/backend/cli/KiloBackendCliManager.kt |
packages/kilo-web-ui | 浏览器 UI 组件层 | src/components/ |
packages/kilo-gateway | Kilo 侧扩展:统一网关与鉴权 | src/provider.ts、src/auth/、src/server/ |
packages/kilo-indexing | Kilo 侧扩展:代码索引引擎 | src/indexing/、src/tree-sitter/、src/plugin.ts |
一个命名上的坑:目录叫 opencode、内部包名前缀是 @opencode-ai/,但发布出去是 @kilocode/cli,二进制叫 kilo。原因写在 README 里——Kilo CLI 是 OpenCode 的 fork(README.md:171)。源码里大量 // kilocode_change 注释标出了改动边界,看到这个注释就知道“这段是 Kilo 加的”。
kilo-gateway 和 kilo-indexing 是“挂在内核上的扩展”,不是独立服务:两者都导出 plugin.ts,通过内核的 Plugin 机制注入。
3. 服务器形态:kilo serve 起了什么
3.1 一张图看清进程
kilo serve --port 0
│
▼
┌──────────────────┐ Effect.runPromise
│ Server.listen() │ ───────────────────► Effect 世界
│ server.ts:84 │
└────────┬─────────┘
│ 端口回退:0 → 先试 4096 → 再试任意空闲
▼
┌──────────────────────────────────────┐
│ NodeHttpServer + HttpRouter │ ← serverLayer(server.ts:202)
│ ├─ 全局路由 /global/* │
│ ├─ SSE 路由 /event、/global/event │
│ ├─ WebSocket 路由(pty) │
│ ├─ 实例路由(session/file/…) │
│ └─ 兜底静态 UI │
└──────────────────────────────────────┘
│
▼ stdout: "kilo server listening on http://127.0.0.1:PORT"
前端正则抓端口,建立连接
怎么读:从上往下是启动顺序;最后一步的那行 stdout 是IDE 前端与后端唯一的握手信号——下面 §7 会看到 VS Code 和 JetBrains 都在正则匹配它。