* refactor(web): extract pure turn-rendering helpers from ChatPane
* chore: add changeset for chat pane helper extraction
* test(kimi-web): cover chat turn-rendering helpers
Pure-logic tests for the helpers extracted from ChatPane, focused on
assistantRenderBlocks (tool-stack grouping, interrupt/media break, single
tool) plus the formatting/boundary helpers. Doubles as a safety net
confirming the extraction preserved behavior.
The question adapter only set allow_other on the wire when the SDK item carried an otherLabel/otherDescription, but the AskUserQuestion tool never provides those fields. Web clients honor allow_other, so the free-text option silently disappeared in the web UI while the TUI (which renders it unconditionally) kept working. Set allow_other unconditionally to match the tool's 'users always have an Other option' contract.
The lowercase -c now maps to --continue, shown in help as the primary short flag. The uppercase -C still works as a hidden alias since commander does not allow two short flags on a single option.
* feat(web): remove sidebar and panel max-width limits
Make the resize handle max width optional so the web sidebar and right-side detail/preview panel can be resized beyond their previous fixed maximums.
* fix(web): keep sidebar resize handle reachable on narrow windows
Cap the restored sidebar width at a viewport-aware maximum (viewport width minus the conversation pane minimum) so a width saved on a wide display cannot push the resize handle or collapse button off-screen on a narrower window. The cap updates on resize.
* fix(web): cap preview panel to viewport and share panel-width logic
Apply the same viewport-aware maximum to the right-side detail/preview panel and extract the viewport tracking and width clamping into a shared composable used by both panels.
* fix(web): keep resize caps reactive and reserve room for the preview
Make the resize handle read its max width reactively so a viewport-derived cap keeps working as the window grows after mount. Also have the sidebar reserve the preview panel's minimum width whenever the right-side panel is open, so the conversation column can never be squeezed to zero.
* fix(web): clamp sidebar content width and ignore stale preview target
Render the Sidebar content at the clamped width so controls stay reachable when the saved width exceeds the viewport cap. Also stop reserving space for a hidden right panel by keying the sidebar preview-open check off detailTarget instead of the stale previewTarget.
* fix(web): clamp drag start to current resize cap
When the saved width exceeds the current cap (after the window narrows or a side panel opens), start the drag from the clamped width so the handle responds immediately instead of first covering an invisible delta.
* fix(web): clear detailTarget when closing side chat via /btw
The bare /btw close path called client.closeSideChat() directly, which hid the panel but left detailTarget set to 'btw', so the sidebar kept reserving room for a hidden right panel. Route it through the detail-layer close which clears detailTarget.
Read `.kimi-code/local.toml` through the persistence (local) kaos instead of
the ACP tool kaos during session bootstrap. The ACP reverse-RPC bridge needs
the session registered on the client, which is not true until `session/new`
returns, so reading through it failed with "unknown session" and blocked new
threads in ACP editors such as Zed.
Fixes#988
* fix(web): clear all per-session state when archiving or removing a session
* fix(web): clear queued and in-flight prompt state in session teardown
* fix(web): unsubscribe session before clearing its state in teardown
* fix(web): cancel pending WS subscriptions on unsubscribe
* chore(skills): add release-precheck skill
Add a project-scope agent skill that audits an open kimi-code release PR ("ci: release packages") before merge: it lists the changesets the release will publish, maps each to its source PR, scans the release window for merged PRs that forgot a changeset, and flags wrong bump levels, wrong packages, and non-compliant wording. Outputs the release PR link and a concise suggestion table.
* chore(skills): fix release-precheck package glob and base filter
* chore(skills): classify shipped apps/vis paths as needing changeset
* chore(skills): simplify release-precheck to principle-based audit
* chore(skills): scope release-precheck to changeset validation only
* chore(skills): surface possibly-missing changesets in release-precheck
* chore(skills): replace release-precheck with pre-changelog
* feat(tui): detach foreground tasks to background with Ctrl+B
- Add Ctrl+B shortcut to detach all foreground Bash/subagent tasks at once
- Show "Press Ctrl+B to run in background" hint in tool cards (Agent immediately, Bash after 10s) and in the agent group panel
- Mark detached foreground subagents as ◐ backgrounded instead of ✓ Completed
- Filter foreground tasks out of the /tasks panel (they appear after detach)
- Steer the model away from blocking on TaskOutput after a detach
* fix(tui): address Codex review on Ctrl+B detach
- Preserve `◐ backgrounded` for detached subagents inside AgentGroupComponent by reusing getDerivedSubagentPhase in getSubagentSnapshot
- Distinguish detached-from-foreground subagents from started-in-background ones so the latter still read as `done`
- Let Ctrl+B fall through to readline backward-char at the idle prompt instead of always consuming the key
* fix(tui): address follow-up Codex review on detach hints
- Auto-clear the "No foreground task running." hint via showDetachHint so it doesn't stick on the footer
- Don't clobber a newer transient hint (e.g. exit confirmation) when the detach hint timer fires
- Add FooterComponent.getTransientHint()
* fix(tui): address Codex review on backgrounded gating and /tasks counts
- Only mark foreground-running subagent cards as backgrounded (skip done/backgrounded cards so background resumes don't mutate older rows)
- Count /tasks header from the filtered (background-only) task set so foreground-only sessions don't read misleading counts
* feat(server): add fast disk-based snapshot reader
- add ISnapshotService that reads session state and wire log directly from disk for fast initial sync
- gate the reader behind KIMI_SNAPSHOT_READER (auto/legacy) with a KIMI_SNAPSHOT_TIMEOUT_MS ceiling, keeping the legacy assembly as a fallback
- version @moonshot-ai/server and other internal packages in changesets instead of ignoring them
* fix(server): resolve TS4111 error in snapshot perf test
Use bracket access for process.env['KIMI_SNAPSHOT_READER'] to satisfy
noPropertyAccessFromIndexSignature.
* feat: add workspace add-dir support
Add multi-directory /add-dir management with session-only or project-remembered persistence, directory completion, confirmation UI, and runtime workspace/permission wiring.
* fix: honor --add-dir for resumed sessions
Pass CLI additional directories through shell and prompt resume paths, resolve caller-relative dirs against workDir, and add regression coverage.
* fix: keep additional dirs AGENTS.md out of default context
Load only user-level and cwd AGENTS.md by default, while preserving additional directory listings in the prompt context.
* feat: append /add-dir result as user message
Add a session appendUserMessage RPC and use it after /add-dir so the command result is recorded as a normal user message and surfaced in the transcript.
* docs: add add-dir research and follow-up todos
Document the add-dir / local-command-stdout research findings and the follow-up tasks for stdout wrapping, slash file completion, and hints.
* feat: wrap /add-dir output as local-command-stdout
Insert the /add-dir result as a user-role <local-command-stdout> record with an injection origin directly inside Session.addAdditionalDir. It enters the model context on the next turn but does not start a turn, and stays out of the live and resumed transcript; the transient status toast is kept for immediate feedback. --add-dir is unaffected since it bypasses addAdditionalDir.
Remove the now-unused appendUserMessage RPC and SDK method.
* feat: reopen /add-dir completion after accepting a directory
Generalize the slash-argument completion reopen so it fires whenever the text before the cursor ends with '/', not only when the literal '/' key is typed. After Tab-accepting a directory (or auto-applying a single-child dir), the next level's completion list reappears automatically, so repeated Tab keeps drilling down into subdirectories. '@' file mention is unaffected.
* feat: reopen file mention completion after accepting a directory
Extend the path completion reopen so it also fires for '@' file mentions. After Tab-accepting a directory in an '@' mention, the next level's completion list reappears automatically, matching the '/add-dir' continuous-Tab behavior.
* feat: show inline argument hints for slash commands
Render a dim ghost-text argument hint inside the input box after a slash command that takes arguments, replacing the popup-only hint that was easy to miss. The hint appears once the command is typed and disappears as soon as an argument is entered, and is truncated to fit the box width. Add argument hints for /compact, /swarm, /goal and /title; /add-dir already had one.
* test: remove stale additional-dirs AGENTS.md assertion
The subagent-host test still asserted that an additional directory's AGENTS.md content appears in the agent system prompt, but additional-dirs AGENTS.md has been intentionally excluded from the default context since an earlier commit (covered by context.test.ts). Drop the stale assertion.
* fix: resolve /add-dir paths against workdir and persist via kaos
Resolve user-supplied /add-dir paths against the current workdir instead of the project root, so launching from a subdirectory behaves like the CLI --add-dir flag. Also route the local.toml read/write through the kaos abstraction instead of host fs, so the remember path works for non-local sessions.
* fix: expand ~ in /add-dir paths before resolving
The /add-dir completer emits ~/... values, but the core treated ~/foo as a relative path because pathe isAbsolute('~/foo') is false, producing <workDir>/~/foo. Expand ~ and ~/ to the home directory (via kaos.gethome()) before resolving.
* chore: remove add-dir dev docs from the branch
These were working notes (research and follow-up todos) that don't belong in the PR.
* chore: clarify add-dir changeset for users
* docs: document /add-dir, --add-dir, and local.toml
* test: flush records before reading wire in add-dir runtime tests
FileSystemAgentRecordPersistence.append buffers records and flushes asynchronously, so readMainWire can read the wire before the local-command-stdout record lands. Flush the main agent's records explicitly in the two add-dir runtime tests to make them deterministic.
Merge the two duplicate image-extension guards in detectFileType into a single mode-independent rule: an image extension without confirming magic is not an image in any mode. The video extension fallback stays before the NUL check so video containers with no magic still win. No behavior change.
Add and align tests: Read rejects an image-extension file with non-image bytes as not readable instead of redirecting to ReadMediaFile; file-type asserts the sniff-failed image case in both media and text modes.
When ReadMediaFile reads a file whose bytes have no recognisable image magic (for example a `.png` that is actually plain text), detectFileType previously fell back to the extension MIME type and built a data URL whose bytes did not match the declared format, which the model API rejected.
Every image format the model accepts (PNG/JPEG/GIF/WebP) has a reliable magic signature, so a failed sniff means the bytes are not a supported image. Report such files as `unknown` so ReadMediaFile returns a clear error instead of a bad data URL. The extension fallback is kept for video containers with no magic signature (for example MPEG-PS `.mpg`); format acceptance beyond that is left to the provider.
* fix: surface provider content filter and preserve context tokens
* fix: complete filtered turn handling across surfaces
- context: accumulate token estimate for zero-usage steps to preserve
the tokenCount / tokenCountCoveredMessageCount invariant
- turn/goal: pause the goal when a turn is blocked by safety policy
- subagent: surface a filtered child turn as a distinct error
- acp: map filtered to the native ACP refusal stop reason
- tui: show a filtered-specific message in the btw panel
- cli: drop the redundant content_filter suffix from the error message
- tests: cover filtered across cli, web, acp, and goal flows
- add windowsHide:true to spawn options so commands do not flash a console on Windows
- extract buildLocalSpawnOptions helper shared by exec and execWithEnv
- add regression coverage for the Windows console-window behavior
* test(kimi-web): keep only pure logic unit tests
Remove jsdom/component Vitest coverage from apps/kimi-web, keep server-e2e as the e2e path, and add focused pure-logic Vitest coverage for diff parsing, file path links, tool summaries, turn grouping, and todo derivation.
* build(nix): update pnpm deps hash
Report the effective thinking effort (off/low/medium/high/xhigh/max) on
compaction_finished, compaction_failed, and micro_compaction_finished events.
The value matches the thinking level applied to the compaction provider, so we
can analyze how thinking mode affects compaction token usage, duration, and
failures.
* feat(web): add scroll-up lazy loading for older session messages
* fix(web): keep new-messages pill above the composer dock
* fix(web): observe top sentinel after DOM flush in ChatPane
* fix(web): avoid eager lazy-load on open and suppress pill during history prepend
* fix(web): gate scroll-key watcher and skip scroll restore on session switch
* fix(web): restore scroll position from stable top anchor when prepending history
* fix(web): preserve new-message pill during history lazy load
* fix(web): resolve lint regressions in lazy load tests
* fix(web): harden session lazy-load retry and scroll restore
* fix(web): treat same-turn history prepends as non-bottom updates
* feat(web): add session search
Add a search box to the web sidebar that instantly filters all loaded
sessions by title and the last user prompt (case-insensitive).
Surface the last user prompt from the server: the daemon already
persisted it in session metadata, and it now flows through the session
schema into the REST response so the web client can match against it.
* fix(web): keep lastPrompt fresh on session.meta.updated
Address Codex review: the daemon emits session.meta.updated with
patch.lastPrompt whenever a new prompt is submitted, but the web
projector only forwarded the title. That left the cached session's
lastPrompt stale, so sidebar search by the latest prompt text failed
until a full reload. Forward lastPrompt through the projector and
reducer, and cover it with a pipeline test.
* refactor(web): avoid conditional spreads in meta patch
Address Codex review: per the root AGENTS.md, optional object properties
should be passed directly rather than via conditional spreads. Use nullish
coalescing so a field the event does not carry keeps its prior value.
* fix(web): stop Escape from aborting a run while search is focused
Address Codex review: ConversationPane registers a document-level keydown
that aborts the active prompt on Escape. Without handling it on the search
input, pressing Escape to dismiss the search would unexpectedly stop the
agent. Stop propagation and clear the query, matching the inline rename
inputs.
* fix(web): exclude hidden-workspace sessions from search
Address Codex review: removing a workspace only records its root in
hiddenWorkspaceRoots and leaves the sessions intact; the grouped sidebar
skips the hidden root, but sessionsForView (the search source) did not,
so a matching title or prompt could resurrect sessions from a removed
workspace. Filter sessionsForView by the visible workspace set so the
flat list matches what the grouped sidebar renders.
The daemon's workspace session_count counted archived session directories,
so a workspace still reported a non-zero count after its last session was
archived. The web sidebar then showed the workspace as non-empty, making it
look like the archive had failed (and a retry would error out).
Count only non-archived sessions in the workspace registry, and trust the
live local count in the web app once sessions have loaded.
* refactor(telemetry): merge duplicate session-start and goal events
* test: align telemetry tests with merged session-start events
- run-shell: assert sessionStartedProperties plumbing instead of the removed 'started' event, drop the now-redundant resumed-lifecycle test, and fix the startup_perf call-count assertion
- node-sdk: cover process-level and session-level sessionStartedProperties merging on session_started
* fix(telemetry): keep session_started canonical fields authoritative
Caller-supplied sessionStartedProperties were merged after the canonical fields (client_name, client_version, ui_mode, resumed), so a caller could silently override them via the public SDK options. Reorder so the harness-owned canonical fields always win, while session-level properties still override process-level ones for non-canonical keys.
* feat(web): show server version in settings
Display the server version reported by GET /api/v1/meta in the web
settings General tab, under a new Build section.
* feat(web): show server version in mobile settings too
Address Codex review: the mobile settings sheet renders instead of
SettingsDialog on mobile, so surface the server version there as well.
* feat(agent-core): cap AgentSwarm concurrency via env var
Add KIMI_CODE_AGENT_SWARM_MAX_CONCURRENCY to limit how many subagents run concurrently during the initial ramp, so large swarms do not trip provider rate limits as easily. Leave it unset to keep the previous uncapped ramp behavior.
* chore: drop ignored agent-core from changeset
* fix(agent-core): fail fast on invalid AgentSwarm concurrency cap
* fix(web): scroll active slash item into view and stabilize item keys
* fix(web): use function ref for slash menu items to preserve order
* chore(changeset): add changeset for web slash menu scroll polish
- prefer coreProcessOptions.identity.version in start.ts for /meta and the OpenAPI/AsyncAPI docs
- fall back to getServerVersion() when the server runs standalone without a host identity
- update meta.ts and version.ts docs to describe the new version source
- add e2e test verifying server_version reports the host identity version
* feat(web): redesign OAuth login dialog layout
Lead with a single 'Authorize in browser' button that opens the verification link with the device code embedded; demote manual code entry to a secondary fallback; remove the duplicate open-browser and cancel controls and the redundant footer hints so the step order is clear.
Props/emits unchanged; no caller changes needed.
* fix(web): align login slash copy
* fix(web): keep login dialog open on backdrop click
* docs(reference): 修正 kimi web 为后台守护进程运行
kimi web 实际复用 server run 的后台守护进程流程(web-alias.ts 中
defaultOpen 置为 true),原文档误写为前台运行。改为后台启动、命令返回,
并补充 --foreground 示例。
* docs(reference): 与文档站参考手册版本对齐 kimi web 说明