* feat(desktop): add Retina DMG background tooling
* feat(desktop): customize the macOS DMG layout
* ci(desktop): validate DMG background assets
* fix(desktop): adjust DMG Applications icon position
* ci(desktop): drop redundant DMG artwork validation from publish workflow
Tauri's beforeBuildCommand already runs dmg:background (with its own
validation) at the start of the build/sign/notarize step, and the
release/beta config overlays do not override the build section, so this
step duplicated work the publish job performs anyway. PR-time coverage
lives in desktop-test.yml.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
The PublishNightly environment gained required reviewers, so each cron
run parked on approval, held the workflow's concurrency group, and
silently cancelled every scheduled run queued behind it. 20 consecutive
scheduled nightlies died this way between 2026-07-31 and 2026-08-21;
the only nightlies that shipped in that window were manual dispatches.
Drop the cron rather than leave a trigger that cannot succeed unattended.
The job sets working-directory: apps/vscode, but that default applies to run
steps only, not to `uses:` steps. Since #10961 moved the extension under apps/
and added that default, the artifact path has resolved against the repo root,
matched nothing, and every failing run logged "No files were found with the
provided path: test-results/playwright/" instead of uploading recordings.
Widen to test-results/ so Playwright's error-context snapshots ship alongside
the videos.
Publish workflows now always do clean npm installs (no dependency
cache in their test gates), the e2e workflow's cache keys are
exact-match only, and the e2e job drops an id-token permission it
never used.
Slack section blocks reject text longer than 3000 characters. The Slack
action logs that rejection as ##[error] but does not fail the step, so an
over-long changelog drops the release announcement while the run stays
green — cline@3.0.50 (3272 chars) published to npm, tagged, and cut a
GitHub release with no Slack post and nothing red to notice.
Every publish workflow pasted the changelog section verbatim into one
section block, so all six were exposed; the SDK, desktop, and extension
sections were only 150-350 chars under the ceiling.
Add a slack_content output alongside content: unchanged when the section
fits, otherwise trimmed on a line boundary with a link to the full
release notes. Only the Slack payload uses it — GitHub release bodies and
the desktop updater manifest still get the whole section.
@cline/ui's generated-media imports @cline/shared/browser, which resolves to
shared's dist output. The build-shared step sat after typecheck/test/build,
so the first ui-publish dispatch since #13025 failed at Typecheck UI with
TS2307. Move the step to right after install.
The branch dispatch input was a free-form string with no validation. Both
jobs checked it out and ran full npm lifecycle scripts from it: the publish
job next to VSCE_PAT/OVSX_PAT (and npm run publish:marketplace executes a
script from that same ref with the PATs in env), and the test job with NO
environment approval at all while inheriting the workflow-level
contents/packages/checks/pull-requests write grants. A dispatch pointing at
e.g. refs/pull/N/head would run outside-contributor code with the
marketplace keys behind one approval, or with a repo-write token behind
none.
Remove the input and hardcode the protected legacy-extension branch, drop
the workflow-level permissions to contents: read, and elevate only the
publish job to contents: write (tag push + GitHub release). The branch
input's default was legacy-extension, so normal publishes are unchanged.
publish-extension skill dispatch command updated to match.
The combined-VSIX workflow took legacy-ref as a free-form dispatch input
with no publish-time validation (next-ref has one: publish requires main).
Any typed ref — a PR merge ref, an unprotected branch — would be built
into the published VSIX by the environment-less build job, and the publish
environment approver only ever sees an opaque prebuilt artifact, so the
approval protected the marketplace PAT but not the shipped bytes.
Remove the input entirely and hardcode the protected legacy-extension
branch, which makes that branch's protection rules load-bearing for
releases. The tested-sha pinning between test-legacy and build is
unchanged. publish-extension skill dispatch command updated to match.
* feat(desktop): add beta release channel from desktop-experimental branch
Adds a 'channel' input (stable|beta) to desktop-publish.yml. Beta releases
are tagged desktop-vX.Y.Z-beta.N on the desktop-experimental branch, built
with the tauri.beta.conf.json overlay (Cline Code Beta / bot.cline.app.beta,
side-by-side install with stable), published as prerelease GitHub releases,
and served by a separate rolling desktop-beta update feed. Both channels
dispatch from main so the PublishDesktop signing gates are unchanged.
Guards: stable channel now rejects prerelease tags (previously a beta tag
could clobber desktop-latest and auto-update every stable install onto it),
feed selection is fail-closed and cross-checked in the release job, and the
build asserts the compiled binary embeds exactly its own channel's feed URL.
Changelog extraction is exact-version now that stable and beta sections
interleave across branch merges.
Process doc in apps/examples/desktop-app/EXPERIMENTAL.md; publish-desktop
skill now asks stable-or-beta.
* docs(desktop): warn against renaming the desktop-latest feed
* docs(desktop): document the code-trust model for publish approvals
The beta dispatch-from-main invariant protects the workflow definition, not
the checked-out tag's build scripts, which run with signing secrets in scope
for stable and beta alike. Make explicit that the PublishDesktop reviewer
approval is the trust gate for that code, and that desktop-experimental
therefore needs main-grade merge controls.
The publish job ran under the shared `Publish` GitHub environment, whose
required reviewers turned every @cline/ui release into a two-person
ceremony. Nothing in the job reads secrets from that environment — it
authenticates to npm purely over OIDC trusted publishing — so the
environment bought us an approval prompt and nothing else. sdk-publish
and cli-publish already publish unattended the same way.
The npm trusted publisher for @cline/ui was registered with
`environment: Publish`, which pins the OIDC token's environment claim, so
it has been re-registered without it (same repo, workflow file, and
permissions). That change is already live; landing this without it would
have broken publishing.
Access is still gated by workflow_dispatch (write access required), the
`refs/heads/main` ref check, and the typed `publish` confirmation.
Tauri's universal-apple-darwin target lipos the Rust binary but expects
sidecars to already be fat binaries, so build-sidecar-bin.ts now compiles
both Bun slices and merges them when the target triple is universal.
The publish workflow builds one universal bundle instead of a two-leg
matrix, verifies every Mach-O in the bundle carries both slices, and the
updater manifest points both darwin-aarch64 and darwin-x86_64 at the same
universal artifact so existing per-arch installs migrate automatically.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* ci(desktop): drop the Rust build cache from the code-signing job
The `build` job is the only one that can read the Apple Developer ID
certificate and the Tauri updater signing key, and it restored a
swatinem/rust-cache archive before running them. A restored cache archive
is attacker-controlled the moment the Actions cache is poisoned, which is
the pivot used against this repo's nightly workflow in Feb 2026 and the
reason actions/cache was stripped from the credential-bearing publish
jobs at the time. This workflow was added months later and reintroduced
the pattern. The updater key is the worst thing here to leak: it signs
every auto-update the installed desktop app accepts.
The cache was also not buying anything. Across the eight runs of this
workflow, seven logged "No cache found" on both matrix legs; only the run
32 minutes after another one hit, saving 1-3 minutes. A release cadence
measured in days does not outlive the entry under the repo's 10 GB LRU
eviction, so the steady state was a cold build regardless. Cold builds
took 5-7 minutes against a 90-minute timeout.
No behaviour change otherwise: the step had no id and no outputs, so
nothing referenced it.
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* ci(desktop): trim the cache-removal comment to the constraint
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
---------
Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
* ci(desktop): gate desktop publish secrets behind PublishDesktop environment
The Apple signing/notarization and Tauri updater secrets were repository
secrets, readable by any workflow in the repo and by anyone with push
access via a branch carrying a modified workflow. Move them behind the
PublishDesktop environment, which requires reviewer approval and
restricts deployments to main.
The build job now declares the environment, so those secrets are readable
only there and only after an approval. Add a preflight check because a
missing secret fails dangerously rather than loudly: Tauri silently skips
code signing when APPLE_CERTIFICATE is empty and skips notarization when
APPLE_API_KEY is empty, so a misconfigured environment would still
publish an unsigned, un-notarized bundle. Only a missing updater key was
already caught, by the .sig check in Collect artifacts.
validate stays ungated so a bad tag fails in seconds rather than after an
approval, matching the ungated-build/gated-publish split in
ext-vscode-ab-package. The shared Slack and telemetry secrets stay where
they are; scoping them to this environment would silently empty them in
the CLI, SDK, and extension publish workflows.
* ci(desktop): verify signing secrets are not repository-scoped
The preflight added in the previous commit checks that the signing
secrets are non-empty, which proves presence but not scope, and then
reported that they had resolved from PublishDesktop. An environment-gated
job resolves repository and organization secrets too — environment values
merely take precedence — so a credential left at repository level would
pass that check while the message claimed the migration had worked. This
workflow already demonstrates it: the gated build job reads the shared
Slack and telemetry secrets, none of which are on the environment.
Add the complementary check to validate, which declares no environment: a
signing secret that resolves there can only be repository- or
organization-scoped, so it fails the run and names the offenders. Neither
check establishes provenance alone; together they do. validate is
ungated, so a misplaced secret now fails before the approval rather than
after it.
Also drop the provenance claim from the build message and correct the
skill doc, which stated that a repository-level secret would be invisible
to the gated job.
Reported by greptile on #12854.
* ci(vscode): gate the combined A/B package workflow on both bundles' test suites
* docs(skills): add publish-extension skill for VS Code extension releases
* ci(vscode): pin tested revision for next bundle and refuse publishing untested next-refs
* ci(vscode): pin legacy bundle to the revision its test gate ran against
The desktop chat integration test renders components from @cline/ui, but
it also pulls @cline/shared/browser through the desktop app's own
message-content module. That subpath resolves to dist output no step in
this job produced, so the suite failed to collect.
Build @cline/shared before the test, and install the full workspace: the
two-package filter did not provide enough of the tree for that build.
* feat(desktop): auto-update via Tauri updater with restart prompt
The Rust shell now checks the desktop-latest GitHub release feed on launch
and every 2 hours, downloads and stages updates in the background, and
exposes get_update_status/restart_to_apply_update commands. The webview
polls the status and shows a persistent toast with a one-click restart once
an update is staged; ignored updates apply on next launch. Updater
artifacts are only produced with the CI config overlay
(tauri.release.conf.json) so local packaging keeps working without the
updater signing key. Also mounts the previously-unmounted Toaster so
existing toast() calls render.
* ci(desktop): add desktop-publish release workflow and publish-desktop skill
desktop-publish.yml mirrors cli-publish: dispatch with a desktop-vX.Y.Z
tag + confirm gate, validates the tag against package.json and
tauri.conf.json, builds signed+notarized DMGs for aarch64 (native) and
x86_64 (cross-compiled sidecar via bun --target), generates the updater
manifest, publishes the versioned GitHub release, refreshes the rolling
desktop-latest auto-update feed, and posts to Slack. Adds the release
skill, changelog, and README docs for the required GitHub secrets.
* fix(desktop): address review — outlast sidecar shutdown window, dedupe update toast across remounts
stop() now polls for 7s before escalating to kill, past the sidecar's own
5s SHUTDOWN_TIMEOUT_MS graceful-shutdown budget, so clicking Restart now
(or quitting) during session persistence can't SIGKILL the sidecar
mid-write. notifiedVersion moves to module scope so a page remount doesn't
re-toast an update the user already dismissed.
* docs(desktop): move publish-desktop skill to .cline/skills, slim README release section
Match the publish-cli convention: the skill lives in .cline/skills/ and is
symlinked from both .agents/skills/ and .claude/skills/ so all agents pick
it up. The README's release section shrinks to a pointer + the two
never-lose invariants (desktop-latest feed, updater private key); the repo
secrets table moves into the skill, which also fixes its dangling reference
to a 'Release automation' README section and escapes the pipe that broke
the GFM table cell.
* fix(vscode-rollout): align bundle versions in the stable AB workflow
Found by Max in local testing: the union manifest's version (what the
Marketplace and auto-update see) is the stitch input, but each bundle's
About tab and telemetry extension_version read that bundle's OWN
package.json — so the stable combined VSIX reported three different
versions (dispatch input / main's 4.0.0 / legacy's 4.0.8) depending on
where you looked. The nightly channel doesn't have this problem
(nightlify.mjs stamps one version into everything); this gives the stable
channel the identity-preserving equivalent: scripts/set-version.mjs stamps
the dispatch version into each checkout after install, before its build.
Also fixes a latent ab-package bug while restructuring the steps: the
next-bundle build never ran build:sdk, so the @cline/* workspace deps had
no dist and esbuild would fail on a fresh CI checkout (the workflow has
never run end-to-end — the publish environment gate blocked pre-merge
dispatches). Split install/build:sdk/align/build into separate steps,
mirroring the nightly workflow.
* fix(vscode-rollout): assert bundle sub-manifest versions in identity guardrails
Greptile round on #12321: the stable guardrail didn't assert version at
all. Went one further than the suggestion — both workflows' guardrails now
also assert each bundle sub-manifest's version (and name, for nightly)
matches the expected version, which is the check that actually regression-
guards the set-version.mjs/nightlify.mjs stamping (About tab + telemetry
extension_version read the sub-manifests, not the union). Expected version
routed through env rather than interpolated into the script body. Adds the
conventional paired test for set-version.mjs.
* fix(vscode-rollout): don't fail the nightly run when the tag push is rejected
First real combined publish (run 29454994164) published to both registries
successfully but the run went red at the last step: the default
GITHUB_TOKEN cannot create a ref whose commit modifies workflow files, and
HEAD was the #12253 squash merge which rewrote this very workflow. There
is no workflows permission grantable to the token, so this recurs any
night HEAD touched .github/workflows. The tag is bookkeeping — mark the
step continue-on-error so a successful publish isn't reported as a
failure. (Today's missing tag was pushed manually.)
* feat(vscode-rollout): A/B loader and packaging for staged SDK extension rollout
Ship one marketplace VSIX containing a tiny loader plus two complete
extension bundles: next/ (SDK-based apps/vscode from main) and legacy/
(the legacy-extension branch). The loader picks one bundle per window
from a PostHog-flag-driven, sticky, one-way cohort assignment, activates
it with a Proxy-scoped ExtensionContext so each bundle resolves its
resources from its own subdirectory, and falls back to legacy (with
partial-registration cleanup and version pinning) if the next bundle
crashes during activation.
Includes the union-manifest generator with per-cohort when-clause
gating, the VSIX stitcher, a node-level loader smoke test, and the
ext-vscode-ab-package workflow that builds both refs and packages
(optionally publishes) the combined VSIX.
* fix(vscode-rollout): address rollout review feedback
* feat(vscode-rollout): versioned kill-switch, user-setting override, launch-cadence telemetry
Review follow-ups from #12253:
- Kill-switch is now scoped by version instead of boolean: the PostHog flag's
payload carries {"maxKilledVersion": "x.y.z"} and the loader demotes only
combined VSIXes <= that version, so killing a broken release never blocks
the release that fixes it. Arming with no payload still demotes everything,
and the old boolean memento format is normalized on read.
- cline.rollout.bundleOverride user setting (auto | next | legacy) as a
manual escape hatch editable straight from settings.json: beats flags and
the kill-switch in both directions, applies on window reload, reported as
'override' on the activation event. Injected into the union manifest by
gen-manifest so neither bundle has to know about it.
- parseRolloutFlags hardens flag typing: only a literal boolean true promotes
(multivariate variants, numbers, junk fail safe), kill payloads are parsed
defensively from /decide's JSON-string encoding.
- Activation events now carry ms_since_last_activation so the real window-
reload cadence bounds how fast the rollout percentage gets dialed up.
- Walkthrough manifest invariant relaxed from byte-equality to structural
equality (ids/media/completionEvents): the branches already diverge on one
MCP step description, and since walkthrough markdown at the VSIX root comes
from next regardless, hard-failing on copy tweaks bricked the release
pipeline while protecting nothing. Copy divergence now warns and ships
next's text.
* feat(vscode-rollout): identity-aware namespace, authoritative activation telemetry, nightly indicator
- Derive the setting section and sdkBundle context key from the packaged
manifest name (cline.* for stable claude-dev, cline-nightly.* for the
nightly identity, whose packaging rewrites the whole ID namespace);
gen-manifest derives the same prefix for gates and the injected
bundleOverride setting.
- Call the activated bundle's reportRolloutActivation export (merged on
both branches) with attempted/actual/fallback — the authoritative
extension.rollout.bundle_activated event, attributed via the bundle's
variant-built telemetry. On crash fallback the LEGACY bundle reports it.
- Rename the loader's direct PostHog event to
extension.rollout.loader_decision: it collided byte-for-byte with the
bundles' event name under a different schema. It keeps the loader-side
metadata (override, launch cadence, loader_version, extension_name) and
gains double_failure for the both-bundles-dead case.
- Fix duplicate activation events on crash fallback: the recursive legacy
activation no longer emits a second, contradictory fallback:false event.
- Nightly-only status bar indicator (Cline: Next / Cline: Legacy) so
dogfooders can see which bundle a window is running.
- Union diverged engines to the newer requirement instead of hard-failing:
main's VS Code engine (^1.101.0) has legitimately moved ahead of
legacy-extension's (^1.84.0), which bricked every combined build.
- Smoke scenarios for all of the above.
* feat(vscode-rollout): publish the nightly as the combined A/B VSIX
Convert ext-vscode-publish-nightly.yml (cron + dispatch) from the
standalone SDK build to the combined loader + next + legacy package,
published as saoudrizwan.cline-nightly at <major>.<minor>.<unix-seconds>:
- scripts/nightlify.mjs reproduces publish-nightly.mjs's identity mutation
(claude-dev -> cline-nightly, "cline. -> "cline-nightly., displayName,
activity bar title) with the version as an explicit argument so ONE
version reaches both bundle manifests and the union manifest. Runs after
dependency install and before each bundle build.
- Both bundle builds get CLINE_ROLLOUT_VARIANT (next/legacy) in the nightly
AND stable workflows — without it the merged rollout telemetry
(extension_variant common prop + the authoritative bundle_activated
capture) silently no-ops.
- dry-run dispatch input builds and uploads the installable .vsix without
publishing or tagging; publish/tag steps are additionally gated to main,
so the PR branch can be dispatched for pre-merge verification.
- Identity guardrails before packaging: nightly workflow asserts
cline-nightly, the stable ab-package workflow asserts claude-dev.
- The nightly tag now records the legacy bundle sha in its message.
- README: nightly channel section (identity mapping, the two telemetry
events and their owners, dry-run verification), and a note that the
PostHog flags govern nightly only until the stable combined VSIX ships.
The single-bundle publish-nightly.mjs path remains for manual
feature-branch pre-release publishes; CI no longer invokes it.
* chore(vscode-rollout): harden nightly workflow gating
- Restore a job-level branch allowlist on the publish job (main + the
rehearsal branch). Advisory defense-in-depth: the enforced gate is the
PublishNightly environment's deployment-branch policy in repo settings,
which must list the same branches; a dispatched branch runs its own copy
of this file.
- Route the legacy-ref dispatch input through env instead of interpolating
it into the run script body (script-injection hygiene; dispatch already
requires write access).
* add otel vars to rollout build (#12316)
- Extension will not emit otel metrics to otel without these vars, so
adding those into the slow-rollout build workflow
Co-authored-by: Max Paulus 🥪 <max@cline.bot>
* fix(vscode-rollout): pass OTel env to the nightly legacy bundle build
Legacy's esbuild inlines OTEL_* at build time and its standalone publish
workflow passes them, so the combined nightly's legacy bundle was being
built with the OTel logs/metrics pipeline dead. Companion to #12316,
which fixes the same gap in ext-vscode-ab-package.yml (both bundles
there).
* feat(vscode-rollout): make the rollout two-way, remove the kill-switch
The one-way cohort + versioned kill-switch existed to avoid demoting users
whose SDK-bundle tasks aren't listed by legacy and whose rotated creds may
need a re-login. Decision: those are acceptable, temporary UX costs on an
emergency-only path — not worth a second flag and permanent mechanism
complexity (payload parsing, version scoping, killed-up-to cache format).
Now there is ONE knob: each background refresh caches exactly what
ext-sdk-bundle-rollout says for the next window. Dialing the percentage
down demotes; 0% pulls everyone back to legacy on their next reload.
Fail-safe direction preserved: only a literal boolean true promotes —
variant strings / numbers / a deleted flag all resolve to legacy; malformed
/decide responses leave the cache untouched. Local crash pinning (next
threw -> pin this version to legacy on this machine) is unchanged and
independent of the flag.
Removes KILLSWITCH_FLAG/KILLSWITCH_STATE_KEY/isVersionKilled/
normalizeKilledUpTo/compareVersions/nextCachedBundle; parseRolloutFlags
becomes parseRolloutAssignment returning the bundle to cache. Smoke
scenarios replaced with two-way promote/demote coverage.
---------
Co-authored-by: Max <maxpaulus43@gmail.com>
Co-authored-by: Max Paulus 🥪 <max@cline.bot>
* fix(ci): harden ext-vscode stable release workflow
- Resolve previous tag to the latest vX.Y.Z ancestor instead of the most
recent reachable tag. The nightly workflow now pushes a nightly-main-*
annotated tag on every main commit, so git describe was resolving the
release notes' Full Changelog compare link to a nightly tag rather than
the prior release tag.
- Extract the changelog section by exact version heading (and fail if it
is missing) instead of always taking the first ## [ block, so a stale
top entry can no longer ship as the release notes for a different
version.
- Add a pre-publish Verify Changelog Entry gate so a release cannot be
published unless CHANGELOG.md leads with the version being released.
- Add a Verify Marketplace Tokens gate so a missing VSCE_PAT/OVSX_PAT
fails fast before packaging rather than mid-publish.
- In existing-tag mode, require the tag to point at the tested SHA so the
published artifact always matches what CI verified.
- Add a concurrency group keyed on the tag to prevent duplicate
concurrent publishes of the same release.
* fix(ci): validate stable release metadata before publish
* fix(vscode): store MCP OAuth in shared settings file like the CLI (ENG-2108)
VSCode stored MCP OAuth tokens in a single mcpOAuthSecrets secrets blob
keyed by sha256(name:url), while the CLI/SDK store per-server oauth state in
cline_mcp_settings.json. The two never interoperated (CLI auth was invisible to
VSCode), and VSCode's read-whole-blob/write-whole-blob through StateManager's
non-refreshing cache meant concurrent windows clobbered each other's tokens.
- Store MCP OAuth state in the shared settings file in @cline/core's format.
- Reads are fresh from disk; writes are scoped read-modify-write of one
server's oauth key via updateMcpServerOAuthState (now atomic temp+rename).
- Replace the vscode:// callback flow with HTTP-based token collection via
authorizeMcpServerOAuth (same local loopback flow the CLI uses).
- Reconnect an unauthenticated server when its tokens appear (e.g. CLI auth).
- One-time migration of legacy mcpOAuthSecrets tokens into the shared file.
- Remove McpOAuthRedirectResolver, mcpOAuthFlow, completeOAuth, and the
mcp-auth URI callback route.
* feat(vscode): add --instances/--random-port to MCP OAuth test server
Lets you start several independent test servers, each on its own OS-assigned
random port, so you can add multiple streamableHttp MCP servers to Cline at
once and exercise concurrent OAuth flows. baseUrl now reflects the actually
bound port so discovery metadata and redirect URIs stay correct under random
ports.
* fix(vscode): stop MCP OAuth handshake writes from livelocking the settings watcher (ENG-2108)
Now that codeVerifier/clientInformation live in the shared settings file, the
MCP SDK's per-connect-attempt saveCodeVerifier() writes were tripping the
settings watcher, which re-entered updateServerConnections -> connectToServer
-> another write, looping forever. It was especially bad with two+
unauthenticated servers, where each server's verifier churn re-triggered the
other (visible as a flickering, ever-changing codeVerifier nonce).
The watcher now compares a connection-relevant fingerprint (full per-server
config minus the oauth block, plus a boolean for whether an access token
exists) and skips writes that only churn OAuth-handshake fields. A token
appearing/disappearing still changes the fingerprint, so CLI/other-window
authorization continues to trigger a reconnect via serverGainedOAuthTokens.
* feat(vscode): print paste-ready MCP settings fragment from OAuth test server
On startup the test server now emits an mcpServers JSON fragment (nested
transport shape, matching cline_mcp_settings.json) alongside the banner, so you
can paste it straight into the settings file instead of hand-writing it. With
--instances the entries get distinct names (oauth-test-1, ...), each carrying
its actual bound port.
* fix(vscode): atomic MCP settings writes + fingerprint gate; drop timer guards (CLINE-2097)
Deleting one MCP server could empty the whole list. Root cause: settings
writes were non-atomic (fs.writeFile), so chokidar (and any other process)
could read a transient empty/torn file mid-write and reconcile to zero servers.
The previous fix only masked this with a per-process isUpdatingClineSettings
boolean cleared on a 300ms timer — it did nothing for the CLI or other windows
and was racy.
Replace both timer guards (isUpdatingClineSettings, isUpdatingFromRemoteConfig)
with two deterministic, process-agnostic mechanisms:
- writeSettingsFile(): atomic temp-file + rename for every settings write, so
any reader always sees a complete file. Holds for any number of concurrent
writers (CLI, multiple windows, SDK OAuth handshake).
- content fingerprint: the watcher reconciles only when the connection-relevant
view changed. writeSettingsFile pre-seeds the fingerprint so our own write is
a no-op, while a genuine change from any other process is still processed.
Because reconcile is idempotent and reads are never torn, a missed
suppression is at worst a redundant reconnect, never data loss.
All RPC writers (toggle disabled, autoApprove x2, timeout, add, delete) and the
remote-config sync now go through writeSettingsFile. Removes all setTimeout(.,
300) flag juggling.
* feat(vscode): add a non-guessable 'frozzle' tool to the MCP OAuth test server
The MCP OAuth test server now serves tools/list + tools/call exposing a
'frozzle' tool whose output cannot be derived without calling it (reverse the
string and swap each letter's case, wrapped in guillemets). This gives an eval
a reliable end-to-end signal that the OAuth-authenticated MCP round-trip really
happened: a correct 'frozzle <text>' answer can't be hallucinated. The
transform is easy to verify at a glance and invertible. Adds frozzle.test.ts.
* fix(sdk): drop lingering OAuth callback sockets on close so deny->approve re-auth works (ENG-2108)
The local OAuth callback server's close() called Server.close(), which only
stops accepting new connections and lets existing keep-alive sockets linger.
The browser / global-fetch connection pool keeps such a socket to the fixed
callback port (1456) alive. So after the user denied an MCP OAuth request and
retried, the retry's approve callback could be delivered over the pooled socket
to the FIRST (already-settled) server. That server's settle() was a no-op, so
waitForCallback() never resolved, finishAuth()/token exchange never ran, and no
token was saved — the server stayed unauthenticated (the deny->approve repro).
Call server.closeAllConnections() in close() so no pooled socket outlives the
server. Adds a regression test driving a keep-alive agent across close().
* fix(vscode): actually reconnect MCP server when toggled back on (ENG-2108)
toggleServerDisabledRPC only flipped the in-memory disabled flag and set status
to 'connecting', but never rebuilt the connection. A disabled server's
connection has no live transport/client, so re-enabling left it stuck on the
yellow 'connecting' indicator forever and never re-advertised its tools to the
agent.
Tear down and rebuild the connection through deleteConnection + connectToServer
(which opens a real transport when enabled, or a disconnected stub when
disabled), then notifyWebviewOfServerChanges so the SDK session's tool list is
refreshed. OAuth state is preserved (deleteConnection doesn't clear it). Adds
McpHub.toggleServerDisabledRPC.test.ts.
* fix(vscode): reload MCP tools silently without chat spam (ENG-2108)
Restarting the SDK session to pick up MCP tool changes appended visible chat
messages ('MCP tools changed - reloading...' and 'MCP tools reloaded
successfully...') plus a completion_result banner. Toggling several servers
piled up many of these. Tool reloading should be transparent.
Emit only the session status transitions (running -> idle) via
emitSessionEvents([], ...) instead of appendAndEmit, so no chat messages or
completion banner are shown. Genuine reload failures still surface an error
message. Updates sdk-mcp-coordinator.test.ts accordingly.
* docs(mcp): clean up comments to describe current behavior
Revise comments across the MCP OAuth and settings code to document the code as
it stands, dropping references to prior implementations, task IDs, and
before/after narration. Also reflow the auth-server regression test to the
repository's formatter. No behavior change.
* fix(vscode): atomic fallback write in remote MCP sync; document sync OAuth I/O
Make the no-McpHub branch of syncRemoteMcpServersToSettings write via an
atomic temp-file + rename so a concurrent reader never observes a torn or
empty settings file, matching every other settings write.
Document why the OAuth state read-modify-write in McpOAuthManager is
synchronous: it serializes this process's shared-file updates without a
Promise queue, which we prefer over async I/O for reliability of the
cross-process settings file.
* fix(mcp): serialize settings read-modify-writes
* docs(vscode): clarify MCP settings create race
* fix(vscode): create MCP settings atomically
* fix(cli): keep clearing missing MCP OAuth state a no-op
* fix(vscode): avoid yielding while holding MCP settings lock (#11596)
* fix(mcp): async lock acquisition for VSCode MCP settings/OAuth writes
Add updateMcpSettingsFile/updateMcpServerOAuthStateAsync to @cline/core that
yield the event loop while acquiring the cross-process settings lock instead of
blocking it with Atomics.wait. The critical section stays synchronous and the
mutator stays pure, so the lock is never held across an await and serialization
is preserved without an in-process queue.
Route the VSCode extension host's OAuth state writes (McpOAuthManager) through
the async variant so a connection-time OAuth callback can no longer freeze the
extension host event loop or deadlock against an in-flight updateMcpSettingsFile
whose lock-releasing continuation needs the loop.
Unify the sync and async acquisition paths on a shared reentrancy guard
(activeLocks) so a nested settings update on the same file fails fast instead of
self-deadlocking.
Tests: contended async serialization asserting zero Atomics.wait calls, async
stale-lock reclaim, reentrancy fail-fast, and uncontended run+release.
* fix(mcp): bootstrap missing settings file inside the lock; tidy docs
Creating the MCP settings file now happens in one place: the locked
read-modify-write helpers. A missing file reads as an empty settings object, so
the first write to a fresh path (e.g. a fresh-install `cline mcp add`) creates
it inside the lock instead of throwing ENOENT. The SDK (updateMcpSettingsFile /
updateMcpSettingsFileSync) and the VSCode lock helper share this contract, so
callers no longer need to pre-create the file. Add regression tests for the
SDK, the CLI wizard addServer(), and the VSCode helper on a missing path.
Also flag the synchronous SDK entry points (updateMcpSettingsFileSync,
updateMcpServerOAuthState) as preferring their async siblings, with a TODO to
delete them once all callers migrate, and tighten the lock-helper doc comments
to describe current behavior.
* fix(vscode): finish npm->bun migration in dev tooling, tasks, and docs
The npm->bun migration (#11632) updated package scripts, .vscodeignore and .vscode-test.mjs but left a trail of npm/npx/node invocations in editor configs, dev scripts, and docs. Following the breadcrumbs from 'npm run protos':
- .vscode/launch.json: standalone-core debug uses 'bun <file>.ts' (was npx tsx); Open Storybook uses 'bun run' (was npm run).
- .vscode/tasks.json: all task commands use 'bun run' (was npm run).
- scripts/run-extension-host.sh and .claude/hooks/claude-code-for-web-setup.sh: 'bun run' (was npm run).
- debug-harness/server.ts: shebang 'bun'; build steps use 'bun run protos', 'bun esbuild.mjs', 'bunx vite build' (were npm/node/npx).
- dev script shebangs (test-hostbridge-server, test-standalone-core-api-server, testing-platform-orchestrator, interactive-playwright): '#!/usr/bin/env bun' (was npx tsx).
- WebviewProvider HMR hint, e2e README, copilot-instructions, PR template, mcp-oauth-test-server docs, generate-state-proto message, tsconfig.test comment, state-keys test comment: bun.
Left untouched (correct per .clinerules/bun-and-node): Node-runtime invocations (node build.mjs), prebuild-install --target=<node>, vsce, 'npm install -g cline' (user CLI install), and App.stories.tsx mock chat fixtures.
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Co-authored-by: Cline Agent <cline-agent@users.noreply.github.com>
* chore(vscode): migrate package management & build from npm/node to bun
Fold apps/vscode (+ webview-ui, testing-platform) into the root bun
workspace so the extension consumes the local @cline/* SDK packages via
workspace symlinks instead of pinned published versions, eliminating the
SDK vendoring cycle. Node remains the runtime (extension host, standalone
cline-core, esbuild platform:node, prebuild-install ABI target).
- root: drop "!apps/vscode", add nested members, relocate overrides to
root, add trustedDependencies [better-sqlite3, grpc-tools]
- apps/vscode: @cline/* -> workspace:*, scripts -> bun/bunx,
npm-run-all -> bun --parallel, drop cross-env; keep esbuild + vite;
declare previously-hoisted phantom deps (nice-grpc-common, playwright)
- package-standalone.mjs: npm install -> bun install (isolated dist dir)
- CI: setup-bun + single root bun install --frozen-lockfile, build:sdk
before extension build, better-sqlite3 binary + zero-test guards;
publish workflows intentionally keep setup-node for vsce/ovsx
- docs/comments: curated pass (keep-list vs rewrite-list), add
apps/vscode/docs/bun-migration-notes.md guard doc
- delete npm lockfiles (root bun.lock authoritative)
Deferred to follow-up PRs: test-runner migration to bun test (Phase 4)
and devDep cleanup (Phase 6).
* test(vscode): add bun test foundation for the vitest-native unit suites
Phase 4a of the test-runner migration. Adds a bun test runner that
reaches full parity (582 pass / 0 fail / 50 files) with the existing
vitest SDK-adapter + model-catalog suite, without touching the
@vscode/test-cli integration tests or the webview vitest suite.
- bunfig.toml: [test] preload
- src/test/bun-test-preload.ts: mock.module() shadows `vscode` and
`@cline/core` with their unit-test stubs (bun's onResolve plugin hook
does not intercept host/symlinked specifiers); seeds real @cline/core
export names as undefined to satisfy bun's strict ESM named-import
linking; full vitest->bun:test shim (vi.fn/mocked/spyOn, describe/it/
expect/before*/after*)
- scripts/run-bun-tests.ts: mirrors vitest.config.ts include[] exactly and
runs with --parallel for per-file mock isolation (bun test's single-process
default lets mock.module clobber across files)
- test:bun script
* test(vscode): migrate node-side unit suite from mocha to bun test
Phase 4b of the test-runner migration. The standalone mocha unit runner
(.mocharc spec: __tests__/* + test/services/**) was already broken under
bun (mocha was a phantom dependency — only @types/mocha/ts-node were
declared, npm hoisted mocha transitively). Migrate it to `bun test`.
- codemod 77 files: import { ... } from "mocha" -> "bun:test", renaming
before->beforeAll / after->afterAll at imports and call-sites; chai,
should and sinon kept as libraries (they work under bun test)
- convert sinon.stub() on ESM namespace exports to mock.module()/spyOn
(bun loads real ESM: "ES Modules cannot be stubbed")
- scripts/run-bun-unit-tests.ts: runs the .mocharc spec set with one
isolated `bun test` process per file (Bun.spawn + concurrency pool),
restoring vitest-forks module-registry isolation (bun's single-process
default lets mock.module leak across files)
- scripts/codemod-mocha-{to-bun,this}.ts: one-shot migration tooling
- test:unit now runs the bun unit runner; CI calls bun + a non-zero
pass-count guard instead of `bunx nyc ... mocha`
- tsconfig: add root node_modules/@types to typeRoots so `bun:test`
types resolve under tsc; cast loose os.userInfo mocks in shell.test
Result: unit suite 58 files / 880 pass / 0 fail; vitest set still
582/0. @vscode/test-cli integration tests and webview vitest unchanged.
* chore(vscode): remove dead mocha-runner deps and artifacts
Phase 6 cleanup after the bun test migration. The standalone mocha unit
runner is gone (replaced by scripts/run-bun-unit-tests.ts), so its
config and now-unused devDependencies are removed.
- remove dead files: .mocharc.json, tsconfig.unit-test.json,
src/test/requires.ts, .nycrc.unit.json
- remove unused devDeps: @types/mocha, @types/proxyquire, ts-node,
tsconfig-paths, cross-env, npm-run-all, nyc, proxyquire, husky
(root owns the husky hook; chai/should/sinon stay — used as libs)
- install:all -> single root `bun install` (workspace covers webview-ui)
- drop .mocharc.json / .nycrc*.json from CI paths-filters and
.vscodeignore; add bunfig.toml to the filters
Verified: check-types clean, unit 880/0, vitest 582/0.
* fix(vscode): import bun:test globals in tests that relied on ambient @types/mocha
CI Quality Checks (clean `bun install` without @types/mocha) surfaced
TS2582/TS2304 "Cannot find name 'describe'/'it'/'beforeEach'" in test
files that used the global mocha/jest test functions without importing
them. The Phase 4b codemod only rewrote files that imported from
"mocha"; these used ambient globals, so they were missed (and passed
locally because a stale @types/mocha lingered in node_modules).
Add explicit `bun:test` imports (before->beforeAll, after->afterAll in
TelemetryService.test.ts). chai/sinon stay as libraries.
Verified against a clean tree (no @types/mocha): check-types 0 errors,
unit suite 58 files / 880 pass / 0 fail.
* style(vscode): biome-format migrated test files + codemod scripts
The mocha->bun:test codemod and manual import edits left formatting that
didn't match biome (the CI `format` check, which validates files changed
since main, flagged them). Also narrow setup.ts's bun:test import to the
actually-used beforeEach/afterEach (describe/it only appear in a JSDoc
example), fixing a noUnusedImports lint error.
ci:check-all (check-types + lint + format) now passes locally.
* fix(webview-ui): declare phantom deps + pin React 18 types under bun workspace
Folding webview-ui into the bun workspace changed its install topology
from an isolated npm flat tree to the shared hoisted store, surfacing
two classes of pre-existing latent issues that npm hoisting had masked:
1. Phantom dependencies: src imports `marked`, `unist`, `unist-util-visit`
and `@heroui/theme` directly but never declared them. Declared them
(marked ^15, unist-util-visit ^5, @types/unist ^3, @heroui/theme 2.4.26).
2. React types: @testing-library/react's optional peer pulls @types/react@19
into a resolvable location; tsc mixed it with the toolkit's React 18
types (React 19 dropped Component.refs), breaking 452 JSX usages. Pin
react/react-dom type resolution to webview-ui's React 18 copy via
tsconfig paths.
build:webview (tsc -b && vite build) and ci:check-all now pass.
* fix(vscode): restore @types/mocha for integration build + add bun:test types
The @vscode/test-cli integration runner still uses mocha, and
tsconfig.test.json compiles all src/**/*.test.ts (including bun-migrated
files) to out/. So:
- restore @types/mocha (integration compile needs the mocha ambient types)
- add `bun` to tsconfig.test.json types + root @types to both tsconfig
typeRoots so `bun:test` resolves under tsc for the migrated tests
* fix(vscode): declare glob — phantom dep used by package-standalone.mjs
scripts/package-standalone.mjs imports `glob` but it was never declared
(resolved transitively under npm's flat hoist). Under the bun workspace
store it's unresolvable, failing postcompile-standalone with
ERR_MODULE_NOT_FOUND. Declare glob ^11 (modern named-export API).
compile-standalone now produces dist-standalone/standalone.zip.
* fix(ci): strip ANSI before vitest zero-test guard grep
The vitest summary line colorizes the count ("Tests <ansi>582 passed"),
so the count isn't adjacent to the "Tests" label in raw bytes and the
guard regex failed even though 582 tests passed. Strip ANSI escapes
before matching.
* fix(vscode): declare minimist — phantom dep in testing-platform-orchestrator
scripts/testing-platform-orchestrator.ts imports `minimist` (undeclared,
resolved transitively under npm hoist). Declare it so the testing-platform
integration job runs under the bun workspace store.
* fix(vscode): restore tsconfig-paths for integration runner; tp-orchestrator uses bun
Phase 6 over-removed tsconfig-paths: test-setup.js (loaded by the
@vscode/test-cli mocha integration runner) requires it to resolve @/
aliases in the compiled out/ tree — the extension host test runner failed
with "Cannot find module 'tsconfig-paths'". Restore it. Also switch the
testing-platform spawn from `npx ts-node index.ts` to `bun index.ts`
(bun runs TS natively; avoids the removed ts-node).
* fix(vscode): route tests by bun:test import marker; integration runner stays mocha
The mocha->bun codemod swept up tests that the Node-based @vscode/test-cli
integration runner compiles/runs, which cannot load the `bun:test` builtin
(and some need the real VSCode host). Establish a single source of truth:
a *.test.ts is bun-runner-owned IFF it imports "bun:test".
- run-bun-unit-tests.ts: discover files by the bun:test import marker
(not fixed globs), so every migrated file runs under bun.
- build-tests.js: generate a tsconfig that excludes all bun:test files
from the integration compile (json5-parsed), so out/ never contains
bun:test; gitignore the generated config.
- .vscode-test.mjs: exclude the bun unit dirs from the runner globs.
- revert host-dependent tests (hostbridge/*, extension, terminal,
FileContextTracker host bits) and 3 files with sinon-on-ESM/behavioral
issues (ClineIgnoreController, mentions, TelemetryService) back to
mocha; they run on @vscode/test-cli as before.
Verified: check-types 0 errors; compile-tests 0 bun:test in out/;
bun unit 65 files/962 pass/0 fail; vitest 582/0.
* fix(vscode): declare mocha — phantom dep for @vscode/test-cli integration runner
The @vscode/test-cli extension host loads `mocha` at runtime to run the
integration suite, but only @types/mocha was declared (npm hoisted the
mocha package transitively; bun's store does not expose it). The host
failed with "Cannot find module 'mocha'". Declare mocha ^11.7.4 (matches
@vscode/test-cli's own range).
* fix(vscode): robust Windows protoc-gen-ts_proto plugin resolution under bun
build-proto.mjs hardcoded node_modules/.bin/protoc-gen-ts_proto.cmd for
Windows, but bun's workspace store places/extensions the bin shim
differently (hoist + .cmd/.bunx), so Windows protos failed with
"protoc-gen-ts_proto: The system cannot find the file specified". Probe
the local + root .bin with known shim extensions instead. Also update
the testing-platform usage string (ts-node -> bun).
* fix(vscode): generate node .cmd wrapper for ts-proto plugin on Windows
The previous probe found bun's `.bunx` shim, but protoc cannot exec it
("%1 is not a valid Win32 application"). Instead, on Windows generate a
small .cmd wrapper that runs the resolved protoc-gen-ts_proto JS via
`node`, which protoc can execute regardless of package manager. POSIX
path (direct JS bin) is unchanged.
* fix(vscode): package VSIX with --no-dependencies (bundled) to stop monorepo traversal
Under the bun workspace, @cline/* are workspace:* symlinks pointing to
../../../../sdk/packages/*. vsce, walking the dependency tree, followed
them out of apps/vscode and packaged the whole monorepo (../, ~84MB incl.
root node_modules and .env), which crashed vsce's secret scanner and
failed all e2e jobs.
The extension is fully esbuild-bundled into dist/extension.js, so vsce
should not walk node_modules at all. Add --no-dependencies to every
vsce/ovsx package/publish path (e2e build, marketplace, nightly), and
tighten .vscodeignore to drop nested node_modules and dev-only inputs
(scripts, proto, testing-platform, bunfig, esbuild.mjs, etc.).
Result: VSIX is 39 files / ~7 MB and the secret scan passes.
* docs(vscode): tighten bun/node comments and consolidate into a clinerule
- add .clinerules/bun-and-node.md (eternal-now: bun=tooling, node=runtime,
keep-list, and the bun:test-vs-mocha test routing rule); remove the
apps/vscode/docs/bun-migration-notes.md migration doc and point
.clinerules/general.md at the rule (single-line bullet matching the file).
- fix the hotfix-release note: there is no infra step that regenerates the
lockfile; a CHANGELOG+version bump leaves bun.lock consistent (workspace
versions aren't pinned) and publish runs --frozen-lockfile.
- reframe runner/preload comments to describe the code as-is (drop
"migrated off mocha"/codemod history); add a TODO on the bun-test preload
to migrate suites off the vitest `vi` shim to native bun:test and delete it.
- remove the one-shot mocha->bun codemod scripts.
* fix(debug-harness): pin debugee VSCode version so bundled Playwright can drive it
The harness downloaded "stable" VSCode (currently 1.125 / Electron 42),
which the bundled Playwright cannot drive — `_electron.launch()` hangs
until its 60s timeout (Electron started and a window appeared, but the
launch handshake never completed). Default to a known-good version
(1.103.0, matching the e2e CI matrix) and allow override via
VSCODE_TEST_VERSION.
* fix(webview): render under bun workspace — dedupe React, drop stale codicons link
The webview mounted but crashed before rendering (blank sidebar; e2e
"Login to Cline" never visible) with "Cannot read properties of null
(reading 'useRef')" — the classic two-React-copies / null hook dispatcher.
Under the bun workspace, sibling packages pull react@19 into the shared
store and a transitive webview dep resolved a second React instance into
the vite bundle. Add resolve.dedupe + pin react/react-dom to webview-ui's
own React 18 copy.
Also drop the separate `<link>` to node_modules/@vscode/codicons in the
webview HTML: the webview's index.css already @imports codicons, so the
font is bundled into the build assets. Under bun that node_modules path
is a symlink to the root store (outside the webview localResourceRoots)
and isn't packaged with --no-dependencies, so the link 404'd; the bundle
covers it. Re-scope the .vscodeignore nested-node_modules exclude so it
no longer shadows the codicons re-include.
* fix(debug-harness): disable GPU so the debugee renders in headless/VM envs
On headless/VM GPU stacks the debugee Electron's GPU process crash-loops
("Exiting GPU process during initialization" / CreateCommandBuffer
kTransientFailure), killing the window before Playwright finishes
attaching and tripping the 60s launch timeout. Force software rendering
(--disable-gpu and friends) for a stable harness launch.
* fix(debug-harness): survive launch failures; configurable, longer launch timeout
The harness crashed (whole bun process exited) whenever VSCode launch
failed/timed out: Playwright emits a late unhandled rejection on the dead
CDP transport after we've already handled the launch error, and the
default behavior takes the HTTP server down with it — forcing a full
restart just to retry.
- Add process-level unhandledRejection/uncaughtException guards so stray
async errors are logged and the server keeps serving (retry via `launch`).
- On launch failure, close the orphaned Electron so a retry isn't blocked.
- Make the _electron.launch timeout configurable (--launch-timeout) and
raise the default to 120s for cold launches; document VSCODE_TEST_VERSION.
* fix(ci): address review feedback — vsix --no-dependencies, drop stale coverage path, Windows shell
- ext-vscode-publish-stable.yml: add --no-dependencies to the release-artifact
`vsce package` (Max's catch). Without it, vsce follows the @cline/* workspace
symlinks out of the package and bloats the .vsix with the whole monorepo.
- ext-vscode-test.yml: drop the stale apps/vscode/coverage-unit/lcov.info upload
path (Max's catch). That file was produced by the removed nyc unit-coverage
step (.nycrc.unit.json); nothing generates it now.
- ext-vscode-test-e2e.yml: the better-sqlite3 assert step ran under the Windows
runner's default pwsh and failed to parse the POSIX test. Pin it to `shell: bash`
(Git Bash ships on windows-latest); the non-e2e job already defaults to bash.
---------
Co-authored-by: Cline Agent <cline-agent@users.noreply.github.com>
Omnibus squash of the 10 oldest SDK-migration commits (authored 2026-05-27
through 2026-06-02), collapsed during the 2026-06-09 rebase onto origin/main.
Squashed commits:
- sdk migration: squashed pre-2026-05-27 work
- sdk migration: squashed 06-05-2026 -- instead of listHistory, use host.get(sessionId) instead
- updat gitignore
- fix xai provider
- fix(vscode): forward Bedrock region + AWS auth to the SDK gateway
- fix(vscode): keep in-progress MCP OAuth flow across reconnects
- fix(vscode): wire auto compact into SDK sessions (#11197)
- fix(vscode): compact Codex OAuth before input cap (#11194)
- fix unauthed user flow
- fix(llms): strip Cerebras reasoning history (#11214)
* Improve bug report form: rename surface dropdown, add IDE/CLI diagnostics
Rename the 'Plugin Type' dropdown to 'Cline Surface' since CLI is not a plugin; the option values keep each choice unambiguous.
Add an 'IDE / CLI Diagnostics' field with per-surface copy-paste steps for About info (VSCode Help/About, JetBrains Help/About Copy button) and a CLI exception using 'cline --version'. System Information is left as-is; minor overlap is acceptable.
* Update repo-label-issues workflow for renamed Cline Surface field
The auto-labeler matches the rendered '### Plugin Type' heading. Since the form label was renamed to 'Cline Surface', update the three regexes so JetBrains/VS Code/CLI labels keep applying.
* Move the apps to the root dir
* Update all references from sdk/apps/ to apps/
* Update dependencies
* Install bun types
* Fix types
* Fix types
* Fix linter
* Ingore apps from vscode
* Fix security warning
* Fix windows install
* Enable windows dev mode
* Revert "Enable windows dev mode"
This reverts commit a46c99282e.
* Revert "Ingore apps from vscode"
This reverts commit 47f7b265d2.
* Revert "Fix windows install"
This reverts commit 1dabba1556.
* update the repo root
* fix root dir
* fix path
* fix other path
* Fix unrelated changes
* fix: address apps move follow-up blockers (#11228)
* fix: update root app command paths
* fix: include moved apps in root checks
* fix: clean up moved app path references
---------
Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Eve Killaby (@candieduniverse) has left Cline; transfer her /.github/ codeowner slot to @dominiccooney so .github changes still have four code owners able to approve.
* ci: gate ext-jb-test-integration auto-trigger on PR author association
Extend the existing MEMBER/OWNER/COLLABORATOR allow-list (already used
for the /test-jetbrains comment path) to pull_request_target [opened,
reopened] as well, so the same trust model applies regardless of how
the workflow is triggered. PRs from non-trusted authors no longer
auto-trigger; a maintainer can still opt them in via /test-jetbrains.
* ci: replace hardcoded app-id with CLINE_JETBRAINS_WORKFLOW_ID var
Matches the convention already in use in cline/intellij-plugin and lets us change the App ID without touching workflow code.
* Update .github/workflows/ext-jb-test-integration.yml
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* ci: rename CLINE_JETBRAINS_WORKFLOW_KEY to CLINE_JETBRAINS_APP_KEY
The secret holds a GitHub App private key. Matches the rename of the matching app-id var in the previous commit.
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>