* feat(core): persist plan/act mode, tool auto-approve, and compaction mode in global settings
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(cli): restore /settings general toggles across restarts
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(core): make global settings updates cross-process safe
Targeted setters previously did unlocked read-modify-write cycles over the
shared global-settings.json, so concurrent hosts (two CLIs, or CLI + VS Code)
could silently discard each other's changes. Route all setters through a new
updateGlobalSettings(mutate) helper that re-reads the latest on-disk state
under a short-lived lock file (with stale-lock reclaim and a bounded wait)
and replaces the file atomically via temp-file rename so readers never see
torn writes.
* Revert "fix(core): make global settings updates cross-process safe"
This reverts commit 198c1c831b.
---------
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* Introduce the concept of free models that have the cline-free ID
* Add (free) to explicitly free models
* Render (free) in free models name
* Add pricing to the free model info
* Fix free model pricing
* fix tests
* SEt cline-free model pricing to 0
* revert pricing changes
* Add free limit error handling
* Include the reset time in the message
* Add button to switch model in VSCode
* add model not found error
* remove problematic tests
* fix review messages
* Fix model promotion ended
* Revert "revert pricing changes"
This reverts commit 7e5b2a34fd.
* Introduce the concept of free models that have the cline-free ID
* Add (free) to explicitly free models
* Render (free) in free models name
* Add pricing to the free model info
* Fix free model pricing
* fix tests
* SEt cline-free model pricing to 0
* perf(desktop): make the app feel snappy end-to-end
Fixes several compounding sources of UI jank that made every click and
keystroke feel seconds-slow:
- Aurora background: drop per-frame 46-64px CSS blur re-rasterization;
bake softness into gradients + a static mask and animate only
opacity/transform (compositor-only). Onboarding/home idle went from
~10fps to a locked 60fps under 4x CPU throttling.
- Hide the app shell while the opaque onboarding overlay is up so a
second aurora + hero animations are not composited underneath.
- Hero verb animation: opacity/transform only (no text blur filter).
- Composer: keystroke state now lives inside ChatInputBar (versioned
promptDraft injections for quick actions/undo/resets), and mention/
slash detection is derived instead of effect-synced; typing went from
245/246 keystrokes over 50ms to 3/240.
- Chat streaming: coalesce per-token text/reasoning deltas into ~48ms
flushes; memoize MessageBubble/ToolMessageBlock with stable callbacks
so finished messages skip re-rendering during streams.
- Session history: only surface isLoadingHistory before the first load;
background refreshes no longer re-render the whole app twice each.
- Provider catalog (~700KB): dedupe concurrent fetches with a short TTL
so app boot issues one round-trip instead of three.
- Sidecar: session-log appends are now ordered async writes instead of
writeFileSync per streamed token; git/folder-picker/editor discovery
use async execFile so the native picker no longer freezes every
pending command; editor discovery results cached for 60s.
* fix(desktop): address Bugbot review findings
- Invalidate the shared provider-catalog cache after any provider
mutation (onboarding connect paths, account sign-in/out, settings
save, add provider) so post-save reloads never see a pre-save copy.
- Clear the injected composer draft on send so a composer remount
cannot repopulate the previous prompt.
- Mark the hidden app shell inert + aria-hidden while the onboarding
overlay covers it, keeping covered controls out of the tab order.
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
read_files rendered file rows keyed by raw path, so the same path listed twice (e.g. find-skills reading a SKILL.md repeatedly) produced duplicate React keys and the two-children-with-the-same-key warning. Build index-namespaced keys instead, at both render sites.
Fixes#9784
Signed-off-by: Minhkunn <minh.12072k6@gmail.com>
Co-authored-by: Minhkunn <minh.12072k6@gmail.com>
* docs: fix typos and incorrect slash command reference
- Fix double period in MiniMax provider description
- Remove duplicate 'through' in kanban install description
- Fix /new -> /newtask (correct slash command name)
* docs(hooks): fix description to reference SDK Plugins, not SDK Hooks
The description said 'SDK Hooks page' but the content links to the
SDK Plugins page (/sdk/plugins). Align the description with the
actual destination.
* fix(desktop): clear busy status when queued turns finish; add Cline API key onboarding path
* feat(desktop): allow cancelling a pending Cline browser sign-in during onboarding
* fix(desktop): address review findings on OAuth cancel, API key verification, and queued-turn status
* fix(desktop): cancel pending OAuth logins when the initiating transport connection closes
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(vscode): resolve base URL and knownModels for compaction summarizer
The agentic compaction summarizer creates its LLM handler from the
session's ProviderConfig alone. For the OpenAI Compatible provider
stored under its SDK spelling (openai-compatible), resolveBaseUrl had
no mapping, so ProviderConfig was built without a baseUrl and the
summarizer silently hit the provider default endpoint (api.openai.com),
failed auth, and fell back to basic compaction - the UI still showed
'Context compacted' with no hint that agentic summarization never ran.
- resolveBaseUrl: accept the SDK spelling of the OpenAI Compatible
provider, and fall back to the providers.json base URL (mirroring
resolveApiKey) when legacy state has none.
- buildSessionConfig: expose knownModels at the top level of
CoreSessionConfig, so manual compaction (sdk-compaction.ts) budgets
against the real model context window instead of the 64k fallback.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(core): project compaction sidecar even when auto-compaction is disabled
Manual /compact persists a compaction sidecar and promises the next turn
will use the compacted working context, but the runtime host only wired
the compaction-state-aware prepareTurn when compaction was enabled. With
Auto Compact off (the VS Code extension default), a manual /compact was
a silent no-op for the model: the sidecar was saved and the UI showed
'Context compacted', yet every subsequent request still sent the full
canonical transcript.
createCompactionStateAwarePrepareTurn already supports an undefined
compact fn (project existing state, never re-compact), so wire it
unconditionally; sessions without a sidecar are unaffected. Also keep a
resumed/initial sidecar instead of dropping it when compaction is
disabled.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(vscode): stop the task at the mistake limit like the CLI, drop the max-mistakes setting
When the SDK's consecutive-mistake limit is hit, the extension used to
block on an ask (Proceed Anyways / Start New Task) while the agent loop
kept running against the provider — reproduced 2,100+ consecutive API
requests behind the unanswered prompt.
Replicate the CLI's non-interactive resolver instead: show an error row
and resolve the decision as an immediate stop. The run aborts cleanly at
the turn boundary, the turn phase becomes awaiting_followup, and the
user continues whenever they want by sending a new message (which also
resets the SDK's mistake tracking on the next productive turn).
Also remove the extension's maxConsecutiveMistakes setting (state key,
settings RPC, webview state, proto fields now reserved). It was never
wired into the SDK session config — the SDK's own default governs — so
the setting was dead weight. Legacy mistake_limit_reached asks from
persisted conversations still render via the existing webview paths.
* fix(proto): reserve retired Settings field 139 (max_consecutive_mistakes)
The original removal added 'reserved 139' but the proto generator at the
branch base had no reserved-statement support and silently dropped it on
regeneration. Main (b4c640733) taught generate-state-proto.mjs to
preserve reserved statements, so after the merge the reservation now
survives. Also reserve the field name, mirroring the custom_prompt
removal pattern.
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* fix(core): resolve relative read_files paths against the session cwd
The built-in FileReadExecutor resolved relative paths against process.cwd(),
which in a VS Code extension host is typically '/' rather than the workspace.
Every relative-path read failed with ENOENT, so models fell back to reading
files through the terminal. Resolve relative paths against the tool's
configured cwd in createReadFilesTool before invoking the executor.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(vscode): never let a stalled diff preview open fail or delay an edit
Thrown errors from opening the edit diff preview were already swallowed, but
a hung vscode.diff call was unbounded: on auto-approve it burned the editor
tool's 30s execution timeout (failing the whole edit), and on manual approval
it delayed the approval ask indefinitely. Bound the preview open with a 5s
timeout; on timeout the edit proceeds without a preview and the late-opening
tab is closed once the open settles.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* style(core): order node:path import first for biome
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* refactor(vscode): flatten the preview-open timeout into a plain race
Replace the custom timeout error class, the race helper with timer
bookkeeping, and the two-branch cleanup with a single Promise.race and one
settle-then-close line. Same behavior: a rejected or stalled preview open
never blocks the approval ask or fails the edit, and any late-appearing tab
is closed once the open settles.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* refactor(vscode): move the read_files cwd fix out of the SDK into the host
Revert the SDK change and instead override the read_files executor in the
extension, alongside the existing editor/apply_patch/askQuestion overrides.
The override resolves relative paths against the workspace root before
delegating to the SDK's built-in reader, since the extension host's
process.cwd() is usually '/' and every relative-path read failed with ENOENT,
pushing the model into terminal fallbacks. The SDK is left untouched.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(desktop): consistent installed cards and single uninstall in marketplace views
* fix(desktop): surface marketplace setup guidance on matched installed cards
* fix(desktop): show setup guidance for all matched marketplace entries, not just first match
* fix(desktop): unambiguous entry-to-item matching and no stale installed card flash
* fix(desktop): drop orphaned installed keys optimistically instead of hiding cards during recheck
* fix(desktop): guard recheck races and avoid duplicate uninstall for ambiguous matches
* fix(desktop): keep uninstall action on ambiguous fallback marketplace cards
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
* Remove dead 'Use compact prompt' toggle from LM Studio settings
The compact system prompt option was never wired up in the SDK-based
extension: the customPrompt value was stored in state and echoed back
to the webview, but nothing in the session factory or SDK ever read it
to alter the system prompt. Remove the checkbox (only shown for the
LM Studio provider) and all the dead state/proto plumbing behind it.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* Add changeset for compact prompt toggle removal
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* Reserve removed custom_prompt field number/name in Settings proto
Teach generate-state-proto.mjs to preserve reserved statements in the
generated Secrets/Settings messages so removed fields keep their wire
identity reserved across regenerations, and reserve field 150 and the
custom_prompt name (plus the name in UpdateSettingsRequest).
Addresses Greptile review feedback on #12551.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* Never assign reserved proto field numbers to new Settings fields
If the highest-numbered field was removed and reserved, the generator
would hand that same number to the next new field, emitting both a
reserved statement and a live field at the same number. Parse reserved
numbers (including ranges) from the existing message, skip them when
assigning new numbers, and fail fast if an active field collides with
a reservation.
Addresses Bugbot review feedback on #12551.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* Format generate-state-proto.mjs
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(vscode): fold SDK openai-compatible provider id to legacy openai spelling
The settings provider dropdown sources ids from the SDK catalog, so picking
OpenAI Compatible stored 'openai-compatible' into plan/actModeApiProvider.
Every provider-keyed code path (webview model label, planModeOpenAiModelId
slots, session factory) expects the legacy 'openai' spelling, so the model
id under the chat field went stale after Done and fell back to the catalog
default (gpt-4o).
- parseProviderId + toLegacyApiProvider now alias openai-compatible -> openai
- state-keys load transform migrates already-stored SDK spellings
- convertProtoToApiProvider normalizes provider ids written from the webview
- commitModelSelection writes the legacy spelling and posts state to the
webview so model-only commits refresh the chat model label immediately
- session factory normalizes provider ids from state and providers.json
* fix(vscode): make toLegacyApiProvider alias lookup case-insensitive
parseProviderId lowercases before its alias lookup, but toLegacyApiProvider
(used directly by convertProtoToApiProvider and the state-keys load
transform) matched aliases case-sensitively, so a mixed-case
'OpenAI-Compatible' would not fold. Fall back to a lowercased lookup while
preserving original casing for unknown ids.
* fix(vscode): treat spelling-only provider differences as the same provider
Addresses the Bugbot finding on PR #12552: stale snapshots can still hold
the SDK spelling (openai-compatible) while new writes use the legacy
spelling (openai). Normalize both sides of the provider comparisons in
SdkProviderChangeCoordinator.providerForMode and
SdkController.isSelectionForActiveModeProvider so a spelling-only
difference neither restarts the active session nor skips the lightweight
in-session model update.
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
The pre-SDK extension auto-retried failed API requests and surfaced
'Auto-retrying in X seconds' rows (say:'error_retry') plus a retryStatus
header on api_req_started. The SDK-based extension never emits either:
errors map straight to an api_req_failed ask with a manual Retry button,
and retrying is handled silently by the AI SDK / auth-refresh retry.
Remove the orphaned webview rendering (ChatRow error_retry case,
ErrorBlockTitle, combineErrorRetryMessages, isRequestInProgress chain,
stories), the unused say types and proto enum values (reserved), the
retryStatus field, and the never-invoked onRetryAttempt callback from
ApiHandlerOptions, sdk-api-handler, and @cline/llms provider config.
Legacy transcripts may still contain error_retry / api_req_retried rows;
readUiMessages now drops them so old tasks don't render raw JSON.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(vscode): keep webview alive when moved between sidebars
Moving the Cline view between the primary and secondary sidebars made the
view go blank with 'this.unsubscribeHostTelemetrySettings is not a function'.
Two fixes:
- The vscode host bridge streaming client returned the async IIFE's Promise
instead of the cancel function its contract declares, so callers invoking
the stored unsubscribe function threw a TypeError. It now returns a
synchronous wrapper that resolves the real cancel function in the background.
- VscodeWebviewProvider disposed the whole Controller on WebviewView
onDidDispose. VS Code destroys and re-resolves the view when it is moved
between sidebars, so the re-resolved view was served by a dead controller
(postStateToWebview no-ops after dispose) and rendered blank. onDidDispose
now only releases view-scoped resources; the controller is disposed on
extension deactivation via WebviewProvider.disposeAllInstances.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix(vscode): address review — don't clear active task on re-resolve, guard stale view dispose
- resolveWebviewView no longer calls clearTask on re-resolves (moving the
view between sidebars must not terminate a running task); it only clears
stale task state on the first resolve after activation.
- onDidDispose now only tears down view resources if the disposed view is
still the active one, so a stale dispose event arriving after a newer view
resolved cannot clobber the active view's listeners. resolveWebviewView
also releases the previous view's resources up front.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
The 'Enter this code in your browser' box shown after clicking
'Sign in to Cline' was left-aligned while the surrounding logged-out
message and button are centered. Center the label and the code/copy row.
Fixes#12531
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* fix: normalize trailing slash in OpenAI Compatible base URL for model list fetch
* fix: construct OpenAiModelsRequest via proto create in refreshOpenAiModels test
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
@opentui-ui/dialog@0.1.2 is built against @opentui/core ^0.1.69, whose
Renderable.remove(id) took a string id. Core 0.4.x renamed it to
remove(child) and throws when handed anything but a renderable, so the
dialog package's removeDialog()/provider teardown aborted before
detaching the panel: the React portal content unmounted but the
imperative grey box stayed on screen over the chat after every dialog
close (model picker, help, command palette, ...).
The upstream package is abandoned at 0.1.2, so pin the fix with a bun
patch that passes the renderable object on all three bindings (react,
solid, core container). A tui-test opens and dismisses the help dialog
and asserts the panel's #262626 background is fully gone, not just its
text.
Fixes#12506
Co-authored-by: Cline Agent <cline-agent@users.noreply.github.com>
* feat(desktop): use the shared Cline Hub runtime
* fix(hub): group code-sidecar-observer clients under Code App
The desktop observer client type was renamed from code-sidecar-approvals
to code-sidecar-observer, but the Code App grouping matchers in the hub
dashboard and menubar sidecar still only matched the old type. Since the
observer now registers on the shared Hub, it showed up as a separate
ungrouped client. Keep the old type matched for older desktop builds.
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
* feat(core): support pathless sessions with temporary workspaces
* fix(desktop): mark editor icons as decorative
* fix(core): omit absent auth request IDs
* test(sdk): restore request_id auth telemetry param in core-events test
The branch's drive-by request_id -> requestId rename was dropped while
resolving the merge conflict with #12444 (which added requestIdDetails on
main), so the public captureAuthLoggedOut/captureAuthRefreshSoftFailure
API keeps its original parameter name.
* refactor(sdk): root pathless session workspaces under the cline data dir
Move the workspace created for pathless session starts from
<os.tmpdir()>/cline/sessions/<id>-temp/project to
<cline-data-dir>/workspaces/<id>/project (default
~/.cline/data/workspaces/<id>/project), per PR review:
- OS tmp reapers (macOS ~3-day purge, systemd-tmpfiles, reboot cleanup)
silently delete user work created in 'New Project' sessions
- /tmp is a shared namespace on Linux: the first user to create /tmp/cline
owns it (EACCES for everyone else), and guessable session IDs let a local
attacker pre-create the workspace directory
- under the data dir the workspace shares the session store's lifecycle and
the existing CLINE_DATA_DIR / CLINE_DIR overrides for tests and sandboxes
isTemporaryWorkspacePath now matches the .cline/data/workspaces/<id>/project
segment shape, and the -temp suffix is gone since the id-scoped directory no
longer needs to mark itself as reapable.
* feat(sdk): open pathless sessions in one shared chat workspace
Instead of minting a workspace directory per session
(<data>/workspaces/<session-id>/project), all sessions started without a
cwd/workspaceRoot now share <cline-data-dir>/workspaces/chat (default
~/.cline/data/workspaces/chat). Starting a pathless session seeds the
directory with an AGENTS.md rules file (only when missing, so users can
edit it) that tells the agent to treat the session as a chat: don't create
or edit files unprompted, ask where a project should live when the user
wants one built, and default to a new named folder inside the chat
directory that later sessions can reference.
This avoids unbounded per-session directory sprawl, gives chat sessions a
stable home the user can revisit, and groups them naturally in the desktop
sidebar. The desktop app now labels the shared workspace "Chat" (menu
action "Just chat") instead of "New Project", and isChatWorkspacePath
matches only the chat directory itself, so project folders created inside
it behave as regular workspaces.
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
* feat(desktop): add replay new-user-experience setting
Adds an onboarding state module (localStorage-backed, with a reset event
the app shell can subscribe to) and a 'New user experience' row in
Settings -> General with a Replay button so beta testers and designers
can re-run the first-run flow. The flow itself ships in the stacked
follow-up PR.
* feat(desktop): first-run onboarding flow
Full-screen first-run experience shown until completed once: a welcome
step (3D glass logo over the aurora background), a connect step offering
Cline sign-in (recommended) or bring-your-own API key against the
provider catalog, and a done step that drops the user into a fresh
thread. Completion is tracked by the onboarding state module from the
previous PR; the Settings replay row now re-enters the flow in place via
the reset event, so its toast is gone. Skipping is always available so
nobody gets trapped; the connected provider (and its default model when
known) is remembered so the chat composer opens pointed at it.
* fix(desktop): address greptile review on onboarding flow
- Filter the bring-your-own-key picker to providers a lone API key can
fully configure: providers with structured config fields (Vertex gcp.*,
Bedrock aws.*) or no API-key field at all (Claude Code) no longer appear,
since connecting them here would report success without working.
- Record Cline as the active provider when a signed-in user hits Continue,
so replaying onboarding doesn't leave the chat pointed at a previously
selected provider.
* feat(desktop): accent color themes and switchable app icon (#12496)
* feat(desktop): accent color themes and switchable app icon
Settings -> General grows an appearance cluster next to Dark mode:
- Accent color: six palettes from the Figma exploration (violet default,
graphite, cyan, pink, espresso, ember). Non-default accents re-anchor
--primary/--primary-foreground/--primary-emphasis/--ring per light and
dark mode via html[data-cline-accent] overrides in globals.css, tuned in
OKLCH to mirror the brand token relationships; chart and sidebar tokens
alias var(--primary) so they follow. Persisted in localStorage and
applied at boot alongside the dark-mode sync.
- App icon: the four Figma variants (Classic, Sunrise, Steel, Midnight).
The webview persists the choice, swaps the favicon in browser mode, and
in the Tauri shell calls the new set_app_icon native command, which
loads the matching bundled resource (icons/dock/*.png) and applies it
via NSApplication.applicationIconImage on the main thread. macOS resets
the dock icon every launch, so the shell re-applies the stored choice at
boot; classic is also loaded from a resource because the objc2 binding
warns against passing nil to restore the bundled icon. Other platforms
no-op (Ok(false)).
* fix(desktop): don't let a stale app-icon failure roll back a newer selection
* polish(desktop): cleaner chat markdown + external links that actually open
Links in chat markdown never opened in the packaged app: the confirm
dialog's window.open(_blank) is silently dropped by the Tauri shell.
Route opens through openExternalUrl (open_external_url sidecar command)
and only keep the confirmation dialog for deceptive links whose visible
text reads as a URL on a different host than the real destination —
ordinary external links now open directly in the default browser.
Visual pass on Streamdown output for the chat pane: collapse the
double-boxed code block card and drop the language header row, reveal
the copy button on hover only, turn off line numbers, single-box tables,
chat-scale the heading ramp (h1 was text-3xl next to 14px body), outside
list markers, and tighter block rhythm.
* fix(desktop): harden deceptive-link detection per review
Recurse into element children when extracting link label text so inline
formatting (e.g. a bolded hostname) can't dodge the deception check, and
compare port and (when the label states one) scheme in addition to
hostname so same-host links to an unexpected scheme or port still get
the confirmation dialog. An unparseable destination behind URL-shaped
label text is now treated as deceptive rather than waved through.
* fix(desktop): treat trailing-dot FQDN labels like their plain hostname
Browsers resolve 'github.com.' identically to 'github.com', but the
URL-shaped-label pattern rejected the trailing dot, so a deceptive label
like [github.com.](https://evil.example) skipped the deception check and
opened directly. Accept one trailing dot in the pattern and strip
trailing dots during hostname normalization on both sides, so the FQDN
form is deceptive exactly when the plain form is.
* fix(desktop): treat protocol-relative labels like their https form
A label spelled '//github.com' reads as a URL but failed the URL-shaped
pattern (which only tolerated an https?:// prefix), so it skipped the
deception check and opened an unrelated destination directly. Accept a
protocol-relative prefix in the pattern, and parse '//'-prefixed values
as https-relative in parseLinkParts — prepending 'https://' to them
produced an empty hostname and made the comparison a no-op.
* feat(desktop): drag and drop files to attach them to the chat
The Tauri webview swallows OS file drags by default (dragDropEnabled),
so HTML5 drop events never fire. Disable it on the main window per the
Tauri v2 docs, then handle standard dragenter/dragover/dragleave/drop on
the chat pane: dropped files feed the same dedupe-and-append pipeline as
the paperclip picker, with a depth-counted 'Drop to attach' overlay while
files are dragged over. Image drops become data-URL images via the
existing serializeAttachments path.
* feat(desktop): display image attachments in chat
* 225x225
* fix(desktop): preserve queued attachments
* fix(desktop): distinguish queued image turns
* fix pending
* fixed
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
* feat(desktop): add custom overlay title bar navigation
Configure Tauri to use a hidden overlay title bar and host back/forward navigation in the draggable sidebar header. Preserve agent title width during editing to prevent layout shifts, with tests covering both behaviors.
* fix(desktop): reconcile deleted navigation entries
* fix(desktop): dedupe session deletion events
* fix(desktop): serialize session deletion state
* fix(desktop): use exported DesktopAppView type in page.tsx
AppView is a non-exported type local to agent-sidebar.tsx, so referencing
it in page.tsx was a TS2304 error hidden by the typecheck script's webview
exclusion and next's ignoreBuildErrors.
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Adds an onboarding state module (localStorage-backed, with a reset event
the app shell can subscribe to) and a 'New user experience' row in
Settings -> General with a Replay button so beta testers and designers
can re-run the first-run flow. The flow itself ships in the stacked
follow-up PR.
* fix(schedules): default headless routines to yolo
Centralize the Cline default model ID in @cline/shared while preserving the @cline/llms export. Keep explicit modes stable and disable ask_question for unattended scheduled runs.
* autoapprove
* fix unit test
* fix(schedules): harden headless routine execution
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>