You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(tests): the Jobs sidebar no longer serves a launch-time job list — useReadJobResult now fetches ['jobs'] only while a job page is open, so jobs created outside the renderer and running spinners show when Jobs opens. The desktop-apps offer asks settledByCredential() instead of comparing engine to 'opencode' in two places, bringing the kind-branch ratchet back to zero. The bare-agent removal spec reloads after adopting its folder over raw IPC, since the Chats list now holds the folder-agent list from launch. Unit, typecheck, hub, packaging, contract and the affected E2E specs pass.
test(e2e): composer-paste pastes a stubbed clipboard image on the new-chat screen and finds one timestamped PNG under tmp/pasted and a 64×64 thumbnail with Preview and Remove controls. Clicking the thumbnail opens the image preview without Download, and a text-only paste is let through without reading the clipboard image. Sending hands the scripted runtime exactly one image/png block, and the thumbnail under the sent message opens a preview that offers Download. The host clipboard is never touched: main's clipboard readers are stubbed inside the sandboxed app. The E2E notes gain the thumbnail and preview accessible names and the fake agent's image-capability gotcha.
feat(chat): pasting an image or a Finder-copied file into the composer attaches it — main reads the clipboard itself, file references win over image data, and a bare image is saved as a timestamped PNG under userData/tmp/pasted (cleared at startup) and allowlisted in the path guard before the usual pick-from-paths pipeline takes it, while text on the clipboard still pastes natively. Images get a preview kind: FilePreviewModal shows them fitted and settles only after decode, read through files:read-image (20 MB cap, MIME sniffed from the bytes) instead of the save dialog. Image attachments render as fixed 64×64 thumbnails in the composer, under user messages and under agent replies, from small files:read-thumbnail images made by a desktop-host nativeImage hook, loaded four at a time newest first and cached per profile; a failed load keeps the box with a broken-image icon. Composer badges and thumbnails open the same preview without Download, including path-held files on the new-chat screen through guarded by-path reads. Drops and pastes during an upload queue instead of vanishing, attach errors sit between + and Send so nothing moves, Cinna file reads time out after 60 s, and the undefined --color-bg-elevated on chips is replaced.
test(e2e): file-preview-formats folds an XML tree and jumps through Contents into a folded branch, renders an agent's HTML page with its CSS, fetched data and exact sandbox, and runs Open in browser from the right-click and ⋯ menus against a stubbed launch.
feat(chat): file preview renders XML as a collapsible, highlighted tree with a Contents panel four levels below the root (50 entries per parent, then a note), and falls back to highlighted source when the file is malformed or cut at 512 KB. HTML renders like a browser — scripts, remote content and assets beside an agent-folder file — in a sandboxed frame served over a cinna-preview: scheme, with a Rendered/Source toggle. The frame has no same-origin, popup or permission access, reads no dot or credential files, and reaches the browser only through a clicked top navigation, one tab per click. Open in browser joins the right-click menu, the preview's ⋯ menu and the attachment header, and badges are named Preview when a click previews.
test(e2e): desktop-apps-offer strips the developer's claude and codex from PATH wherever the offer is expected, and the ChatGPT connect now starts signed out and signs in through a scripted codex. Four new cases show no offer for a signed-in codex, a codex or claude on PATH, and an enabled API key, each with a control that brings it back.
fix(ui): the detected desktop apps offer shows only when nothing works yet — no signed-in claude or codex, no installed one whose login is unknown (a PATH copy counts), and no OpenCode default with an enabled credential. The default chat mode no longer keeps it up, so a working setup is not nagged about which engine or key its chats spend. The CLI checks run only when a credential has not already settled it, and a connect in flight or just failed keeps the banner.
fix(ui): the On Hover sidebar peeks from a band of half its width at the window's left edge after 60ms, instead of an 8px strip after 120ms. The band takes no pointer events, ignores moves with a button held or a menu or dialog open, and stops at the left edge of the chat or page column so a narrow window keeps the composer's controls clickable.
test(e2e): the Active block holds an unread chat under the pointer, returns it to its reopened group, and goes when switched off.
feat(chats): Show Active group in the renamed Chats list options menu draws running and unread chats in an Active block above Pinned, off by default. The block holds still under the pointer, during a row menu or rename, and a chat opened from it is revealed in its group when it leaves.
fix(ui): a sidebar revealed under a pointer that has not moved stays while the pointer is on it — the close now asks what is under the pointer before trusting the last move, which was over the chat.
test(e2e): sidebar-docking spec — On Hover from the button's right-click menu, a peek from the left edge that leaves the chat's width alone and hides once the pointer moves into the chat, Fixed from Settings docking it open, and the mode surviving a restart.
feat(ui): Sidebar docking — Settings → Features → Interface and a right-click on the sidebar button choose Fixed or On Hover. On Hover hides the sidebar and slides it in over the chat, without reflowing it, when the pointer rests at the window's left edge; it hides 300ms after the pointer leaves, and an open menu, dialog or a field being edited in it holds it. A click on the sidebar button docks it back to Fixed, and a reveal from code (Show in the Chats list) peeks it for 2.5s unless the pointer goes onto it.
test(e2e): desktop-apps-offer specs — the offer stays out of onboarding, Dismiss survives a restart, Use ChatGPT on a signed-in codex switches the Default runtime and chat mode, and a failed setup keeps the banner with its reason. The bare-mac spec plants stub apps in the real /Applications, checks that no system dialog appears, and connects ChatGPT against the real pinned Codex.
feat(agents): the new-chat screen offers a detected Claude Desktop or ChatGPT app — after onboarding, a dismissible banner names what is installed with one Use button per app. One click installs the pinned CLI, signs in only when needed (a ChatGPT app login in ~/.codex is reused) and makes that engine the Default runtime, moving the default chat mode off another engine when it has to. Detection reads only each bundle's Info.plist under /Applications and ~/Applications, so it raises no macOS dialog; CINNA_DESKTOP_APP_ROOTS overrides the roots for tests.
feat(auth): connecting a Cinna account no longer offers the opencinna.io cloud option — onboarding and Create account go straight to a labelled Server URL field, Enter connects and Connect waits for a URL. auth:register now defaults a missing hosting type to self-hosted instead of cloud.
fix(agents): a new agent's first message waits for its draft, and the New agent dialog stays up until Create returns — while the one-shot draft writes the prompts (up to two 90s calls), any new-chat composer with that agent picked, on its page or the main New chat screen, holds Send and Enter, keeps the text and says why in the placeholder and tooltip; example prompts go inert. The drafting ids live in ui.store, written by the draft hook's own callbacks, so the hold survives leaving the page. Escape, outside click, X and Cancel no longer close the dialog mid-call, which dropped the landing and the draft request. Mutations now default to networkMode 'always': they are all IPC to main, and TanStack's online mode paused them while the browser reported offline, leaving Create on "Creating…".
feat(agents): creating a local agent no longer asks which tool to build it with — Create closes the dialog onto the new agent's page in chat mode, and Add a folder lands in chat mode too. The in-app runtimes run the agent directly and the page header already has Open in, so the "Build it with…" step only covered the page with a copy of that button; a runtime that is not ready is the readiness strip's and Runs with panel's to explain. The localAgentsAutoOpen setting, the "Create and open in " label and its Settings → Agents checkbox go with it; an old stored row is ignored. The default tool now drives only the header's Open in.
feat(engines): log in to Claude Code or Codex from the app — Log in runs the vendor's own claude auth login / codex login on the binary and environment the turns use, which is usually Cinna's managed copy and not on PATH, so "run claude in a terminal" pointed at nothing. Offered on the composer's readiness strip, the Runs with panel and the build page, with Cancel (also during the download), a 10-minute timeout and the re-probed auth status as the verdict. The child's output is discarded and its stdin closed, so the CLI's paste-a-code fallback is never surfaced; a sign-in that does not finish offers the absolute terminal command with Copy.
test(bare-mac): a suite that installs the packaged app in a fresh macOS VM (Tart) with no Command Line Tools, Homebrew or uv, and fails on any system dialog it raises, named with the step it appeared in. make bare-mac-image builds the base from Cirrus Labs' vanilla image, which ships the tools and has Gatekeeper off, so both are undone and verified before the image is renamed into place. make bare-mac packages the working tree or installs APP=<.dmg|.zip|.app>, a DMG quarantined and Gatekeeper-assessed like a download. Three specs: first launch, Developer Tools with the managed git, and a first Claude agent message without a login; 0.5.1 fails the first on the command line tools dialog, main passes all three.
feat(telemetry): move session telemetry into the mode badge's popover — a Context row (used tokens and fill) that expands to the full details above it, collapsed by default — and drop the separate gauge badge.
feat(telemetry): a session badge under the composer — context fill in a fixed-width pill, and a popover with the model and login, context size with the setup/conversation split or measured categories (Measure on Claude, refusals said in place), spend in this chat with its qualifiers, cache warmth with a live countdown, the next message's pre-context price, current prices, and the runtime details in verbose mode.
fix(telemetry): Claude's running totals (cost, per-model cost, API time) start from 0 whenever the adapter starts a fresh query — session/new, a load on a new process, a load under changed params — as a live run on claude 2.1.276 showed; drop the persisted Claude cost fallback and the main-loop-only first turn. A loaded session is live from the load on, so a failed turn is never zeroed twice. Codex keeps its restored total.
test(e2e): a Codex turn's telemetry reaches the verbose message popup (model, per-turn tokens, estimated cost, duration) and a message without it shows none; the fake Codex app server can report token usage. Codex login checks now expect the login method.
feat(telemetry): measure a chat's context categories on demand through a reviewed patch of the pinned Claude adapter (_cinna/contextUsage over getContextUsage, refused while a turn runs, before the first answered prompt and on a closed query), exposed as sessionTelemetry:measureContext; extend the Codex adapter patch with the running token total so Codex turns count every request, not the last one — the total is restored on resume, which the contract now pins. postinstall reverses the previous reviewed Codex patch before applying the new one.
feat(telemetry): read Claude's raw SDK frames (init, assistant, result, compact boundary) for the resolved model from turn 0, cache TTL and expiry with invalidation on model, params, compaction and new session, per-model runtime cost, API time and follow-up tokens; add a dated price table for Claude and OpenAI models, estimated Codex cost, price calibration against Claude's runtime cost, a coarse context split and read-time cache state and next-message estimates. Raw frames yield numbers only and are held for follow-ups like session updates.
feat(telemetry): collect session telemetry for local Claude and Codex agents — model, context used/size, tokens, runtime cost and login kind per chat (session_telemetry table) and per assistant message (messages.telemetry), served by sessionTelemetry:get and a push channel and shown in the verbose message popup. Session-less ACP ext notifications now reach a connection handler, so the adapter's login is heard and the foreign-login notice fires, once per chat, process and login. A resumed Claude session is measured against the saved cost reading and counts main-loop tokens on its first turn, so a restart does not re-count the history.
kit: re-sync the agent kit from cinna-core f1c55fdb, whose desktop notes and root AGENTS.md no longer say .cinna-kit/ may hold only the contract. Contract 1.5.0 is unchanged; the kit hash moves to 7085a29d0ca713c0.
build(kit): afterPack restores the agent kit's .gitkeep files that electron-builder drops, so packaged scaffolds keep files/, app-data/uploads and app-data/storage. The shipped kit must then match kit.lock.json's file count and tree hash, or the build fails.
feat(kit): bundle cinna-core's full agent kit (guides, assistants, tools/kit.py, VERSION) as resources/cinna-agent-kit, so workshop builder steps no longer find the kit missing. A workshop's .cinna-kit/ is installed whole where missing or broken, a kit the user downloaded is never touched, and the desktop's own installs follow the bundled kit hash; building mode points kit agents at the kit's desktop notes.
fix(agents): on a Mac without the command line developer tools, the /usr/bin git, make and python3 stubs no longer pop the install dialog at every agent session start. The tools are detected with xcode-select -p; the app's own git probes skip the stubs, and engine, custom ACP and MCP stdio children get exit-127 stand-ins ahead of /usr/bin on PATH. When no usable git exists (macOS or Linux), a pinned dugite-native git is downloaded in the background and run through a wrapper in git-shim/, and a real git always wins. A git that will not run on the machine is marked unsupported and never downloaded again; CINNA_GIT_DOWNLOAD=off turns the download off in E2E.
feat(runtime): the managed Codex runtime installs the pinned codex-code-mode-host beside codex, which 0.155.0 needs for Code Mode. A fresh install verifies both archives in staging before publishing and shows one progress bar across them; an existing install that has only codex gets the host on its next resolve, and a failed repair only warns. Pins gain companion rows and a dugite-native git pin, and installPinnedAsset can publish a whole tree. install-runtime.mjs and pin-assets.mjs handle companions.
test(e2e): drive the file-reference right-click menu — copy contents, save a markdown and a json file to Notes, the path-only menu for a credential file, copy full path and reference in a new chat.
feat(chat): right-clicking a file reference offers Copy contents, Save to Notes, Copy full path and Reference in a new chat; folders, binaries and credential files get the path actions only. Save to Notes stores the file's text, titled from a markdown file's frontmatter or first heading and fenced with its language otherwise; files over 4 MB are refused. The credential-file rule now also covers SSH private keys, .npmrc, .netrc, .pgpass, .git-credentials and the aws, docker and kube credential files, and the consent dialog says when a file is read for copying.
docs(chat): describe the compact dot preview, tool-step pairing and the below-left popover placement. Adds an E2E spec that hovers, switches, dismisses and keyboard-drives the preview over a scripted ACP turn with a stdout and a stderr step.
feat(chat): hovering a compact tool dot previews its step — the call, its input and its output — without expanding the group. A call and its output stay two dots linked by toolId, and hovering either rings both; once open, the preview follows the dot it rests on and the pointer can move into it to scroll or copy. Previews are built only for the hovered dot and clipped, so long outputs cost nothing while a turn streams.