* 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
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>
@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(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>
* 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>
* feat(core): default to agentic compaction
Use agentic compaction when no valid strategy is configured while preserving explicit basic selection. Add a session compaction CLI and package script for testing and comparing compaction strategies.
* createHandlerMock
* fix(core): let the agentic compaction cut land on assistant boundaries
Agentic auto-compaction only accepted typed user messages (turn starts)
as cut boundaries. The canonical host transcript — one typed task
followed by a long assistant tool_use / user tool_result loop — has no
turn start past index 0, so findCutIndex snapped to 0 and
runAgenticCompaction returned undefined: the UI showed "auto-compacting"
then "auto-compaction-skipped" on every turn while the context kept
growing. Re-compaction had the same failure permanently, because the
projected transcript starts with a compaction summary message, which is
excluded from turn starts.
Assistant messages are equally safe boundaries: an assistant's tool_use
keeps its result in the user message that follows it, so a cut there
never orphans half of a tool pair. Typed-user protection is preserved —
when a typed turn exists past index 0 the cut still stays at or before
it, so the latest typed prompt is never folded into the summary.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* add compaction fixtures for testing
* basic compaction improvement
* feat: attach metadata to the merged compaction message
* fix(core): address review comments on compact-session script
- add cline provider to the API key env defaults (CLINE_API_KEY)
- accept legacy string-content messages in readMessages
- print usage instead of a stack trace when --provider/--model are missing
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(core): preserve basic compaction across restores
## Summary
- keep tool-result message IDs stable across restore/persist round-trips
- preserve concluding assistant responses as real messages during basic compaction
- freeze prior compaction output so later passes only fold newly added history
- accumulate removed-message and usage metadata across repeated compactions
- update the basic compaction fixture and regression coverage
## Problem
Tool-result IDs were re-suffixed every time persisted messages were converted
back into agent messages. Because compaction state hashes the source message
prefix, restoring a session changed that hash and invalidated an otherwise
successful compaction, causing the full transcript to be sent again.
Basic compaction also reprocessed its own output on subsequent passes. This
could stack duplicate system notices, discard assistant conclusions retained by
the previous pass, and replace cumulative compaction statistics with values
from only the latest pass.
## Solution
Only add tool-result suffixes when splitting a mixed message, leaving already
split and single-result message IDs unchanged. Mark non-user compaction
survivors as preserved, carry those messages through future passes verbatim,
and budget older turns' final assistant answers as first-class messages.
Compaction metadata now adds prior removed-message and usage totals to the work
performed by the current pass.
## Validation
- 66 focused codec and compaction tests pass
- @cline/core typecheck and smoke typecheck pass
- Biome checks pass for all changed TypeScript files
- git diff --check passes
* fix unit test
* fix compaction defaults and fallback
* fix basic compaction credential lookup
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(cli): upgrade opentui 0.1.102 -> 0.4.3
Brings the TUI stack up from April's 0.1.102 to the current 0.4.x line
(0.4.4/0.4.5 are <7 days old and blocked by the registry release-age
gate; bump again once they age out).
- @opentui/core + @opentui/react 0.1.102 -> 0.4.3
- opentui-spinner ^0.0.6 -> ^0.0.7 (0.0.7 peers on @opentui/core ^0.3.4)
- react-reconciler pin 0.32.0 -> 0.33.0 to match @opentui/react 0.4.x
@opentui-ui/dialog stays at 0.1.2 (abandoned upstream, peers ^0.1.69 so
bun warns on install) but its runtime surface (DialogProvider,
useDialog, useDialogKeyboard) works against core 0.4.3 - the tui-test
command-palette spec renders a real dialog in a pty and passes.
Validation: tsc clean, unit 889/890 (the one failure repros on an
untouched main checkout - stale bun pm pack guard expectation), tui-test
62/62 across repeated runs.
* fix(cli): force single opentui generation via root overrides
The previous commit left @opentui-ui/dialog's ^0.1.69 peer range
unsatisfied by core/react 0.4.3, so bun recorded nested
@opentui/core@0.1.102 + @opentui/react@0.1.102 copies under the dialog
package in bun.lock. Local installs happened to link the dialog against
the hoisted 0.4.3 store variant (which is why tui-test passed), but a
fresh install from the lockfile - CI, release builds - would follow the
nested entries and run two renderer generations in one process: dialog
components extending 0.1.102 Renderable classes inside a 0.4.3 renderer
tree.
Pinning @opentui/core and @opentui/react in the root overrides block
forces every consumer, dialog included, onto 0.4.3. The nested lockfile
entries are gone and a runtime identity check confirms
DialogContainerRenderable's prototype chain reaches the same class
objects as the 0.4.3 core the app imports.
Side effect: changing overrides makes bun fully re-resolve the
lockfile. The only drift is ~108 @radix-ui entries nested under the
vscode webview-ui workspace moving to newer patch versions (~1.1.15 ->
~1.1.19); webview-ui's full build (tsc -b && vite build) passes with
them. This drift would land at the next release anyway since bun run
version deletes and re-resolves bun.lock.
Re-validated: tsc clean, tui-test 62/62, unit 889/890 (same single
pre-existing bun pm pack guard failure that repros on untouched main).
* fix(vscode): recognize SKILL.md frontmatter with a leading UTF-8 BOM
SKILL.md files saved with a UTF-8 BOM (e.g. by Windows Notepad's 'UTF-8 with BOM' encoding) were silently skipped and not recognized as skills, because gray-matter/regex-style frontmatter parsers require '---' at byte offset 0 and never accounted for the leading BOM byte sequence Node's utf-8 decoder does not strip.
Fixes the shared parseYamlFrontmatter() helper (used by skills, rules, workflows, and remote skill entries in the VS Code extension) and every duplicated ad-hoc frontmatter regex across the SDK/CLI/hub/desktop-app/example-plugin code paths to strip a leading BOM before matching.
Adds regression tests exercising the exact reported scenario (BOM-prefixed SKILL.md silently missing name/description) in frontmatter.test.ts, skills.test.ts, skill-frontmatter-toggle.test.ts, user-instruction-config-loader.test.ts, and configured-agent-config.test.ts.
Fixes https://github.com/cline/cline/issues/12151
* refactor(shared): centralize UTF-8 BOM stripping
* refactor(shared): add UTF-8 file readers
* docs: guide UTF-8 configuration reads
* fix: auto-discover OS trust anchors in the CLI wrapper
The 3.x CLI ships as a Bun-compiled binary. Bun does not read the OS
trust store unless NODE_USE_SYSTEM_CA is set, and even with the flag its
Windows enumeration covers only the `Root` store, not `CA`/Intermediate
(verified empirically across the CLINE-2353 Windows repro rounds). So a
corporate MITM root is not trusted out of the box and inference fails
with "unable to get local issuer certificate". The pre-3.0 (Node) CLI
had no app-level CA handling either; users only succeeded by setting
NODE_EXTRA_CA_CERTS manually. The reporter's ask: have it just work
without the env var.
This follows the CLINE-2353 SDK fetch-threading change. That made the
inference client honor a host-provided proxy/CA-aware fetch, but on the
CLI Bun's global fetch is already proxy-aware and a fetch function
cannot cross the hub-daemon process boundary, so the CLI's missing piece
is trust material, not the fetch. Env vars do inherit across spawns.
The npm `bin/cline` wrapper runs on Node (not Bun), so it can read the
full OS store via tls.getCACertificates("system") (Node >= 22, no flag
required) — including the Windows `CA` store Bun skips — and hand the
certs to the Bun child via NODE_EXTRA_CA_CERTS, which both runtimes
honor. This mirrors the JetBrains plugin's configureCertificates(),
replacing "harvest from the IDE trust store" with "harvest from the OS".
The merge logic lives in a dependency-free, injectable-module CommonJS
helper (bin/ca-certs.cjs) so it is unit-testable and ships verbatim in
the generated wrapper package (publish copies bin/ wholesale). A
user-set NODE_EXTRA_CA_CERTS is merged ahead of the system certs; a
self-reference to the managed bundle is detected to avoid re-appending
every launch; when no system certs are available the user's setting is
left untouched. Writes are atomic (temp + rename) and owner-only.
Adds ca-certs.test.ts (13 cases) covering harvest filtering, user-bundle
PEM/DER/missing handling, newline-separated merge, managed-path
self-reference, and the no-system-certs no-op.
* fix: harden CLI auto-CA harvesting (review follow-ups)
Follow-ups from the CLINE-2353 review of the CLI auto-CA wrapper.
- H1: a legacy NODE_EXTRA_CA_CERTS set to an OS-path-delimited list
("a.pem;b.pem", the CLINE-2324 footgun Node never split) was stat'd as
one file, failed, and silently dropped the user's certs. readUserCerts
now tries the whole value as one file first, then splits on the OS path
delimiter and reads each existing PEM, merging them all.
- M1: skip the rewrite when the managed bundle is already current, instead
of re-harvesting and rewriting on every launch (mirrors the JetBrains
hash-and-skip). configureNodeExtraCaCerts now returns a typed outcome
(unchanged | written | write-failed-reused | write-failed |
no-system-certs) with cert counts.
- M2: tolerate rename-over-existing failures (Windows EPERM/EBUSY when a
concurrent child holds the file open) by removing the target and
retrying, then falling back to a previously-written bundle. Combined
with M1 the steady state no longer rewrites at all.
- M3: the wrapper prints a one-line diagnostic under CLINE_DEBUG=1
(cert counts + managed path, or a warning when no OS certs were found
or the write failed). Runs once per startup.
- M4: corrected the now-stale CLI guidance in shared/net.ts (the CLI no
longer requires users to set NODE_EXTRA_CA_CERTS manually).
- L1: documented the auto-trust behavior, the managed ~/.cline bundle,
the merge-not-replace override semantics, and CLINE_DEBUG in the CLI
README.
- L4: trimmed the helper's file header; DI is still injectable for tests.
ca-certs.test.ts grows to 20 cases: adds readUserCerts (single path,
delimited split, missing-segment skip, managed-bundle exclusion, empty),
the unchanged/second-run skip, and a write-failure outcome via an
fs that throws.
* fix: address CLI auto-CA review issues (temp cleanup, cert count, test)
- writeBundle now hoists the temp path so the outer catch removes a
partially-written temp file (e.g. ENOSPC / ACL failure mid-write).
Previously only the inner double-rename failure cleaned up, so repeated
disk-full/permission failures left a stale .tmp per launch in ~/.cline.
The inner Windows-rename fallback now lets its failure fall through to
the single cleanup path instead of duplicating rmSync.
- userCertCount now counts individual certificates (via countCerts, which
tallies BEGIN CERTIFICATE markers) rather than the number of PEM files,
so a user bundle with N intermediates reports N and is comparable to
systemCertCount. countCerts is exported for testing.
- Adds tests for the write-failed-reused branch (stale bundle reused when
the rewrite fails but the old file is still readable) and for countCerts
(one file holding two certs reports 2).
* fix: warn when the CLI wrapper's Node cannot read the OS trust store
tls.getCACertificates("system") needs Node >= 22.15; on older hosts the
auto-CA harvest silently did nothing, which is indistinguishable from a
broken corporate proxy. Distinguish the missing-API case as its own
outcome (api-unavailable) and print a non-debug warning when the user
has no NODE_EXTRA_CA_CERTS of their own. Found in round-5 Windows
validation (wrapper under Node 22.1.0).
* fix: copy only certificate blocks into the managed CA bundle
Combined cert+key PEMs (nginx/haproxy-style server.pem) passed the
old contains-a-certificate check, so a user NODE_EXTRA_CA_CERTS
pointing at one duplicated the private key into the managed bundle,
where it outlives rotation of the original and gets no permission
tightening on Windows. Extract complete BEGIN/END CERTIFICATE blocks
instead; files with none are treated as not PEM, and certificates-only
files pass through byte-identical so the unchanged-skip stays stable.
Raised in PR review.
* fix: show the old-Node trust warning once per Node version
The api-unavailable warning printed on every CLI invocation, turning
an actionable nudge into stderr noise for users pinned to an old Node.
Stamp the warning per Node version under the cline dir: it shows once,
re-arms when the Node version changes, and a bookkeeping failure never
suppresses the diagnostic. Raised in PR review.
* fix(telemetry): attach organization context to cached-credential identity
CLI cached credentials only stored the account id, so telemetry identity
resolved from them (headless runs via #11581, the hub daemon via #12177)
carried user_id but no organization_id - making CLI/hub usage invisible
to organization-scoped dashboards even where per-user attribution works.
- AuthSettingsSchema gains optional organizationId/organizationName/
memberId
- loadClineAccountSnapshot persists the active organization into the
cached cline provider settings after fetching /me (cleared when the
user is on their personal account), so the context survives across
processes without a network call
- the CLI runtime identify and the hub daemon identity refresh read the
persisted fields and pass them to identifyAccount; the daemon re-keys
its refresh on account+organization so an org switch re-identifies a
long-lived daemon
* fix(telemetry): strip stray NUL byte, drop needless reshaping of daemon identity resolve
* fix(cli): prevent use-after-free when setting terminal title during TUI teardown
* fix(cli): re-check renderer destruction before title reset in teardown microtask
* test(cli): cover terminal title teardown lifecycle
* fix(vscode): use the requested provider's stored credentials when listing OpenAI-compatible models
The OpenAI-compatible settings pane already fetches GET <baseUrl>/models to
suggest model IDs, but the host handler always read the built-in "openai"
provider's stored settings. Custom OpenAI-compatible providers only expose a
masked API key to the webview, so their model-list requests went out
unauthenticated and the suggestion dropdown stayed empty.
Add provider_id to OpenAiModelsRequest and read that provider's stored API
key and custom headers in refreshOpenAiModels. Old clients omit the field,
which defaults to "openai" and preserves the previous behavior.
* feat(cli): suggest model ids from OpenAI-compatible endpoints in the model picker
The CLI showed a bare free-text input for openai-compatible providers and
never asked the endpoint what it serves. Fetch GET <baseUrl>/models with the
provider's stored API key/headers when opening the picker; when the endpoint
answers, show the standard fuzzy list (which keeps the "Create custom model
ID" row for manual entry). Any failure or empty answer falls back to the
existing free-text input.
* fix: resolve OpenAI-compatible model discovery config
* feat(shared): move plan/act mode prompt instructions into the shared prompt builder
The CLI's #12057 fixes (mode-tag explanation, plan-mode contract,
mode-switch notice tracker) were CLI-only wiring, so the VSCode extension
never told the model what the <user_input mode> attribute means and plan
mode kept mutating files (CLINE-2576, CLINE-2607, CLINE-2579). Promote
the pieces every host needs into @cline/shared:
- buildClineSystemPrompt now appends MODE_TAG_INSTRUCTIONS for every mode
and PLAN_MODE_INSTRUCTIONS for plan sessions, composed into the rules
slot in the exact order the CLI historically built by hand, so CLI
output is byte-identical after the refactor.
- The plan-mode contract gains an explicit run_commands paragraph:
the tool intentionally stays available in plan mode (essential for
read-only investigation) but is inspection-only there -- no file
mutations, no state-changing commands. The mitigation for plan-mode
mutations is prompting plus mode-switch notices, not tool removal.
- createModeSwitchNoticeTracker moves from apps/cli/runtime/interactive
to @cline/shared next to formatModeSwitchNotice; the CLI re-exports it
so its import surface and tests stay unchanged.
- deriveTitleFromPrompt gets a regression test pinning that titles never
pick up mode-notice text.
* fix(vscode): teach the model about plan/act modes and surface mode switches
Port the CLI's #12057/#12058 plan-mode fixes to the extension:
- The session factory drops its local PLAN_MODE_INSTRUCTIONS copy; the
shared prompt builder now emits both the mode-tag explanation and the
plan-mode contract (including the read-only run_commands rule), so the
extension's system prompt finally explains the <user_input mode>
wrapper its own messages have carried all along.
- Manual Plan/Act toggles record a mode-switch notice in
SdkModeCoordinator (shared round-trip-cancelling tracker, scoped to
the rebuilt session so it never leaks across tasks), recorded only
after the session replacement actually commits. The model-initiated
switch_to_act_mode path passes source: "tool" and records nothing,
matching the CLI: its tool result and continuation prompt already
announce the switch.
- SdkSessionLifecycle.fireAndForgetSend -- the single funnel for
outbound turn sends -- consumes the notice and prepends
formatModeSwitchNotice() to the next message, exactly like the CLI's
run-interactive stamping.
- Display boundaries never render the raw tag: the queued-prompt echo
in the message translator now goes through formatDisplayUserInput,
and isSyntheticUserPrompt strips notices before matching so a stamped
continuation prompt cannot shift edit/regenerate ordinals.
* feat(cli): manual API key escape hatch for Cline OAuth providers
Add a way to configure the cline / cline-pass providers with a dashboard
API key from the /settings provider flow, for users where OAuth login
isn't working:
- "Enter API key manually" option in the already-configured dialog
- K keybinding in the OAuth login dialog to switch to key entry
- Saving clears stored OAuth tokens (on both the shared cline storage
entry and any direct cline-pass entry) since the auth handler prefers
auth.accessToken over apiKey — a stale token would otherwise keep
winning over the manual key
- isProviderConfigured now counts a persisted API key for OAuth
providers so escape-hatch users aren't forced back into OAuth on
every provider switch
* fix(cli): move API key fallback to OAuth dialog
* Add the ClinePass limit error to the CLI
* Update apps/cli/src/runtime/run-agent.test.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* format code and improve instructions
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix(auth): add early SDK debug logging for Cline credential lifecycle (ENG-2213)
Adds targeted debug-level logging at key points in the Cline/Cline Pass
credential lifecycle to diagnose intermittent logout issues. Credentials
are never logged in cleartext; an 8-hex-digit SHA-256 hash is used instead.
The SDK has two logger layers:
1. ClineCore.logger — session-scoped, threaded from ClineCore.create({logger})
into session config and the agent event bridge.
2. setSdkLogger() — early/module-level, for components that operate before
or outside of ClineCore sessions: ProviderSettingsManager (constructed
at startup), RuntimeOAuthTokenManager, and cline.ts auth functions
(token refresh). These can't be reached by the session-scoped logger.
Both VS Code (common.ts) and CLI (main.ts) call setSdkLogger() once at
startup. When no logger is registered (or the host filters out debug),
every call is a no-op — logging is never collected in normal use.
Instrumentation points (SDK core, shared by both surfaces):
- ProviderSettingsManager.read(): logs provider IDs, last-used, and whether
Cline auth is present (with hashed access/refresh token fingerprints)
- ProviderSettingsManager.saveProviderSettings(): logs the provider being
saved, tokenSource, whether Cline auth was present before/after, and
flags authDropped when a previously-present Cline auth block disappears
- RuntimeOAuthTokenManager.resolveProviderApiKeyInternal(): logs each
decision point (no_settings, no_credentials, refresh_start, refresh_null,
refreshed+saved, not_refreshed) with hashed token fingerprints
- cline.ts refreshClineToken(): logs the refresh request URL, response
status/errorCode on failure, and new token hashes on success
- cline.ts getValidClineCredentials(): logs the outcome at each branch
(no_current_credentials, still_valid, needs_refresh, invalid_grant,
transient_failure_kept_current, transient_failure_expired)
VS Code extension (auth-service.ts):
- readClineCredentials/writeClineCredentials/clearClineCredentials: logs
credential presence and hashes at each disk I/O point
- refreshAccessToken: logs refresh start, null result (cleared), changed
(written), or unchanged outcomes
- fetchUserInfoFromApi: logs the GET /api/v1/users/me request and response
status
What to collect when investigating:
VS Code extension:
- Open the "Cline" output channel (View -> Output -> select "Cline")
- Look for lines containing: [SdkAuthService], providers.read,
providers.save, oauth.resolve, cline.refresh, cline.getCredentials
- Debug logging is emitted at the DEBUG level; it appears in the output
channel when IS_DEV=true or in development builds
CLI:
- Set CLINE_LOG_LEVEL=debug environment variable before running cline
- Collect the log file at ~/.cline/data/logs/cline.cli.log (or the path
set by CLINE_LOG_PATH)
- Look for the same event names as above
Files changed:
- sdk/packages/core/src/auth/auth-debug.ts (NEW): hashSecret,
setSdkLogger, getSdkLogger, sdkDebug
- sdk/packages/core/src/auth/cline.ts: refresh/getCredentials logging
- sdk/packages/core/src/services/storage/provider-settings-manager.ts:
read/save logging
- sdk/packages/core/src/runtime/orchestration/runtime-oauth-token-manager.ts:
resolve logging
- sdk/packages/core/src/index.ts: export early logger utilities
- apps/vscode/src/sdk/auth-service.ts: credential lifecycle logging
- apps/vscode/src/common.ts: register SDK early logger
- apps/cli/src/main.ts: register SDK early logger
* fix(vscode): inline SDK debug metadata into log message string (ENG-2213)
* fix(auth): gate debug logging on CLINE_LOG_LEVEL at runtime (ENG-2213)
* fix(auth): use interpolated debug strings, remove log-level gating (ENG-2213)
* refactor: move early logger to sdk/packages/core/src/logging/early-logger.ts
* fix: address review feedback — early logger registration, log after write, remove getSdkLogger from public API
* fix(vscode): add ISO timestamps to all log lines
* fix core import
* fix import
* fix tests
---------
Co-authored-by: Tomás Barreiro <52393857+BarreiroT@users.noreply.github.com>
Co-authored-by: BarreiroT <tomasmbarreiroi@gmail.com>
* fix(sdk): set versioned Cline client-identity headers for Cline provider
* address feedback
* feat: add platform metadata to client context
Include platform, platformVersion, and isMultiRoot in extension client
context for CLI, ACP, and VS Code sessions. This provides downstream
core/session logic with richer runtime information and distinguishes ACP
clients from the standard CLI client.
* lint
* clean up
* fix: resolve client host identity via HostProvider for standalone compatibility
cline-session-factory.ts is also bundled into the standalone cline-core
(JetBrains), where the 'vscode' module resolves to the generated Proxy-stub
module: vscode.env.appName and vscode.version return Proxy objects, which
would flow into X-PLATFORM/X-PLATFORM-VERSION header values and fail at
request serialization.
Resolve the identity through HostProvider.env.getHostVersion() instead —
the VS Code hostbridge returns the identical values (vscode.env.appName,
vscode.version, ClineClient.VSCode, extension version), and JetBrains'
hostbridge returns its real host values, so the standalone stops reporting
itself as the VS Code extension as a bonus. Multi-root detection goes
through HostProvider.workspace.getWorkspacePaths() for the same reason.
Both resolvers degrade gracefully (undefined/false) if the host bridge is
unavailable, in which case the header builder falls back to source-derived
values.
* Add unit test as proof
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
* feat(llms): include Cline free models in the cline-pass catalog
* feat(vscode): show Subscribed/Free model tabs on the ClinePass provider
* feat(cli): show Subscribed/Free sections in the ClinePass model picker
* fix(cli): drop redundant browse-all entry from ClinePass picker
* fix(cli): show only subscribed models in ClinePass onboarding picker
* feat(cli): include free models and quota explainer in ClinePass onboarding picker
* fix: shorten ClinePass free section copy
* fix(cli): strip redundant free markers from sectioned picker names
* fix: drop free from ClinePass free section copy
* fix: tighten ClinePass free section copy
* refactor: address review feedback on ClinePass free models
- single buildFeaturedModelEntries(providerId) dispatcher, builders private
- rename isClineProvider to isClineManagedProvider (includes cline-pass)
- use isClineManagedProvider in the free-model cost check
- themed tab border, pretty names on free model cards
- clearer cline-pass cost test name
* fix: address ClinePass free-model review blockers
- Stop re-sorting the cline-pass live catalog by release date in
mergeKnownModels: free models carry OpenRouter release dates, so the
sort could put a free model first and make it the fallback default
when the bundled default id rotates out of the live clinePass bucket.
Preserve the normalize-time order (pass models first) and pin it with
an end-to-end resolveProviderConfig test.
- Add the browse-all escape to the CLI ClinePass picker when the
clinePass bucket is empty (bundled fallback after a fetch failure),
so a subscriber isn't left with a free-models-only picker.
- Rename ErrorRow's local isClineManagedProvider to
isClineUsageBillingProvider: it only matches the cline provider,
unlike the shared util of the same name that also matches cline-pass.
* fix(sdk/cli): emit user_id in telemetry identity attributes
Per CLINE-2406, downstream analytics expects an explicit user_id field
in authenticated SDK/CLI OpenTelemetry log attributes.
Changes:
- sdk/packages/core/src/services/telemetry/core-events.ts: add
user_id: account.id alongside the existing account_id in
identifyAccount() updateCommonProperties call.
- sdk/packages/core/src/services/telemetry/core-events.test.ts: new
identifyAccount suite verifying user_id, account_id, distinct_id, and
org context fields for authenticated user without org, with active org,
absent/blank id handling, and no-op when telemetry is undefined.
- apps/cli/src/main.ts: after loading Cline provider settings in the
runtime path, read auth.accountId and call identifyTelemetryAccount so
subsequent task.* and workspace.* events carry user_id. Document
user.extension_activated as pre-auth by design for subcommand flows.
- apps/cli/src/main.test.ts: three new tests covering saved accountId
triggers identity, missing accountId skips identity, non-Cline
provider skips identity.
* fix(sdk/cli): address review feedback on telemetry identity
- Use trimmed distinctId for user_id in identifyAccount() to keep
user_id and distinct_id consistent when IDs have whitespace
- Remove fragile type cast in CLI main.ts; ProviderSettings already
exposes auth.accountId via AuthSettingsSchema