mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-23 08:04:41 +00:00
35 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e91a616f21
|
fix(web): dedupe optimistic user message against snapshot resync (#1620)
* fix(web): dedupe optimistic user message against snapshot resync * fix(web): match snapshot messages by identity |
||
|
|
098623ed9f
|
chore(web): drop the /help, /model, /provider, and /permission slash commands (#1615)
* chore(web): drop the /help, /model, /provider, and /permission slash commands * chore: drop the changeset |
||
|
|
f338fcdac4
|
fix(web): restore swarm member list after page refresh (#1589)
* fix(web): restore swarm member list after page refresh * chore: add changeset for swarm roster refresh fix |
||
|
|
5a208cb041
|
fix(web): auto-enable default thinking effort when switching to an effort-capable model (#1475)
Some checks are pending
CI / typecheck (push) Waiting to run
CI / build (push) Waiting to run
CI / test (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Desktop release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* fix(web): auto-enable default thinking effort when switching to an effort-capable model * chore: add changeset * fix(web): preserve thinking off when reselecting current model |
||
|
|
d2c2c33f3e
|
feat(web): type absolute paths directly in the workspace picker (#1556)
* feat(web): type absolute paths directly in the workspace picker The add-workspace dialog's fuzzy-search box now doubles as an absolute path entry: input starting with "/" or "~" is validated live (missing path / missing parent get specific errors plus prefix-matched candidates), and a valid path live-follows the folder browser so the existing "Open this folder" button submits it. Enter accepts the first candidate or opens a valid path; Esc clears the box. The collapsed paste-path section at the bottom is removed, and the degraded (no-browse) mode reuses the same box with format-only validation. * fix(web): recognize Windows absolute paths and gate Open button in path mode Two review fixes on the workspace picker's path entry: - PATH_LIKE now also matches Windows drive (C:\x, C:/x) and UNC (\\srv\x) forms, matching node:path.isAbsolute on the daemon side. Without this, Windows users in degraded (no-browse) mode had no way to submit a path at all. Parent-dir splitting and trailing-separator trimming are now separator-aware (drive roots are preserved). - "Open this folder" is disabled while path mode has no validated target. Previously, after typing a valid prefix and then an invalid path, the button still submitted the stale followed prefix. * fix(web): submit the typed lexical root when adding a workspace in path mode fs:browse canonicalizes via realpath, but workspace/session ids are based on the lexical root. For a symlinked cwd (/tmp/project -> /private/tmp/ project on macOS), live-follow stored the resolved target in currentPath and "Open this folder" emitted it, so sessions under the typed cwd would not group under the workspace. Keep the typed normalized path for the add action and use the browse result only to populate the visible browser. * fix(web): handle workspace path input edge cases |
||
|
|
170ae44205
|
style(web): polish the session sidebar (#1519)
* feat(web): use sidebar fold/unfold icons for sidebar toggle * feat(web): move settings entry to a sidebar footer row * feat(web): fully collapse sidebar with animated width transition * feat(web): redesign sidebar colors, spacing and macos desktop chrome * feat(desktop): center traffic lights on the 48px header row * fix(web): restore webkit thin scrollbars and unify sidebar icon sizes * feat(web): add Kbd keycap component and justify sidebar search shortcut * style(web): rework sidebar palette and pin a resident sidebar toggle * fix(desktop): sync window appearance with web UI theme so dimmed traffic lights stay visible * feat(web): adopt Kimi design icons in the sidebar via a local icon collection * style(web): mute workspace group title color in the sidebar * style(web): refine sidebar typography, unify shortcut keycaps, float workspace row actions * style(web): cap sidebar draggable width at 480px * style(web): derive sidebar row height from type and padding, float the kebab * chore: add changeset for sidebar UI polish * fix(nix): update pnpmDeps hash * style(web): put the sidebar collapse button inside the header on non-mac * fix(nix): update pnpmDeps hash |
||
|
|
ad30a1c632
|
style(web): polish web UI typography and controls (#1502)
* style(web): polish sidebar and tool typography - Use UI font and medium weight for sidebar and composer controls - Add reusable shortcut and tool output blocks - Cap long tool output at 50 lines with a scrollbar - Update sidebar show-more copy and muted styling * style(web): refine workspace picker sizing * style(web): align composer mode menus * style(web): tune list and question typography * style(web): reuse shortcut keys in approvals * style(web): size workspace picker from content * feat(web): localize chat status labels * style(web): refine composer toolbar controls * style(web): use complete Inter variable font * style(web): tune sidebar workspace typography * style(web): polish composer and workspace picker * style(web): refine markdown and thinking typography * chore: add web UI polish changeset * fix(web): pin Inter package for Nix build * style(web): polish goal tool calls * style: polish goal mode display * fix: layer latest message pill below menus * style: align goal strip content |
||
|
|
735922c291
|
feat(kimi-web): add status-aware browser notifications (#1479)
* feat(kimi-web): add approval notification storage key and i18n copy
* feat(kimi-web): add approval notification helpers and tests
* feat(kimi-web): wire approval notifications and guard completion alerts
* fix(kimi-web): extract shouldNotifyCompletion helper and add tests
* feat(kimi-web): add approval notification settings toggle
* chore(kimi-web): add changeset and tidy notification module comment
- Align approval notification tag with spec (kimi-approval-${approvalId})
- Update module header to describe all three notification kinds
* fix(kimi-web): make notifications fire reliably
- Key completion notification tags by turn (sid + promptId) and question
tags by request id, so a stale notification left in the notification
center no longer swallows every follow-up alert in the same session
- Suppress notifications only while the window is actually focused, not
merely visible (document.hasFocus() on top of visibilityState)
- Play the attention sound when a tool needs approval, matching the
completion and question sounds
* chore(kimi-web): simplify changeset
|
||
|
|
b0809ddac8
|
feat(web): prefix skill slash commands with skill: to distinguish them from built-in commands (#1492) | ||
|
|
2ad0120c2a
|
feat(web): redesign cron reminder as a message bubble (#1480)
* feat(web): redesign cron reminder as a message bubble Restyle the cron trigger notice as a right-aligned user-style message bubble that shows the scheduled prompt in full (wrapping across lines), with a small meta row beneath it for the schedule, status, job id and run time. Extract a shared MessageTime component used by both user messages and the cron reminder so the timestamp format and click-to-expand behavior stay consistent, and give the CronCreate/CronList/CronDelete tools distinct calendar icons. * refactor(web): render cron reminders only as standalone turns Remove the embedded cron block path from the web transcript projector so cron reminder fires always render through the standalone right-aligned bubble path. * chore(web): simplify cron redesign changeset |
||
|
|
ee385456d0
|
refactor(web): migrate icons to unplugin-icons (#1467)
* refactor(web): migrate icons to unplugin-icons Replace the hand-written gen-icon-data.mjs + @iconify/utils runtime rendering with unplugin-icons build-time imports. The public API (<Icon name>, iconSvg, IconName, SIZE_PX, NAME_TO_REMIX) is unchanged; 127+ call sites are untouched. - add unplugin-icons@^23.0.0 (devDep) + Vite Icons() plugin (compiler: vue3) - rewrite src/lib/icons.ts: static ~icons/ri/* imports (component + ?raw) for 56 distinct Remix icons across 59 IconName entries - Icon.vue renders <component :is> with unknown-name fallback - append ICON_GROUPS export for DesignSystemView catalog - DesignSystemView: v-for catalog, remove legacy-script references - delete gen-icon-data.mjs, gen-icon-catalog.mjs, icon-data.ts, gen:icons script - remove @iconify/vue and @iconify/utils from dependencies; move @iconify-json/ri to devDependencies - drop Icon.vue from check-style ICON_EXEMPT (no hand-written <svg>) * refactor(web): drop unused NAME_TO_REMIX icon mapping NAME_TO_REMIX was a Record<IconName, string> table introduced to map internal icon names to their ri: ids. After the unplugin-icons migration it has no production consumers — only icons.test.ts imported it (for two drift tests) and DesignSystemView mentioned it in descriptive copy. The ICONS table already conveys the same ri: id via each entry's paired component + ?raw imports (e.g. RiFolderOpenLine / RawFolderOpenLine). - remove NAME_TO_REMIX const from src/lib/icons.ts (-63 lines) - remove NAME_TO_REMIX import + describe block from icons.test.ts - update DesignSystemView §02 copy: describe the import-pair idiom and stop claiming ICON_GROUPS is sourced from NAME_TO_REMIX * chore: add changeset for web icon migration * chore(nix): bump pnpmDeps hash for unplugin-icons Adding unplugin-icons changed pnpm-lock.yaml, so the fixed-output pnpmDeps derivation hash is stale. Update to the hash reported by the Nix Build CI run. |
||
|
|
2374bc41c3
|
feat(kimi-web): render cron fire notices in the web chat (#1426)
* feat(kimi-web): render cron fire notices as in-transcript cards Show scheduled-reminder fires as distinct notice cards in the web chat, both live and after a reload, instead of hiding them. Each card carries a humanized schedule, a dimmed job id, and a collapsible prompt body. * fix(kimi-web): isolate cron notice prompt id and route prefixed events - Give synthesized cron messages a fresh promptId so a fire mid-turn cannot be reconciled into the optimistic user echo and hide it. - Add cron.fired to KNOWN_AGENT_CORE_TYPES so event.-prefixed frames reach the projector and render live too. * fix(kimi-web): truncate long one-line cron prompts when collapsed Slice the first line to the collapse limit with an ellipsis when a single-line prompt exceeds it, so the collapsed state actually truncates and the expand toggle is not a no-op for common one-line reminders. * fix(kimi-web): keep cron notices from reconciling into optimistic user echoes Skip optimistic-echo reconciliation for user messages whose origin is cron_job or cron_missed: their prompt text can coincide with a still- optimistic user message, and the loose content match would otherwise replace the user's turn with the cron notice instead of appending. * fix(kimi-web): keep in-turn cron injections from breaking tool results A cron injection steered into an active turn lands inside that turn's message sequence, between a tool use and its result. Treating it as a hard user-turn boundary flushed the pending assistant group, so the next tool result had no group to fold into and the tool rendered without output. Embed such in-turn cron notices as a block inside the assistant group instead, and only render a cron at a turn boundary as its own turn. * fix(kimi-web): only embed cron notices while a tool is in flight Embedding whenever a group was pending was too broad: on REST snapshots without prompt ids the whole transcript shares one group, so an idle cron fire merged into the previous assistant answer and its own reply kept going in that group. Embed only while the group has a running tool (a cron sandwiched between a tool use and its result); flush to its own turn otherwise. * fix(kimi-web): omit synthetic prompt id on cron notices The synthesized cron message carried a cron_pr_ promptId that the web client caches into promptIdBySession for Stop/abort. Because it is not a real daemon prompt id, it clobbered the active promptId, so Stop first aborted a nonexistent prompt and only recovered via the error fallback. Omit the promptId; the reducer already skips optimistic-echo reconciliation for cron-origin messages, so it is not needed for de-dup. |
||
|
|
ac5b5e4cbf
|
fix(kimi-web): keep tool components from jumping on expand or collapse (#1433)
* fix(kimi-web): keep tool components from jumping on expand or collapse Also show the scroll-to-bottom button whenever scrolled up, and render a fallback icon for tools without a dedicated glyph. * fix(kimi-web): preserve bottom follow during content-only resizes Late-loading media can grow after scrollKey has run; keep chasing the bottom on content growth, and only suppress follow during the pinned expand/collapse window. |
||
|
|
c5e3e80041
|
feat(web): render AgentSwarm as an inline tool card (#1425)
* feat(web): render AgentSwarm as an inline tool card Replace the bottom SwarmCard footer and the messagesToTurns live-skip with one dedicated inline tool card for AgentSwarm. The card shows a phase overview plus a per-subagent accordion: live progress while it runs, parsed aggregated result once it completes (and after a refresh that has already dropped the live tasks). Refresh and resync keep member identity metadata (swarmIndex, parentToolCallId, subagentType, runInBackground) stable across skeleton task replacement in the reducer, and the .content-wrap flex layout is hardened against the overflow compression that previously displaced the footer. * fix(web): handle swarm review feedback - SwarmTool: when AgentSwarm fails before producing a structured agent_swarm_result (e.g. argument validation), render the raw tool output instead of the "waiting for subagents" placeholder so the failure cause is visible. - resolveSwarmMembers: source live members from the AppTask store keyed by parentToolCallId rather than buildSwarmGroups, which filters out single-member groups. A resume-only AgentSwarm now streams its live progress before the final result arrives. The badge counter still relies on buildSwarmGroups's filter. * fix(web): carry streamed subagent text into swarm rows Swarm subagents that stream normal assistant output accumulate it on AppTask.text (text-kind taskProgress), not outputLines. The new live member map was dropping `text`, so a still-composing subagent rendered an empty / stale row until the structured result arrived. - Add `text` to SwarmMember and thread it through buildSwarmGroups and swarmMembersByToolCall. - SwarmTool: prefer member.text for both the row activity preview and the expanded body; fall back to outputLines / summary. - Tests cover text propagation through both helpers. * fix(web): merge swarm result rows and fall back to raw output Address the two latest swarm review comments: - Rows: when a parsed agent_swarm_result coexists with live AppTasks (which the detail panel also depends on), the inline card previously only rendered the live members. Interrupted swarms can carry state="not_started" / outcome="aborted" result entries for items that never spawned a task; those rows were dropped until a refresh cleared the live tasks. Extract the row model into buildSwarmCardRows and merge result-only aborted/not-started rows with the live member rows. - Fallback: when the tool is no longer running but produced no structured result (argument validation, parser miss, or legacy legacy transcript), render the raw tool output instead of "Waiting for subagents…" so the final text / failure cause is visible to the user. * fix(web): parse swarm result subagent bodies defensively Producer writes subagent body unescaped, so a subagent that analyzes or emits an AgentSwarm snippet can include a literal "</subagent>" inside its body. The non-greedy regex treated that as the row close and truncated the body in the result-only path (post-refresh where the AppTask store is gone). Rewrite the parser to scan opening tags, then resolve each row's body as everything up to the last "</subagent>" before the next row's opening tag (or document end), preserving embedded close-tag strings. Add tests for a literal "</subagent>" within a single body and across sibling rows. * fix(web): only count top-level subagent result tags A subagent body that contains a literal `<subagent ...>` tag — for example emitting an AgentSwarm/XML snippet — was being pre-collected as another result row, splitting the real body and producing duplicate / bogus subagents after refresh where the AppTask store is gone. Rewrite parseSubagents with a depth-tracking tokenizer: scan every `<subagent ...>` / `</subagent>` token in order, push a real row frame only at the outermost level, and treat openings / closings while nested inside another body as body text. Drop the now-inaccurate "literal </subagent> without matching open" regression tests; replace with tests that verify a balanced nested snippet stays inside the parent body and does not register as a separate row. |
||
|
|
578f7d334c
|
fix(web): reconcile session from snapshot on reopen (#1409)
* fix(web): reconcile session from snapshot on reopen * fix(web): discard stale snapshot when a newer prompt races reopen * fix(web): harden reopen snapshot against first-open and optimistic-send races * fix(web): keep evicted reopens subscribed when a snapshot races * fix(web): let resync snapshots bypass the reopen staleness guard * fix(web): force-apply the snapshot after an undo * fix(web): gate session reopen on durable seq instead of updatedAt * refactor(web): always rebuild reopened sessions from a snapshot * fix(web): sharpen reopen snapshot discard and skip rebuilds mid-stream * refactor(web): unconditionally apply session snapshots, drop the staleness guard * fix(web): preserve loaded older messages when reopen snapshots apply |
||
|
|
c5c6282f44
|
feat(web): render AskUserQuestion result as an option list (#1391)
Some checks are pending
CI / build (push) Waiting to run
CI / test (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Desktop release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* feat(web): render AskUserQuestion result as an option list
Parse the AskUserQuestion tool result and echo the full option list, highlighting the chosen option(s) and dimming the rest, instead of dumping raw JSON. Handles single/multi select, free-text Other answers, and the dismissed state. Answers are zipped back to the input questions by index since the input carries no ids.
* fix(web): drop the stray indent in the tool-call card body
The expanded body of every tool-call card carried a hard-coded 36px left indent (a magic number meant to align with the header name). Drop it so expanded content aligns with the header's 11px padding instead. The design-system preview page mirrored the same rule and is updated to match.
* fix(web): align markdown diff block with the design system
Restyle the local ```diff renderer in chat Markdown to match the ~/diff panel: code text keeps the normal ink colour, the +/- sign carries the add/del colour, and rows use a soft background with an inset accent bar instead of dyeing the text green/red. The header and copy button now match the standard code-block chrome (height, hover, focus ring).
* fix(web): match the markdown diff block chrome to code blocks
Make the local markdown diff renderer's shell identical to a regular code block: swap the text copy button for the same icon button, inherit the header's text-xs sizing, and keep the container / header / code-area padding, background, radius and shadow in lockstep with .code-block-container and .code-block-header. The diff-specific row tinting (soft background, inset accent bar, coloured sign) is kept since that is what makes it a diff.
* fix(web): fall back to raw output for non-answer AskUserQuestion results
Background launches and error cases return plain-text tool output (task_id/status lines, or a failure reason), not the { answers } JSON the card expects. The card used to render an empty, fully-unselected option list in those cases, hiding the task id or error. Now the card only renders the option list when the output parses as the answer payload; otherwise it shows the raw output. Addresses review feedback (P2).
* fix(web): localize AskUserQuestion result labels
The card hard-coded user-visible strings (Dismissed, answer/answers, Answered, the (+N more) summary), so Chinese-locale transcripts mixed in English. Move them into the en/zh tools locale files and read them via t(). Addresses review feedback (P2).
|
||
|
|
26b90225d2
|
feat(web): support multi-level thinking effort selection (#1344)
Some checks are pending
CI / build (push) Waiting to run
CI / test (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
Nix Build / Check flake.nix workspace sync (push) Waiting to run
Nix Build / nix build .#kimi-code (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Desktop release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
* feat(web): support multi-level thinking effort selection Surface each model's declared reasoning efforts (support_efforts / default_effort) in the web model picker as a segmented control, replacing the on/off toggle. ThinkingLevel is now an open string, the model catalog carries the effort metadata to the web app, and the mobile settings sheet and /thinking command cycle through the available levels. * fix(web): preserve persisted thinking level before models load coerceThinkingForModel returned 'on' for any non-'off' level when the active model was still undefined (catalog not loaded yet), which rewrote a persisted/default effort like 'high' to 'on' and silently dropped the model's declared effort on later prompts. Keep the requested level as-is until loadModels() re-runs coercion with the real model. Addresses Codex P1 review on modelThinking.ts. * fix(web): coerce stale thinking level against the active model When selecting another session, the persisted thinking level can be a boolean 'on'/'off' carried over from a previous model. Deriving the pill suffix and active segment from that raw value could show "thinking: off" on an always-on model or hide the concrete effort behind a bare "thinking" tag. Coerce the level against the current model before deriving display state. Addresses Codex P2 review on Composer.vue. * fix(web): submit coerced thinking level for the prompt's target model The send paths (submitPromptInternal / steerPrompt) previously submitted rawState.thinking verbatim, so a value carried over from another session (e.g. 'max' from an effort model) was sent to a model that doesn't declare it, even though the composer already showed the coerced default. Coerce the level against the target model before submitting so the first turn runs with the level the UI displays. Addresses Codex P2 review on Composer.vue. * fix(web): coerce stale thinking in /thinking and mobile settings Two more surfaces derived their active state from the raw persisted level, which is stale when the saved level came from a different model: - /thinking slash command: indexing the raw value (e.g. 'on' from a boolean model) into an effort model's segments returned -1 and jumped to 'off' instead of advancing from the model's default effort. - Mobile settings sheet: clamping the raw prop fell back to the first segment, showing/selecting 'off' or the first effort while the composer and prompt submission coerce to the model default. Coerce the level against the active model in both places, matching the composer and send-path behavior. Addresses Codex P2 reviews on App.vue and MobileSettingsSheet.vue. |
||
|
|
c3653a1c50
|
refactor(web): show an up arrow on the composer send button (#1301)
* refactor(web): show an up arrow on the composer send button * docs(web): regenerate design-system catalog with the send up-arrow |
||
|
|
6a469b3e07
|
refactor(web): replace hand-written icons with Remix Icon (#1293)
* refactor(web): replace hand-written icons with Remix Icon Generate a tree-shaken Remix Icon subset at build time via @iconify/utils + @iconify-json/ri, keeping the <Icon>/iconSvg() API. Add a chat-new icon for the new-chat buttons and reveal the workspace 'new chat in group' button on hover. Unify the message copy and undo buttons (matching hover style and tooltip, drop the undo hover label, align sizes). Switch the mobile switcher kebab to the horizontal dots icon and tweak sidebar search colors. Regenerate the design-system icon catalog. * fix(web): address PR review feedback Restore accessible names (aria-label) on the message copy and undo buttons. Keep the workspace add button reachable for keyboard users by revealing it on header focus-within. Update the nix pnpmDeps hash for the newly added icon dependencies. * fix(web): address follow-up review feedback Keep the workspace add/more buttons focusable without hover by revealing them via opacity instead of display:none, so keyboard and non-hover users can reach the control. Drop explicit .ts extensions in icon imports to satisfy oxlint, and read the design-system icon catalog directly from the generated icon data. |
||
|
|
b905dd4910
|
feat(web): redesign web UI and add design system (#1258)
* feat: redesign web ui & add design system * feat(web): add motion to redesigned UI and add changesets Animate toast enter/leave, dialog open, and workspace-list and tool-row expand/collapse instead of snapping, and add the changesets covering the web redesign. * fix(web): remove undo message exit animation * fix(web): route agent tools to AgentTool and focus dialog on open - toolRegistry matched the raw 'agent' name, but normalizeToolName folds agent/subagent into 'task', so agent calls fell through to GenericTool and lost the inline Open button for the subagent detail panel. - Dialog's focus watcher only fired on change; callers that mount with open already true (Login, Settings, ...) never moved focus into the modal. Run it immediately so initial focus and restore-on-close work. * feat(web): add logo long-press design-system easter egg Hold the sidebar logo for 3 seconds to open a dialog showing the design system page. Also trim and rebalance the redesign changesets. * fix(web): silence Sidebar v-show warning by making it single-root Nest the design-system Teleport inside the sidebar <aside> so the component has a single element root. App applies v-show to Sidebar, which needs an element root to attach to; the fragment root logged a "non-element root node" warning on every reactive update and the collapse did not take effect. * fix(web): thinking toggle, tool-group i18n, agent detail button - Show the default-thinking switch as on whenever thinking is effectively enabled (enabled !== false), matching the core resolver. - Route the grouped tool-call header and status through vue-i18n. - Hide the subagent "Open detail" button when no matching task exists (e.g. a completed foreground subagent after a refresh). * fix(web): use strict equality in agent detail button guard oxlint eqeqeq flagged the loose != null check; resolveAgentTaskId returns string | undefined, so compare with !== undefined. * chore(web): remove stray design mockups and screenshots Remove the design exploration mockups, screenshots, prompts, and notes that were accidentally committed under apps/kimi-web/design. Keep design-system.html, which the sidebar logo easter egg still references. * fix(web): keep sessions on continuation failure, treat absent thinking as on - Keep sessions already loaded from earlier pages when a continuation page fetch fails, instead of replacing the workspace with an empty page. - Treat an absent thinking config as enabled in the settings toggle, matching the core resolver (thinking is on unless explicitly disabled). * feat(web): open design-system easter egg on 10 logo clicks Replace the 3-second long-press trigger with 10 consecutive clicks on the Kimi mark; the count resets after a short idle. The long-press was unreliable because pointerleave cancelled the timer on any drift. * fix(web): treat cancelled swarm members as finished phaseForTask now lets a terminal status (completed/failed/cancelled) override a stale subagentPhase, so a cancelled swarm member no longer stays live and suppresses the finished AgentSwarm card. * feat(web): use 1s long-press for design-system easter egg Switch the logo easter egg back to a long-press, shortened to 1 second, and make it reliable this time: use pointer capture plus touch-action:none so a slight drift no longer cancels the hold. * fix(web): use plain Spinner for activity notices ActivityNotice renders for non-chat loading states (e.g. compaction), so it must use Spinner per the design-system rule that reserves MoonSpinner for the chat first-response state. * docs(web): add a11y guidance to design system * docs(web): drop stale design README link * fix(web): restore model search focus and define panel header weight - Bind the model picker's search Input to searchRef so useDialogFocus moves focus into it on open instead of the dialog's close button. - Use the defined --weight-semibold token for panel header titles (--weight-bold is not declared, so the shorthand was invalid). * fix(web): let any open dialog own Escape over the side panel Track open design-system Dialog instances in a shared count and include it in App.vue's anyOverlayOpen, so a dialog whose open state lives outside App.vue (such as the sidebar session search) captures Escape before the background side panel closes. * fix(web): base dock-work flag on filtered dock task lists Foreground subagents are excluded from the dock task lists, so a session whose only task is a foreground subagent no longer renders an empty workbar above the composer. * fix(web): create subagent task before forwarding text deltas A client that subscribes from a snapshot after subagent.spawned already fired never received the lifecycle taskCreated; the reducer only applies taskProgress to existing tasks, so assistant text deltas were dropped and the live subagent detail stayed blank. Emit taskCreated (via patchSubagent) before the text progress, mirroring the tool-progress path. * fix(web): keep plan, swarm, and goal mode toggles per session Plan, swarm, and goal modes were stored as global scalars on the web client and a single localStorage key each, so they leaked across sessions. Bind them to the active session via per-session maps, persist per session, and apply server status/events to the originating session so background sessions keep independent state. * fix(web): keep subagent detail reachable for synthesized tasks When the web client subscribes after a subagent already spawned, the synthesized subagent task has no parentToolCallId, so the Agent tool's Open-detail button was hidden and the panel would not open. Fall back to the single unmapped subagent task when resolving the detail target in both the button visibility and the panel open paths. * fix(web): keep session kebab menu from being clipped Teleport the SessionRow kebab menu to body and anchor it with fixed positioning so the collapsing group-sessions list's overflow:hidden no longer clips the dropdown. * fix(web): apply staged modes to the created session by id When starting the first prompt, apply the staged plan/swarm/goal modes to the just-created session's per-session maps by id instead of via the activeSessionId-based setters, so a session switch during the selectSession await can't drop the modes for this session or pollute another. * refactor(web): unify confirmation dialogs into a single modal Replace the inconsistent confirmation patterns (native confirm(), two-step menu arming, hand-rolled inline strips, bare buttons) with one modal ConfirmDialog driven by a global useConfirmDialog() composable, and consolidate the duplicated confirm/cancel i18n keys. * feat(web): inline message queue with separate stop button - Send button always sends/enqueues; interrupt moves to a separate red Stop button shown only while running, so the two can no longer be confused. - Queued prompts now render inline at the tail of the transcript (after the running turn) instead of behind the dock panel: click to edit, remove, drag the grip to reorder, with image thumbnails and a "next up" marker. - Remove the dock queue panel and the QueuePane component; Steer stays on Ctrl/Cmd+S. * chore: add changeset for web queue UX * feat(web): prompt reliability, sidebar menu, and composer/markdown polish - Fix spurious errors when question/approval/task actions were already complete - Add loading feedback to question and approval prompts; block double-clicks - Make the question "Other" option selectable by row click and let Enter advance/submit - Consolidate workspace section actions into an overflow menu - Tighten markdown prose line-height and block spacing - Recall input history only when the caret is at text start |
||
|
|
882cf355a9
|
fix(web): persist workspace rename and hide provider manager (#1234)
* fix(web): persist workspace rename via the daemon update API * fix(web): hide the unshipped provider manager * fix(web): fall back to a local override for derived workspace renames * fix(web): preserve workspace name override across registration |
||
|
|
210cedb3bf
|
chore: add KCD client for test (#1230)
* feat(kimi-desktop): add Electron desktop client wrapping kimi-web
New apps/kimi-desktop — a thin Electron shell + process manager around
the existing web UI. It reuses kimi-code's shared daemon: it runs the
bundled SEA's `server run` (the same ensureDaemon reuse-or-spawn flow as
`kimi web`), reads ~/.kimi-code/server/lock for the real origin, and
loads the SEA-served kimi-web same-origin. The daemon is left running on
quit so the CLI / browser / TUI keep sharing it.
- main process: ensure-server (run SEA, read lock, confirm healthz),
sea-path (dev vs packaged), window + native menu + window-state +
loading/error screens
- packaging: electron-builder config; before-pack stages the
matching-platform SEA into <resources>/bin/<target>
- CI: desktop-build workflow builds unsigned mac/win/linux installers,
each runner building its own SEA
- workspace wiring: register in flake.nix, allow electron postinstall
(onlyBuiltDependencies), root dev:desktop + typecheck entries
v1 is unsigned, default icon, no auto-update.
* feat(kimi-desktop): sign + notarize macOS builds
Unsigned macOS builds are blocked by Gatekeeper ("app is damaged") once
transferred to another Mac. Add Developer ID signing + Apple notarization,
mirroring the TUI native build:
- build/entitlements.mac.plist: hardened-runtime entitlements (allow-jit,
disable-library-validation for koffi/clipboard, etc.) applied to the app
and — via entitlementsInherit — the nested SEA backend
- electron-builder.config.cjs (replaces .yml): hardenedRuntime + entitlements;
signing and notarization are env-driven (CSC_* + KIMI_DESKTOP_NOTARIZE +
APPLE_API_* ), so the same config builds unsigned locally or signed+notarized
- desktop-build CI: sign-macos input reuses the existing macos-keychain-setup
action + APPLE_* secrets, notarizes via the notary API key
- README: document signing, the Developer-ID requirement, and the
"don't rename the .app" gotcha
Verified locally that electron-builder signs both the app and the nested SEA
with hardened runtime + the entitlements, and the signed app still launches and
serves the web UI. Notarization itself needs a Developer ID cert (CI / a machine
that has one).
* feat(kimi-desktop): rename product to Kimi Code Desktop
productName / window title / menu label / error-screen text all use
"Kimi Code Desktop" so the bundle name matches its executable (a
mismatch from manual renaming is itself reported as "damaged").
* ci(kimi-desktop): build and attach desktop installers in the release pipeline
Make desktop-build.yml reusable (workflow_call) and invoke it from the
release workflow, mirroring the native-build pipeline, so each release
also attaches signed+notarized macOS, Windows and Linux desktop
installers to the GitHub Release.
* feat(kimi-desktop): brand the desktop as an internal testing build
- Add an inline 'internal testing build' tag next to the Kimi Code brand
in the sidebar header, shown only inside the desktop app.
- Use a hidden native title bar on macOS with the traffic lights folded
into the sidebar header, and pin the window title to the product name.
- Ship the Kimi app icon for macOS and Linux builds.
Desktop detection is runtime (a query hint from the Electron shell,
persisted in sessionStorage) so the branding appears even when the
window is served by an already-running shared daemon.
* docs(kimi-desktop): update v1 scope now that the app icon ships
* feat(kimi-desktop): add the Kimi app icon for Windows builds
* chore(nix): update pnpmDeps hash after lockfile refresh
* ci(kimi-desktop): build desktop on release but do not attach to GitHub Release
The desktop build is an internal-testing artifact (branded as such), so
keep it as a CI artifact for internal download instead of publishing it
to the public GitHub Release.
* chore(kimi-desktop): mark installers as internal pre-release builds
Rename the packaged artifacts to KCD-Internal-<version>-<arch>.<ext> and
bump the version to the 0.1.1-internal.0 pre-release, so a leaked or
forwarded installer file is not mistaken for an official public release.
* feat(kimi-desktop): strengthen the internal-build tag wording
Change the sidebar tag to 'Internal testing · do not distribute' /
'内部测试 · 禁止外传' so the no-distribution intent is explicit.
* feat(kimi-desktop): tweak internal-build tag to '仅供内部测试'
* fix(kimi-desktop): pass the server token to the web UI on launch
Read the daemon's persistent bearer token from <KIMI_CODE_HOME>/server.token
and carry it in the URL fragment (#token=), matching how 'kimi web' opens
the Web UI. Without this, a fresh launch (no saved credential) boots the
web UI without a token, hits 401, and falls into the manual token dialog
even though the desktop started the daemon itself.
Addresses review feedback on the desktop URL.
|
||
|
|
a3f9cec8a9
|
fix(web): deduplicate workspaces shown in the sidebar (#1221)
Collapse registered workspaces that share a root in the daemon registry (preferring the canonical id) and in the web sidebar merge, so the same folder no longer renders as two identical, synchronously-selected entries. |
||
|
|
fc3d69dbdc
|
feat(web): add completion sound and question notifications (#1179)
* feat(web): play a sound when a turn completes Synthesize a short chime when a session finishes a turn. Opt-in via Settings -> Notifications (off by default); the audio context is unlocked on the first user gesture so it also plays while the tab is backgrounded. * feat(web): notify and play a sound when a question needs an answer Reuse the existing notification/sound toggles so they also fire when the agent asks a question (the awaiting-answer state). Generalize the Settings labels to cover both cases. * fix(web): don't queue the chime on a suspended audio context A suspended AudioContext has a frozen clock, so tones scheduled on it would play stale when the context later resumes (e.g. on the next click). Only schedule the chime when the context is actually running; if it is still suspended, try to unlock it for next time and skip this one. * fix(web): gate question notifications behind explicit opt-in Question notifications surface question text, so they must not fire for users who only opted into turn-completion alerts (which default on). Split question notifications into their own persisted preference that defaults off, with a separate Settings toggle. Completion notifications keep their existing default-on behavior. * fix(web): show the question text in question notifications Lead with the actionable question text in the desktop notification body, keeping the short header as context (e.g. 'Storage: Which database?'). Previously the header alone was shown, so users had to open the tab to learn what was being asked. |
||
|
|
dfcfdfd9dd
|
feat(web): hide empty sessions from the session list (#1166)
* chore(web): remove the /sessions slash command
* feat(web): hide empty sessions from the session list
Add an optional exclude_empty parameter to the session list API; the web client passes it so unused "New Session" entries are hidden by default, with pagination and has_more computed on the filtered set.
* fix(protocol): add exclude_empty to the session list query schema
Keep the shared protocol schema in sync with the server route so clients using the protocol type see the new parameter.
* fix(protocol): keep exclude_empty off the child session list schema
listSessionChildrenQuerySchema aliased the main list schema, so it inherited exclude_empty even though the /sessions/{id}/children route does not filter by it. Split it so generated clients are not misled.
|
||
|
|
18f7c34a07
|
feat(web): show edit diffs inline in tool call cards (#1103)
* feat(web): show edit diffs inline in tool call cards Render a line-by-line diff inside Edit/Write tool cards in the web chat, reusing the existing diff-line style from the changes panel. The diff is built client-side from the tool input, so no protocol or server changes are needed; the header chip now shows real +/- counts. * fix(web): extend diff line backgrounds through horizontal scroll Diff rows were only as wide as the viewport, so the add/del background stopped where long lines overflowed and the area revealed by horizontal scroll had no color. Size each row to its content so the background paints the full line. * fix(web): make all diff rows fill the longest line width Size the diff container to the longest line and have every row fill it, so add/del backgrounds form one continuous band across the whole horizontal scroll instead of stopping at each line's own length. * fix(web): resolve oxlint errors in diff line builder Use Array.at(-1) and Array.from instead of index access and new Array(length), which oxlint flags as errors. * fix(web): show tool output for failed edit/write calls When an Edit/Write call fails, render the tool output (the failure reason) instead of the requested diff, so error cards explain why no change was applied. * fix(web): fall back to tool output for replace_all and append edits A single-pair diff misrepresents replace_all edits (which change many occurrences) and from-empty diffs misrepresent append writes (which extend an existing file). Skip the synthetic diff in those cases and render the truthful tool output instead. * feat(web): open edit diffs in the right-side detail panel Move the Edit/Write diff out of the inline tool-card body into the shared right-side detail layer, opened by clicking the card (like the subagent detail panel). The panel shows the line diff when it faithfully represents the operation, otherwise the tool output (replace_all, append, errors), so failed calls explain why no change was applied. * feat(web): toggle detail panels closed when their trigger is clicked again Clicking the same Edit/Write card, file link, or git-status area a second time now collapses the right-side detail panel, matching the existing thinking / compaction / subagent toggle behavior. * fix(web): cap client-side edit diff to avoid freezing on large inputs The line-level LCS allocates an (oldLines+1) x (newLines+1) matrix and runs eagerly when an Edit/Write card renders. For large edits (e.g. a 5k x 5k block, ~25M cells) this can freeze or exhaust the chat. Cap the matrix at 1M cells and fall back to the raw tool output beyond that. * fix(web): keep the edit diff panel in sync with live tool state Store only the tool id and re-derive the diff panel payload from the live tool call in the session turns, so a panel opened while the tool is still running reflects later status/output changes (e.g. an eventual error shows the failure output instead of the stale attempted diff). * fix(web): do not render a synthetic diff for Write calls Write only reports the new content, so the client cannot tell a new file from an overwrite of an existing one. A from-empty diff showed overwrites as all additions and no deletions, which is misleading. Fall back to the tool output for every Write (append already did). * fix(web): also cap diff output rows, not just the LCS matrix The matrix-size cap alone let through asymmetric edits (e.g. one line replaced by hundreds of thousands) whose small matrix still produced a huge row array that the chip computed on render. Cap each side's line count too, so the diff output is bounded. * fix(web): keep edit/write cards expandable when the diff panel is unwired Clicking an Edit/Write card opens the right-side diff panel, but the nested ChatPane in the side chat does not wire that event, so the click became a no-op and the card could no longer expand to show its output. Gate the panel behavior behind a toolDiffPanel prop (enabled only in the main conversation); elsewhere the cards expand inline as before. * fix(web): close the tool diff panel when its target disappears When a session resync removes the tool call an open diff panel is showing, toolDiffTarget becomes null but detailTarget stayed 'toolDiff', leaving an empty aside that Escape would not close. Gate sidePanelVisible on toolDiffVisible so the panel collapses once its target is gone. |
||
|
|
884b65a040
|
fix(web): coalesce snapshot reloads on resync (#1087)
Avoid concurrent session snapshot requests when resync_required fires repeatedly, while still allowing one queued rerun after the in-flight reload settles. |
||
|
|
98d3e5b71d
|
feat(web): stabilize and drag-reorder workspaces in the sidebar (#1047)
* feat(web): stabilize and drag-reorder workspaces in the sidebar * fix(web): preserve dragged workspace order after refresh * fix(web): float session to top of its group on new message * fix(web): align workspace drop order with insertion marker * fix(web): allow dropping a workspace after the last item * fix(web): use reordered workspaces for active fallback * fix(web): honor drag order for next-workspace fallback on removal |
||
|
|
ac1882fe28
|
feat(web): persist collapsed workspace groups to localStorage (#1045) | ||
|
|
9d197e0f67
|
fix(web): make clipboard copy work over plain HTTP (#1044)
* fix(web): make clipboard copy work over plain HTTP
The Clipboard API (navigator.clipboard) is only exposed in secure contexts. When the web UI is served over plain HTTP, every copy action threw synchronously and silently failed. Route all copy call sites through a helper that falls back to execCommand('copy') in insecure contexts, and surface success or failure feedback to the user.
* test: address review feedback and a flaky goal-badge test
- clipboard test: drop the jsdom environment and mock the small navigator/document surface in the default node environment, per the kimi-web "pure logic tests only" rule.
- footer-goal-badge test: assert the absence of the "[goal" badge instead of the bare "goal" substring, which could match a rotating working tip ("/goal ...") and fail depending on Date.now().
|
||
|
|
83384ee6d4
|
fix(web): persist input history so recall works after the first message (#1015)
* fix(web): persist input history so recall works after the first message The composer has two mutually-exclusive instances: the empty-session composer and the docked composer. The first message of a new session is sent by the empty composer, which unmounts as soon as the first turn appears; the docked composer then mounted with an empty in-memory history, so ArrowUp did nothing until a second message was sent. The history was also lost on every page reload. Persist the history to localStorage as a single global list and re-read it on mount. Global (not per-session) because a new session has no id until after the first submit, so per-session keys would not line up across the empty -> docked handoff. Caps the list at 200 entries. Adds persistence-focused unit tests (surviving a remount, the 200-entry cap, and a malformed stored value). * fix(web): record slash commands in input history too Move the history.push call ahead of the slash-command branch so that known commands (with or without args, e.g. /goal <task> or /model) are recorded and can be recalled with ArrowUp, instead of only plain messages. Steer already pushed; only the submit slash path was missing it. * fix(web): record menu-selected slash commands in history Bare slash commands picked from the slash menu (e.g. /model, /login) go through selectSlashCommand and emit directly, never reaching handleSubmit, so they were not recorded even after the typed-slash fix. Push the command name before emitting. acceptsInput commands are still recorded later by handleSubmit together with their argument. |
||
|
|
d4ae02d82e
|
fix(web): keep sidebar unread dots in sync across browser tabs (#978) | ||
|
|
3b9938b4c3
|
refactor(web): consolidate localStorage access and split appearance/notification modules (#973) | ||
|
|
a74a6b7f6b
|
fix(web): improve slash menu and skill editing experience (#878)
* fix(web): keep slash skills editable * fix(web): wrap long slash menu entries * fix(web): rank exact slash matches before substrings |
||
|
|
9a8fea5c85
|
feat(web): introduce Kimi web app and daemon gateway (#625)
* docs(reports): collapse P3 plan into a single final-solution doc Drop the per-step TDD/commit scaffolding; keep the substance as one final approach per area (what it does, files to touch, key types/events/projection, component responsibilities, verification, risks, sequencing). * fix(kimi-web): normalize chat block spacing Group consecutive tool cards structurally so chat block spacing is applied consistently without leaking card borders or shadows. * feat(web): land P3 — goal / swarm / subagent + terminal + view split Implements the locked P3 design end-to-end: - subagent lifecycle projection (spawned→started→suspended→completed/failed) + inline Agent / AgentGroup cards; swarm progress card (multi-column) derived from swarmIndex; goal dock strip (expandable) from goal.updated; plan/goal/ swarm activation badges in the composer status line. - terminal as a view (xterm + WS terminal_* frames with since_seq replay) and a tab/view-dimension split (usePaneLayout tree + ViewGroup + SplitLayout, VSCode editor-group style), persisted to localStorage. Adds swarm-groups / subagent-goal / agent-group-turns unit tests and stub-daemon seeds. 98 tests pass; vue-tsc + oxlint clean; production build OK. Accepted by review (see reports/web-p3-acceptance.md); no blocking issues. * docs(reports): P3 landing acceptance review Comprehensive acceptance of the P3 landing ( |