* feat(kimi-desktop): add Electron desktop client wrapping kimi-web
New apps/kimi-desktop — a thin Electron shell + process manager around
the existing web UI. It reuses kimi-code's shared daemon: it runs the
bundled SEA's `server run` (the same ensureDaemon reuse-or-spawn flow as
`kimi web`), reads ~/.kimi-code/server/lock for the real origin, and
loads the SEA-served kimi-web same-origin. The daemon is left running on
quit so the CLI / browser / TUI keep sharing it.
- main process: ensure-server (run SEA, read lock, confirm healthz),
sea-path (dev vs packaged), window + native menu + window-state +
loading/error screens
- packaging: electron-builder config; before-pack stages the
matching-platform SEA into <resources>/bin/<target>
- CI: desktop-build workflow builds unsigned mac/win/linux installers,
each runner building its own SEA
- workspace wiring: register in flake.nix, allow electron postinstall
(onlyBuiltDependencies), root dev:desktop + typecheck entries
v1 is unsigned, default icon, no auto-update.
* feat(kimi-desktop): sign + notarize macOS builds
Unsigned macOS builds are blocked by Gatekeeper ("app is damaged") once
transferred to another Mac. Add Developer ID signing + Apple notarization,
mirroring the TUI native build:
- build/entitlements.mac.plist: hardened-runtime entitlements (allow-jit,
disable-library-validation for koffi/clipboard, etc.) applied to the app
and — via entitlementsInherit — the nested SEA backend
- electron-builder.config.cjs (replaces .yml): hardenedRuntime + entitlements;
signing and notarization are env-driven (CSC_* + KIMI_DESKTOP_NOTARIZE +
APPLE_API_* ), so the same config builds unsigned locally or signed+notarized
- desktop-build CI: sign-macos input reuses the existing macos-keychain-setup
action + APPLE_* secrets, notarizes via the notary API key
- README: document signing, the Developer-ID requirement, and the
"don't rename the .app" gotcha
Verified locally that electron-builder signs both the app and the nested SEA
with hardened runtime + the entitlements, and the signed app still launches and
serves the web UI. Notarization itself needs a Developer ID cert (CI / a machine
that has one).
* feat(kimi-desktop): rename product to Kimi Code Desktop
productName / window title / menu label / error-screen text all use
"Kimi Code Desktop" so the bundle name matches its executable (a
mismatch from manual renaming is itself reported as "damaged").
* ci(kimi-desktop): build and attach desktop installers in the release pipeline
Make desktop-build.yml reusable (workflow_call) and invoke it from the
release workflow, mirroring the native-build pipeline, so each release
also attaches signed+notarized macOS, Windows and Linux desktop
installers to the GitHub Release.
* feat(kimi-desktop): brand the desktop as an internal testing build
- Add an inline 'internal testing build' tag next to the Kimi Code brand
in the sidebar header, shown only inside the desktop app.
- Use a hidden native title bar on macOS with the traffic lights folded
into the sidebar header, and pin the window title to the product name.
- Ship the Kimi app icon for macOS and Linux builds.
Desktop detection is runtime (a query hint from the Electron shell,
persisted in sessionStorage) so the branding appears even when the
window is served by an already-running shared daemon.
* docs(kimi-desktop): update v1 scope now that the app icon ships
* feat(kimi-desktop): add the Kimi app icon for Windows builds
* chore(nix): update pnpmDeps hash after lockfile refresh
* ci(kimi-desktop): build desktop on release but do not attach to GitHub Release
The desktop build is an internal-testing artifact (branded as such), so
keep it as a CI artifact for internal download instead of publishing it
to the public GitHub Release.
* chore(kimi-desktop): mark installers as internal pre-release builds
Rename the packaged artifacts to KCD-Internal-<version>-<arch>.<ext> and
bump the version to the 0.1.1-internal.0 pre-release, so a leaked or
forwarded installer file is not mistaken for an official public release.
* feat(kimi-desktop): strengthen the internal-build tag wording
Change the sidebar tag to 'Internal testing · do not distribute' /
'内部测试 · 禁止外传' so the no-distribution intent is explicit.
* feat(kimi-desktop): tweak internal-build tag to '仅供内部测试'
* fix(kimi-desktop): pass the server token to the web UI on launch
Read the daemon's persistent bearer token from <KIMI_CODE_HOME>/server.token
and carry it in the URL fragment (#token=), matching how 'kimi web' opens
the Web UI. Without this, a fresh launch (no saved credential) boots the
web UI without a token, hits 401, and falls into the manual token dialog
even though the desktop started the daemon itself.
Addresses review feedback on the desktop URL.
* ci: deploy docs only on release to keep docs in sync with published versions
Previously docs were deployed on every push to main, which meant
unreleased features could appear in the public documentation.
This changes the trigger to release:published so that docs only
update when a new version is actually shipped, plus manual dispatch
for emergencies.
* ci: deploy docs from release workflow
---------
Co-authored-by: root <root@localhost.localdomain>
Co-authored-by: qer <wbxl2000@outlook.com>
* chore(flake): simplify nix build and add ci validation
- Replace dynamic pnpm-workspace.yaml parsing with hardcoded workspacePaths
and workspaceNames to reduce format assumptions
- Remove update-pnpm-deps script and kimi-code-pnpm-deps package; use
lib.fakeHash for standard hash mismatch workflow
- Remove nodejs_latest fallback in nodejsFor, hardcode to nodejs_24
- Add nix-build CI workflow that posts hash-mismatch details to PR comments
- Remove unused Nix installation step from release.yml
- Add workspace maintenance note to AGENTS.md
Nix's profile prepends its bin directory to PATH, shadowing the Node.js version installed by setup-node. Moving Nix installation before setup-node ensures the Node >=24 PATH entry remains first, fixing `ERR_PNPM_UNSUPPORTED_ENGINE` during release.
- Add version:release script combining changeset version with Nix hash update
- Update release workflow to install Nix and use version:release
- Document updated hash refresh workflow in for-agents/workflows.md
- Include changeset for the fix
* feat: add /connect command with models.dev catalog support
Add a /connect slash command that configures a provider and model
from a models.dev-style catalog. Users no longer need to hand-write
model metadata (context window, output limit, capabilities).
Architecture (3 layers):
- kosong: pure data layer — Catalog schema, inferWireType,
catalogModelToCapability
- node-sdk: IO + config write — fetchCatalog, applyCatalogProvider,
catalogModelToAlias
- app: TUI flow — /connect command, provider/model selection,
credential input, config persistence
UI improvements in this PR:
- ChoicePickerComponent: add searchable (fuzzy filter + search bar)
- ModelSelectorComponent: add searchable (same)
- Extract reusable paging.ts for list pagination
Changesets included for kosong, kimi-code-sdk, and kimi-code.
* feat: bundle pruned models.dev catalog for offline /connect
When the network is unavailable, /connect now falls back to a built-in
snapshot of the models.dev catalog.
- `scripts/update-catalog.mjs`: fetches models.dev/api.json, strips
unnecessary fields, and writes `src/built-in-catalog.ts` with the
JSON string as a TS constant.
- `loadBuiltInCatalog(text?)` in node-sdk: parses the JSON string safely;
returns undefined on any failure.
- `handleConnectCommand`: on fetch failure, shows an informative offline
message and tries the built-in snapshot.
- The snapshot file is a placeholder (`undefined`) in source control;
`update-catalog.mjs` populates it before release builds so the actual
catalog is inlined into the bundle by rolldown.
* refactor(tui): share search and pagination across list pickers
ChoicePicker and ModelSelector each carried their own copy of the cursor +
fuzzy-search + pagination state machine. Extract it into a reusable
SearchableList so both pickers share one implementation; behavior is unchanged.
* fix(tui): filter unsupported catalog providers
* docs(tui): clarify /connect stale-alias cleanup depends on removeProvider
* fix(kimi-code): inject built-in catalog at release time
* feat(tui): hint at /login and /connect when /model has no models
Replace the bare "No models configured." error with a notice that
points users to /login for Kimi and /connect for other providers.
* fix(tui): tighten /connect error reporting for edge cases
Two silent-failure cases in /connect could leave users without any
feedback to act on:
- Reject `--url` when its value is missing (e.g. `/connect --url` or
`/connect --url=`). Previously the argument parser silently fell
back to the default catalog, so a malformed flag still appeared to
succeed but with the wrong source.
- Show an explicit error when the resolved catalog yields no providers
with supported wire types. Previously the picker resolved with no
selection and the command returned without any UI feedback.
* chore(tui): restore slash invalid intent type
* fix(tui): support /logout for /connect-configured providers
After /connect writes a non-managed provider (e.g. openai), /logout
fell through to "Nothing to logout." because the handler only matched
the managed default and isOpenPlatformId branches, leaving users no
in-app way to drop the API key and model aliases they just configured.
Collapse the OpenPlatform branch into a generic "provider is present
in config" check so any non-managed provider in config — OpenPlatform
OAuth targets and /connect catalog providers — goes through the same
removeProvider path.
* fix(tui): reject --url values that are not http(s) URLs
`resolveConnectCatalogRequest` previously matched any non-space token
after `--url` as the URL, so `/connect --url --refresh` parsed
`--refresh` as the value and bypassed the missing-value error path.
Bare non-URL tokens (`/connect --url not-a-url`) and non-http(s)
schemes were also silently accepted.
Constrain the captured value to `https?://...` so flag-like and
non-URL tokens fall through to the existing `URL_FLAG_PRESENT_RE`
check and surface a clear error.
* ci(native): scope built-in catalog generation to signed macOS jobs
The catalog-generation step ran whenever `inputs.sign-macos` was true,
including Linux and Windows targets that take the local-profile build
path and never consume the generated catalog. A transient models.dev
outage would therefore fail unrelated artifact builds.
Match the condition to the macOS signed release-profile build that
actually consumes the bundled catalog.
* fix(ci): embed built-in catalog in non-macOS native artifacts
The earlier narrowing to `runner.os == 'macOS' && inputs.sign-macos`
relied on a misread of build.mjs: its `profile === 'release'` guard
only auto-fetches the catalog as a dev fallback. Whether the binary
actually embeds the catalog is decided by tsdown's define at bundle
time, which reads KIMI_CODE_BUILT_IN_CATALOG_FILE regardless of
profile.
Linux and Windows release artifacts therefore lost their bundled
catalog and silently regressed offline /connect on those targets.
Restore generation for all OS jobs when sign-macos is true.
* chore(tui): mention /connect in welcome panel hints
Align the welcome panel with the /model picker so the empty-state copy
points users to both /login and /connect.