* refactor(agent-core-v2): rebuild undo as wire-level journal rewind Replace the compensating context.undo op with a wire-layer rewind primitive: a log.cut control record with a persisted target, applied uniformly by the wire during fold. Turn boundaries become first-class (TurnIndexModel indexing turn.prompt record positions), models declare a temporal classification (rewindable), and a single IAgentRewindService owns the undo pipeline (quiesce -> precheck -> cut -> reconcile) with all entry points converged. - wire: log.cut record, rewindable model flag, re-fold rebuild; OpApplyContext.recordIndex for position-aware reducers - rewind service: aborts the active turn, cancels in-flight compaction, preserves the pending queue, rebases measured tokens, reconciles lastPrompt, tracks conversation_undo - todo list, plan mode, task-notification delivery and the turn index now rewind together with the undone turns - transcript reducer applies cut ranges so snapshot/messages surfaces stay consistent with the model context - REST/RPC/debug undo entry points converge on the rewind service; TUI parses the v2 undo-unavailable error shape - legacy context.undo records keep replaying for old journals * refactor(agent-core-v2): keep undo domain-owned * refactor: enhance /undo functionality for consistency and safety, including todo list rollback and improved event handling * chore: clean up undo changeset artifacts * refactor: rebuild rewind consistency * fix: make conversation undo durable and consistent * fix(agent-core-v2): stabilize undo restoration * fix: keep TUI undo on legacy error contract * refactor(agent-core-v2): drop unused full compaction cancel API Undo now rejects with session.busy while compaction runs instead of cancelling it, so the awaitable cancel() added for the earlier rewind semantics has no callers left. Remove it from the interface and implementation; the RPC cancel path keeps using the task abort controller directly. * fix(agent-core-v2): remove injected context on undo * chore(agent-core-v2): regenerate wire manifest * docs(agent-core-dev): rename rewind to undo in layer table * fix(agent-core-v2): undo prompt-owned image reminders * refactor: remove transcript undo reconciliation * fix(kap-server): map undo busy errors * refactor(agent-core-v2): rename undo participant registry and attribute checkpoint depth - Rename IAgentConversationUndoReconciliationRegistry to IAgentConversationUndoParticipantRegistry (conversationUndoParticipants). - Return the limiting model from checkpointDepth and include it in the SESSION_UNDO_UNAVAILABLE details; report checkpoint_lost instead of compaction_boundary when no compaction explains the missing depth. - Add a registry invariant test: every model reacting to context.* ops must be registered via defineCheckpointedModel or explicitly exempt. * Delete .changeset/fix-undo-injections.md Signed-off-by: 7Sageer <sag77r@hotmail.com> --------- Signed-off-by: 7Sageer <sag77r@hotmail.com> |
||
|---|---|---|
| .. | ||
| public | ||
| scripts | ||
| src | ||
| test | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| index.html | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
Kimi Web
A browser client for Kimi Code — a peer to the TUI (apps/kimi-code) that talks
to a local server over REST + WebSocket. Vue 3 + Vite + TypeScript.
Quick start
# Against a REAL server (the server must be running and reachable)
WEB_PORT=5197 KIMI_SERVER_URL=http://192.168.97.91:58627 pnpm -C apps/kimi-web run dev
# …or from the repo root: pnpm dev:web (uses the defaults below)
# checks
pnpm -C apps/kimi-web run typecheck # vue-tsc --noEmit
pnpm -C apps/kimi-web run test # vitest (pure logic only)
pnpm -C apps/kimi-web run build # vite build
How it connects to the server
The browser cannot reach the server cross-origin (no CORS), so Vite same-origin
proxies /api/v1 (HTTP + WS) to the server (vite.config.ts):
| env var | default | meaning |
|---|---|---|
WEB_PORT |
5175 |
port the dev server listens on |
KIMI_SERVER_URL |
http://127.0.0.1:58627 |
where /api/v1 (and /api/v1/ws) is forwarded |
Behind a corporate HTTP proxy, also set
NO_PROXY=<server-host>(for example,NO_PROXY=127.0.0.1,localhost) so the proxy forward reaches the server directly.
Architecture
A strict one-direction data flow; components never touch the network or the reducer — they consume computed view props and call actions.
server (REST + WS)
└─ src/api/daemon/client.ts REST adapter (envelope → AppX types)
└─ src/api/daemon/ws.ts WS frames → classify → projector/reducer
└─ agentEventProjector.ts RAW agent-core events → AppEvent[]
└─ eventReducer.ts AppEvent[] → state
└─ src/composables/useKimiWebClient.ts the ONLY place that imports api + state;
exposes computed view props + actions
└─ src/components/*.vue render props, emit intents (no api access)
The directory name
src/api/daemon/is historical and kept to minimise diff churn; conceptually it is the server adapter.
- Adapter (
src/api/): wire types are snake_case;AppXtypes are camelCase.config.tsbuilds/api/v1URLs. - Event projector (
agentEventProjector.ts): the server streams raw agent-core events (noevent.prefix).classifyFrameroutes raw vs protocol (event.*) frames; the projector converts them toAppEvents. - i18n (
src/i18n/): vue-i18n, en/zh, per-namespace flat camelCase keys. Detect order:localStorage('kimi-locale')→navigator.language→en.
Server contract — non-obvious notes
The server's wire protocol has a few things that will bite you if forgotten:
- Envelope: every response is
{ code, msg, data, request_id }and the HTTP status is always 200 — checkcode(0 = ok), not the status. - Prompts require five fields.
POST /sessions/{id}/promptsmust carry{ content, model, thinking, permission_mode, plan_mode }. The web fills these from settings (model ← session/default_model, thinking/permission/plan ← the StatusLine controls). Sending only{ content }→40001 model …. - Creating a session needs a registered workspace.
workspace_idmust be awd_<slug>_<hash>id that exists in the server's registry. Sessions get one auto-assigned by cwd, but it isn't registered until youPOST /workspaces { root }(idempotent). The web registers on demand beforecreateSession(otherwise:workspace not found: wd_…). - Persisted sessions are directly promptable — selecting an old session and
sending a message just works; there is no
:activatestep. - Workspaces = real folders.
GET/POST/PATCH/DELETE /workspaces,GET /fs:browse?path=,GET /fs:homeback the rail + folder picker.
Release & deployment
Kimi Web is not published as a standalone package. It ships as the built-in
web UI of the kimi CLI (apps/kimi-code).
Current release flow
- Develop —
pnpm dev:web(orpnpm -C apps/kimi-web run dev). - Build —
pnpm -C apps/kimi-web run buildproducesapps/kimi-web/dist. - Bundle into CLI —
pnpm -C apps/kimi-code run buildrunsscripts/copy-web-assets.mjs, which copiesapps/kimi-web/distintoapps/kimi-code/dist-web. - Publish — the root
.github/workflows/release.ymlpublishes@moonshot-ai/kimi-codeto npm;dist-webis listed in the packagefilesarray, so the built web assets travel with the CLI package. - Serve —
kimi webservesdist-webfrom the installed package.
The web UI does not display its own package version or build commit. It is
bundled into the CLI package and follows the published @moonshot-ai/kimi-code
release.
Suggested improvements
- Keep the current coupling for now. Because Kimi Code is primarily a local CLI/server product, bundling the web UI into the CLI package keeps installs self-contained and avoids cross-origin/CORS complexity.
- Add an independent web-deploy workflow only when needed. If a public
standalone web deployment is required later, create
.github/workflows/web-deploy.ymlthat buildsapps/kimi-weband uploadsdist/to the chosen static host (S3/CloudFront, Cloudflare Pages, Vercel, etc.). Until then, do not maintain a separate deploy target. - Keep versioning owned by the CLI release.
apps/kimi-web/package.jsonremains internal workspace metadata; do not surface it as a separate user version unless the web app becomes an independently published product. - Ensure the web build is exercised in CI. The root
buildscript already builds every workspace, sopnpm run buildin CI coversapps/kimi-web. Keep it that way; do not bypass the web build in release pipelines.