A transient connection reconnect while the app was paused for legacy
migration re-ran load(), which skipped migration (gate=AlreadyOffered)
and dropped the app into Ready, silently dismissing the wizard. The
connection-state watcher now preserves MigrationRequired across
Connecting/Connected/Error churn, mirroring the existing reconnect()
guard.
The worktree session editor also sat on a blank panel: while the backend
was paused it could not create a session and never retried. It now shows
the empty session panel (like the tool window) when creation is not yet
possible, and re-runs start() once migration completes so the session
appears.
Adds script/clear-migration-status.sh to reset the migration status for
local testing.
* fix(tui): keep Kilo Gateway models visible in the model picker
Selecting a model removed it from its provider section, so a recently
used Kilo sonnet vanished from "Recommended"/"Kilo Gateway" and only
survived under "Recent". Search also keyed off title and section header
only, so filtering by `kilo` never matched titles like "Anthropic Claude
Sonnet 4.5" grouped under "Recommended".
Recents now stay in their provider section (favorites are still deduped
into their own section) and search additionally keys off the provider
name, provider id, and model id, matching the VS Code selector.
Option building moves to kilocode/model-picker.ts so the grouping and
search rules are unit testable.
* chore: add changeset for TUI gateway picker
* fix(tui): identify the selected picker row by reference
Keeping recents in their provider section means a model can legitimately
appear twice in the list (once under "Recent", once under its provider or
"Recommended" section). DialogSelect resolved the selected row by value
equality, so both copies lit up as active whenever either was selected —
visible on every picker open, since the current model is usually a recent
— and hovering the provider-section copy warped selection and scroll to
the "Recent" copy instead.
Match the selected row by object reference instead. Rows are always
distinct objects, so this is a strict refinement for every other dialog;
`current` still uses value equality, which is correct — both rows really
are the current model.
Permission rules are positional, so the global config merged after the
read-only guards and any catch-all shadowed them. Ask kept its edit deny
and simply routed around it through the shell.
Reapply the guard after the user layer for ask and plan: the catch-all
deny plus the read-only allowlist, the user's rules re-expanded onto safe
permissions by exact name, then the bash, MCP and mutating-tool ceilings.
Config rules can no longer widen bash, task, write, notebook_edit,
notebook_execute, agent_manager, repo_clone or interactive_terminal for
these modes, whatever pattern they use. `agent.<name>.permission` remains
the way to opt a single mode in.
A blanket guard deny stays an absolute ceiling, but one aimed at a single
target is only a default: naming that exact target still lifts it, so
plan keeps honoring `task: { general: "allow" }` while no wildcard
reaches it.
Guarding the agent is not enough on its own, since plan may delegate and
a subagent builds its ruleset from the same config, so KiloTask.inherited
carries the same set into delegated sessions.
Fixes#12053