288 Commits

Author SHA1 Message Date
Saoud Rizwan 8981079a43 Build and Authenticode-sign a Windows x64 desktop installer in desktop releases (#13607)
* feat(desktop): build and Authenticode-sign a Windows x64 NSIS installer in desktop releases

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

* fix(desktop): pin OIDC-adjacent actions to commit SHAs in the Windows signing job

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

* fix(desktop): pin checkout and upload-artifact to commit SHAs in the Windows signing job

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

---------

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
2026-08-26 23:07:50 -07:00
Saoud Rizwan 89970ea794 Sign Windows CLI binaries with Azure Trusted Signing; surface app-control launch errors (#13021)
* feat(cli): sign Windows binaries with Azure Trusted Signing and surface app-control launch errors

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

* fix(cli): use _CLI-suffixed signing profile secret, normalize endpoint, fail loud on partial config

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

---------

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-08-26 16:13:23 -07:00
Haley Park 3497391c5a feat(desktop): customize macOS DMG install window (#13563)
* 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>
2026-08-25 14:30:59 -07:00
Saoud Rizwan f91af30401 Add Desktop App and Cloud Platform to bug report issue template (#13532)
* Add Desktop App and Cloud Platform to bug report surfaces

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

* Rename Surface Diagnostics field to Diagnostics

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

---------

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
2026-08-24 19:49:47 -07:00
Saoud Rizwan e7ed29109b ci(vscode): make combined nightly manual-dispatch only
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.
2026-08-21 17:01:56 -07:00
Mikołaj Kondratek e70b3ffc4b ci(vscode): upload E2E failure recordings from the right path (#13427)
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.
2026-08-20 20:10:12 +02:00
Saoud Rizwan 878faf0a95 Rename desktop app from "Cline Code" to "Cline" (#13401)
* Rename desktop app from Cline Code to Cline

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

* Format touched Rust test assertions

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

---------

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
2026-08-19 15:29:00 -07:00
Saoud Rizwan 36397f47eb ci: tidy workflow cache config and job permissions (#13403)
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.
2026-08-19 14:31:41 -07:00
Saoud Rizwan 3f0c5cdc92 ci: stop over-long changelogs from silently dropping release Slack posts (#12955)
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.
2026-08-19 13:34:40 -07:00
Saoud Rizwan 76ac1c7f55 ci(ui-publish): build @cline/shared before ui typecheck (#13354)
@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.
2026-08-18 18:01:10 -07:00
Saoud Rizwan eeaed357ef fix(ci): lock the legacy publish workflow to the legacy-extension branch (#13350)
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.
2026-08-18 16:12:04 -07:00
Saoud Rizwan bca9b64206 fix(ci): always build the legacy bundle from the legacy-extension branch (#13349)
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.
2026-08-18 16:00:35 -07:00
Saoud Rizwan 5ad2dd5fc8 feat(desktop): beta release channel from desktop-experimental branch (#13321)
* 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.
2026-08-17 17:24:01 -07:00
Saoud Rizwan ddfb67515b fix(desktop): inline telemetry config into the packaged sidecar binary (#12925)
* fix(desktop): inline telemetry config into the packaged sidecar binary

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>

* fix(desktop): reject non-http OTLP endpoints in the telemetry selfcheck

---------

Co-authored-by: Saoud Rizwan <saoudrizwan@users.noreply.github.com>
2026-08-04 20:43:01 -07:00
Saoud Rizwan 62c57a0ccd ci(ui): publish @cline/ui without a manual approval gate (#12938)
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.
2026-08-04 16:23:46 -07:00
Saoud Rizwan 058c8c90a2 feat(desktop): ship a single universal macOS DMG instead of per-arch downloads (#12923)
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>
2026-08-04 12:42:55 -07:00
Saoud Rizwan 46fcde0a96 ci(desktop): drop the Rust build cache from the code-signing job (#12898)
* 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>
2026-08-03 19:16:23 -07:00
Saoud Rizwan 1654517614 ci(desktop): gate desktop publish secrets behind PublishDesktop environment (#12854)
* 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.
2026-08-02 01:55:24 -07:00
Saoud Rizwan b0ee2cc80a ci(vscode): publish combined stable VSIX to Open VSX and harden ab-package gates (#12805)
* ci(vscode): publish combined stable VSIX to Open VSX and harden ab-package gates

* ci(vscode): address greptile review — env-routed version input, bookkeeping survives Open VSX failure
2026-07-31 20:09:09 -07:00
Saoud Rizwan 69e3149f5f ci(vscode): add tag, GitHub Release, and Slack bookkeeping to combined publish workflow 2026-07-30 20:59:08 -07:00
Saoud Rizwan 311959e757 ci(vscode): add test gate to combined A/B publish + publish-extension skill (#12764)
* 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
2026-07-30 17:54:29 -07:00
Saoud Rizwan 078abcd055 fix(ci): build shared package before the ui-publish desktop chat test
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.
2026-07-30 12:02:42 -07:00
Saoud Rizwan 283c3ba937 ci: grant pull-requests write so promo-comment deletion works on PRs (#12606) 2026-07-27 16:51:00 -07:00
Saoud Rizwan 69c9a9ac28 ci: delete coding-agent promo comments on PRs (#12604) 2026-07-27 16:44:48 -07:00
Saoud Rizwan 1bd200e906 ci: strip cloud-agent promo wrappers from PR bodies (#12588)
* ci: strip cloud-agent promo wrappers from PR bodies

* ci: make PR body strip vendor-agnostic, pin github-script to SHA
2026-07-27 15:10:05 -07:00
Saoud Rizwan f5224abdf5 feat(desktop): auto-updates + automated signed releases from GitHub Actions (#12420)
* 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.
2026-07-21 16:37:18 -07:00
Saoud Rizwan 7274d8badc feat(ui): add agent chat components, Storybook, and npm releases (#12374)
* feat(ui): add shared agent chat components and Storybook

* ci(ui): add standalone npm publishing

* docs(ui): keep release commands environment-neutral

* refactor(ui): simplify package validation

* refactor(ui): tighten package and release contracts

* docs(ui): remove duplicate install guidance

* ci(ui): make publishing workflow manual-only
2026-07-17 18:22:57 -07:00
Saoud Rizwan d618f8073a fix(vscode-rollout): align bundle versions and harden combined publish workflows (#12321)
* 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.)
2026-07-15 17:39:44 -07:00
Saoud Rizwan eb21ba583c fix(ci): restrict nightly publishing to main (#12322) 2026-07-15 15:35:09 -07:00
Saoud Rizwan f29c25395c feat(vscode-rollout): A/B loader and packaging for staged SDK extension rollout (#12253)
* 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>
2026-07-15 15:07:45 -07:00
Dominic Cooney 12703bf407 Improve VS Code terminal reliability: OSC 633 parser, exit codes, timeout handling (#11972) 2026-07-14 16:34:36 -07:00
Saoud Rizwan bd9ac5872b ci(sdk): create GitHub release and post to Slack on latest SDK publish (#12223)
* ci(sdk): create GitHub release and post to Slack on latest SDK publish

* ci(sdk): use random heredoc delimiter for changelog output
2026-07-14 01:31:45 -07:00
Max 11d5ebe8bc chore: schedule nightly VS Code extension publish (#12124)
Co-authored-by: Max Paulus 🥪 <max@cline.bot>
2026-07-07 10:30:04 -07:00
Saoud Rizwan c7de31ae24 ci(vscode): gate legacy publish on test job (#11936) 2026-06-27 19:33:37 -07:00
Saoud Rizwan 45dddb9a4e ci(vscode): add legacy extension publish workflow (#11935) 2026-06-27 19:17:46 -07:00
Saoud Rizwan 408be18be9 fix(ci): harden ext-vscode stable release workflow (#11887)
* 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
2026-06-26 12:50:28 -07:00
Dominic Cooney 4829f08b3f fix(vscode): reliable MCP OAuth on the SDK extension (ENG-2108, CLINE-2304) (#11529)
* 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>
2026-06-24 14:11:34 +09:00
Dominic Cooney 82d1846a45 Migrate apps/vscode from npm/node to bun (#11632)
* 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>
2026-06-24 14:11:34 +09:00
Dominic Cooney 94f5a47a59 sdk migration: squashed pre-2026-06-02 work
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)
2026-06-24 14:11:26 +09:00
Mikołaj Kondratek 70303d8541 Improve bug report form: rename surface dropdown, add IDE/CLI diagnostics (#11381)
* 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.
2026-06-09 18:38:53 +02:00
Mahesh Narayan acc1a25e51 Update agent storage guidance (#11025) 2026-06-04 09:53:18 -07:00
Tomás Barreiro 38e5b7c26b Fix VSCode CI (#11236)
* Fix VSCode CI

* fix nightly publish

* Fix install

* Fix biome

* fix tsc

* Fix windows set-up

* Ignore .vscode-test

* Add a LICENSE to the vscode extension

* Add type roots

* Remove workspaces

* remove vscode as a bun workspace
2026-06-03 18:58:27 +02:00
Tomás Barreiro 220a21bdcf Move sdk/apps/ to apps/ (#11200)
* 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>
2026-06-03 01:49:57 +02:00
Tomás Barreiro d7cc9b6155 Move bun from the sdk/ to root (#11104)
* Move bun to root

* Fix scripts and pre-commit

* Update scripts

* Update workflows

* Fix cd

* fix pre-commit

* fix cli publish
2026-06-01 22:29:41 +02:00
Dominic Cooney e330695cb5 chore(codeowners): replace @candieduniverse with @dominiccooney (#11111)
Eve Killaby (@candieduniverse) has left Cline; transfer her /.github/ codeowner slot to @dominiccooney so .github changes still have four code owners able to approve.
2026-05-28 10:38:42 -07:00
Mikołaj Kondratek f2d692cfc2 ci: gate ext-jb-test-integration auto-trigger on PR author association (#11108)
* 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>
2026-05-28 10:36:38 -07:00
Ara 7530900166 fix: repair vscode nightly publish workflows (#11072) 2026-05-26 12:14:25 -07:00
Dominic Cooney 2b45b7b7aa Remove the VSCode Nightly (SDK) publish workflow; we are just running the regular publish workflow from the SDK branch now. (#11074) 2026-05-26 11:34:25 -07:00
Tomás Barreiro 791d238996 Move vscode to apps (#10961)
* Move all vscode related files to /apps/vscode

* Fix launch and biome

* Ignore generated files

* Remove unused icons

* fix tsconfig

* Update workflows (#10962)

* Add default branch

* Move files to the right dir

* fix: add vscode publish README placeholder

---------

Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
2026-05-25 21:35:59 +02:00
Tomás Barreiro 2c842328a8 Inject OTEL variables into the cli at buildtime (#10958)
* Inject OTEL variables

* Add telemetry to the nightly

* Add variables to the build script
2026-05-21 23:43:30 +02:00