The daemon lock now records the host CLI version and entry path. When
kimi web / kimi daemon finds a healthy daemon started by a different
build (e.g. an older pkg.pr.new install), it warns that the running
daemon lags the invoked CLI instead of silently reusing it; the new
--restart flag stops the managed daemon and starts a fresh one with the
current build. A daemon whose lock does not match the requested port
(foreign process on the port) is never stopped.
- Simplify session timestamps: drop 'ago' suffix (1h ago → 1h)
- Replace running status text with a non-intrusive pulse dot on session title
- Add hover-triggered kebab menu for workspaces (copy path, rename)
- Speed up fold expand/collapse animation (0.28s → 0.12s)
- Quick-start input for empty workspaces in conversation pane
- add optional DaemonStartupReporter callback to ensureDaemonRunning\n- report startup progress in daemon and web CLI commands\n- update unit tests to cover reporter output
- Replace emoji with inline SVG icons for attach/permission/plan buttons
- Unify attach-btn, perm-pill, toggle-pill styles (same padding/radius/font)
- Add SVG icons in permission dropdown rows
- Convert context bar from horizontal bar to circular SVG ring
- Strip provider prefix from model display name; fall back to models list lookup
- Load models eagerly on app init for friendly name resolution
- Increase toolbar and dropdown font sizes
- Increase textarea default height from 40px to 56px
- Remove plan/permission/ctx from model dropdown (keep only models + thinking)
- Fix ctx number spacing (remove spaces around slash)
2f229b3 added the image-resolving watcher above the defineProps call.
watch() invokes its getter synchronously to collect dependencies, so
the closure read props while the const was still in its temporal dead
zone — every Markdown mount threw 'Cannot access props before
initialization', crashing the whole chat transcript (session content
rendered blank, Vue warn loop in console). vue-tsc can't catch this
(the reference sits inside a closure). Verified by a mount test that
reproduced the ReferenceError before the move and passes after, plus
an in-browser check that session content renders again.
- add kimi web subcommand to open the daemon-hosted browser UI\n- refactor kimi daemon to start in background by default; add --foreground flag\n- serve web assets from daemon via new registerWebAssetRoutes\n- copy kimi-web build output into CLI bundle at build time\n- update docs for daemon and web commands\n- add unit tests for daemon and web command handlers
A prompt queued while the agent is busy can carry image attachments
with no text; the queue strip rendered its bare text — an empty string,
so the row was just a blank button next to a remove cross. Queue items
now expose {text, attachmentCount}: image-only prompts render an
'image ×N' placeholder with a small badge, and any item carrying
images disables the load-back-into-input edit action (the uploaded
files can't be restored to the composer; editing would silently drop
them — remove stays available). Verified with component render tests
for the three shapes (image-only / text-only / text+images).
- move event payloads and tool display schemas from agent-core into protocol\n- make agent-core depend on protocol instead of the reverse\n- remove alias workarounds in protocol build config\n- add changeset for agent-core, protocol, and kimi-code
- Replace `@moonshot-ai/kimi-code-sdk` with `@moonshot-ai/agent-core` in protocol\n- Remove `@moonshot-ai/kimi-code-sdk` from services dependencies\n- Introduce internal `managedAuth` facade in services to replace `KimiAuthFacade`\n- Add compile-time assertions that neither package references the node SDK
The follow-to-bottom gate was an atBottom position snapshot updated by
scroll events, which broke in three ways users hit daily:
- the scroll event fired by our own pin could observe a view that had
already grown past the 80px threshold mid-stream (thinking / tool
phases) and flip the gate off — the view stopped above the newest
content and a 'new messages' pill appeared without any user scroll;
- QuestionCard replaces the Composer in the bottom dock OUTSIDE the
scroller, so its appearance (and the composer growing via queue strip
/ attachments / multiline input) shrank the scroll viewport without
producing a single scroll or mutation event — nothing re-pinned and
the newest message stayed hidden behind the dock;
- sending a prompt while scrolled up only raised the pill.
following is now an intent flag: it turns off ONLY when the user
scrolls up out of the bottom zone (our own scrolls always move down,
so an upward scrollTop is always user intent; sub-80px drifts never
break it), and back on when they return, click the pill, send a
prompt, answer a question, or switch session/tab. ResizeObservers on
the dock, the scroller and the content column re-pin on pure layout
changes (the QuestionCard case and image loads), without raising the
pill; the 1200ms stick-window machinery is replaced by the flag.
Also re-pins on visibilitychange (background tabs freeze rAF).
Verified e2e against the stub daemon: full-stream follow stayed within
1px across thinking/tool/approval phases (155 samples); mid-stream
scroll-up stopped following and raised the pill; sending and answering
while scrolled up force-pinned; QuestionCard appearance kept the view
pinned (max 1px); content-collapse clamp events did not break follow.