v0.9.6 — Auto-update window restoration, mid-session credential refresh, and #807/#798/#804 fixes
Features
-
Workspace name in window title when multiple windows are open — With one window open the title stays as the app name ("Craft Agents"). Open a second window and each window's title becomes the workspace name it belongs to, so windows are trivial to tell apart in Cmd-Tab, Mission Control, and the Windows taskbar. The renderer's static
<title>is suppressed so it can't clobber the main-process title. (5a49b6ca) -
Inline
markdown-previewblock for rendering.mdfiles — A newmarkdown-previewcode-block type mirrorshtml-preview/pdf-preview/image-preview: reference a.mdfile by absolute path and the chat renders it through the shared Markdown component, with adisablePreviewBlocksguard that preventsmarkdown-preview-inside-markdown-previewrecursion without disabling other nested preview blocks. Registered in bothminimal(assistant chat) andfullmodes; supports multi-itemitemsarrays. Partially addresses #807. (45760a6f)
Improvements
-
Online-docs coverage for multi-window titles and auto-update restoration —
apps/online-docs/go-further/workspaces.mdxnow documents the new window-title behavior and the auto-update window-state preservation, so users discovering these features in-app can find rationale and edge-case notes in the docs. (755a8b77) -
Online docs introduction polish — Tightened wording in the getting-started introduction (Mintlify dashboard edit). (
3a5378db) -
Messaging gateway docs reflect the 0.9.5 fallback fix — Clarifies that
progressandfinal_onlymodes now both fall back to the most recent assistant text when a run ends on a tool call without a non-intermediatetext_complete, instead of leaving a thinking bubble (progress) or staying silent (final_only). Genuinely empty runs are still silent. (0cfd1ffb)
Bug Fixes
-
Multi-window state survives auto-update — electron-updater (Squirrel.Mac) destroys all BrowserWindows between
quitAndInstallandbefore-quitfiring, so the existing window-state save ran with an empty snapshot and clobbered~/.craft-agent/window-state.jsonwith{ windows: [] }. Users lost their multi-window setup every time they accepted an update.installUpdatenow fires asetBeforeUpdateQuitHookcallback that captures and saves window state while windows still exist, and the latebefore-quitpath adds an empty-snapshot guard so the pre-update save can't be overwritten. (3db842e0) -
API source credentials refresh mid-session — Sources with bearer/header/query/basic auth captured the credential as a static string at tool-creation time. After refreshing an expired token via
source_credential_prompt, the in-process tool kept sending the stale value (401 until full session restart) even thoughsource_testconfirmed the new token worked. Non-OAuth API sources now route through a credential getter that reads the vault on every call, mirroring the existing OAuth / renew-endpoint path. OAuth and renew-endpoint sources are untouched — they already have refresh viaTokenRefreshManager. (5b6a0588) -
Stale
source_apikeycredential no longer leaks when flipping authType to'none'—SourceCredentialManager.getCredentialId()maps'none','header', and'query'to the samesource_apikeyslot. Flipping a source from a credential-bearing authType to'none'left the stored credential addressable under that slot, where it could later overridedefaultHeaderson a rebuild — the bare credential value got sent as a Cookie header instead of the newdefaultHeaders.Cookievalue.saveSourceConfignow best-effort-deletes thesource_apikeyslot when the new config is an API source withauthType:'none'. Cleanup never throws and never blocks the config write. (d0c70f23) -
Blocked URL schemes now explain why + DOM
hrefs are sanitized — When react-markdown'sdefaultUrlTransformstripped afile:/javascript:URL to empty, the anchor handler fell back to anchor text andnew URL(text)rejected it as "Invalid URL" — a generic toast with no rationale.DANGEROUS_SCHEMESis now aMap<scheme, reason>, the reason flows through theOPEN_URLhandlers in bothserver-coreand the Electron GUI, and the error message now reads e.g.URL blocked (file:). file: URLs are blocked because shell.openExternal can launch local executables on Windows…. The DOMhrefattribute is also sanitized throughdefaultUrlTransformand set toundefinedfor dangerous schemes, closing the middle-click / cmd-click escape route through Electron'ssetWindowOpenHandlerandwill-navigate. Fixes #807 (URL handling part). (746ebb34) -
cache_control1h TTL ordering bug and over-broad "tool not supported" classifier — Two bugs surfaced together whenextendedPromptCachewas enabled on an Anthropic connection at session start. (1)upgradePromptCacheTtlwalked system + messages + top-levelcache_controlbut skippedbody.tools. Anthropic processes blocks in ordertools → system → messagesand rejects requests wherettl='1h'appears afterttl='5m', so a stale 5m on any tool producedsystem.0.cache_control.ttl: a ttl='1h' cache_control block must not come after a ttl='5m' cache_control block. Tools are now walked first in both the upgrade and disabled-strip paths. (2)parseErrormisclassified the same 400 as "Model Does Not Support Tools" because the heuristic fired on the API's hint string mentioningtools. The overly broad pattern is dropped and a finalinvalid_request_error / 400branch routes generic Anthropic 400s toinvalid_requestinstead ofunknown_error. (26e6e675) -
Mobile WebUI send button stays visible when the model name is long — The compact bottom-bar layout had every left-side item as
shrink-0with no overflow guard on the outer row, so a long custom-endpoint model name on a 375 px viewport overflowed the row and pushed the send button off screen.CompactModelSelector's trigger is now shrinkable with amin-w-[64px]tap-target floor, and the compact bottom-bar children are wrapped in their ownmin-w-0 shrink overflow-hiddengroup so the model label truncates first and the send button stays anchored to the right. Fixes #798. (5e95e72e) -
Headless server auto-retries
source_activatedlike the Electron renderer did — The[<slug> activated]re-send moved intoSessionManager.processEventso headless deployments (WebUI, docker server) chain source activations the same way the Electron renderer did. The renderer'sauto_retryeffect is removed. A 2 s content-match dedup window keyed on a{content, deadlineMs, committed}slot onManagedSessionprevents a double-send during a mixed-version rollout (legacy renderer + new server) — first matchingsendMessage(server timer OR legacy RPC) wins and claims the slot, subsequent matches within the window drop. Retry timer + pending slot are cancelled on both session-delete sites (main deleteSession path and the branch-creation rollback path). Fixes #804. Co-authored with Guillaume Gay. (5cb7b8c1) -
PR 378 review hardening (markdown / Electron URL handling, source-activation auto-retry guards, deterministic stale-credential cleanup) — Follow-up commit addressing review findings on the URL-safety, auto-retry, and credential-cleanup PRs above; also removes a leaking source-test module mock that was hiding the credential-cleanup regression. (
42b986e1)
Breaking Changes
- None. All changes are backward-compatible.