- 后端 (backend): the agent backend — the coding-agent engine that runs a session: JuCode's own engine, Claude Code, Codex, or an ACP agent. In code it is
BackendId/backendId; the daemon protocol calls itengine. It never means a server side, the daemon (the UI calls that 后台服务, "background service"), or a model provider (provider). - 草稿 (draft session): a new session before its first message. It has a chosen backend, model and effort but no engine and no daemon session; the first op sent to it starts the engine (
markDraftinsrc/lib/backends/router.ts,SessionStore.#startDraft). Until then nothing may spawn a backend: switching backend, model or effort only records the choice.
- An
$effectthat calls store methods reads that store's state too, so the store's own changes re-run it (the web chat reset a new conversation as its first message saved it). Wrap the calls inuntrackand depend only on the inputs that should drive it. - The CSP applies only to the packaged app, so dev mode and CI never hit it. Tauri adds a nonce to
style-srconce the HTML has a<style>, and that disables'unsafe-inline'; CodeMirror then loses every style.src/csp.test.tspins the settings the frontend needs. Before a release, open the editor and a reply with math in a packaged build. - The daemon outlives desktop updates, so a field a newer desktop reads may be missing from the daemon still running. Treat a missing field as unknown and keep the current state; never read it as null or empty (read as null, a missing
projectwould move every session out of its project, and the next save would drop their tabs from workspaces.json). - A session the daemon closed for idleness is asleep (
markAsleep), not exited: it must not restart on its own, and anything that starts its engine clears the sleep (#spawndoes). An op a sleeping session should act on goes in the router'sWAKING, or it waits silently. - A global class in
app.cssmust not reuse a name components already scope locally: the unscoped rule styles every one of them (a global.backdrophid the click-outside layer of everySelect, so menus stopped closing). Prefix app-wide classes (theme-backdrop). - A dialog that shows the head of a queue (connect requests) must remount per item (
{#key item.id}) and ignore clicks while a decision is in flight: otherwise a double click, or an Enter, answers the next item that slid under the pointer. SelectcallsonChangewhen the option already chosen is picked again. A handler that restarts an engine or writes config must ignore the current value (re-picking the current provider in the model menu restarted the engine mid-reply).- A user message is its text, its images and its files (
files, sent apart from the text). Anything that sends one again or puts it back in the composer (automatic retry, rewind, edit, a queued message taken back) carries all three; a retry once sent the text alone and the files were silently gone. - While the theme follows the system, the native window
setThemegetsnull, never a concrete theme: setting one flips the webview'sprefers-color-scheme, whose listener re-resolves the mode and flips it back, without end.