Commit graph

340 commits

Author SHA1 Message Date
liruifengv
1b97e95243
feat(web): settings-native provider management, blue-mark brand fork (#173)
- Move custom provider management into Settings as a Providers tab
  (ProvidersPanel + AddProviderFlow + ProviderForm + providerForm lib),
  replacing the standalone ProviderManager overlay; add/update/delete,
  models.dev directory import, custom registry import, API key
  show/hide, inline error banners
- Onboarding login step gains a custom-provider card landing on
  Settings → Providers
- Fork web branding back to the legacy little-blue mark (sidebar,
  onboarding BrandLogo, favicon); build-brand-icons.mjs now only
  writes desktop assets
- Drop the dev backend switcher pill from the sidebar (switch backends
  via KIMI_SERVER_URL instead)
- Rebind web new-chat shortcut to Ctrl+Shift+O (browsers reserve
  Cmd/Ctrl+N for new window)
- Source __KIMI_CLIENT_VERSION__ from the kimi-code submodule CLI
  version instead of apps/web/package.json
- Warning toasts honor notice severity (info/success/error variants)
- Remove the stale ToolRow.vue copy from the desktop renderer snapshot
- Minor internal tidy-ups in transcript/detail-panel helpers
2026-08-04 16:44:25 +08:00
liruifengv
bc02d894ec chore: bump kimi-code submodule 2026-08-04 15:02:11 +08:00
liruifengv
e88aae2231 chore: bump kimi-code submodule 2026-08-04 11:17:02 +08:00
qer
ec74eab9ce
feat(chat): preview files outside the workspace via host fs:content (#172)
* feat(chat): preview files outside the workspace via host fs:content

File preview is a local read-only action, so out-of-workspace absolute
paths (chat/Markdown links, tool-call paths, turn-summary files) now read
through the daemon's global fs:content instead of being refused with the
outsideWorkspace error. The allowHostRead opt-in is removed entirely;
workspace-level trust gating will land as a separate feature.

* fix(chat): harden out-of-workspace preview reads

- Lexically normalize absolute preview paths so an in-cwd path with ".."
  (src/../a.ts) keeps the session fs:read path (download / reveal / line
  count) instead of falling into the host-read branch.
- Preserve the POSIX root when resolving relative links/images inside an
  out-of-workspace Markdown preview (/tmp/notes/a.md + ./b.md no longer
  resolves to the workspace-relative tmp/notes/b.md).
- Cap readHostFileContent at 10 MiB (FileTooLargeError): fs:content has no
  truncation semantics and the body is decoded in full in the renderer, so
  an unbounded read could hang or OOM the app. The preview maps it to a
  dedicated too-large error state.

* fix(chat): refuse oversized host reads early and load external markdown images

- DaemonHttpClient.getBlob gains a maxBytes option that rejects at the
  Content-Length header (cancelling the body stream) instead of after the
  whole body is downloaded; readHostFileContent passes its 10 MiB cap
  through it, keeping the post-read check as the missing-header fallback.
- resolveImageUrl now reads out-of-workspace absolute image paths via the
  host fs:content (base64 data URL), so relative images inside an external
  Markdown preview — and model-referenced /tmp images in chat — render
  instead of falling back to a same-origin URL that can never load.

* fix(chat): handle Windows absolute paths in image and markdown-link resolution

- resolveImageUrl classifies any local absolute path (POSIX, Windows drive,
  UNC) instead of POSIX-only: in-cwd ones relativize via pathRelativeTo for
  the session fs:read (in-workspace Windows absolute images render too now),
  outside ones read via the host fs:content.
- The Markdown preview's link/image resolvers pass Windows-drive and UNC
  absolute targets through unchanged instead of拼接ing them onto the current
  file's directory (C:/tmp/b.md no longer becomes C:/notes/C:/tmp/b.md).
2026-08-03 19:47:36 +08:00
liruifengv
d17567e621
feat(settings): reorganize General tab and rework Dock icon picker (#171)
* feat(settings): reorganize General tab and rework Dock icon picker

* chore: simplify changeset summary
2026-08-01 18:44:53 +08:00
liruifengv
8d1720af37 Merge branch 'main' of https://github.com/MoonshotAI/kimi-code-app 2026-08-01 17:30:13 +08:00
liruifengv
9b49dc48a9 chore: bump kimi-code submodule 2026-08-01 17:27:21 +08:00
liruifengv
413f7ad5ba
fix(chat): stop new-messages pill misfiring on scroll clamping (#170)
* docs: add the OAuth desktop-handoff integration note for the auth service

* fix(chat): stop new-messages pill misfiring on scroll clamping
2026-08-01 17:22:55 +08:00
liruifengv
6fc20c68dd
fix(sidebar): backfill session list after archiving a session (#169)
* chore: add release notes for v0.0.14

* fix(sidebar): backfill session list after archiving a session

* fix(sidebar): correct cursor re-anchor and discard stale session pages

* fix(sidebar): cap backfill pages and capture archive state pre-POST

* fix(sidebar): retry stale session pages from the re-anchored cursor

* docs: reword archive backfill changeset

* style(sidebar): trim verbose session-backfill comments
2026-08-01 17:18:32 +08:00
liruifengv
9c3a5f417a Merge branch 'main' of https://github.com/MoonshotAI/kimi-code-app 2026-08-01 16:43:48 +08:00
liruifengv
852e5493f5
feat(sidebar): show tooltips on session pin and archive buttons (#168)
* chore: add release notes for v0.0.14

* feat(sidebar): show tooltips on session pin and archive buttons
2026-07-31 17:09:10 +08:00
liruifengv
c1a16b4dbe
fix: identify free managed accounts by user level (#167)
* fix: identify free managed accounts by user level

* chore: drop the changeset

* refactor: flatten the membership derivation branches
2026-07-31 15:37:10 +08:00
qer
739b693110
feat(desktop): move the internal-test badge next to the sidebar user name (#165)
* feat(desktop): move the internal-test badge next to the sidebar user name

* fix(desktop): give the user-menu name an explicit shrink floor for the badge
2026-07-31 14:27:43 +08:00
github-actions[bot]
6a30096c13
ci: release desktop (#154)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-31 11:13:22 +08:00
liruifengv
9e17cee9dc
feat(desktop): add secondary model settings with a linked model-effort picker (#163)
* feat(desktop): add secondary model settings with a linked model-effort picker

* feat(desktop): rename the subagent settings copy to 子智能体

* feat(desktop): drop the tool-name parenthetical from the subagent model hint
2026-07-31 10:54:42 +08:00
liruifengv
5272a23f59
feat(sidebar): rework archiving with an inline action and undo toast (#164)
* docs: add the OAuth desktop-handoff integration note for the auth service

* feat(sidebar): rework archiving with an inline action and undo toast

- Session rows drop the kebab: hover shows pin + archive; the full menu
  stays on right-click. Archiving skips the confirm dialog and raises the
  new top-center ActionToast (web-ui) with Undo (restore) and Settings
  (deep link to the archived tab / sheet).
- Remove the "last edited" workspace sort mode: archiving an anchor
  session collapsed the workspace's recency and reshuffled the sidebar.
  Workspaces now always follow the manual (dragged) order.

* docs(changeset): reword the change notes
2026-07-31 10:50:14 +08:00
liruifengv
12cc99ca74
fix(account): show upgrade entries for signed-in free managed accounts (#162)
* fix(account): show upgrade entries for signed-in free managed accounts

A signed-in free managed account (no active membership) can call neither
/models (402) nor /usages + /oauth/userinfo (403/402), so the app used to
mislabel it: the composer offered a sign-in entry, the send gate demanded
login, and Settings -> Account rendered the raw usage 403.

Derive a membership tri-state from the userinfo probe (ok -> member,
402 -> free, anything else -> unknown) and key every surface off it:

- Composer model-pill slot: upgrade entry for free accounts, empty for
  other signed-in states, sign-in only when actually signed out.
- Send gate: free accounts get an upgrade prompt instead of the sign-in
  dialog.
- Settings -> Account: a PlanUpgradeCard replaces the plan-usage module
  for free accounts (the usage card also swaps itself on a 402/403 while
  the probe is still in flight).
- UserMenu: free accounts see the upgrade entry and no plan-usage row.
- Empty-session landing: an upgrade banner above the composer, styled
  after the design-system Banner(info) recipe.

The upgrade entries share lib/upgrade.ts (per-app 'from' param via
isDesktop) opening the kimi.com code page.

* fix(providers): show an explicit empty state when a provider has no models

A managed provider with zero models rendered a single disabled blank row
whose placeholder hints (gpt-4.1 / 1047576) read like real values. Render
a muted "no models" line instead, and update the add-model placeholders
to kimi-k3 / 1048576.

* fix(login): unify the login dialog copy around "sign in"

The dialog mixed "authorize" and "sign in" wording; use "sign in"
(登录) consistently in both locales, including the polling error hint.

* chore: merge the changesets into a single entry

* fix(account): await the membership probe before the send gate picks a dialog

checkAuth fires the /oauth/userinfo probe fire-and-forget, so a signed-in
free account submitting inside the probe window still snapshotted a null
membership at the send gate and got the sign-in dialog. Extract the
guarded fetch into fetchManagedProfile (same generation/logout guards),
expose an awaitable probeManagedMembership, and let the gate await it
when the account is authenticated but the membership is still unknown.
2026-07-30 21:02:37 +08:00
qer
0c9a22fd1b
fix(markdown): upgrade markstream-vue to 1.0.9-beta.1 to fix fallback line-number overlap (#160) 2026-07-30 19:28:08 +08:00
liruifengv
b8b513b63c Merge branch 'main' of https://github.com/MoonshotAI/kimi-code-app 2026-07-30 17:40:05 +08:00
liruifengv
42125177b9
fix(chat): keep the conversation outline out of the terminal panel (#161)
* docs: add the OAuth desktop-handoff integration note for the auth service

* fix(chat): keep the conversation outline out of the terminal panel
2026-07-30 17:39:20 +08:00
liruifengv
ee263a29af Merge branch 'main' of https://github.com/MoonshotAI/kimi-code-app 2026-07-30 16:53:27 +08:00
liruifengv
ac9b35c52c
feat(desktop): show the signed-in user's profile and add the sidebar user menu (#157)
* feat(desktop): show the signed-in user's profile in settings

* feat(desktop): add the sidebar user menu

* fix(desktop): prevent stale userinfo fetches from overwriting the profile

* fix(desktop): make the user-menu flyouts keyboard accessible

* fix(desktop): address review follow-ups for the sidebar user menu

* fix(desktop): gate the mobile sheet's Escape and use dialog semantics for the usage flyout

* style(desktop): trim the rationale comments in the user menu

* fix(desktop): redact profile fields in debug and renderer logs

* fix(desktop): assign the userinfo fetch generation at checkAuth entry

* chore: bump kimi-code submodule

* chore: link zod for the bumped oauth package
2026-07-30 16:35:39 +08:00
liruifengv
8dde44d1c5 docs: add the OAuth desktop-handoff integration note for the auth service 2026-07-30 14:53:41 +08:00
qer
223323b518
fix(composer): keep the mention menu closed for a bare @ (#152)
* fix(composer): show a type-to-search hint for a bare @ mention

A bare @ fired an fs:search with an empty query, which the server always
scores zero, so the menu permanently showed "No matches". Skip the
request for empty queries, open the menu immediately, and show a
type-to-search hint; "No matches" is kept for real queries with no hits.

* fix(composer): unblock Enter in empty mention states, drop stale results

Review feedback:
- Enter/Tab/arrows are no longer consumed while the mention menu has no
  items (bare-@ hint / no-match state); only Escape is handled there
- in-flight search responses that no longer match the live query are
  ignored, and the pending debounce is cleared when the @token is gone
- trim the root-cause comments per repo guidance

* fix(composer): keep the mention menu closed for a bare @

Simpler take on the empty-query state after preview: no popup at all
until the query is non-empty, so the hint state and its i18n strings go
away. The stale-response guard now re-derives the live @token instead of
tracking the query in state.
2026-07-30 14:43:20 +08:00
liruifengv
34d47a22bc
feat(desktop): unify the host identity and mark OAuth logins as desktop-originated (#159)
* feat(desktop): add kimi-code:// deep link to surface the app after OAuth login

The OAuth device-flow completion page can now link to
kimi-code://auth/success to bring the desktop window to the front once
the user finishes authorizing in the browser. No credentials ride the
URL: the daemon's device-flow poll completes the login on its own and
the renderer converges through its existing daemon polling, so the only
deep-link action is showing the main window.

- main/deep-link.ts: scheme constant, a strict URL whitelist (any
  webpage can fire the scheme), dev-only setAsDefaultProtocolClient,
  and the showMainWindow handler
- main/app.ts: macOS open-url listener registered before ready, queued
  until launch routing is up (same pattern as second-instance argv);
  Windows/Linux deliver the URL via argv and are covered by the existing
  second-instance / cold-start paths
- electron-builder.config.cjs: top-level protocols so packaged builds
  register the scheme (macOS Info.plist, Windows registry, Linux
  x-scheme-handler in the desktop file)

* fix(desktop): gate second-instance deep links through the URL whitelist

Windows/Linux deliver deep links as plain argv, and the second-instance
handler surfaced the window unconditionally — any webpage could fire
kimi-code://anything to steal focus. Route those argv through
handleDeepLink so only whitelisted URLs focus the window; plain
relaunches (no URL in argv) keep the existing always-show behavior,
including launches queued before the window is ready.

Also redact rejected deep-link URLs with redactUrlForLog before they
reach the persistent log, so a malformed auth link cannot persist codes
or tokens from its query or fragment.

* feat(desktop): unify the host identity and mark OAuth logins as desktop-originated

Resolve the desktop host identity once (main/identity.ts) and pass it to
the embedded server through kap-server's new typed hostIdentity option:
the OAuth device flow, model, and WebSearch requests now all carry the
desktop's User-Agent + X-Msh-* set (kimi_code_desktop) with headers
derived downstream — the manual X-Msh-Platform override, the header-seed
plumbing, and the device-id scraping are gone. The engine version keeps
traveling as serverVersion.

first_launch now means the desktop product's first launch: a marker in
ui-state.json instead of the shared device_id file, whose existence only
proves some kimi-code product ran before (the CLI could silently swallow
the desktop's first launch). No migration for existing installs.

The OAuth verification URL opened from the login dialog and onboarding
wizard gains from=kimi_code_desktop, so the authorization page can offer
an "open the desktop app" handoff only for desktop-originated flows;
CLI and web URLs stay bare.

Design doc: docs/plans/2026-07-29-host-identity-unification.md. Requires
the kimi-code host-identity unification (submodule bump follows its
merge).

* chore: bump kimi-code submodule to the host-identity branch

Point the submodule at feat/host-identity-unification HEAD (f2a293c02)
so the desktop builds against the new kap-server hostIdentity API.
Update to the main merge commit once MoonshotAI/kimi-code#2382 lands.

* docs(desktop): trim the host-identity native-todos entry to the divergence essentials

* docs(desktop): drop the native-todos entries for deep link and host identity

* docs: drop the review-tool mention from the host-identity plan

* chore: bump kimi-code submodule to the merged host-identity commit

Point the submodule at the main merge commit of the host-identity
unification (MoonshotAI/kimi-code#2382), replacing the temporary pointer
at the feature branch head.

* chore: sync the lockfile with long-declared workspace deps

kap-server's minidb and node-sdk's agent-core-v2/klient links were
declared in package.json by earlier PRs but never written into the
lockfile; pnpm install registers them now.

* chore: drop the desktop host-identity changeset
2026-07-30 14:00:41 +08:00
liruifengv
6e1c9da713
feat(desktop): add kimi-code:// deep link to surface the app after OAuth login (#156)
* feat(desktop): add kimi-code:// deep link to surface the app after OAuth login

The OAuth device-flow completion page can now link to
kimi-code://auth/success to bring the desktop window to the front once
the user finishes authorizing in the browser. No credentials ride the
URL: the daemon's device-flow poll completes the login on its own and
the renderer converges through its existing daemon polling, so the only
deep-link action is showing the main window.

- main/deep-link.ts: scheme constant, a strict URL whitelist (any
  webpage can fire the scheme), dev-only setAsDefaultProtocolClient,
  and the showMainWindow handler
- main/app.ts: macOS open-url listener registered before ready, queued
  until launch routing is up (same pattern as second-instance argv);
  Windows/Linux deliver the URL via argv and are covered by the existing
  second-instance / cold-start paths
- electron-builder.config.cjs: top-level protocols so packaged builds
  register the scheme (macOS Info.plist, Windows registry, Linux
  x-scheme-handler in the desktop file)

* fix(desktop): gate second-instance deep links through the URL whitelist

Windows/Linux deliver deep links as plain argv, and the second-instance
handler surfaced the window unconditionally — any webpage could fire
kimi-code://anything to steal focus. Route those argv through
handleDeepLink so only whitelisted URLs focus the window; plain
relaunches (no URL in argv) keep the existing always-show behavior,
including launches queued before the window is ready.

Also redact rejected deep-link URLs with redactUrlForLog before they
reach the persistent log, so a malformed auth link cannot persist codes
or tokens from its query or fragment.

* docs(desktop): trim the deep-link native-todos entry and note the custom protocol in the README

* docs: move the custom protocol note to the root README and drop the native-todos entry

* fix(desktop): match the deep-link scheme case-insensitively

Schemes are case-insensitive per RFC 3986, so an uppercased scheme like
KIMI-CODE://unknown/path slipped past extractDeepLink's startsWith check
and took the unconditional plain-relaunch focus path, bypassing the URL
whitelist. extractDeepLink now lowercases before comparing, and
isKnownDeepLink parses the URL — comparing scheme and host
case-insensitively while keeping the path case-sensitive — instead of a
fragile exact-string match.

* fix(desktop): self-register the deep-link scheme on Windows

electron-builder 26's protocols config only lands in the macOS
Info.plist, the Linux desktop file, and AppX manifests — NsisTarget
contains no protocol handling at all, so the NSIS installer never writes
the HKCU\Software\Classes\kimi-code registry entry and browsers fall
back to a web search for the scheme. The app now registers the scheme
itself on every Windows launch (packaged via the exe path, dev via
electron + app path); macOS keeps the Info.plist and Linux the deb
desktop file, where the runtime call stays dev-only.
2026-07-30 12:27:02 +08:00
qer
54cf068eba
fix(ui): drop copy success checkmark and new-message pill hover (#158) 2026-07-30 11:36:41 +08:00
qer
dd04056d5d
fix(markdown): restore streaming code highlight via markstream-vue 1.0.7 (#155) 2026-07-29 21:38:46 +08:00
liruifengv
8abde94b2b
feat(sidebar): unify workspace session expand into one control (#153)
* feat(sidebar): unify workspace session expand into one control

Replace the two separate controls at the bottom of each workspace group
("Load N more" fetching the next page, and a local expand/collapse
toggle for already-loaded rows) with a single expand/collapse pair:

- "Show more" steps a per-group display cap up by one batch of 5; the
  next page is fetched only when the locally loaded rows can't cover
  the step, so users can't tell whether a reveal came from memory or
  the server. While fetching, the button shows "Loading…" disabled.
- "Show less" resets the cap to the first page without losing the
  already-loaded data (re-expanding never refetches).
- Both controls share one row as compact content-width pills with
  chevron icons (down/up) aligned to the session-title x, separated by
  a faint middot; labels no longer show counts (the workspace
  session_count is only a possibly-stale label).

Applied to the desktop sidebar, the mobile switcher sheet, and synced
to apps/web; design-system docs and i18n updated accordingly.

* chore: simplify changeset wording

* fix(sidebar): unstick adjacent template attrs, truncate show-more pills at min width

Two template attributes ended up concatenated without whitespace after
an edit (harmless to the Vue parser, but a typo); separate them. Give
.show-more min-width: 0 so at the narrowest sidebar (170px) the pill
labels truncate with the existing ellipsis instead of the row
overflowing the workspace group.
2026-07-29 19:44:57 +08:00
liruifengv
5fbfa7c01f chore: add release notes for v0.0.13 2026-07-29 18:30:42 +08:00
github-actions[bot]
8ec25b80ee
ci: release desktop (#147)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-29 17:46:29 +08:00
liruifengv
ac146a738c Merge remote-tracking branch 'origin/main' 2026-07-29 17:43:59 +08:00
liruifengv
5bdb742da7 docs: trim AGENTS.md to hot-path rules and one-line directory map 2026-07-29 17:41:16 +08:00
qer
5c22dc91d7
fix: reconcile session work state after reconnect (#109)
* fix: reconcile session work state after reconnect

* fix: order work reconciliation after replay

* fix: harden session work reconciliation

* fix: reconcile session work state by sequence

* fix: retain session activity ordering
2026-07-29 17:34:02 +08:00
liruifengv
a588a3df88 docs: slim down READMEs and point duplicated rules at AGENTS.md 2026-07-29 17:19:52 +08:00
liruifengv
9e0e486357
feat(desktop): inherit shell KIMI_* env with an explicit blacklist (#150)
* feat(desktop): inherit shell KIMI_* env with an explicit blacklist

The shell env probe used to drop every KIMI_* variable. Most of them are
legit power-user config the desktop should inherit: KIMI_CODE_HOME,
endpoint overrides for test environments (KIMI_CODE_OAUTH_HOST /
KIMI_OAUTH_HOST / KIMI_CODE_BASE_URL), experimental flags, log tuning.

The blacklist keeps out what would silently override the desktop's own
auth/settings or weaken the embedded server (it runs without a bearer
token, so CORS and Host checks are its only defenses):
- secrets and request-header injection (*_API_KEY, KIMI_CODE_PASSWORD,
  KIMI_CODE_CUSTOM_HEADERS)
- endpoint overrides outside the managed-account flow (KIMI_BASE_URL,
  KIMI_WEB_SEARCH_BASE_URL, KIMI_WEB_FETCH_BASE_URL)
- KIMI_MODEL_* (env-synthesized provider hijacks the default model)
- embedded-server defenses (CORS origins, allowed hosts, host check,
  OAuth lock)
- desktop dev switches (KIMI_SERVER_URL, KIMI_RENDERER_DEV_URL,
  KIMI_DESKTOP_NO_SHELL_ENV) and internal parent-to-child plumbing

Two follow-on fixes:
- when the probe imports KIMI_CODE_HOME, re-target the main log file to
  the new home so server-side session export keeps finding it
- await the probe before reading the external-server token, which
  resolves <KIMI_CODE_HOME>/server.token

Also drop the probe's own KIMI_PROBE_BIN from the dump merge.

* docs(desktop): trim shell-env policy comment and sync README

Review feedback: the blacklist rationale lives in the feature commit
message, so the code keeps only short labels; sync the desktop README
with the new contract (KIMI_* inherited minus blacklist, main log
re-targets when the probe imports KIMI_CODE_HOME, and the probe is
awaited before the external-server token read).
2026-07-29 16:59:44 +08:00
qer
6720944aed
fix(chat): revive the turn file-change summary's dead file rows (#148)
* fix(chat): revive the turn file-change summary's dead file rows

The summary card's file rows rendered as inert plain-text spans in the
main conversation, so they had no hover feedback and ignored every click:

- An optional boolean prop without a declared default casts ABSENT to
  false, so "interactive unless explicitly false" silently resolved to
  false wherever the flag wasn't passed (ChatPane → TurnFilesSummary).
  Both boundaries now declare the default true explicitly; only the BTW
  side chat keeps the plain-text rows, by design.

With the rows alive again, two latent defects on the never-exercised
interactive path surfaced and are fixed here:

- The turn-diff panel could not be toggled closed by tapping the same
  row again: openTurnDiff compares the stored change by identity, but a
  deep ref reads back a reactive proxy that never matches the raw
  object. turnDiffChange is now a shallowRef.
- AgentDetailPanel's embedded ChatPane never forwarded open-turn-diff,
  so an Edit row there would have been a dead button; the event now
  flows through to the shared detail layer.

Plus two style corrections on the card:

- The row hover underline rode the full-strength text colour; it now
  uses the faint text token, matching the spec's "lightly".
- The foot "N more files" toggle no longer inherits the shared Button's
  press-scale, which read as the whole strip denting inward on a
  full-width square-cornered row.

Tests: SSR-render assertions pin the interactive defaults and the
button-vs-span rows (turn-files-summary.test.ts), and composable tests
cover the second-tap toggle of both the turn-diff and file-preview
panels (detail-panel-toggle.test.ts) — mirrored desktop/web.

* refactor(chat): trim invariant comments, keep web tests pure-logic

Review feedback on the turn file-change summary fix:

- The shallowRef / prop-default notes carried bug-narrative detail that
  repo rules keep out of source comments; each is now a one-line
  invariant hint (root causes live in the earlier commit message).
- apps/web tests are pure logic only (apps/web/AGENTS.md), so the web
  copies no longer render components: turn-files-summary pins just the
  compiled prop defaults (rendered button-vs-span coverage stays in the
  desktop renderer tests), and detail-panel-toggle calls the composables
  directly instead of mounting a host. Same coverage, no renderer.

* fix(chat): show a real not-found state for moved or deleted preview files

Clicking a file the turn touched after it was renamed or deleted showed the generic unable-to-read message — the daemon precise fs.path_not_found (40409) was swallowed into null by readFileContent, collapsing every failure into one misleading message. readFileContent now rethrows the not-found code (its two loadFileDiff call sites keep their null-on-error behavior via .catch), and openFilePreview maps it to the dedicated not-found state that only the host-read branch used before.

* chore(chat): drop the css rationale note, trim the not-found changeset

Review feedback: the press-scale override carries its reason in the commit message rather than a source comment, and the changeset stops at the fixed problem per the changeset skill (no behavior supplement).

* chore(chat): drop the remaining prop-default rationale notes

Review feedback: the one-line boolean-cast note is still regression rationale; the defaults are guarded by the turn-files-summary tests, so source stays bare per the comment-restraint rule.

* chore(chat): drop regression narrative from the new tests

Review feedback: test names and assertions already carry the regression intent; setup-constraint notes (module mocks) stay, bug root causes live in the commit history.
2026-07-29 16:01:35 +08:00
7Sageer
c7ae597e3e
Merge pull request #134 from MoonshotAI/feat/desktop-telemetry
feat(desktop): add usage telemetry for the desktop host
2026-07-29 14:31:35 +08:00
7Sageer
4519e12e84 test(desktop): sync tray telemetry mock 2026-07-29 14:25:00 +08:00
7Sageer
b059ad6e1b
Delete .changeset/desktop-telemetry.md
Signed-off-by: 7Sageer <sag77r@hotmail.com>
2026-07-29 13:36:45 +08:00
qer
2aa50b5c09
fix(chat): concatenate stream-chunk text parts on history reload (#145)
* fix(chat): concatenate stream-chunk text parts on history reload

Third-party OpenAI-compatible providers can persist one text part per
stream chunk. The history projection joined every part with '\n', so a
reloaded long reply rendered as vertical text (MoonshotAI/kimi-code#2323).
Adjacent same-kind parts within one message are chunks of a single
segment — concatenate them verbatim; keep the newline only across
messages or an intervening tool call.

* fix(chat): dedupe chunked persisted copies of a streamed message

Sign message content for seenSigs after merging adjacent same-kind
parts, so a provider that persists one part per stream chunk still
matches the assembled live copy sharing the promptId instead of
rendering the reply twice. Also trim the new absorbContent comment to
the local invariant per the repo comment policy.
2026-07-29 13:36:31 +08:00
7Sageer
823c98e888 refactor(desktop): inline renderer track validation into ipc.ts
The standalone renderer-track-validation.ts module only existed to keep
the bootstrap path (index -> log -> track) free of the zod import.
ipc.ts is late-loaded via import('./app'), so inlining the 5-line
validator there preserves that constraint with one less module. The
whitelist matrix tests tied to the split module are removed; the area
is stable and the schema itself is enforced by the shared contract.
2026-07-29 13:29:22 +08:00
qer
a1702a54ba
fix(chat): keep a Skill tool call inside the turn's activity fold (#146)
A Skill invocation persists the loaded skill body as a user-role message
(origin skill_activation, trigger model-tool / nested-skill) between the
tool call and its result. messagesToTurns treated it as a hard turn
boundary: it flushed the pending assistant group, then hid the message.
The turn split in two and each half rendered its own "worked Ns" fold
row, with the Skill card stranded between them.

Upstream's isAgentReplayUserTurnRecord already counts only user-slash
activations as turn anchors; mirror that here by skipping non-user-slash
skill activations the same way hidden injections are skipped, so the Skill
call folds into the same activity run as the rest of the turn.
2026-07-29 13:18:11 +08:00
7Sageer
62b3dfc9b5 refactor(desktop): inline connect failure classification into connectOnce 2026-07-29 13:12:23 +08:00
7Sageer
0aa8eea38b refactor(desktop): drop server_mode and fold runtime locale into track 2026-07-29 13:00:48 +08:00
7Sageer
0c41ca675a feat(desktop): report session count in system metrics 2026-07-29 12:21:41 +08:00
liruifengv
088cc00186 chore: add release notes for v0.0.12 2026-07-29 12:19:36 +08:00
7Sageer
59e9114c78 chore: merge main into desktop telemetry 2026-07-29 12:17:21 +08:00
7Sageer
889ffb416f fix(desktop): keep bootstrap logging dependency-light 2026-07-29 12:03:43 +08:00
7Sageer
445dac79e5 fix(desktop): bind telemetry source to session selection 2026-07-29 12:03:43 +08:00