mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-09-24 16:02:55 +08:00
Merge pull request #10718 from Kilo-Org/quaint-gate
docs: clarify shared snapshot guard scope
This commit is contained in:
@@ -51,6 +51,8 @@ All products are clients of the **CLI** (`packages/opencode/`), which contains t
|
||||
|
||||
**Agent Manager** refers to a feature inside `packages/kilo-vscode/` (extension code in `src/agent-manager/`, webview in `webview-ui/agent-manager/`). It is not a standalone product. See the extension's `AGENTS.md` for details.
|
||||
|
||||
In each VS Code extension host, one `KiloConnectionService` is created for the sidebar, every Kilo editor tab, and Agent Manager; it lazily starts and reuses one current `kilo serve` backend at a time. Agent Manager worktree sessions pass a directory context to this shared backend rather than starting one per worktree. State captured by the active service layer, such as Snapshot `trackState`, is shared across those requests; only directory-keyed `InstanceState` data is isolated.
|
||||
|
||||
Extension-specific settings should live in the Kilo extension settings, not default VS Code settings, unless they are intentionally VS Code-wide.
|
||||
|
||||
## Package Instructions
|
||||
|
||||
@@ -88,7 +88,7 @@ The script checks for a prebuilt binary in `packages/opencode/dist/`, builds the
|
||||
|
||||
### Extension ↔ CLI Backend
|
||||
|
||||
The extension is a client of the CLI. At startup it spawns `bin/kilo serve --port 0`, captures the dynamically-assigned port from stdout, and communicates over HTTP + SSE. A random password is generated and passed via `KILO_SERVER_PASSWORD` env var for basic auth.
|
||||
The extension is a client of the CLI. Activation creates one shared `KiloConnectionService`; on its first connection, which autocomplete may prewarm, `ServerManager` spawns `bin/kilo serve --port 0`, captures the dynamically assigned port from stdout, and communicates over HTTP + SSE. The current child process is reused unless it exits. A random password is generated and passed via `KILO_SERVER_PASSWORD` env var for basic auth.
|
||||
|
||||
```
|
||||
Extension (Node.js) CLI Backend (child process)
|
||||
@@ -104,9 +104,10 @@ Extension (Node.js) CLI Backend (child process)
|
||||
└──────────────────────────┘
|
||||
```
|
||||
|
||||
- **`KiloConnectionService`** (`src/services/cli-backend/connection-service.ts`) is a singleton shared across all webviews. It owns the server process, HTTP client, and SSE connection.
|
||||
- **`ServerManager`** (`src/services/cli-backend/server-manager.ts`) spawns the CLI binary and manages the process lifecycle.
|
||||
- Multiple **`KiloProvider`** instances (sidebar, Agent Manager, "open in tab" panels) subscribe to the shared connection. SSE events are filtered per-webview via a `trackedSessionIds` Set.
|
||||
- **`KiloConnectionService`** (`src/services/cli-backend/connection-service.ts`) is created once during extension activation and shared across the sidebar, Kilo editor tabs, and Agent Manager. It owns the current server process, HTTP client, and SSE connection.
|
||||
- **`ServerManager`** (`src/services/cli-backend/server-manager.ts`) lazily spawns the CLI binary, reuses its current process, and can start a replacement if that process exits.
|
||||
- The sidebar, every **Open in Tab** Kilo panel, and the Agent Manager chat provider reuse this connection. Multiple **`KiloProvider`** instances subscribe to it, with SSE events filtered per-webview via a `trackedSessionIds` Set. Agent Manager terminals may use additional PTY/WebSocket channels to the same backend, not separate `kilo serve` processes.
|
||||
- Backend state follows where it is allocated, not the worktree shown in a panel. Snapshot repository state uses directory-keyed `InstanceState`, while `trackState` is created once in the active Snapshot service closure. For these shared VS Code session paths, its slow-track `asked` guard spans worktree requests; choosing **Continue with snapshots** resets `asked` only when continued tracking returns a snapshot hash.
|
||||
|
||||
### Builds
|
||||
|
||||
@@ -161,7 +162,7 @@ The Agent Manager is a feature within this extension (not a separate product). I
|
||||
|
||||
### Architecture
|
||||
|
||||
All Agent Manager sessions share the **single `kilo serve` process** managed by `KiloConnectionService`. No separate server is spawned per session. Session isolation comes from directory scoping — worktree sessions pass the worktree path to the CLI backend, which creates a session scoped to that directory.
|
||||
Agent Manager local worktree sessions use the current shared `kilo serve` process owned by `KiloConnectionService`; no session starts its own backend. Their CLI requests pass the worktree path as `directory`, which resolves directory-scoped backend state. Setup scripts, terminal PTYs, git subprocesses, and a separately opened VS Code window are separate process or extension-host boundaries, not per-worktree `kilo serve` instances.
|
||||
|
||||
Extension-side code lives in `src/agent-manager/`, webview code in `webview-ui/agent-manager/`. The webview reuses the sidebar's provider chain and `ChatView` component, adding a `WorktreeModeProvider` and a split layout.
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ const state = Instance.state(async () => {
|
||||
// later: (await state()).someValue
|
||||
```
|
||||
|
||||
**Service-closure state vs. directory state** -- A value created in a service-layer closure, outside `InstanceState`, is shared by that service instance rather than keyed by request directory. The shared VS Code session paths use one active Snapshot service for the sidebar, Kilo tabs, and Agent Manager local worktree requests, so Snapshot `trackState` and its slow-track `asked` guard span those directories. Choosing **Continue with snapshots** resets the guard only when continued tracking returns a snapshot hash.
|
||||
|
||||
**`fn(schema, callback)`** -- Wraps functions with Zod input validation. Used for most exported functions:
|
||||
|
||||
```ts
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
// - "Disable for this project": interrupt the in-flight snapshot,
|
||||
// persist `"snapshot": false` to `.kilo/kilo.json`, and skip. All
|
||||
// future sessions on this project load with snapshots off.
|
||||
// - Dismissed / no sessionID: interrupt and skip. Mark the instance
|
||||
// so we don't prompt again until the instance reloads.
|
||||
// - Dismissed / no sessionID: interrupt and skip. Mark the active
|
||||
// Snapshot.Service guard so later calls through it do not prompt again.
|
||||
//
|
||||
// While the snapshot is running, we inject a synthetic text part into the
|
||||
// live assistant message so the user sees an "Initializing snapshot…" line
|
||||
@@ -25,8 +25,9 @@
|
||||
// removed when the snapshot finishes, so the chat history stays clean.
|
||||
//
|
||||
// Design notes:
|
||||
// - The question is asked once per instance — `state.asked` guards follow-up
|
||||
// prompts so a slow repo doesn't spam the user every turn.
|
||||
// - `state.asked` is scoped to the active Snapshot.Service closure, not the
|
||||
// directory-keyed snapshot state. It suppresses follow-up prompts until a
|
||||
// continued snapshot successfully produces a hash.
|
||||
// - We do NOT call `Config.update()` when the user picks "Disable" because
|
||||
// that finalizer runs `Instance.dispose()` and tears down the live turn.
|
||||
// Instead we write the file directly via `KilocodeConfig.updateProjectConfig`
|
||||
@@ -123,11 +124,11 @@ export namespace KiloSnapshotTrack {
|
||||
/** Replace the `{spinner}` placeholder in `template` with the given frame. */
|
||||
export const formatProgress = (template: string, frame: string): string => template.replace("{spinner}", frame)
|
||||
|
||||
/** Per-instance state. Lives as long as the Snapshot.Service scope. */
|
||||
/** Guard state shared by one Snapshot.Service scope, outside directory-keyed InstanceState. */
|
||||
export interface State {
|
||||
/** Skip every future track call once this flips. Resets when the instance reloads. */
|
||||
/** Skip every future track call through this service once this flips. */
|
||||
disabledForSession: boolean
|
||||
/** One-shot guard so we don't prompt the user every turn. */
|
||||
/** Guard prompt display until a continued snapshot successfully produces a hash. */
|
||||
asked: boolean
|
||||
}
|
||||
|
||||
@@ -303,9 +304,9 @@ export namespace KiloSnapshotTrack {
|
||||
// decided whether to keep waiting, disable, or skip below.
|
||||
|
||||
// Slow path. No target session to prompt against, or we've already
|
||||
// prompted on this instance — skip silently.
|
||||
// prompted through this service scope — skip silently.
|
||||
if (!input.sessionID || input.state.asked) {
|
||||
log.warn("snapshot track slow; skipping for this instance", { timeoutMs })
|
||||
log.warn("snapshot track slow; skipping for this service scope", { timeoutMs })
|
||||
input.state.disabledForSession = true
|
||||
yield* Fiber.interrupt(fiber)
|
||||
if (progressFiber) yield* Fiber.interrupt(progressFiber)
|
||||
@@ -349,7 +350,7 @@ export namespace KiloSnapshotTrack {
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
log.info("user dismissed snapshot prompt; disabling for this instance only")
|
||||
log.info("user dismissed snapshot prompt; disabling for this service scope only")
|
||||
}
|
||||
|
||||
yield* clearProgress()
|
||||
|
||||
@@ -786,7 +786,7 @@ export const layer: Layer.Layer<
|
||||
}),
|
||||
)
|
||||
|
||||
// kilocode_change start - per-instance state for the slow-repo track wrapper
|
||||
// kilocode_change start - Snapshot.Service-scoped state for the slow-repo track wrapper
|
||||
const trackState = KiloSnapshotTrack.makeState()
|
||||
// kilocode_change end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user