* fix(cli): resolve macOS screenshot paths with narrow no-break space
macOS Sonoma+ embeds U+202F (NARROW NO-BREAK SPACE) before AM/PM in
screenshot filenames like "Screenshot 2026-05-12 at 4.42.48\u202FPM.png".
When the path travels through clipboards, terminals, or anything that
normalizes whitespace, U+202F collapses to a regular space (U+0020) --
but the on-disk filename still contains U+202F, so readFileSync fails
with ENOENT and the paste handler silently drops the image.
Add resolveExistingImagePath() with a tiered Unicode-variant lookup
(narrow no-break space before AM/PM, NFD normalization, curly
apostrophe for localized names, and a parent-directory canonical-
whitespace scan as a last-resort fallback). Wire it into the TUI image
paste handler so dragged/pasted screenshots resolve correctly.
Tests added in image-paste.test.ts cover both the targeted AM/PM
variant and the generic NBSP-in-filename fallback path.
* fix(core): resolve macOS U+202F screenshot paths in read_files tool
The first commit on this branch fixed the CLI image-paste handler only.
A live repro from session 1778635423953_jac9b showed the same U+202F bug
on a different surface: the agent`s read_files tool. When the LLM was
asked about a macOS screenshot, it called read_files with the path text
from the user message -- which had a regular space where the on-disk
filename has U+202F -- and fs.stat returned ENOENT.
Extract the tiered Unicode-variant resolver into @cline/shared as
resolveExistingFilePath (the algorithm is generic, not image-specific).
Wire it into:
- packages/core/src/extensions/tools/executors/file-read.ts (the
new fix; read_files now tolerates U+202F / NFD / curly apostrophe
variants before falling back to a parent-dir scan).
- apps/cli/src/utils/image-attachments.ts (refactor to use the
shared helper instead of duplicating the algorithm).
Regression tests in packages/shared/src/path-resolution.test.ts and
packages/core/src/extensions/tools/executors/file-read.test.ts; the
CLI tests from the first commit continue to pass via the shared helper.
Live verification against the real screenshot from the bug repro
(/Users/robin/Desktop/Screenshots/Screenshot 2026-05-12 at 6.18.40 PM.png,
on-disk name uses U+202F): direct invocation of the executor with a
regular-space path now returns an image block (42,296 bytes) instead
of throwing ENOENT.
* fix(shared): tighten unicode path variant probes
* fix(shared): move path resolver to storage exports
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
* feat(cli): add --worktree flag to auto-create and run in a new git worktree
Adds a --worktree flag to the CLI root command and 'cline task' that detects the git repo root for the current directory, creates a detached-HEAD worktree at ~/.cline/worktrees/<uuid>/<repoName>/ (matching Kanban's convention), and runs the task with cwd set to the new worktree.
The core implementation lives in src/utils/git-worktree.ts as createTaskWorktree() so any surface (CLI, VS Code, JetBrains, future tools) can use the same helper.
Works with --taskId and --continue so the legitimate workflow of 'resume this task in a fresh clean worktree to try a different approach' is supported. For --continue, the most-recent-task lookup uses the original cwd before the worktree rewrite so history resolves correctly.
Refs: ENG-2028
* address greptile review
- Distinguish 'git not installed' from 'not a git repo' so the error message points at the actual problem instead of misleading the user.
- Reject taskIds containing a null byte; would otherwise sneak past the '..' substring check on some kernels (e.g. 'safe\\0../escape').
- Reject `--worktree` without a prompt / --taskId / --continue before kanban auto-launches, so 'cline --worktree' no longer creates an orphan worktree that's abandoned if the user exits the welcome TUI without submitting a task.
* feat(cli): move worktree flag to sdk cli
* fix(cli): match kanban worktree ids
* fix(cli): handle piped worktree input
* chore: remove legacy worktree diff
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
* feat(core): add user.provider_configured event and captureProviderConfigured helper
Adds a new standardized telemetry event for when a user successfully
saves a BYO (bring-your-own) provider API key, separate from the
existing user.auth_* OAuth events.
- Add USER.PROVIDER_CONFIGURED = 'user.provider_configured' to the
core event registry.
- Add captureProviderConfigured(telemetry, provider) helper that
mirrors the { provider } payload shape of captureAuthSucceeded and
routes through capture() (so it respects telemetry opt-out).
- Export captureProviderConfigured from @cline/core.
- Add focused tests for payload shape, provider=undefined fallback,
and telemetry=undefined no-op.
* feat(core): thread optional telemetry through loginLocalProvider
Adds an optional telemetry parameter to loginLocalProvider so callers
can opt into standardized auth event emission without changing
existing behavior when no telemetry is passed.
- loginLocalProvider() accepts optional telemetry service.
- Forwards telemetry to loginClineOAuth, loginOcaOAuth, and
loginOpenAICodex for the start/success/failure auth events.
- For Cline device-code login, passes telemetry into
completeClineDeviceAuth().
- Telemetry remains optional throughout; existing callers continue to
compile and run unchanged.
* feat(sdk-tui): emit auth and provider_configured telemetry in onboarding flows
Wires the SDK TUI onboarding login page into the standardized
telemetry events introduced in earlier commits.
- runOAuthAuthFlow() and runDeviceCodeAuthFlow() accept an optional
telemetry service and forward it into loginLocalProvider so the
start/success/failure auth events fire from the underlying core
auth helpers.
- useOnboardingController() passes getCliTelemetryService() into the
OAuth and device-code login paths so events use existing CLI
metadata and respect telemetry opt-out.
- saveByoConfig() fires captureProviderConfigured for the BYO
(bring-your-own API key) onboarding path right after the
credential save. Invalid credentials still surface later as the
existing task.provider_api_error on the first API call.
- Esc/cancel remains a local abort and does not synthesize extra
failure telemetry unless the underlying auth helper itself emits
an error.
- Adds a focused test confirming the SDK TUI auth path passes
telemetry into the underlying auth helpers.
ENG-2018
* test(core): lock in telemetry opt-out policy for captureProviderConfigured
Adds captureProviderConfigured to the existing telemetry-policy
regression suite (`describe("telemetry policy: helpers respect
telemetry opt-out")`) so a disabled adapter is verified to drop the
event end-to-end through a real TelemetryService instance, matching
the coverage the other capture* helpers already have.
Addresses PR #10686 review feedback.
* test(core): include captureProviderConfigured in disabled-adapter policy test
The policy regression test that asserts a correctly-policed disabled
adapter drops all non-required events was missing a call to
captureProviderConfigured. Add it alongside the other captures and
include the expected dropped event in the assertion.
Display session status labels in CLI history output and refresh the
standalone history TUI so running sessions can update in place.
Merge refreshed status rows with existing hydrated metadata to preserve
titles and cost details while keeping status current.
* feat(sdk): emit telemetry for compaction lifecycle events
Adds two SDK telemetry events to give us observability into the
compaction pipeline, which previously only fired a generic
`agent.status-notice` pass-through that carried no result data.
- `task.compaction_executed` fires after a successful compaction with
strategy, mode, before/after message counts, before/after token
counts, threshold, durationMs, provider, modelId, and agent identity.
- `task.compaction_skipped` fires when the configured strategy returns
`undefined` (reason: "no_result"). Strategy exceptions still propagate.
`createContextCompactionPrepareTurn` is extended to accept `telemetry`
and `sessionId` from `CoreSessionConfig`; the CLI manual `/compact`
path forwards both so manual compactions emit events alongside auto.
Known gap (documented inline): plugin `registerMessageBuilder()` and
runtime hook `beforeModel` compactions bypass this wrapper and emit no
telemetry today.
Field names follow the existing `TASK.*` capture-function convention
(`provider`, `modelId`, `ulid`, `Partial<TelemetryAgentIdentityProperties>`)
so downstream PostHog joins remain consistent.
Fixes CLINE-2174
* test(sdk): cover compaction telemetry opt-out policy
* fix(cli): wire telemetry service into run config so compaction events fire
Prepare cli-v3.0.0 as the first proper CLI release cut from cline/cline.
Workflow (.github/workflows/publish-cli.yaml):
- Add Get Previous CLI Tag step (git describe --match 'cli-v*' so the
lookup ignores the VS Code extension's v* tags)
- Add Get Changelog Entry step (awk extraction from
apps/cli/CHANGELOG.md, mirroring the extension's publish.yml)
- Switch to softprops/action-gh-release@v1 for the release step and
paste the changelog content into the body
- Slack payload now includes the changelog body via toJSON plus an npm
link, mirroring the extension's pattern
- Both the GitHub release compare link and the Slack compare suffix
are guarded on prev_tag != '' so the first cli-v* release ships
without a broken compare URL
- Drop bold formatting (**Full Changelog**, *Cline *) per the
repo's no-bold rule
Publish script (sdk/apps/cli/script/publish-npm.ts):
- Copy apps/cli/README.md into the generated wrapper package so the
npm registry listing has a real landing page
- Forward keywords, author, homepage, and bugs from the source
package.json into the wrapper (the script previously only forwarded
name/version/description/license/repository/bin/scripts/optionalDeps,
so the metadata polish would have been invisible on the npm page)
Package metadata (sdk/apps/cli/package.json):
- Drop [EXPERIMENTAL] from description, align wording with the VS Code
extension
- Add keywords, author, homepage, bugs
Changelog (sdk/apps/cli/CHANGELOG.md):
- Strip publication dates from all entries so the awk regex is just
'^## [0-9]'
- Replace the bare 3.0.0 placeholder entry with a proper section
framing this as the first release from the cline/cline monorepo
README and dev docs (sdk/apps/cli/README.md, DEVELOPMENT.md):
- Rewrite README as a user-facing npm landing page with header image
and links table, aligned with the new cline/cline monorepo voice
(Run Cline in your terminal — interactive chat or fully headless
for CI/CD and scripting)
- Add Headless mode for CI/CD section with concrete pipe / JSON
examples
- Cover all five registered connectors (Telegram, Slack, Google Chat,
WhatsApp, Linear) with correct flag names
- Move dev-only sections (Publishing, Runtime Ownership, Connector
runtime behavior, Logging Adapter) into DEVELOPMENT.md
Skill doc (sdk/apps/cli/.cline/skills/publish-cli/SKILL.md):
- Document the no-date header format and the workflow's awk-based
changelog extraction
* docs: rewrite README as product showcase and remove locales
Replaces the VS Code-only README with a product line overview
covering CLI, VS Code extension, JetBrains plugin, and SDK.
Adds dedicated feature sections for code editing, terminal
commands, Plan/Act mode, MCP and plugin extensibility,
multi-agent teams, messaging platform connectors, scheduled
agents, headless CI/CD mode, rules, and model provider support.
Removes the outdated locales/ directory with translated
README, CONTRIBUTING, and CODE_OF_CONDUCT files for 8 languages
that were no longer maintained.
* docs: add Kanban to product grid and reorganize as 2x2 layout
* docs: add line breaks at end of each product table cell
* docs: add line breaks at end of each product table cell
* docs: add more bottom padding to product table cells
* small updates to readme
* first attempt
* docs: fix README product links and examples
* docs: address Greptile README followups
* docs: add Vercel AI Gateway provider
* nit
* one more small change
* Update VS Code Extension link and status in README
* Fix link formatting for VS Code Extension in README
---------
Co-authored-by: Renee Huang <renee@cline.bot>
Co-authored-by: Arafatkatze <arafat.da.khan@gmail.com>
Filter teammate/subagent sessions out of session history unless explicitly
requested. Increase the backend scan limit to compensate for filtered rows so
root session listings can still satisfy the requested limit.
* ci: migrate SDK publish workflows to repo root
Move publish-cli.yaml, publish-sdk.yaml, and test.yml (renamed to
sdk-test.yml) from sdk/.github/workflows/ to the repo root so GitHub
Actions actually picks them up. Adapt them to run with cwd sdk/ via
workflow-level defaults.run.working-directory, repoint repo guards
from cline/sdk to cline/cline, switch publish-sdk's nested test call
to sdk-test.yml, add path filters on sdk-test.yml so it doesn't fire
on extension-only PRs, and re-enable NPM_CONFIG_PROVENANCE now that
cline/cline is public.
Update the publish-cli skill with a cwd note so the documented
release commands keep working from sdk/.
* ci: remove legacy CLI publish workflows
The legacy publish chain (publish-cli-trusted.yaml dispatching into
npm-main.yaml + npm-nightly.yaml) publishes the old cli/ folder to
the same cline npm package the new SDK CLI is taking over. Leave
both wired up and a maintainer could accidentally publish an old
build over the handoff. Remove the dispatcher, the two callees, the
PR-preview tarball workflow (pack-cli.yml + build-cli-artifact.sh),
the TUI test workflow that only fed into them, and the npm packaging
script those workflows shared.
The cli/ source itself is left in place for a separate removal PR.
* chore: remove legacy CLI dev and eval helpers
With the legacy CLI publish workflows gone, the surrounding dev and
eval glue that only existed to feed those workflows is also dead.
Delete tests/e2e/cli/ (TUI tests), evals/smoke-tests/ (CLI smoke
evals), and the cline-evals-regression.yml workflow that drove them.
Trim the root package.json scripts that pointed at this infra:
- cli:link, cli:build, cli:run, cli:build:production, cli:watch,
cli:test, cli:dev, cli:unlink (all delegated into cli/)
- compile-standalone-npm and postcompile-standalone-npm (only the
removed npm-main/npm-nightly workflows called them)
- test:e2e:cli:tui (only the removed cli-tui-tests.yml called it)
- eval:smoke:*, which chained through cli:build + cli:link
Drop the trailing `cd ../cli && npx tsc --noEmit` segment from
check-types so the root typecheck stops walking into cli/.
The cli/ source itself stays in place for a separate removal PR.
* docs(evals): note removed smoke-tests layer
The evals/README.md and evals/ARCHITECTURE.md were structured around
smoke-tests as Layer 2 of the pyramid. With evals/smoke-tests/ and
the eval:smoke scripts gone, those references are stale. Add a top-
of-doc banner pointing at the removal rather than gutting both files
in this PR; a follow-up can scrub the structure when the framework
is updated for the new SDK CLI.
* chore(evals): restore smoke-tests, disable workflow pending rewire
The smoke-test scenarios in evals/smoke-tests/ are CLI-agnostic — each
scenario is just a config.json prompt plus optional template files —
so they're worth preserving across the legacy CLI sunset. Restore the
directory and the cline-evals-regression.yml workflow, but reduce the
workflow's triggers to workflow_dispatch only so it doesn't auto-run
in its current legacy-CLI-coupled form. Add a header comment pointing
at the rewire work.
Update the evals/README.md and evals/ARCHITECTURE.md banners from
"removed" to "temporarily disabled" to match reality.
Wiring the workflow at the new SDK CLI (and restoring the eval:smoke
root scripts) is left for whoever picks up the eval framework refresh.
* chore(evals): restore eval:smoke:run for ad-hoc smoke checks
The runner (`evals/smoke-tests/run-smoke-tests.ts`) shells out to
whichever `cline` is on $PATH, so it already works against the new
SDK CLI once `npm i -g cline` installs it. Add back just the single
`eval:smoke:run` script so docs and manual validation have a working
entrypoint. The build-and-link chain (`eval:smoke:build`, `eval:smoke`,
`eval:smoke:ci`) stays out — those need rewiring before they function.
Update the README/ARCHITECTURE banners accordingly.
* fix(ci): update SDK npm repository metadata
* fix(ci): tighten SDK publish workflows
* Truncate text block tool results in compaction
* Log context sizing diagnostics
* Use default reserve for compaction trigger
* Cap default compaction trigger at ninety percent
* Use provider-sized estimates for compaction
* Update manual compaction test for conservative estimates
* Truncate retained tool results during compaction
* Add live Codex compaction coverage
* Make basic compaction tool-pair atomic
Basic compaction's predicate-based removal could split a tool_use from its matching tool_result, leaving the assistant message with an orphaned tool_use. MessageBuilder then synthesized "Tool execution was interrupted before a result was produced." which the model echoed back to the user.
Make removal expand to all candidates linked by tool_use_id so tool_use and tool_result share a fate.
* Protect latest turn from basic compaction
* Extract token estimator to @cline/shared
agent-runtime had a local /4 estimator while compaction-shared had
a /3 estimator. Both compute the same concept (char-to-token rough
estimate) but with different bias. Reviewer noticed the discrepancy.
Centralize on /3 (slightly conservative, fires compaction trigger
earlier rather than later). Diagnostic logging in agent-runtime now
uses the same estimator, eliminating divergence.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Snap agentic compaction cut to a turn-start boundary
findCutIndex previously walked back by token budget and could land
between an assistant tool_use and its matching user tool_result.
The tool_use ended up folded into the summary while the tool_result
was preserved in the tail, producing an orphaned tool_result that
the provider rejects with:
No tool call found for function call output with call_id ...
The same failure mode can occur in the inverse direction (orphaned
tool_use). Both leave the session unrecoverable.
Snap the cut to the nearest turn-start boundary at or before the
budget candidate. This keeps each turn — its typed user message
plus any tool_use/tool_result/assistant follow-ups — together,
either fully summarized or fully preserved.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat: add SDK cookbook examples with difficulty progression
Add three new example apps to apps/examples/ organized as a
difficulty ladder from beginner to advanced, similar to Cursor's
SDK cookbook. Includes a top-level README linking all examples.
- quickstart: minimal ~15 line agent, send a prompt, stream response
- cli-agent: interactive terminal chat with a shell tool
- code-review-bot: structured code review with custom tools and
completion lifecycle
* feat: add multi-agent fan-out example with streaming web UI
Spawns three specialist agents in parallel, streams their responses
to the browser via SSE, then a synthesizer agent combines their
findings into a unified answer. Single-file server with inline HTML.
* chore: replace pnpm with bun in example docs and source
* fix: use claude-sonnet-4-6 model ID in examples
* fix(examples): use Cline keys in cookbook
* docs(examples): add SDK build step
* Use input limits for model context windows
* Fix maxTokens discount when input becomes contextWindow
The existing "if contextWindow === outputToken, discount to 5%" heuristic was a safety net for models.dev returning bogus context==output data. After switching contextWindow resolution to min(input, context), the equality check started misfiring on legitimate input==output configurations like gpt-5-pro, o3-pro, and codex-mini.\n\nPin the discount to the raw context limit so the original safety net behavior is preserved.
* Rename ModelInfo.contextWindow to maxInputTokens
The field has been used as an input-token budget throughout the
codebase (compaction trigger, status-bar utilization, gateway
passthroughs) but the name suggested combined input+output context.
After the catalog change to read limit.input from models.dev, the
field's semantics now match its actual use: a prompt ceiling.
Renames:
- ModelInfo.contextWindow -> ModelInfo.maxInputTokens
- GatewayModelDefinition.contextWindow -> maxInputTokens
- CoreCompactionConfig.contextWindowTokens -> maxInputTokens
- CoreCompactionContext.contextWindowTokens -> maxInputTokens
Internal consumers updated. User-facing settings schemas
(provider-settings, remote-config, RPC settings, test fixtures)
intentionally keep their existing names to avoid breaking user
configs and the API server contract.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Rename internal helpers and constants to match maxInputTokens
Naming-only refactor to complete the field rename. No behavior change.
- DEFAULT_CONTEXT_WINDOW_TOKENS -> DEFAULT_MAX_INPUT_TOKENS
- DEFAULT_CONTEXT_WINDOW -> DEFAULT_MAX_INPUT_TOKENS
- FALLBACK_MANUAL_COMPACTION_CONTEXT_WINDOW_TOKENS -> FALLBACK_MANUAL_COMPACTION_MAX_INPUT_TOKENS
- resolveContextWindowLimit -> resolveMaxInputTokens
- getContextWindowTokens -> getMaxInputTokens
- resolveModelContextWindow -> resolveModelMaxInputTokens
- hasContextWindow -> hasMaxInputTokens
- formatContextWindow -> formatTokenCount
Also drops the legacy snake_case context_window fallback in
resolveModelMaxInputTokens, since this PR is a hard break and
no downstream data path emits that shape any longer.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Rename TokenConfig.maxContextTokens to maxInputTokens
Last consumer of the 'context tokens' naming, used internally to
override a model's input ceiling. Renaming for consistency with
ModelInfo.maxInputTokens.
User-facing settings.contextWindow stays as-is and now maps to
TokenConfig.maxInputTokens at the boundary.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Keep context window alongside input limits
* Fallback to contextWindow for interactive compaction
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* Introduce Cline environments to the SDK
* Add partial to the process env
* Replace the default cline api url with a dynamic one
* Make the default base url dynamic
* add tests
* feat: promote remote-config primitives from enterprise
Move remote-config schemas, managed instruction materialization, blob upload metadata, and OpenTelemetry config normalization into @cline/shared so managed configuration can be reused without an enterprise package dependency. Update architecture guidance and runtime coverage for rule/workflow materialization.
* patches
---------
Co-authored-by: BarreiroT <tomasmbarreiroi@gmail.com>
* rename folders
* fix examples reorg references
* move over files
* having agent fixing and validating all examples are still working
* fix sidecar paths
---------
Co-authored-by: abeatrix <beatrix@cline.bot>