98 Commits
Author SHA1 Message Date
Thefool 1ef08d5e7d fix(windows): stop in-app updates from rebooting the machine (#8628)
The MSI now carries REBOOT=ReallySuppress, so Windows Installer never restarts the machine when a file is in use during an in-app update, including updates driven by older updaters. The updater also passes REBOOT=ReallySuppress, a leftover instance is closed on the updater path, and the release workflow fails if the built MSI lacks the property.

Fixes #8534
2026-10-21 15:08:23 +08:00
Dante d23cee4c11 fix(hermes): read live WSL databases inside their distribution (#8254)
Windows SQLite cannot reliably read a live Hermes WAL database through a WSL UNC path. For wsl.localhost / wsl$ Hermes paths only, read the database inside the owning distribution via wsl.exe and Python SQLite (mode=ro, query_only, one short read transaction), streaming the result back in bounded JSON frames into the existing session projection. Non-WSL paths and macOS/Linux are unchanged. Requires python3 (3.7+) and timeout inside the distribution. Fixes #8205.
2026-10-17 21:37:51 +08:00
Lingbou 42d479560c ci(release): fail fast when linux deb or rpm package is missing (#7985)
Signed-off-by: Xingqiu Xu <hilbertanjou83@gmail.com>
2026-10-09 16:44:22 +08:00
Lingbou b1752e1c89 ci(release): require deb and rpm signatures in latest.json check (#7943)
Signed-off-by: Xingqiu Xu <hilbertanjou83@gmail.com>
2026-10-08 22:31:48 +08:00
Jason 5ae6ad3888 ci(wsl): retry flaky lib tests in the WSL2 nightly
The 9P share sometimes aborts a write mid-test with os error 995
(ERROR_OPERATION_ABORTED): a Claude Desktop config test passed in 1.3s
on one run and failed after 17s on the next with no code change.

Retry up to twice in the nightly only. The ci profile used by PRs keeps
failing on the first error, and nextest still lists retried passes as
FLAKY so repeat offenders stay visible.
2026-10-08 11:25:51 +08:00
Jason faae0e4d7e ci(wsl): run the WSL2 nightly from a nextest archive
The nightly has failed since 10-05 with LNK1327: the contract step
re-invoked cargo with TEMP on \\wsl.localhost, cargo re-linked the lib
tests, and mt.exe cannot create its manifest temp file on a UNC path.

Build the lib tests once into a nextest archive with the native TEMP,
and run both the contract test and the lib suite from that archive, so
nothing is built while TEMP points at the WSL share. The archive is
extracted to the runner temp, and --no-tests fail replaces the manual
check that the contract test was discovered.

Supersedes #6856.
2026-10-08 10:43:48 +08:00
Lingbou d90de1ba0e fix(updater): support Linux package auto-updates (#7620)
Align the Tauri frontend packages with the Rust crates, include deb/rpm updater signatures in Linux releases, and publish package-specific entries in latest.json.

Fixes #4060

Signed-off-by: Xingqiu Xu <hilbertanjou83@gmail.com>
2026-10-08 10:10:57 +08:00
Jason a7f66764e3 chore(github): list all ten apps in issue templates
Add Claude Desktop, Grok Build, Hermes, Pi and MiniMax Code to the app
dropdowns, bump the version examples to 4.0.4, and point to
Settings → About for the version number.
2026-10-07 20:02:36 +08:00
Jason 165622b840 feat: show a short summary of what changed after updating
The in-app updater only follows stable releases and its manifest notes
just say "Release vX", so users jumping between stable versions never
saw what the versions in between changed. The full release notes are
too long for a popup.

- Each version gets src/whats-new/<version>.json: up to 4 one-line
  items (new / fix / improve) in zh, zh-TW, en and ja, bundled into the
  app at build time. "items": [] marks a version that should not pop up.
- On the first launch after an update, a dialog lists every non-empty
  version between the last one seen and the current one, newest first.
  Older versions beyond the first three are collapsed. Each version
  links to its page in the website changelog.
- The last seen version is stored per device in settings.json
  (whatsNewSeenVersion) and only moves forward, so a downgrade and
  re-upgrade does not repeat anything. Without a record, only the
  current version is shown. When there is nothing to show, the version
  is recorded silently so the next update has a correct starting point.
- The dialog waits for the welcome and new-layout dialogs. Confirming
  either of them also records the current version, so a 3.x user does
  not get two dialogs in a row.
- Settings > About gets a "Recent updates" button to open the summaries
  again. The 4.0.0 summary is included so that list starts from 4.0; no
  update popup can reach it, since only 4.0.2 and later record a version.
- The release workflow first requires the tagged version's summary file
  and validates every bundled summary with the unit test, since a
  malformed item would crash the dialog and put the whole app on the
  error screen.
2026-10-05 20:30:56 +08:00
Jason ee66be2222 ci(release): build macOS arches in parallel and add manual dry runs
- macOS used one runner that compiled aarch64 and x86_64 one after the
  other inside `tauri build --target universal-apple-darwin`, and every
  notarization retry recompiled both. Now `macos-binary` compiles each
  arch on its own runner with --no-bundle, and `macos-release` merges
  them with lipo and runs `tauri bundle --target universal-apple-darwin
  --bundles app`. Only that bundle/sign/notarize step is retried. The
  styled DMG from create-dmg, the zip and the updater tar.gz are made as
  before. `macos-binary` carries the release environment, so a release
  is still approved once at the start; `macos-release` must not, or it
  would wait for a second approval halfway.
- The Tauri signing key preparation moves into a composite action shared
  by the Linux/Windows matrix and `macos-release`. Its output matches
  the old inline script for every key format tried.
- Windows x64 builds only the MSI. Tauri also built an NSIS setup.exe
  that was never uploaded; the portable zip still comes from the exe.
- latest.json is generated inside publish-release from the downloaded
  signatures, before the release is created, so a missing platform
  fails without leaving a half-published release. The
  assemble-latest-json job is gone.
- workflow_dispatch runs the full build, signing and notarization as a
  dry run, with assets kept as workflow artifacts. Only a tag push
  publishes, even when a dispatch is started on a tag; the concurrency
  group includes the event name so a dry run cannot cancel a release in
  progress; and `/` in branch names becomes `-` in asset file names.
- Quote the $GITHUB_OUTPUT redirects that shellcheck flagged.
2026-10-05 12:18:17 +08:00
Jason e95c5e68d0 ci: path-filter pushes to main too, with a weekly full run
Pushes to main ran every job on the theory that they keep the caches
warm, but a cache whose key hits exactly is never saved again, so those
full runs refreshed nothing. Pushes now skip unaffected jobs like pull
requests do.

A scheduled run every Monday (03:41 Beijing) and workflow_dispatch run
everything, rebuilding caches after eviction: the filter step only runs
for pull_request and push, and the `|| 'true'` fallback on its outputs
turns a skipped filter into "both areas changed". The concurrency group
now includes the event name so the scheduled run and a push to main do
not cancel each other.
2026-10-05 12:17:58 +08:00
Jason b544bc27c6 ci: run backend tests under cargo-nextest and cache deps with rust-cache
- Backend tests run with `cargo nextest run --profile ci`: one process
  per test, a 180s per-test timeout (src-tauri/.config/nextest.toml),
  and no fail-fast. The WSL2 nightly uses it too, still one test at a
  time and with the same selection as the old `--skip database::`, so a
  hung test is killed instead of eating the whole job.
- Integration tests shared one fixed test home, and each process wiped
  it on startup. Under nextest they ran concurrently and failed en
  masse, so tests/support.rs now picks a directory per
  NEXTEST_TEST_GLOBAL_SLOT. Plain `cargo test` keeps the old directory.
- Swatinem/rust-cache replaces the hand-rolled actions/cache step. It
  caches dependencies only, not the cc-switch crate that is rebuilt
  every run, and keys on OS, rustc version and Cargo.lock. The WSL2 CI
  job and the nightly share the `backend` key but only restore it, so
  their lib-only builds never save over the full Windows cache.
- Quote the $GITHUB_OUTPUT redirect that shellcheck flagged.
2026-10-05 12:17:50 +08:00
Jason f344af0256 ci: install the Rust toolchain pinned in rust-toolchain.toml
dtolnay/rust-toolchain@stable installed the latest stable, then rustup
switched to the 1.95 channel from rust-toolchain.toml on the first cargo
call, so every job downloaded two toolchains. Read the channel from
rust-toolchain.toml and pass it as `toolchain` in the CI backend and
WSL2 jobs, the release build and the WSL2 nightly, keeping the file as
the single source of the compiler version.
2026-10-05 11:13:26 +08:00
Jason f9e2ebbb9f ci(release): fail fast on notarization rejections and missing updater signatures
- macOS: tee each build attempt to a log, and stop on HTTP 401/403 from
  Apple instead of retrying. An expired developer agreement cannot be
  fixed by a retry; for v4.0.0 the loop rebuilt both architectures twice
  more and ran into the job timeout.
- Treat a missing macOS .tar.gz.sig, Windows MSI or MSI signature
  (either arch), AppImage or AppImage signature as an error. They used to
  print a warning, and latest.json then silently left that platform out,
  so its users would get no update.
- assemble-latest-json downloads only the *.sig files it reads and fails
  if any of the six platforms lacks a signature.
2026-10-05 11:13:19 +08:00
Jason e4960bbaf0 test(wsl): run the WSL2 nightly as a lib suite that can pass on 9P
The nightly has not passed in weeks: 37 tests failed on the
\\wsl.localhost share before the run hung. They fall into a few causes
that come from the 9P filesystem, not from product bugs:

- Windows cannot lock SQLite files there, so every on-disk SQLite
  fixture fails with "database is locked". Skip `database::` by name and
  let fixture tests return early via config::sqlite_unsupported_in_temp_dir.
  The account recovery test now uses an in-memory DB that it reuses
  across the simulated restart.
- Integration tests all create the app database, so run --lib only.
  Users keep that database in the Windows home unless they override the
  app config dir.
- The share exposes no file identity, so parent timelines are not cached.
  The five cache tests now check reuse only where parent_cache_supported.
- Remote symlinks are not followed. The catalog escape test asserts None
  when the link resolves, and otherwise that the result is unreadable.

With one test binary left, the timeout drops from 90 to 30 minutes.
2026-10-05 11:13:08 +08:00
Jason 913a3bf23e docs(readme): refresh stale facts across all four READMEs and add a tagline and quick nav
- Add Pi (10 managed apps), scope tray/MCP/Skills per app, document additive apps
- Fix "signature bypass" wording (Hide AI Attribution), common-config FAQ labels,
  official-login/restart FAQs, and first-launch auto-import note
- Correct Linux requirements (glibc 2.35 + WebKitGTK 4.1) and release asset names
- Update dev env (Node 20.19+/22.12+, pnpm 10, Rust 1.95), drop broken coverage cmd
- Point release notes to v3.20.4 and SSSAiCode to sssaicodeapi.com
- JA: replace the stale unsigned-macOS instructions; fix Chinese FAQ anchors in
  SUPPORT.md and issue templates
2026-09-25 21:30:49 +08:00
Jason 4b1ec8b55b fix(ci): stabilize frontend tests and verify renderer build 2026-09-22 20:16:27 +08:00
ikimandsaladday 0ae561b8d2 fix(ci): run WSL2 contract tests via prebuilt binaries (#6472)
* ci: run WSL2 contract tests via prebuilt binaries

link.exe/mt.exe fails to create manifests when TEMP points to a WSL UNC path (LNK1327). Run precompiled test binaries directly instead of re-invoking cargo, and explicitly set native TEMP during compilation.

* ci: harden prebuilt WSL2 contract runner

Keep the scheduled full-suite workflow unchanged until it can be validated independently. Drain Cargo's JSON stream before using the test binary and propagate its exit status.

---------

Co-authored-by: saladday <1203511142@qq.com>
2026-08-26 22:55:12 +08:00
Jason c98cc3a9e9 ci: skip frontend/backend checks when a PR touches neither area
Add a changes-detection job (dorny/paths-filter, SHA-pinned) and gate
the frontend job, the 3-OS backend matrix, and the WSL2 contract gate
on whether the PR actually touches their inputs. About two thirds of
merged PRs only touch one side, and docs-only PRs now skip CI entirely.

Pushes to main still run everything unconditionally so the caches that
PRs restore from stay warm. Path groups mirror .github/labeler.yml,
plus rust-toolchain.toml which pins the compiler used by the backend
jobs.
2026-08-10 17:06:52 +08:00
Jason 36ed280d32 ci: fix i18n labeler glob to match actual locales path
The i18n label never fired because the glob pointed at src/locales/**
while the locale files live under src/i18n/locales/.
2026-08-10 17:06:52 +08:00
Allen XuandJason ceef0a52ad ci: run Windows backend tests against WSL2 filesystems (#6233)
* ci: add WSL2 backend checks

* ci: fix WSL2 backend job by keeping MSVC toolchain on native temp

- compile test binaries before pointing TEMP/TMP at the WSL2 UNC path
  (mt.exe fails with c1010070/LNK1327 when TEMP is a UNC path)
- inject WSL2 TEMP/TMP per test step instead of via GITHUB_ENV
- use --tests so doctests cannot trigger link steps under the UNC temp
- run the filesystem contract gate before the full serial suite
- drop fmt/clippy steps duplicated from the existing Windows job

* ci: move full WSL2 suite to nightly, keep per-PR contract gate

- the full serial suite needs 50+ minutes on the 9P filesystem
  (2026/2343 lib tests finished in 39.5min before the 45min timeout)
- per-PR job now runs only the atomic-write contract (~6min total)
  and builds just the lib test binary via --lib
- new nightly workflow (schedule + workflow_dispatch, 90min timeout)
  runs the contract plus the full serial suite on the WSL2 home

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-08-10 16:21:42 +08:00
Jason 290b65c03b chore(sponsors): point Sponsor button to GitHub Sponsors profile 2026-08-04 23:32:39 +08:00
zayokaandClaude Fable 5 6b8f36431b fix(security): cap scripts, file reads, and proxy bodies; surface deeplink usage fields (#5919)
* fix(security): harden usage script execution and Grok session log collection

Three hardening fixes in v3.19.0 code:

1. **usage_script: cap JS runtime resources and execution time**
   `execute_usage_script` used a vanilla `Runtime::new()` with no limits,
   so a malicious or buggy script delivered via deeplink or synced DB could
   hang the backend thread forever with `while(true)`. Add
   `create_script_runtime()` enforcing a 5-second interrupt handler, 16 MiB
   memory limit, and 256 KiB stack limit. Regression test confirms an
   infinite-loop script is rejected within seconds instead of blocking.

2. **Grok session log: skip oversized files**
   `sync_single_grok_file` loaded the entire `updates.jsonl` into memory
   with no size cap. Add a 50 MiB limit and skip files that exceed it.

3. **Grok session log: bound directory traversal**
   `collect_files_named` recursed without depth limits and followed
   symlinks, so a symlink cycle under `~/.grok/sessions` caused a stack
   overflow. Add a 16-level depth limit and skip symlinks entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ui): show hidden usage access token and user id in deeplink provider import dialog

The provider import confirmation dialog parsed usageAccessToken and
usageUserId from ccswitch:// URLs and persisted them in
ProviderMeta.usage_script, but never rendered them. Users could not see
these credentials before approving the import.

- Add i18n keys for usageAccessToken/usageUserId in all locales.
- Render both fields in the usage script section; mask the access token
  like usageApiKey.
- Add a regression test verifying the dialog displays the masked token
  and the user id.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(security): bound Codex model catalog and proxy response bodies

Two issues were found while auditing security boundaries:

1. **Codex model_catalog_json arbitrary file read**
    only checked the filename and
   accepted any absolute path. A malicious  could
   point CC Switch at an external file (e.g. ) or a huge
   file to exhaust memory.

   - Require the resolved path to stay inside
     using a new  helper (lexical, no filesystem calls).
   - Treat Unix-style absolute paths as absolute on Windows.
   - Cap catalog reads at 32 MiB.

2. **Unbounded proxy response bodies / compression bombs**
   Non-streaming responses and error responses were read with
    and fully decompressed without any byte
   limit, allowing a malicious upstream to OOM the backend.

   - Add  with a 128 MiB ceiling.
   - Reject oversized bodies and oversized decompressed payloads with
     .
   - Map the new error variant into the Codex proxy error response.

Regression tests cover: absolute-path containment, traversal rejection,
oversized catalog file, oversized buffered/streamed proxy responses.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ci): set up pnpm via Corepack instead of pnpm/action-setup v6

pnpm/action-setup v6 installs pnpm through a two-step self-installer:
it bootstraps the latest pnpm (11.7.0) via npm, then downloads the
pinned version (10.12.3) from the npm registry to switch. When that
second tarball fetch failed (error 23), the self-installer still
reported "done" and crashed with ENOENT on @pnpm/linux-x64's
package.json, failing the CI setup step.

Replace the action with Node 20's bundled Corepack and pin the version
once via package.json's packageManager field, so setup performs a
single exact-version download with no floating bootstrap. This also
lets release.yml drop its Windows ARM64 special case, since Corepack
has no arch restrictions, and pins the same version for local dev.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(security): close review gaps in proxy body caps, deeplink dialog, catalog path

Address maintainer review on the security PR:

- Proxy: bound the four remaining unbounded forwarder read paths
  (non-2xx error body, failover pre-read, both 2xx error-envelope
  validators) with bytes_with_limit + bounded decompression.
- Proxy: bytes_with_limit now accumulates Hyper/Reqwest/Streamed bodies
  chunk-by-chunk and aborts mid-stream instead of collecting the full
  body before comparing; Buffered keeps the post-hoc check.
- Proxy: decompression is budgeted at the decoder (Read::take on
  gzip/deflate/zstd, bounded brotli reader) via decompress_body_with_limit,
  so bombs are cut off at the byte budget instead of after full expansion,
  including stacked-encoding intermediates.
- Deeplink: show the usage section whenever any usage field is present,
  matching build_provider_meta persistence — a deeplink carrying only
  usageAccessToken/usageUserId no longer imports credentials invisibly.
- Codex catalog: after the lexical containment check, canonicalize the
  existing file and re-verify containment so symlinks inside ~/.codex
  cannot escape the config dir; the path_is_within doc comment no longer
  oversells the lexical check as symlink-safe.
- Grok sync: comment now matches the skip-all-symlinks behavior and each
  skip is logged, so sessions behind a symlink are diagnosable.
- Docs: CONTRIBUTING notes the packageManager pnpm pin and Corepack flow.

Regression tests follow the same methodology as round 1: reverting a
guard fails the corresponding test (server write-count assertions prove
the mid-stream abort; a truncated gzip stream distinguishes TooLarge
from read-to-end errors; symlink escape is rejected only after the
canonicalize re-check).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-04 15:44:08 +08:00
Jason 2b2f2cfad9 ci: mirror in-app updater to Cloudflare R2 with release-gated sync
- Move the R2 sync out of release.yml into a standalone sync-r2.yml
  triggered on release promotion (release: released) or manual dispatch,
  so the mirror follows the same gate as GitHub's /releases/latest
- Hard-fail on the official repo when R2 secrets are missing (a silently
  stale mirror strands updater users); forks may still skip
- Only the tag that is currently releases/latest may rewrite the root
  manifests or prune old versions; backfills of older tags restore
  versioned files only
- Resolve releases/latest with retries and fail instead of guessing on
  API errors; re-verify right before publishing the root manifests
- Add scripts/rewrite-updater-manifest.mjs to point latest.json download
  URLs at the mirror (minisign signatures cover file contents and stay
  valid); upload the macOS .tar.gz updater payload alongside installers
- Put https://dl.ccswitch.io/latest.json first in the updater endpoints
  with GitHub as connectivity fallback
2026-07-27 18:41:49 +08:00
Jason 708b38791c ci: add sha256 and real publish date to download manifest
The manifest generator now hashes each installer (SHA-256) so the
website download page can display verifiable checksums, and accepts an
optional pub-date argument. The sync-to-r2 job passes the release's
actual publishedAt instead of relying on generation time, which drifted
for backfills.
2026-07-27 16:37:35 +08:00
Jason 414b71500c ci: mirror release assets to Cloudflare R2 for ccswitch.io downloads
Add a sync-to-r2 job that downloads the published release assets,
generates the website download manifest, uploads both to the
cc-switch-releases bucket (dl.ccswitch.io), and prunes versions
beyond the latest five. The job skips itself when R2 secrets are
not configured, so forks and the current pipeline are unaffected.
2026-07-24 23:25:14 +08:00
f6e37ed994 fix(ci): run backend checks on Windows/macOS and repair platform-gated tests (#5138)
* fix(ci): run backend checks on Windows/macOS and repair platform-gated tests

The backend CI job ran only on ubuntu-22.04, so every #[cfg(target_os =
"windows")] / macOS path — tests and clippy lints alike — was never
compiled or run. As a result main shipped 8 failing Windows unit tests and
a hard `cargo clippy -- -D warnings` failure on Windows, all invisible to
CI because it only builds and tests Linux.

Changes:

- ci: run the backend job on a {ubuntu-22.04, windows-latest, macos-latest}
  matrix (fail-fast: false); gate the apt install step on runner.os ==
  'Linux' and use `shell: bash` for the dist placeholder so it works on all
  three runners.

- misc.rs: fix 6 stale `anchored_upgrade_windows` tests. Commit 5092fe51
  removed codex from `prefers_official_update`, so codex now anchors to the
  package manager with no `codex update ||` prefix; update the five
  package-manager expectations accordingly, and retarget the no-sibling
  "official-update-without-fallback" test to `claude` (still in the list) so
  that branch stays covered instead of being silently dropped.

- codex_state_db.rs / codex_history_migration.rs: the two sqlite_home tests
  built TOML basic strings from Windows paths, whose backslashes are invalid
  escape sequences and made the override fail to parse; switch to TOML
  literal (single-quoted) strings so the path is taken verbatim.

- clippy (13 Windows-only warnings): move `use std::io::Write` into the
  #[cfg(unix)] block that actually uses it; convert 3 unneeded `return`s in
  Windows-gated tail positions to expressions; mark 9 POSIX-shell helpers
  #[cfg_attr(windows, allow(dead_code))] since they are used only by the
  macOS/Linux terminal launchers.

Verified locally (Windows 11, Rust 1.95.0):
  cargo test --lib                        → 1748 passed; 0 failed (was 1740/8)
  cargo clippy -- -D warnings             → clean (was 13 errors)
  cargo fmt --check                       → clean

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(skills): resolve home via get_home_dir so tests isolate on Windows

services/skill.rs called dirs::home_dir() directly in five places. On
Windows dirs::home_dir() resolves through the Known Folder API and
ignores HOME/USERPROFILE, so the CC_SWITCH_TEST_HOME override set by the
test harness never applied: the skill_sync integration tests scanned the
runner's real user profile, found no skills, and failed (the first panic
then poisoned the shared test mutex, cascading to all seven). On Unix
the harness also sets HOME, which dirs::home_dir() honors, so the suite
passed there by accident.

Route all five call sites through crate::config::get_home_dir(), the
crate-wide home resolver that prefers CC_SWITCH_TEST_HOME. The three
now-unreachable GET_HOME_DIR_FAILED error branches are dropped:
get_home_dir() is infallible, matching every other config-dir resolver.
Production behavior is unchanged (CC_SWITCH_TEST_HOME is unset outside
tests, so get_home_dir falls through to dirs::home_dir).

Add a regression test that discriminates on every platform by pointing
CC_SWITCH_TEST_HOME at a temp dir different from $HOME; it is marked
#[serial_test::serial] to stay mutually exclusive with the other tests
mutating the same process-global variable. Verified the test fails
against the old code on macOS with the same failure mode as Windows CI.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
2026-07-15 10:33:22 +08:00
Jason 468c93d409 ci: harden release supply chain
- Add CODEOWNERS so PRs to main require owner review (closes the gap
  where two collaborators could approve each other's changes).
- Gate the release job behind a 'release' environment, so signing
  secrets are only unlocked after manual approval.
- Stop ignoring the whole .github directory; this had been silently
  swallowing labeler.yml and workflows/labeler.yml, which are now tracked.

Paired with a tag ruleset (created out-of-band) that restricts creation
of v* tags to admins, this prevents a write collaborator from pushing a
tag to trigger a signed release build.
2026-07-07 16:02:16 +08:00
MoonDreamStarsandMoonDreamStars 2db3163cf2 ci: add Windows ARM64 release support (#3950)
* ci: add Windows ARM64 release artifacts

* ci: keep release matrix jobs independent

* ci: fix pnpm cache path on Windows runners

* ci: setup pnpm with corepack on Windows ARM64

* ci: fix Windows ARM64 release build

* ci: retry transient release bundler downloads

* ci: remove non-minimal release workflow changes

* ci: keep release matrix jobs independent

macOS signing fails in forks without Apple secrets and, with default
matrix fail-fast, cancels the sibling jobs (including Windows ARM64)
before they finish. Disable fail-fast so each platform runs to completion.

---------

Co-authored-by: MoonDreamStars <moondreamstar1@gmail.com>
2026-06-23 17:30:41 +08:00
Jason 7685ab7049 chore(release): surface ccswitch.io in release notes template
Each tagged release now leads with the canonical official website
in three languages, ensuring every Release page (which is indexed
independently by Google) becomes a dofollow backlink to ccswitch.io.
2026-05-11 15:49:36 +08:00
Jason ddc7b4567e fix(ci): pin Claude review checkout to PR head sha
Prevents `git fetch origin pull/<N>/head:main` failures on fork PRs
whose head branch is also named `main` — using a SHA puts the runner
in detached HEAD so the main ref is free for the action's internal fetch.
2026-05-02 20:33:54 +08:00
Jason faa6021c6f fix(ci): drop --max-turns 5 from Claude review args
Cap was too tight — review tasks need 8-15 turns to read files, analyze,
and post results. The first run after the previous prompt change failed
with error_max_turns at turn 6. The disallowedTools list already keeps
the agent in read-only mode, so an explicit turn cap is redundant.
2026-05-02 10:28:47 +08:00
Jason 79d6ede7ae chore(ci): tune Claude review prompt to reduce nitpick noise
Previous prompt produced 5-10 findings per PR including dead-code/style
nits mixed with real bugs. New prompt adds severity tiering, an 80
confidence threshold, an explicit anti-pattern list, a 5-nit cap, and
permits zero-comment LGTM as a valid outcome. Calibration follows
Anthropic Code Review docs and the claude-plugins-official prompt.
2026-05-02 10:26:36 +08:00
dependabot[bot] c2714774b9 chore(deps): bump actions/stale from 9 to 10 (#2520)
Bumps [actions/stale](https://github.com/actions/stale) from 9 to 10.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v9...v10)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: '10'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-02 09:44:36 +08:00
dependabot[bot] 026b5dbcb5 chore(deps): bump softprops/action-gh-release from 2 to 3 (#2519)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2 to 3.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2...v3)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-02 09:44:32 +08:00
dependabot[bot] 59f7105cbc chore(deps): bump pnpm/action-setup from 5 to 6 (#2518)
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 5 to 6.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v5...v6)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-02 09:44:28 +08:00
dependabot[bot] 586450a372 chore(deps): bump actions/checkout from 4 to 6 (#2517)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-02 09:43:44 +08:00
Jason 7621b645d1 chore(ci): upgrade Claude review model to Opus 4.7 2026-05-01 23:47:51 +08:00
Jason d75e4e7eb3 fix(ci): add id-token:write permission required by claude-code-action v1 2026-05-01 23:19:22 +08:00
Jason adc7ffefa4 chore(ci): add Claude Code Action for review-only @claude mentions
- Restrict to repo collaborators via author_association check
- Use OAuth token for subscription billing
- Disable Edit/Write tools and set contents:read permission to enforce review-only
2026-05-01 23:07:46 +08:00
Jason Young e4fe2763cd chore(deps): bump actions/cache from 4 to 5 in ci.yml (#1860)
Sync ci.yml with release.yml after dependabot updates.
2026-04-03 16:24:55 +08:00
dependabot[bot] 3e1de466db chore(deps): bump actions/download-artifact from 4 to 8
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 8.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v8)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '8'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-03 08:40:29 +08:00
dependabot[bot] 1abe474e75 chore(deps): bump actions/upload-artifact from 4 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-03 08:40:22 +08:00
dependabot[bot] 74d7e86b7a chore(deps): bump pnpm/action-setup from 2 to 5
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 2 to 5.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v2...v5)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-03 08:40:14 +08:00
dependabot[bot] b9297e42f5 chore(deps): bump actions/setup-node from 4 to 6
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-03 08:40:09 +08:00
dependabot[bot] 7de2db9ee8 chore(deps): bump actions/cache from 4 to 5
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-03 08:32:17 +08:00
Jason 1b4c3cbcaa ci: add stale bot to auto-close inactive issues after 60 days
- Mark issues as stale after 60 days of inactivity
- Auto-close after 14 more days without response
- Bilingual (zh/en) stale and close messages
- Exempt security and performance labeled issues
- Runs daily at UTC 00:00, processes up to 100 issues per run
- Only affects issues, not pull requests
2026-04-03 00:01:13 +08:00
Jason 2af38a63b5 docs: point FUNDING.yml to Chinese README sponsor section 2026-04-02 22:22:12 +08:00
Jason 3388cba1dc docs: add sponsor call-to-action to READMEs and fix FUNDING.yml 2026-04-02 22:15:49 +08:00
Jason 8b44d9f54d fix(test): resolve HOME env race condition in parallel tests
- Use get_home_dir() instead of dirs::home_dir() in get_opencode_dir()
  and get_openclaw_dir() to respect CC_SWITCH_TEST_HOME override
- Add CC_SWITCH_TEST_HOME to all TempHome implementations
- Add #[serial] to all with_test_home tests to share serialization
  with other env-mutating tests
- Remove --test-threads=1 workaround from CI
2026-04-02 22:08:12 +08:00