Commit graph

705 commits

Author SHA1 Message Date
Haozhe
efce74e435
fix(cli): show the full remote control link in the startup output (#3331) 2026-08-28 15:54:19 +08:00
Kimi Agent
0310f223da
fix(cli): give the interactive update check a longer CDN timeout (#3307)
* fix(cli): give the interactive update check a longer CDN timeout

`kimi update` shared the 3-second CDN fetch budget sized for passive
background checks. Every CLI invocation is a fresh process paying full
DNS+TCP+TLS setup, so a slow connection to the CDN intermittently
aborted the interactive check with a raw "This operation was aborted".

Thread a per-request timeout through the CDN fetch helpers and
refreshUpdateCache; the interactive upgrade command now passes a 10
second budget (INTERACTIVE_UPDATE_CHECK_TIMEOUT_MS) while all
background refresh paths keep the 3-second default.

* refactor(cli): drop motivational comments and simplify the update-check changeset

* docs(cli): reword the update-check changeset

* docs(cli): English changeset for the update-check timeout

---------

Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
2026-08-28 12:21:57 +08:00
Kimi Agent
15f3d93613
fix(vscode): bundle immer into vsix extension (#3304)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (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 / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
Release / Release (push) Waiting to run
Release / Deploy docs (push) Blocked by required conditions
2026-08-27 23:25:08 +08:00
github-actions[bot]
52e8d19dbd
ci: release packages (#3140)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-27 19:33:51 +08:00
liruifengv
df9e858388
chore: sync web dist from code-app (#3296)
* chore: sync web dist from code-app

code-app: 758f4587d10e28de8ac04678df8e379ca0f10387

* chore: consolidate web dist changesets by theme

* chore: trim web dist changesets to headline items

* chore: drop web prefix from fix-known-issues changeset

* chore: drop web-mobile-interaction changeset as duplicative of existing mobile entries
2026-08-27 19:30:07 +08:00
7Sageer
bd5e32f683
fix(secondary-model): stop rewriting the section when providers refresh or are removed (#3284)
* fix(secondary-model): stop rewriting the section when providers refresh or are removed

Provider refresh, provider deletion/rename, catalog/registry import,
OAuth logout, and SDK removeProvider used to cascade into the user's
[secondary_model] block: pool entries were silently pruned, and the
whole section was deleted when its effective default dangled. The
cascade ran from a cache-refresh path (including an unattended 6h
scheduler), so upstream model-list changes could irreversibly destroy
hand-written configuration without any notice.

Config is user intent; the catalog is an availability snapshot. Stop
rewriting the section on every provider/models writer. An entry whose
model no longer resolves fails pool validation on the next session
create with a message naming the offending alias, which is the same
fail-fast contract hand-written typos already had.

* chore(sdk): add changeset for the removed secondary-model cascade export

* Delete .changeset/sdk-remove-secondary-model-cascade.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* Delete .changeset/secondary-model-no-silent-rewrite.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>
2026-08-27 16:50:42 +08:00
liruifengv
7066950653
fix(oauth): show a cancelled state when authorization is denied on the web page (#3291)
* fix(oauth): show a cancelled state when authorization is denied on the web page

* chore: drop the changeset and the dist-web sync from this PR
2026-08-27 16:20:48 +08:00
Grapedge
f34b2ecfb0
fix(vscode): serialize per-view session opens to stop duplicated streaming (#3276)
Concurrent openSession/attachResumedSession calls for the same webview
both missed the sessions map before either wrapped the SDK session, so
one Session facade got two SessionRuntimes. The overwritten runtime
leaked and kept broadcasting, doubling every streamed delta and tool
call in the view. Queue opens, attaches, and detaches per webviewId so
the second caller sees the first one's runtime.
2026-08-27 15:19:24 +08:00
Haozhe
04fdb49627
fix(kimi-code): reconnect remote control tunnel after silent relay death (#3283)
Add a liveness watchdog on the management and HTTP tunnel WebSockets
(client ping every 30s, terminate after 300s without inbound activity)
so the client recovers when a relay redeploy drops connections without
a close frame. Treat registration failures after a successful session
as transient and keep backing off instead of stopping permanently.
2026-08-27 14:02:29 +08:00
LCZcn96
75550c5686
fix(vscode): restore live context usage on v2 (#3098)
* fix(vscode): restore live context usage on v2

* chore: point changeset at vscode extension and node-sdk packages
2026-08-26 19:57:50 +08:00
Kimi Agent
41a75adfc7
fix(tui): recompute stale context usage ratio from status update token counts (#3164)
v2 engine status events carry contextTokens/maxContextTokens but never
contextUsage, so appState.contextUsage was only refreshed by getStatus
pulls and then went stale while the token counts kept updating live.
The /usage panel and footer render the ratio as a bar but recompute the
percentage text from the counts, so a stale ratio showed as a bar that
disagreed with the percentage (e.g. bar ~74% next to "18% (180k / 1M)"
after compaction or a model switch).

Recompute the ratio from the post-patch token counts whenever a status
update touches contextTokens or maxContextTokens without carrying an
explicit contextUsage. v1 events carry the ratio and are unaffected.

Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
2026-08-26 13:59:24 +08:00
Haozhe
de0f6b179e
fix(kimi-code): render newlines instead of literal backslash-n in rc output (#3244)
* fix(kimi-code): render newlines instead of literal backslash-n in rc output

* fix(kimi-code): print plain URL in rc output when hyperlinks are unsupported
2026-08-25 21:23:39 +08:00
Haozhe
f0a609487f
feat(kimi-code): add remote control web tunnel (#3034)
* feat(kimi-code): add remote control web tunnel

Add CLI and TUI entry points for exposing the local web UI remotely.
Bridge HTTP and WebSocket traffic with local authentication and reconnect handling.

* fix(kimi-code): prevent remote control websocket crash

* fix(kimi-code): align websocket dependency versions

* fix(kimi-code): harden remote control connection setup

Reconnect when management closes during the HTTP tunnel handshake.
Reject non-loopback Remote Control binds whose CSP blocks path bootstrap.

* fix(kimi-code): fix remote control rewriting, caching, and WS frame loss

* feat(kimi-code): add remote control QR output

* build: update pnpm dependencies hash

* refactor(kimi-code): remove the --allow-remote-terminals flag

* feat(kimi-code): add remote control lock, rc command, and QR fixes

* fix(kap-server): broadcast user prompts to all session clients on submit

- agent-core-v2: emit prompt.submitted (status running|queued) at enqueue and prompt.started when the turn launches
- kap-server: project prompt.submitted/prompt.started into transcript prompt entities and the live transcript REST response
- update flake.nix pnpmDeps hash for the PR lockfile

* fix(node-sdk): drop v2-only prompt.started from SDK event stream

- event-mapper: add prompt.started to the dropped v2-only prompt lifecycle types (parity with submitted/completed/aborted/steered)
- cli test: assert only visible sub-commands and stub the experimental flag env for determinism

* ci(pkg-pr-new): post custom install comment for npm 12 compatibility

* feat(kimi-code): render remote control QR as inline image on capable terminals

* feat(kimi-code): improve remote control terminal output

- add onboarding, security, device management, and help guidance
- show compact clickable links and QR image fallback details
- report relay and remote device connection lifecycle

* test(agent-core-v2): update tool event snapshot

* revert(ci): keep preview workflow unchanged in rc pr

---------

Co-authored-by: liruifengv <liruifeng1024@gmail.com>
2026-08-25 20:22:06 +08:00
Kimi Agent
d1a46db94e
fix(tui): render /plugins marketplace before version lookups resolve (#3219)
* fix(tui): render /plugins marketplace before version lookups resolve

The Third-party/Official tabs waited on the slowest GitHub
releases/latest lookup before painting any catalog row, with no
timeout (undici defaults: 10s connect, 300s headers) and no caching,
so a stalled connection to github.com left the panel on "Loading
marketplace…" for minutes on every /plugins open.

Load in two phases: render the catalog as soon as it is parsed, then
resolve latest versions in the background (5s per-lookup timeout,
per-entry failures degrade to a missing badge) and refresh when they
land. Update badges appear slightly later; row order is unaffected
since sorting only depends on installed state.

* refactor(tui): move marketplace version lookup timeout to constants

Per AGENTS.md, application constants live in src/constant/ — moves
MARKETPLACE_VERSION_LOOKUP_TIMEOUT_MS next to the other marketplace
constants in constant/app.ts.

* fix(tui): resolve marketplace versions before built-in injection

Phase 1 injected built-in capability rows into the marketplace before
phase 2 ran, masking the matching catalog entries' GitHub sources
behind capability:<id> rows — so installed built-ins could never
receive update badges (the pre-change resolve-then-inject ordering
preserved them).

Keep the raw parsed catalog for phase 2, re-apply withBuiltInEntries
after versions resolve (resolved versions flow onto capability rows),
and keep the built-ins-only fallback when the catalog is unreachable.

* fix(tui): surface marketplace parse errors instead of masking them

The phase-1 catch converted every failure into a built-ins-only loaded
marketplace, hiding malformed-catalog errors behind a silently empty
Curated tab. Restore the error state for all phase-1 failures — the
panel already keeps built-in capability rows installable in the
Official tab while the error is displayed.

---------

Co-authored-by: kimi-agent-bot <kimi-agent-bot@users.noreply.github.com>
2026-08-25 17:31:48 +08:00
7Sageer
8ddcb5ca13
fix(kimi-code): persist picked thinking effort up to the model's default effort (#3205)
* fix(kimi-code): persist picked thinking effort up to the model's default effort

The persistence gate kept the model's top declared effort session-only
unconditionally, so users whose delivered default_effort is the top tier
(e.g. max) could never save an explicit pick of it. Compare the pick
against the model's default_effort instead, using support_efforts as the
strength ordering: picks above the default stay session-only, picks at
or below it persist. Models without a declared default keep the
historical top-tier rule. The same change lands in the VS Code
extension's mirrored logic.

* docs(kimi-code): document the effective-default ceiling for effort persistence

Clarify in both apps' comments, the changeset, and the config docs that
the persistence ceiling is the model's effective default effort, whether
declared via the catalog / overrides or synthesized by the protocol
profile inference (Claude models resolve to high, so an xhigh pick is
session-only there). Pin the inference path with tests in both apps.

* fix(vscode): resolve the save-config model with its provider type

Mirror the TUI's effectiveModelForHost: without the provider type the
Anthropic fallback profile (e.g. claude-latest) never matches, so the
inferred default effort that gates persistence was missed and an
above-default pick could persist where the TUI keeps it session-only.

* Delete .changeset/persist-effort-up-to-model-default.md

Signed-off-by: 7Sageer <sag77r@hotmail.com>

* fix(vscode): seed the persisted effort with the effective-default ceiling

* fix(vscode): project webview models with the provider type

* fix(kimi-code): apply a session-only effort pick to the runtime in the /provider flow

* fix(vscode): update the persisted-effort seed on model-switch saves

* docs(kimi-code): drop the default_effort persistence-ceiling note

---------

Signed-off-by: 7Sageer <sag77r@hotmail.com>
2026-08-25 12:18:26 +08:00
Haozhe
243f348329
refactor(agent-core-v2): drop in-place system prompt refresh (#3211)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (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 / Publish native release assets (push) Blocked by required conditions
2026-08-24 21:55:23 +08:00
Haozhe
71caabdc6d
feat(kap-server): add workspace-agnostic multi-root POST /api/v1/fs:suggest (#3210) 2026-08-24 21:37:41 +08:00
Haozhe
a664226bf2
fix(tui): preserve active session after provider logout (#3212) 2026-08-24 21:22:15 +08:00
tpoisonooo
15f20537c7
fix(tower): remove command queue (#3193)
* fix(tower): remove command queue

* feat(agent-core-v2): support an explicit base branch in TowerInit

* fix(kimi-code): keep tower objective order across a mid-turn compaction

* feat(agent-core-v2): add abandoned tower mission status to release stale scopes

* chore: consolidate tower changesets into one feature entry

* chore: consolidate tower changesets into one feature entry

---------

Co-authored-by: konghuanjun <konghuanjun@moonshot.ai>
2026-08-24 20:30:04 +08:00
Haozhe
9a715820c4
refactor(agent-core-v2): featurize todo/cron/interaction and migrate goal to agent runtime (#3184)
Some checks are pending
CI / test-windows (push) Waiting to run
CI / lint (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (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 / Publish native release assets (push) Blocked by required conditions
* refactor(agent-core-v2): featurize todo/cron/interaction and migrate goal to agent runtime

* refactor(agent-core-v2): move cron scheduling helpers into features/cron/internal
2026-08-23 23:03:51 +08:00
Haozhe
368b4b7400
refactor(agent-core-v2): migrate agent domains to agent runtime architecture (#3175) 2026-08-23 17:36:59 +08:00
liruifengv
d4e0ad4b2d
chore: sync web dist from code-app (#3166)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (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 / Deploy docs (push) Blocked by required conditions
Release / Native release artifact (push) Blocked by required conditions
Release / Publish native release assets (push) Blocked by required conditions
Release / Release (push) Waiting to run
* chore: sync web dist from code-app

code-app: 8c911c08ad

* chore: drop the rc device switcher changeset
2026-08-21 21:03:29 +08:00
liruifengv
491ebd050f
chore: sync web dist from code-app (#3157)
code-app: 9c669bd169
2026-08-21 15:30:17 +08:00
Grapedge
54bb49e138
fix(kimi-code): keep the previous turn's answer visible when a cron turn ends (#3154) 2026-08-21 15:01:07 +08:00
qer
0f44537c13
feat(agent-core-v2): turn /tower into a mode parallel to plan mode (#3099)
* feat(agent-core-v2): turn /tower into a mode parallel to plan mode

* feat(agent-core-v2): align /tower command semantics with the original skill behavior

* fix(tui): harden the /tower command against mid-turn objectives, legacy engines, and stale status

* fix(agent-core-v2): keep restored tower state inert while the feature flag is off

* fix(agent-core-v2): include TowerInit in the mode tool overlay and report flag-gated tower state

* feat(agent-core-v2): expose tower control tools statically and make the mode injection history-derived

* fix(tui): warn that tower mode needs a restart after a live flag flip; drop redundant undefined from SessionStatus mode fields

* fix(agent-core-v2): let tower mode exit clear persisted state while the flag is off

* fix(agent-core-v2): emit the tower exit reminder through a disabled flag and drop the redundant REST state comparison

* fix(tui): show the Tower mode status row only when the experiment is available

* fix(agent-core-v2): confine tower mode to the main agent and always re-assert it for objectives

* feat(kap-server): project tower mode into transcript modes and reassert explicit toggles

* fix(agent-core-v2): fold the main-agent invariant into the effective tower state

* fix(kap-server): gate the cold tower mode badge behind the experiment flag

* fix(agent-core-v2): reapply the tower tool overlay after a profile bind; fix(kap-server): clear cold tower badges on non-main agents

* fix(protocol): mirror towerMode and tower_mode in the shared zod schemas

* test(agent-core-v2): adapt tower tests to the agent lifecycle context architecture

* chore(agent-core-v2): regenerate the wire manifest; test(node-sdk): look up the main agent via findAgentHandle

* fix(agent-core-v2): exit a replayed tower mode when the workspace belongs to another session

* fix(agent-core-v2): carry tower ownership in the enter record so forks clear inherited mode

* fix(agent-core-v2): apply the tower overlay before dispatching enter and repair it on status updates

* fix(agent-core-v2): validate store ownership before entering tower mode

* fix(agent-core-v2): claim the repository tower owner at enter; fix(tui): confirm mode activation before reporting success

* fix(agent-core-v2): make the first tower claim exclusive and refuse adoption over a live owner

* feat(agent-core-v2): guard tower adoption and teardown with a cross-process ownership lease

* revert(agent-core-v2): drop the cross-process lease and enter-time claim, keep ownership checks process-local

* fix(agent-core): hide the v2-only tower flag from the legacy experiments list

* fix(agent-core-v2): keep tower mode inert until the tower feature is assembled

A live /experiments flip refreshes the flag but cannot re-run App-scope
feature assembly, so the tower tools/profile stay unregistered until a
restart. Gate enter()/isActive on the assembly fact and say so in the
TUI error. Also resolve the AGENTS.md conflict block committed by the
merge, and widen the TUI experimentalFlag type to string now that flags
live in two registries.

* fix(kap-server): gate the cold tower badge on tower feature assembly

Same live-flip gap as the mode machinery: a persisted tower_mode.enter
plus a flag enabled without a restart would still show the badge while
the feature is inert. Require isTowerFeatureAssembled() alongside the
flag, re-exported from agent-core-v2.

* fix(agent-core-v2): liveness-aware tower entry and per-App assembly state

enter() now mirrors TowerInit's adoption rule: a stored owner blocks
entry only while that session is live in this process, so a new session
can enter the mode and reach TowerInit to adopt a stale tower. The
assembly marker is keyed by each App's flag service (WeakSet) instead of
process-global module state, so coexisting Apps no longer leak assembly
into one another.

* fix(agent-core-v2): keep stale-owner adoption across resume; reject tower updates that do not take

exitForeignTower now treats a stored owner as foreign only while that
session is live, so a mode entered by adopting a dead owner's tower
survives close/restart. The TUI validates the model prerequisite before
enabling tower for an objective, and the REST agent_config path throws
session.tower_mode_invalid when enter() did not take effect instead of
acknowledging a no-op.

* fix(agent-core-v2): clear the tower assembly marker when the feature unloads

Register the WeakSet cleanup via the feature's onDispose so the
capability follows the managed unit's lifecycle — after
unprovideUnit('tower'), isActive/enter() no longer treat the retracted
tool set as assembled.

* fix(agent-core-v2): publish tower deactivation on gate loss; reject refused setTowerMode in the SDK

isActive now reconciles its projection: restore and feature-manager unit
changes publish AgentStatusUpdated({ towerMode: false }) when the
persisted mode lost a gate (flag off at runtime, feature unloaded), so
live transcript badges and TUI state stop showing an inert mode. The
SDK's setTowerMode(true) verifies the effective state and throws
session.tower_mode_invalid, matching the REST path.

* fix(agent-core-v2): reconcile tower projection on config changes and cold ownership moves

The last unreconciled gate inputs: a live setConfig writing the
experimental section (no session reload, no units event) now republishes
towerMode:false through the config-change subscription, and the cold
transcript badge mirrors the same ownership/liveness rule as enter() —
retained while the store owner is this session or no live session, cleared
once a live session elsewhere owns the tower.

* fix(agent-core-v2): reconcile the tower projection in both directions

The OFF-only reconcile left a hole: re-enabling the flag in the same
process made isActive true again with no towerMode:true publish, and
enter() could not heal it (it early-returns when already effective).
The projection now tracks the last published state and emits both
false→true and true→false transitions from the same restore/units/config
triggers; direct publishes (enter/exit/restoreTowerTools) keep the
tracker in sync.

* fix(agent-core-v2): validate forked tower ownership even while the flag is off

exitForeignTower's flag short-circuit let a fork restored while the
experiment was disabled keep its inherited enter record; re-enabling the
flag later revived both source and fork over the same store. Ownership
validation is flag-independent state hygiene, so restore now runs it
regardless of the effective flag — a live foreign owner clears the
fork's persisted mode before any gate can rise again.

* fix(agent-core-v2): veto tower tools while the tower experiment is off

With the feature assembled and the tool overlay active, disabling the
flag live left TowerInit/TowerTeardown callable — they have no flag
check — so prompts could still mutate or dismantle .tower/ while the
experiment reported disabled. A dedicated onBeforeExecuteTool hook now
denies every tower tool whenever the flag is off, mirroring the TodoList
veto.

* fix(agent-core-v2): keep tower worker write isolation when the flag turns off

The worker Write/Edit guard is identity-scoped (tower-worker profile),
not feature-activity-scoped: disabling the experiment live must not let
already-spawned detached workers write into the main checkout or other
worktrees. The guard no longer checks the flag; the tower-tool veto
added earlier covers protocol access instead.

* test(agent-core-v2): make tower tests hermetic for CI

Three CI-only failures: towerService git fixtures committed without a
repo-local identity (CI has no global gitconfig), the node-sdk tower
positive tests relied on the developer shell's
KIMI_CODE_EXPERIMENTAL_FLAG=1 master switch instead of enabling the
tower flag explicitly, and the legacy harness experimental-features
expectation still listed the tower entry removed from the v1 registry.
2026-08-21 14:47:37 +08:00
liruifengv
3090c1c482
chore: sync web dist from code-app (#3152)
Some checks are pending
CI / typecheck (push) Waiting to run
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (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 / Publish native release assets (push) Blocked by required conditions
code-app: a46821efc6
2026-08-21 11:31:35 +08:00
github-actions[bot]
0999454bdc
ci: release packages (#3074)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-20 21:11:45 +08:00
liruifengv
2c5415f930
chore: sync web dist from code-app (#3135)
code-app: 6c99acc282
2026-08-20 21:09:01 +08:00
Haozhe
fc0f275dd4
refactor(agent-core-v2): extract goal domain into a self-contained feature (#3130) 2026-08-20 19:52:57 +08:00
Haozhe
3fdce983f8
fix: drain in-flight persistence and log writes on session close and shutdown (#3122) 2026-08-20 17:19:20 +08:00
liruifengv
97c2159791
feat(kimi-code): load startup banner from client_configs (#3117)
The startup banner now comes from the backend client_configs endpoint
(config name client_banner) instead of the CDN-hosted tips.json, and is
fetched fresh on every startup with no caching. The payload keeps the
tips.json shape, plus two targeting additions:

- banner_platform (top level and fallback entries) limits display to
  the given platform; missing, empty, or all means every platform, and
  the CLI only shows entries targeting all or cli.
- banner_start_time/banner_end_time on fallback entries add scheduled
  visibility windows with the same semantics as the active banner.
2026-08-20 16:54:55 +08:00
Haozhe
a09d904140
refactor(agent-core-v2): migrate agent domains to model-as-container architecture (#3103) 2026-08-20 16:06:59 +08:00
Grapedge
cfc3350483
feat(kimi-code): collapse long ! shell command output (#3054)
Finished `!` output collapses to the first 10 visual rows with a `... (N more lines, ctrl+o to expand)` marker, sharing the global ctrl+o toggle with agent tool output; ctrl+o also expands the live buffer while the command runs. Replayed output mounts the same card and behaves identically. The shared truncation component, the running card's default view, and the agent bash path are unchanged.
2026-08-20 14:55:38 +08:00
qer
03dcfcf6d0
feat(datasource): add NDA/NBS, standards, IGO, xhcj, and caixin sources (#3115)
* feat(datasource): add NDA/NBS, standards, IGO, xhcj, and caixin sources

* fix(datasource): narrow real-time-news ban to coverage gaps, require PublishTime citation

* fix(datasource): scope the real-time-news limitation to coverage gaps only

* fix(datasource): trim redundant clause in the real-time-news limitation

* fix(datasource): stop on a result that covers the question, not the first success

* fix(datasource): front-load trigger terms in the skill listing description

* fix(datasource): exempt discovery calls from the one-call workflow
2026-08-20 14:16:15 +08:00
Haozhe
15da84606a
feat(kap-server): add workspace-grouped sessions view and lifecycle events (#3114)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (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 / 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 / Publish native release assets (push) Blocked by required conditions
Nix Build / Check flake.nix workspace sync (push) Waiting to run
GET /api/v2/sessions gains view=by_workspace: one request returns every
workspace with a matching session, each carrying its first group.page_size
sessions under the requested sort plus the workspace's full matching total,
with group-level page_token pagination (40922 on condition drift). Groups
key on the alias-canonical workspace id, so legacy split buckets of one
physical directory merge into a single group, matching the v1 alias
semantics. meta.has_prompt filters sessions by prompt presence (the v1
exclude_empty equivalent) in both views. The flat view and v1 routes stay
byte-compatible.

The global WS stream now fans out event.session.archived (live and cold
paths; payload carries the session id and workspace_id) and
event.workspace.created/updated/deleted, published by the core
IWorkspaceService on every mutation path including the implicit
createOrTouch on session creation.

kimi-inspect consumes the grouped projection as a single-column
workspace/session tree in the chat view; the session pane merges into the
right dock as the Session tab. The server API reference (en + zh) documents
the new parameters, the grouped response, and the new events.
2026-08-20 13:45:38 +08:00
liruifengv
3d7762003a
feat(kimi-code): support two OAuth login endpoints (#2862)
* feat(kimi-code): add China/International region selection for OAuth login

- Add region profiles (cn/overseas) and resolver in @moonshot-ai/kimi-code-oauth:
  env override → persisted login host → install-channel marker → default cn
- /login now offers Kimi Code (China) / Kimi Code (International); the CLI
  login entries (kimi login, kimi acp --login) accept --region cn|overseas
- Update/plugin/site/telemetry endpoints derive from the selected region;
  plugin trust list covers both .com and .ai hosts
- kap-server: POST /oauth/login accepts an optional region; new GET /oauth/region

* fix(oauth): keep an explicit default-slot login ahead of the install marker

A China login persists no oauthHost (the default credential slot carries
no host trace), so after switching back from International the resolver
fell through to a stale overseas install marker. Treat a persisted
default-slot oauth ref (key === oauth/kimi-code) as an explicit-cn signal
that outranks the marker; getRegion() on the v2 side mirrors it.

* fix(agent-core-v2): thread the default-slot key through capability region resolution

Capability installs resolved the region from the persisted oauthHost only,
so an explicit China login (which persists no host) lost to a stale
overseas install marker. Pass the oauth ref key through as well, matching
getRegion(). Also move the region contract notes into the auth.ts file
header per the package comment convention.

* fix(agent-core-v2): honor the region-marker opt-out for the telemetry endpoint

Hosts that set KIMI_CODE_REGION_MARKER=off (the desktop embedded server)
skip the install marker in getRegion(), but the default telemetry endpoint
still consulted it, so a stale overseas marker could split the reported
region from the telemetry destination.

* feat(cli): show region site domains in login platform selector

* chore: reword oauth login changesets

* fix: honor the region marker opt-out in the CLI and capability resolvers

* refactor: rename login region values to mainland-cn and global

* fix: keep the --region help text in English

* fix: simplify the --region help text to site domains

* feat: drop the suggested login platform order

* feat: split a browser-safe region profile table out of the region resolver

* Revert "feat: split a browser-safe region profile table out of the region resolver"

This reverts commit a037b1143e.

* fix: read the install marker from the bootstrapped home directory

* fix: resolve the server plugin marketplace from the active login region

* feat: expose the login region option through the klient auth facade

* fix: drop a comment from the v2 auth region test

* fix: keep scoped base-only logins on their environment for a bare login

* fix: invalidate the region cache on the provider-manager logout path

* fix: route client-config fetches through the active region profile

* fix: resolve the telemetry endpoint per flush so a login region switch applies in-process

* test: expect the telemetry endpoint resolver in the CLI init assertions

* fix: resolve the default telemetry endpoint from the bootstrapped home

* chore: reword the oauth login changeset around the two login methods

* chore: trim the oauth login changeset to the headline

* feat: let hosts override the region marker env through the server bootstrap env bag
2026-08-20 11:24:02 +08:00
Haozhe
16499408d5
refactor(agent-core-v2): extract externalHooks into a scope-organized feature (#2805)
Move the external hook services out of app/externalHooksRunner,
session/externalHooks, and agent/externalHooks into
features/externalHooks, assembled as the ExternalHooksFeature unit:

- services live under per-scope subdirectories (app/, session/, agent/);
  shared pure helpers (types, hook matching/dispatch, process spawn,
  prompt result rendering) live under internal/
- the runner and the two observers are contributed through the Feature
  seams (ScopeUnits materialization); the hooks config section stays on
  the static import=register channel
- update the package entry leaf exports, the plugin domain imports, the
  kap-server events-zod import, and the affected tests; regenerate the
  state manifest
2026-08-19 16:52:51 +08:00
Rick
35befdcef2
fix(vscode): multi-select question jumps to next after only one answe… (#3079)
* fix(vscode): multi-select question jumps to next after only one answer selected

* chore: add changeset

---------

Co-authored-by: gaoyuan <gaoyuan@moonshot.ai>
2026-08-19 16:27:07 +08:00
Luyu Cheng
01eeacb59b
feat(kimi-code): specialize the WaitFor tool's transcript display (#3066)
* feat(kimi-code): specialize the WaitFor tool's transcript display

* feat(agent-core-v2): emit status progress while WaitFor is pending

* fix(kimi-code): route WaitFor dimming through the TUI theme

* feat(kimi-code): support replaceable status updates in tool progress

* fix(kimi-code): forward status progress to subagent activity surfaces

* fix(agent-core-v2): drop the redundant undefined from ToolUpdate.replace

* fix(kimi-code): honor replace semantics in the subagent live status path

* test(agent-core-v2): drive the WaitFor progress test through a manual tick

* fix(kap-server): mirror ToolUpdate.replace in the ws event schema

* refactor(agent-core-v2): expose the WaitFor progress scheduler as a public seam

* fix(kimi-code): pass child wait statuses without the trailing newline

* feat(agent-core-v2): tick the WaitFor progress status every second

* feat(agent-core-v2): format WaitFor progress durations as 1m 15s

* feat(agent-core-v2): omit zero seconds and minutes in WaitFor durations
2026-08-19 14:15:38 +08:00
github-actions[bot]
c41fadf0f7
ci: release packages (#3062)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-19 01:37:58 +08:00
qer
5c661f4610
chore: sync web dist from code-app (#3061)
code-app: 221c548c98
2026-08-19 01:33:29 +08:00
github-actions[bot]
1e553fc73b
ci: release packages (#3049)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-18 22:29:43 +08:00
7Sageer
c9c34ae5a8
fix(kimi-code): upload pasted videos to the daemon file store (#3047)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (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 / Publish native release assets (push) Blocked by required conditions
* fix(kimi-code): upload pasted videos to the daemon file store

Video paste staged a cache copy and submitted a bare file:// video_url,
which the v2 engine no longer resolves, so the submission failed and the
persisted history retried it on every turn. Mirror the image flow
instead: upload the paste to the daemon file store in the background and
submit a kimi-file:// reference that the engine's prompt intake
materializes. A video whose upload is still in flight, failed, or
expired now refuses the submission with an actionable error, since video
bytes have no inline fallback form.

* test(kimi-code): fix MessageDriver recallStashedMedia signature
2026-08-18 20:52:27 +08:00
github-actions[bot]
04944f380a
ci: release packages (#2932)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-08-18 19:19:18 +08:00
liruifengv
e31b3a335e
chore: sync web dist from code-app (#3043)
* chore: sync web dist from code-app

code-app: 1fb57f0ee3

* chore: sync web dist from code-app

code-app: 93da508d079b0118cc0338da97dcb738f0a3d46f

Adds the web session admin page. Built from the code-app PR #261 branch tip before its merge; the squash-merged main tree is expected to be identical (will be checked at merge time and rebuilt here if not).

* chore: correct the code-app trailer of the previous sync commit

The previous commit's trailer had a mistyped code-app SHA. The dist content is byte-identical to a build of code-app main at the merge below (tree verified identical to the branch tip it was built from), so the watermark for the next sync is:

code-app: 025805b33f
2026-08-18 19:15:01 +08:00
liruifengv
8c865f4817
feat(kimi-code): support automatic updates for native installations via staged swap (#2994)
* feat(kimi-code): support automatic updates for native installations via staged swap

Native (SEA) installs previously could not self-update on Windows and
relied on 'curl | bash' re-install on Unix. Replace both with a staged
swap updater:

- startup swaps in a staged binary (verified against the release
  manifest sha256, smoke-checked via --version) and re-execs it, so the
  running process never replaces itself (Windows-safe)
- downloads run in a self-spawned hidden sub-command, in the background
  from the update preflight or in the foreground from 'kimi upgrade'
- rollback from .bak on any swap failure; install failures keep the
  existing retry/prompt thresholds

* fix(kimi-code): fully clean staged artifacts on swap discard paths

Real-binary smoke testing on macOS surfaced two cleanup gaps in the
discard path: the claimed metadata file was unlinked after the staging
dir rmdir (so the empty dir survived), and the staged exe was
rediscovered via the already-claimed staged.json (so it leaked on the
downgrade-guard path). Pass the known metadata through and order the
unlink before the rmdir.

* fix(kimi-code): restore staged metadata on swap failure and sweep update leftovers at startup

* fix(kimi-code): address codex review on lock contention and swap crash window

- The background native install no longer takes the outer install lock:
  the self-spawned downloader holds it for the whole download, and the
  parent's spawn-time lock raced the child into a false lastSuccess.
- Smoke-check the staged exe before moving anything, so a bad staged
  binary is discarded with the install path never left empty; the
  remaining crash window is two adjacent atomic renames (documented,
  recoverable via the .bak or by re-running the install script).

* test(kimi-code): align swap test expectation with smoke-before-rename order

The restore-on-failure case now observes the early smoke check's
--version spawn; only the re-exec spawn must be absent.

* fix(kimi-code): stage the bare CDN binary instead of unzipping

The published per-release artifacts are the bare platform binaries
(kimi-code-<target>[.exe]), not zip archives — the staging flow now
streams the download straight to the staged exe after the manifest
sha256 check, and the zip reader is dropped. Verified end-to-end on
macOS against the live CDN: download -> sha256 match -> swap ->
re-exec into the real released binary.

* fix(kimi-code): address second codex review round

- re-exec: forward 128 + signo when the swapped-in child dies by signal
  instead of reporting exit 0
- __update_download: only exit 0 without staging when the lock holder is
  staging the SAME version; a different in-flight version (or a vanished
  lock) no longer surfaces as a successful foreground upgrade
- staging: sweep orphaned .part downloads and unreferenced staged exes
  before downloading, preserving live swap claims and their payloads

* feat(kimi-code): show download progress for native updates

The foreground 'kimi upgrade' path streamed 180 MB with a single static
'Downloading…' line. Render progress instead: a throttled in-place
percentage line on a TTY, one line per 32 MB when piped, and plain MB
counts when Content-Length is unknown.

* fix(kimi-code): bound native update downloads with an idle timeout

Codex review: the manifest fetch cleared its timer once headers arrived,
so a stalled response body hung the worker forever, and the binary
download had no abort at all. The manifest timeout now covers body
consumption, and the binary stream aborts after 30 s without a chunk
(total duration stays unbounded for slow networks). The idle timeout is
injectable for tests.

* fix(kimi-code): retry native updates blocked by an orphaned active record

Windows real-machine verification surfaced that a parent exiting before
the downloader's exit event leaves a fresh-looking 'active' record that
silently blocks every background retry for the 6 h TTL. For native
installs, lock liveness is the truth past a 60 s spawn grace window:
a held lock means a download is running, a free lock means the record
is an orphan and a new attempt may start. Package-manager sources keep
the TTL behavior (no lock to prove liveness).

* fix: skip staged swap while another instance holds a fresh claim

sweepStaleNativeUpdateArtifacts already detected an in-progress swap in
a concurrent instance, but the result stayed inside the cleanup helper:
startup still claimed a newly published staged.json and ran a second
swap, so the two launchers could rename the install path and delete each
other's rollback backup. Propagate the in-progress signal and skip
claiming until the existing claim is released or goes stale.

* fix: keep the install lock while its holder process is alive

The install lock went stale purely by age (30 min), but the native
downloader is idle-bounded, not duration-bounded: a slow link can
legitimately take longer. Another startup would then sweep the lock and
spawn a second downloader, and both would write and clean the same
.staging paths. Past the age threshold, fall back to a pid liveness
probe (signal 0) — the lock is stale only when the holder is gone.

* fix: keep recovery artifacts on rollback failure and wait out same-version downloads

Two robustness fixes from review:

- native-swap: when moving the staged exe into place fails AND the
  rollback rename fails too (transient lock, AV), the install path is
  left absent and no next launch can start. Discarding the staged
  payload and claim on top of that removes the second recovery copy.
  rollback() now reports its result; on a double failure the swap keeps
  the .bak (which IS the old exe), the staged exe and the claim so
  manual recovery or a re-install still works.
- update-download: a foreground `kimi upgrade` racing a background
  downloader of the same version exited 0 immediately, so the CLI
  printed a success message for a download that could still fail. The
  worker now waits while the same-version holder is in flight, adopts
  the verified staged result (staged.json lands before the lock is
  released), and takes over the download when the holder finished
  without staging.

* fix: stamp the swap claim with a fresh mtime when claiming

rename() preserves the staged metadata's mtime, which can be arbitrarily
old — the background download often finishes hours before the next
launch claims it. A concurrent launch's sweep would then classify the
live claim as crash residue (older than the 5-minute window) and delete
the claim, the staged exe, and eventually the first swap's rollback
backup. Stamp the claim file with the claim time so the staleness check
measures the swap's liveness, not the download's age.

* fix: stamp the claim before the rename so it is born fresh

Stamping after the rename left a window: a concurrent launch could
inspect the claim between the two syscalls, see the staged metadata's
old mtime, and delete the staged executable mid-swap. utimes the state
file first so the claim carries a fresh timestamp from the instant it is
published — no fresh-looking-later intermediate state exists.

* fix: chmod the staged download before publishing it at its final name

A swap claims only the staged METADATA; the staged exe stays in
.staging/. A concurrent same-version downloader (possible because swaps
do not hold the install lock) then re-downloads and renames its .part
over that path. If the swap moves the file into the install path between
the downloader's rename and its post-publish chmod, the chmod lands on a
path that is already gone and the installation is left non-executable —
every future launch fails. Apply the executable mode to the private
.part file before the publishing rename so the staged exe is executable
from the instant it appears.

* fix: publish the install lock atomically via hard link

The 'wx' open exposed a momentarily empty lock file before its contents
were written. A concurrent acquirer reading in that window got a
SyntaxError, treated the lock as stale, swept it and also won — two
"holders" then ran stageNativeUpdate against the same .staging paths.
Write the lock contents to a unique temp file and hard-link it into
place: link() fails when the destination exists (same exclusivity as
'wx') and the lock path only ever appears fully written.

* fix: serialize stale-lock takeover through a secondary lock

A pathname-level delete can never be conditioned on the file still being
the inspected stale instance, so a plain compare-and-delete still loses
exclusivity: two workers classifying the same stale lock could interleave
unlink and publish such that both won (proven by a 20-way contention
test). Takeovers now go through a secondary create-if-absent lock
(install.lock.takeover): the delete+publish section only ever runs in
one process, staleness is re-validated inside it, and a fast-path creator
that wins the briefly-free path simply beats the takeover. The takeover
lock itself is age-swept (a live section lasts microseconds), and handles
only release the lock instance they own.

* fix: verify lock ownership after publish and preserve freshly staged exes

Two more race fixes from review:

- install-lock: the stale-marker sweep repeats the inspect-then-delete
  race one level up — two contenders sweeping the same aged takeover
  marker could both win and enter the main-lock section together.
  Pathname APIs offer no conditional delete, so both the takeover marker
  and the main lock now verify ownership after publishing (unique marker
  content, read-back compare): a racing sweep converts to a single
  survivor instead of two holders. The irreducible residual (a delete
  landing in the microsecond link-to-verify window) degrades to a wasted
  download cycle, never a corrupt install — swap claims guard the exe
  independently.
- native-swap: sweeping a stale swap claim deleted the exe it referenced
  even when a FRESH staged.json referenced the same version-derived name
  (a downloader re-staged the version after the swap crashed), throwing
  away a verified ~180 MB stage. The sweep now preserves any exe the
  current staged metadata still references.

* fix: reject mismatched manifests, take over from dead holders, unique .part names

Three robustness fixes from review:

- native-manifest: the per-release endpoint can answer with ANOTHER
  release's manifest (stale cache, mispublish); its checksums would then
  be applied to this version's binary and fail verification on every
  attempt. Compare the parsed manifest version with the requested one.
- install-lock/update-download: a killed lock holder skips its finally
  and never releases, stranding a waiting foreground `kimi upgrade`
  forever. A lock whose recorded pid is dead is now stale at any age
  (the atomic publish guarantees the pid was alive when written), and
  the same-version wait loop polls the acquisition itself, so a dead
  holder's lock is taken over within one poll instead of never.
  Package-manager spawns are unaffected: they hold the lock only around
  the spawn, and the active-record bookkeeping guards that layer.
- native-stage: the download intermediate is now unique per worker
  (`.part` carries pid + counter), so overlapping same-version workers
  can no longer interleave writes into the same file.

* fix: restrict staging cleanup to updater-owned names and retry short writes

- cleanupStagingOrphans recursively deleted anything it did not
  recognize; the staging dir sits next to the exe and can contain files
  belonging to the user or another tool. Deletion now requires a
  positive match on updater-owned artifact names (staged exes and .part
  intermediates) and only ever unlinks files.
- FileHandle.write may persist fewer bytes than requested (short write,
  e.g. near disk exhaustion) while the running hash and size already
  accounted for the whole chunk — publishing a truncated binary under a
  valid checksum. The chunk write now loops until fully persisted.

* fix: scope failure cleanup, recognize all semvers, reverify staged checksums

Three fixes from review:

- native-stage failure cleanup deleted whatever staged update was
  currently published — including a concurrent worker's valid result
  that its caller had already reported as success. The catch path now
  removes only this attempt's own artifacts: its unique .part file and
  its staged exe name when the current metadata does not reference it.
- The orphan-cleanup ownership check only matched stable x.y.z names;
  prerelease/build-metadata versions (1.2.3-rc.1, 1.2.3+build) would
  never be cleaned and accumulate ~180 MB each. Ownership now derives
  from the semver contract via the semver package's valid().
- The swap path trusted a staged exe whose size matched, though the
  metadata records the release checksum; post-download on-disk damage
  could pass the --version smoke check with corrupted bytes.
  claimStagedUpdate now re-verifies the staged exe's sha256 before
  claiming and discards the stage (for a later re-download) on mismatch
  — paid only when an update is actually pending.

* fix: validate versions before path derivation and honor the update opt-out in the swap

- native-stage: stageNativeUpdate derived staging paths (including the
  cleanup rm targets) from the version before fetchNativeReleaseManifest
  rejected it; a traversal string like `x/../../kimi` would resolve the
  staged-exe cleanup onto the running installation. The semver check now
  happens before any path is derived, and the staged-metadata schema
  constrains exeFileName to a plain file name.
- native-swap: the startup swap ran before the update preflight, so
  KIMI_CODE_NO_AUTO_UPDATE / KIMI_CLI_NO_AUTO_UPDATE stopped gating
  update behavior once a payload was pending. The swap now honors the
  same opt-out: the staged payload stays in place for a later launch
  without the variable, and the current exe starts.

* fix: restrict backup cleanup to updater-owned .bak names

cleanupBackups treated every <exe>.*.bak sibling as swap residue, so a
user's own backup like kimi.config.bak in a shared bin directory was
silently deleted on startup. Only the exact <exe>.bak and the numeric
PID fallback <exe>.<pid>.bak are updater-created — cleanup now
positively matches those two formats.

* fix: claim staged metadata before validating it and let manual upgrades bypass the opt-out

- native-swap: claimStagedUpdate validated the metadata and hashed the
  staged exe BEFORE the atomic rename, so a concurrent downloader
  superseding staged.json in between could get its fresh metadata
  claimed under the older object — the smoke check then failed and
  discard() deleted the newly published stage, recording a failure for
  the wrong version. The claim (utimes + rename) now happens first and
  validation acts on exactly the claimed file; discards use a new
  discardClaimedUpdate that never removes anything a meanwhile-published
  stage references.
- The auto-update env opt-out gated the startup swap unconditionally,
  so an explicit `kimi upgrade` with the variable set staged the
  version but no launch ever applied it. Stages now record
  `manual: true` when they answer a user-initiated install
  (`__update_download --manual`, threaded from installUpdate through
  the hidden sub-command), and the swap applies manual stages even when
  automatic updates are opted out.

* fix: promote adopted stages to manual and preserve claim-referenced payloads

Three follow-up fixes from review:

- An explicit `kimi upgrade` adopting an auto-staged payload (already
  on disk, or still downloading via the wait path) returned before the
  manual marker applied, so under the env opt-out the swap still skipped
  it despite the success message. Both adoption paths now promote the
  staged metadata to manual: true via a new promoteStagedUpdateToManual.
- The download-failure cleanup checked only the current staged metadata,
  but a live swap holds the metadata renamed aside as its claim — a
  failing same-version downloader could delete the exe an active swap
  was about to move into place. The catch path now also preserves names
  referenced by any live swap claim.
- Restoring a claimed stage after a failed exe move used rename, which
  on POSIX replaces a newer staged.json a downloader published during
  the smoke check. The restore is now a create-if-absent hard link: it
  only lands when the state-file path is still free, and the older claim
  is discarded when a newer stage has taken it.

* fix: drop exe deletion from stale-claim cleanup

The stale-claim sweep deleted the referenced exe based on a metadata
snapshot taken before the loop; a downloader republishing the same
version between the read and the unlink would have its fresh payload
deleted after reporting success. Publication can never be synchronized
with a pathname-level snapshot, so the sweep now removes only the claim
files themselves — genuinely unreferenced exes are reaped by the
downloader's own orphan cleanup (keep-set aware) before its next stage.

* fix: never delete the staged exe when discarding a claim

The same publication race existed one level down: a same-version
downloader can rename its fresh payload onto the shared exe path after
the discard's metadata snapshot but before the unlink (payloads publish
before their metadata), and the discard would delete a download whose
caller then reports success with nothing behind it. discardClaimedUpdate
now removes only the claimed metadata file; unreferenced exes are reaped
by the downloader's own orphan cleanup before its next stage.

* fix: only reap staging orphans old enough to be abandoned

The orphan sweep could delete a concurrent worker's freshly renamed
staged exe in the gap before its staged.json lands (payloads publish
before their metadata), turning the admitted duplicate-worker race into
a successful stage with no payload behind it. Unreferenced artifacts are
now only deleted once older than a one-hour grace period — publication
takes milliseconds, so unreferenced AND old means definitively
abandoned.

* fix: honor the persisted auto-update preference in the swap and drop claim-unsafe deletions

- The startup swap gated only on the env opt-out, so a payload staged
  automatically still installed after the user disabled automatic
  updates via [upgrade] auto_install = false. The swap now loads the
  persisted preference (only when an automatic stage is actually
  pending) and skips it, exactly like the env opt-out; manual stages
  still always apply.
- Superseding a staged version deleted its exe through an uncoordinated
  read-then-remove that could pull the payload from a live swap. The
  supersede now removes only the old metadata record — the metadata
  write atomically replaces it, and an unreferenced exe is reaped by a
  later orphan cleanup. removeStagedNativeUpdate, left with no callers,
  is removed.
- docs: the kimi upgrade reference (en + zh) no longer claims Windows
  native installations cannot upgrade automatically; native installs
  download and verify in the foreground and swap on the next start.

* fix: gate on claimed metadata, stop shared-path deletes on failure, exact smoke match

- The opt-out gate evaluated a pre-claim snapshot of the staged
  metadata, but the claim could pick up a different (automatic) stage a
  downloader published in between — smuggling it past the gate. The
  env/preference check now runs on the CLAIMED metadata; when disabled,
  the claim is restored via create-if-absent link so a newer stage is
  never overwritten and a later launch can still apply it. The checksum
  re-verify moves after the gates so opted-out launches stop paying for
  the hash.
- The download-failure cleanup still deleted the shared staged-exe path
  based on snapshot reference checks — the same publication race as the
  paths already fixed. It now removes only the attempt's privately owned
  .part file; the shared exe is left for the age-gated orphan cleanup.
- The smoke check accepted the staged version as a substring of the
  --version output, so a mispublished 1.2.30 binary would satisfy a
  1.2.3 target with a matching manifest checksum. It now requires the
  trimmed output to equal the staged version exactly.

* fix: confirm the manual marker before reporting stage adoption

promoteStagedUpdateToManual silently no-oped when a startup swap had
claimed the state file, while the adoption paths still reported success
with manual: true synthesized — under the env opt-out the restored
automatic metadata would then be skipped on every later launch despite
the upgrade's success message. The helper now verifies the marker with a
confirming read (one retry) and returns whether it persisted; the
already-staged branch falls through to a fresh stage when it does not,
and the same-version wait loop only adopts after a confirmed promotion.

* fix(cli): verify the staged payload digest before adopting it as already-staged

readStagedNativeUpdate checks only the recorded size, so a same-size
corruption after the download was adopted and reported as success, only
for the startup swap's claim-time re-verify to reject and discard it.
Compare the actual sha256 before returning already-staged; a mismatch
falls through and re-stages from the CDN.

* fix(cli): keep staged metadata until its replacement is ready

Two related races around staged.json, both reported against the
duplicate-downloader residual:

- stageNativeUpdate deleted the previous record before downloading its
  replacement; a pathname-only delete can remove a concurrent worker's
  freshly published record, orphaning a payload whose worker already
  reported success. The old record now stays until the final atomic
  metadata write replaces it.
- promoteStagedUpdateToManual wrote the marker unconditionally onto
  whichever generation owned staged.json. It now takes the adopted record
  and promotes only while the on-disk metadata still matches it, and the
  post-write confirmation requires the promoted candidate itself.

* fix(cli): preserve the exe referenced by the current staged record during orphan cleanup

Since the supersede path now keeps the previous staged.json until the
final atomic write replaces it, an aged staged exe is still the
applicable update while its replacement downloads — but
cleanupStagingOrphans only pinned exes referenced by swap claim files,
so a payload older than the grace period was unlinked out from under
its own record. Read staged.json itself in the pinning pass so the
current record's exe is preserved like any live claim's.

* chore(kimi-code): reword the native auto-update changeset

* chore(kimi-code): trim the native auto-update changeset

* fix(cli): support update locking on filesystems without hard links

link() fails with ENOTSUP/ENOSYS/EPERM on FAT/exFAT and some network
mounts, which aborted every native update before the download. Add a
shared createFileIfAbsent primitive (hard-link a fully written temp
file, falling back to an exclusive create + write) and use it for the
install lock, its takeover marker, and the swap's claim restore. The
fallback's create->write gap is observable, so the lock inspection now
grants young unparseable content a publish grace before sweeping it as
crash residue.

* fix(cli): publish staged exes under unique names and recover orphaned claims

Two related robustness fixes in the staged swap flow:

- A staged executable is now published under a unique per-worker name
  (kimi-<version>.<pid>.<epoch-ms>.<n>[.exe]) and never replaced; the
  atomic metadata write retargets the pointer. The pathname a swap
  validates at claim time can no longer be exchanged by a concurrent
  same-version publisher between validation and install.
- restoreClaimedUpdate only drops the claim when the restore landed or a
  newer stage holds the state-file path; transient failures retain it.
  The stale-claim sweep now restores aged claims (create-if-absent)
  instead of deleting them, so a stage orphaned by a dead swap or a
  transient restore failure is retried on a later launch.

* fix(cli): verify the staged payload digest in the lock-wait adoption path

waitForStagedUpdate relied on readStagedNativeUpdate, which checks only
the recorded size: while a holder re-stages a same-size-corrupted
payload (its metadata is replaced only when the repaired generation
publishes), a waiter could promote and report the corrupt stage as
downloaded, and startup would later reject its checksum. Apply the same
integrity bar as stageNativeUpdate's already-staged path — adopt only a
payload that hashes to its recorded checksum; a mismatch falls through
to the lock poll, which takes over once the holder finishes without
repairing it.

* fix(cli): serialize swap critical sections and preserve in-flight publishes

- The fresh-claim sweep is only a directory snapshot: two processes could
  both pass it before either claimed, then rename the same installed exe
  concurrently and delete each other's rollback backup. A create-if-absent
  swap mutex (swap.lock, age-gated like the takeover marker) now serializes
  the executable-renaming section; the loser restores its claim and defers.
  The mutex is released as soon as the new exe is in place, before the
  re-exec, so it is never held for the child session's lifetime.
- claimStagedUpdate no longer destroys a claimed record that is unparseable
  but was young at claim time: on filesystems without hard links the
  exclusive-create publish is observable mid-write, and discarding it would
  orphan the staged exe while the writer reports success. Such a record is
  put back with the same inode so the writer completes it; aged corrupt
  residue and well-formed records with a missing/changed exe are still
  discarded.

* fix(cli): keep backup cleanup inside the swap mutex

The early release let a subsequent swap rename the just-installed exe to
the shared .bak path while the previous swap's cleanup was still about to
unlink that same path, destroying the second swap's rollback source. The
mutex now covers the backup cleanup; the cosmetic staging-dir rmdir and
the re-exec stay outside it.
2026-08-18 17:17:18 +08:00
bj456736
d3150fe947
chore: remove internal-network references from comments and test fixtures (#3029)
* chore: remove internal-network references from comments and test fixtures

- Reword two comments that named the internal free-tokens model
  registration flow; the generic OAuth / managed wording carries the
  same meaning
- Replace the qianxun.example placeholder base URL in google-genai and
  runtime-provider tests with genai-gateway.example
- Swap realistic-looking LAN fixture IPs in the kimi web banner tests
  (192.168.98.66, 10.8.12.216) for RFC 5737 documentation addresses
  (192.0.2.66, 198.51.100.216)

* chore: retrigger CI (flaky kap-server searchRoute title-indexing test)

---------

Co-authored-by: bj456736 <bj456736@users.noreply.github.com>
2026-08-18 14:14:56 +08:00
Haozhe
98ebda840a
fix(kimi-code): revert the todo panel to its pre-turn state on undo (#3016)
Some checks are pending
CI / build (push) Waiting to run
CI / test (1) (push) Waiting to run
CI / test (2) (push) Waiting to run
CI / test (3) (push) Waiting to run
CI / test (4) (push) Waiting to run
CI / test (5) (push) Waiting to run
CI / test-pi-tui (push) Waiting to run
CI / test-vscode-legacy (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 / Publish native release assets (push) Blocked by required conditions
* fix(kimi-code): revert the todo panel to its pre-turn state on undo

* fix(kimi-code): hide all-done todo lists on undo refresh and detach SDK todo state
2026-08-18 12:00:19 +08:00
Haozhe
8267bb8fce
feat(kap-server): add workspace fs:suggest file completion endpoint (#3019) 2026-08-18 11:53:48 +08:00
bj456736
09976b0914
feat(cli): add --web-title and expose it via /meta (#2989)
* feat(cli): add --web-title and expose it via /meta

* refactor(kap-server): pass optional web_title directly in /meta

Per the repo rule for optional object properties, pass undefined directly
instead of a conditional spread; serialization omits the unset value.

* fix(cli): sync web bundle with instance tab title support

The committed dist-web bundle predates the document title feature, so a
released `kimi web --web-title` served a client that never read web_title.
Rebuilt from code-app (feat/web-document-title) via sync:web; the bundle
now titles tabs from web_title or the active workspace directory.

* ci: retrigger checks after flaky harness cleanup failure

---------

Co-authored-by: wbxl2000 <wbxl2000@outlook.com>
Co-authored-by: bj456736 <bj456736@users.noreply.github.com>
2026-08-17 20:19:15 +08:00