Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c322f3c
ci(code-qa): upload coverage lcov reports to GitHub artifacts (#939)
zoomote[bot] Jul 18, 2026
6e05ae9
fix(task-history): route invalidate() and invalidateAll() through wit…
morgan-coded Jul 19, 2026
8c17b41
test(task-lifecycle): add regression coverage for issue #566 (interru…
edelauna Jul 20, 2026
45968c0
fix(webview): dismiss welcome after Zoo Gateway sign-in (#961) (#962)
JamesRobert20 Jul 21, 2026
1b372ce
feat: add MiniMax-M3 model (#946)
zoomote[bot] Jul 21, 2026
b132a6b
feat: enable image support for DeepSeek V4 models (#963)
grizmin Jul 21, 2026
f2bdcb6
feat(moonshot): implement provider with model picker, API fetching, s…
grizmin Jul 21, 2026
3024768
feat(gemini): add Gemini 3.6 Flash support (#975)
zoomote[bot] Jul 21, 2026
cc2588b
fix(litellm): preserve reasoning_content for known reasoning model fa…
daewoongoh Jul 21, 2026
71a58a1
chore(deps): update dependency esbuild-wasm to v0.28.1 (#829)
renovate[bot] Jul 22, 2026
badb82c
fix(webview): sync cachedState on mode changes in SettingsView (#925)
easonLiangWorldedtech Jul 22, 2026
c6279d8
Fix codebase indexing for plain text files (#938)
WebMad Jul 22, 2026
a7d7968
fix(mcp): remove obsolete server creation translations (#943)
WebMad Jul 22, 2026
c24a8c5
feat(types): centralize provider identifiers (#952)
WebMad Jul 22, 2026
ae89dbd
feat(subtasks): abandon interrupted subtask — sever parent-child link…
edelauna Jul 23, 2026
7af1a8a
refactor(types): use canonical provider identifiers in categories (#989)
WebMad Jul 23, 2026
6fec173
[Feat] Add Kimi K3 model to Moonshot and OpenCode Go providers (#996)
zoomote[bot] Jul 24, 2026
78c1410
[Feat] Add Kimi Code provider with OAuth device flow (#945)
taltas Jul 24, 2026
e0e7fb9
[Fix] GPT-5.6 Luna requests rejected by Codex backend when using Chat…
taltas Jul 24, 2026
2634d5c
Add Dart support to codebase indexing (#941)
WebMad Jul 24, 2026
d5a8c4a
feat: implement Claude Opus 5 support across all providers (#1010)
zoomote[bot] Jul 24, 2026
d1f3999
Release v3.72.0 (#1013)
navedmerchant Jul 25, 2026
116acfd
[Fix] Flaky mocked e2e subtasks test when parent resume is served the…
zoomote[bot] Jul 25, 2026
933ee98
fix(settings): buffer Save-managed settings in cachedState until Save…
JunyongParkDev Jul 25, 2026
2d2a238
fix(ollama): always respond to model refresh, surface errors, and use…
navedmerchant Jul 25, 2026
4e9543f
Fix bedrock DNS resolution when behind a corporate proxy (#906)
LouisClt Jul 25, 2026
e479b7e
chore: update Node.js to v22 LTS (22.23.1) (#743)
renovate[bot] Jul 25, 2026
dfb8d69
fix(architect): instruct plans directory as workspace-relative ./plan…
zoomote[bot] Jul 25, 2026
ff17dcb
feat(TaskRegistry): introduce TaskRegistry and migrate clineStack (#1…
edelauna Jul 25, 2026
66120b4
chore(deps): update dependency shell-quote to v1.9.0 [security] (#986)
renovate[bot] Jul 26, 2026
1ceb4e6
test(webview): add Playwright visual regression harness (#526)
edelauna Jul 26, 2026
772e716
refactor(api): use canonical provider identifiers (#1012)
WebMad Jul 26, 2026
c52f118
refactor(types): use canonical identifiers for default models (#991)
WebMad Jul 26, 2026
2db2af0
refactor(api): use canonical model cache provider identifiers (#1020)
WebMad Jul 26, 2026
7710513
refactor(shared): use canonical profile provider identifiers (#1019)
WebMad Jul 26, 2026
782e28e
refactor(core): use canonical provider identifiers (#1022)
WebMad Jul 26, 2026
d27153a
fix(ripgrep): support @vscode/ripgrep >=1.18 platform-package layout …
edelauna Jul 26, 2026
488732e
feat(friendli): add reasoning params support (#886)
Lee-Si-Yoon Jul 28, 2026
85f6f27
chore(lint): add core/webview to no-floating-promises ratchet (#950)
morgan-coded Jul 29, 2026
ded7575
fix(branding): replace remaining user-facing "Roo" strings with "Zoo"…
rrewll Jul 29, 2026
2c987fc
[Fix] Zoo prompts about command output when short foreground commands…
zoomote[bot] Jul 29, 2026
1ae8b5b
feat(TaskScheduler): introduce semaphore-based task scheduler (Epic 3…
edelauna Jul 29, 2026
dcaa3cb
[Chore] Harden E2E workflow against VS Code binary download failures …
zoomote[bot] Jul 29, 2026
088b7ea
refactor(webview): use canonical provider identifiers (#1023)
WebMad Jul 30, 2026
c378193
refactor: finish canonical provider identifier audit (#1030)
WebMad Jul 30, 2026
569b43d
refactor(api): centralize service-tier primitives (#1040)
WebMad Jul 30, 2026
cd29243
fix(openai-compatible): add max reasoning effort option (#882) (#1051)
ivanarifin Jul 31, 2026
5971caa
feat(openai-codex): persist and send Fast priority mode (#1063)
WebMad Jul 31, 2026
69e5851
feat(webview): add OpenAI Codex speed selector
WebMad Jul 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .changeset/itchy-moles-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"zoo-code": patch
---

Fix bedrock DNS resolution when behind corporate proxy
2 changes: 1 addition & 1 deletion .github/actions/setup-node-pnpm/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ inputs:
node-version:
description: "Node.js version to use"
required: false
default: "20.20.2"
default: "22.23.1"
pnpm-version:
description: "pnpm version to use"
required: false
Expand Down
27 changes: 24 additions & 3 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,35 @@ Detail the steps to test your changes. This helps reviewers verify your work.
- [ ] **Scope**: My changes are focused on the linked issue (one major feature/fix per PR).
- [ ] **Self-Review**: I have performed a thorough self-review of my code.
- [ ] **Testing**: New and/or updated tests have been added to cover my changes (if applicable).
- [ ] **Visual Snapshot** (UI changes only): If a user would notice this change at a glance (layout, theme tokens, brand elements, empty/error states), I've added or updated a `*.visual.tsx` snapshot in `webview-ui/`. See `webview-ui/AGENTS.md` → "When a UI change needs a snapshot".
- [ ] **Documentation Impact**: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
- [ ] **Contribution Guidelines**: I have read and agree to the [Contributor Guidelines](/CONTRIBUTING.md).

### Screenshots / Videos
### Visual Snapshots

<!--
For UI changes, please provide before-and-after screenshots or a short video of the *actual results*.
This greatly helps in understanding the visual impact of your changes.
For UI changes to static rendered state, the primary artifact is a committed
Playwright CT snapshot (`*.visual.tsx` in `webview-ui/`) — that baseline
becomes durable regression coverage for the surface. See
`webview-ui/AGENTS.md` for what deserves a snapshot.

Before/after screenshots pasted here are welcome as a review aid but are not a
substitute for the committed baseline. If a snapshot is possible, prefer the
snapshot.
-->

### Videos (interaction / animation only)

<!--
Snapshots cannot capture motion or multi-step flows. Attach a short screen
recording here when reviewers need to see:
- A new interactive flow (dropdown, form, dialog progression)
- Animation, transition, or timing behavior
- A regression that only manifests during interaction

Videos are a review aid, not regression coverage. If the *result* of the
interaction has a distinct rendered state worth protecting, still commit a
`*.visual.tsx` snapshot of that end-state alongside the video.
-->

### Documentation Updates
Expand Down
29 changes: 25 additions & 4 deletions .github/workflows/code-qa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,25 +135,32 @@ jobs:
# lanes for behavioral confidence, but duplicating coverage uploads
# there mostly adds Codecov overhead without changing pass/fail
# behavior.
# Coverage is uploaded in three separate steps so each LCOV gets the
# Coverage is uploaded in separate steps so each LCOV gets the
# correct flag set. Codecov double-counts overlapping lines when a
# single upload carries multiple flags whose paths overlap, so the
# two core lanes (which both cover packages/core/src/**) must be
# uploaded individually with their own lane flag.
# core lanes and webview lane must be uploaded individually with
# their own flag.
# See https://docs.codecov.com/docs/flags
- name: Upload non-core coverage to Codecov
if: matrix.upload-coverage
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
with:
files: >-
src/coverage/lcov.info,
webview-ui/coverage/lcov.info,
packages/cloud/coverage/lcov.info,
packages/telemetry/coverage/lcov.info,
apps/cli/coverage/lcov.info
disable_search: true
flags: ${{ matrix.codecov-flag }}
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload webview JSDOM coverage to Codecov
if: matrix.upload-coverage
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
with:
files: webview-ui/coverage/lcov.info
disable_search: true
flags: webview-ui
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload core unit coverage to Codecov
if: matrix.upload-coverage
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
Expand All @@ -170,3 +177,17 @@ jobs:
disable_search: true
flags: ${{ matrix.codecov-flag }},core-integration
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload coverage reports to GitHub
if: matrix.upload-coverage
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: coverage-reports-${{ matrix.name }}
path: |
src/coverage/lcov.info
webview-ui/coverage/lcov.info
packages/cloud/coverage/lcov.info
packages/telemetry/coverage/lcov.info
apps/cli/coverage/lcov.info
packages/core/coverage/unit/lcov.info
packages/core/coverage/integration/lcov.info
retention-days: 7
105 changes: 101 additions & 4 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,100 @@ jobs:
VERSION=$(node -p 'require("./apps/vscode-e2e/package.json").devDependencies["@types/vscode"]')
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Cache VS Code test binary
- name: Restore VS Code test binary cache
if: github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true'
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
id: vscode-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: |
apps/vscode-e2e/.vscode-test/
key: vscode-test-${{ runner.os }}-${{ steps.vscode-ver.outputs.version }}-v1
# Fall back to the most recent stale binary so a version bump or cache
# eviction doesn't force a download when the VS Code CDN is unreachable.
restore-keys: |
vscode-test-${{ runner.os }}-

- name: Probe VS Code download endpoints
if: (github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true') && steps.vscode-cache.outputs.cache-hit != 'true'
id: vscode-probe
# The version-resolution API and the archive CDN are different hosts. The
# archive URL 302-redirects to the CDN, so a HEAD probe that follows the
# redirect covers both. The fallback engages when either is unreachable.
run: |
API_OK=false
CDN_OK=false
if curl -sf --max-time 10 https://update.code.visualstudio.com/api/releases/stable > /dev/null; then
API_OK=true
fi
if curl -sfIL --max-time 20 -o /dev/null "https://update.code.visualstudio.com/${{ steps.vscode-ver.outputs.version }}/linux-x64/stable"; then
CDN_OK=true
fi
if [ "$API_OK" = "true" ] && [ "$CDN_OK" = "true" ]; then
echo "reachable=true" >> "$GITHUB_OUTPUT"
else
echo "reachable=false" >> "$GITHUB_OUTPUT"
echo "::warning::VS Code download endpoints unreachable (api=$API_OK, cdn=$CDN_OK); will try the stale cached binary"
fi

# @vscode/test-electron only skips its live version-resolution request when the
# requested version already exists in .vscode-test/. On an exact-key miss it calls
# the update API before its download retry loop, so an unreachable CDN fails the
# job before any test runs. When the endpoints are down, point the runner at the
# stale binary restored above (runTest.ts honors VSCODE_VERSION) so the suite
# still runs.
- name: Fall back to stale VS Code binary when CDN is unreachable
if: (github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true') && steps.vscode-cache.outputs.cache-hit != 'true' && steps.vscode-probe.outputs.reachable == 'false'
id: vscode-fallback
run: |
STALE=$(ls -d apps/vscode-e2e/.vscode-test/vscode-linux-x64-* 2>/dev/null | sort -V | tail -n 1 || true)
if [ -n "$STALE" ]; then
echo "VSCODE_VERSION=${STALE##*-}" >> "$GITHUB_ENV"
echo "used=true" >> "$GITHUB_OUTPUT"
echo "VS Code download endpoints are unreachable; falling back to cached VS Code ${STALE##*-}"
else
echo "::warning::VS Code download endpoints are unreachable and no cached binary is available; the download step will retry but may fail"
fi

# Retry only the binary download: version resolution and the archive fetch are
# the network-fragile parts. Genuine test failures should fail fast, so the
# test step itself is deliberately not retried.
- name: Download VS Code test binary
if: github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true'
id: vscode-download
run: |
cd apps/vscode-e2e
for attempt in 1 2 3; do
if node -e "const { downloadAndUnzipVSCode } = require('@vscode/test-electron'); const version = process.env.VSCODE_VERSION || require('./package.json').devDependencies['@types/vscode']; downloadAndUnzipVSCode(version).catch((err) => { console.error(err); process.exit(1); });"; then
exit 0
fi
echo "VS Code download attempt ${attempt} failed"
if [ "$attempt" -lt 3 ]; then
sleep 15
fi
done
exit 1

# restore-keys can bring back older binaries alongside the one just
# downloaded; keep only the effective version so each saved cache entry
# stays at one binary instead of growing with every version bump.
- name: Prune stale VS Code binaries
if: github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true'
run: |
EFFECTIVE="${VSCODE_VERSION:-${{ steps.vscode-ver.outputs.version }}}"
for dir in apps/vscode-e2e/.vscode-test/vscode-linux-x64-*; do
[ -e "$dir" ] || continue
if [ "$(basename "$dir")" != "vscode-linux-x64-$EFFECTIVE" ]; then
echo "Pruning stale VS Code binary $(basename "$dir")"
rm -rf "$dir"
fi
done

# Skip the save when the stale-binary fallback ran: the pinned-version key
# must not be populated with an older binary.
- name: Save VS Code test binary cache
if: (github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true') && steps.vscode-cache.outputs.cache-hit != 'true' && steps.vscode-fallback.outputs.used != 'true'
continue-on-error: true
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: |
apps/vscode-e2e/.vscode-test/
Expand All @@ -59,12 +150,18 @@ jobs:
if: github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true'
run: xvfb-run -a pnpm --filter @roo-code/vscode-e2e test:ci:mock

- name: Explain skipped mocked E2E pass marker
if: steps.e2e-marker.outputs.cache-hit != 'true' && steps.run-e2e.outcome == 'success' && steps.vscode-fallback.outputs.used == 'true'
run: echo "Skipping mocked E2E pass marker because tests ran against a stale cached VS Code binary (VS Code download endpoints unreachable)."

- name: Write mocked E2E pass marker
if: steps.e2e-marker.outputs.cache-hit != 'true' && steps.run-e2e.outcome == 'success'
# Skip when the stale-binary fallback ran: a pass against an older VS Code
# must not mint a marker for the intended-version source hash.
if: steps.e2e-marker.outputs.cache-hit != 'true' && steps.run-e2e.outcome == 'success' && steps.vscode-fallback.outputs.used != 'true'
run: mkdir -p .cache/e2e-pass && date -u > .cache/e2e-pass/passed

- name: Save mocked E2E pass marker
if: steps.e2e-marker.outputs.cache-hit != 'true' && steps.run-e2e.outcome == 'success'
if: steps.e2e-marker.outputs.cache-hit != 'true' && steps.run-e2e.outcome == 'success' && steps.vscode-fallback.outputs.used != 'true'
continue-on-error: true
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
Expand Down
57 changes: 57 additions & 0 deletions .github/workflows/visual-regression.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Webview Visual Regression

on:
workflow_dispatch:
pull_request:
types: [opened, reopened, ready_for_review, synchronize]
paths:
- "webview-ui/**"
- "src/shared/**"
- "package.json"
- "pnpm-lock.yaml"
- ".github/workflows/visual-regression.yml"
merge_group:
types: [checks_requested]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
webview-visual:
runs-on: ubuntu-latest
timeout-minutes: 10
container:
image: mcr.microsoft.com/playwright:v1.60.0-noble@sha256:9bd26ad900bb5e0f4dee75839e957a89ae89c2b7ab1e76050e559790e946b948
options: --ipc=host
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Setup Node.js and pnpm
uses: ./.github/actions/setup-node-pnpm
with:
install-args: "--frozen-lockfile"
- name: Run webview visual tests
run: pnpm --filter @roo-code/vscode-webview test:visual
- name: Upload visual test coverage to Codecov
if: always()
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
with:
files: webview-ui/coverage-ct/lcov.info
disable_search: true
flags: webview-ui-ct
token: ${{ secrets.CODECOV_TOKEN }}
- name: Upload visual test artifacts
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: webview-visual-regression
path: |
webview-ui/playwright-report
webview-ui/test-results
if-no-files-found: ignore
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.20.2
22.23.1
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pnpm 10.8.1
nodejs 20.20.2
nodejs 22.23.1
12 changes: 12 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ This file provides guidance to agents when working with code in this repository.
- Settings View Pattern: When working on `SettingsView`, inputs must bind to the local `cachedState`, NOT the live `useExtensionState()`. The `cachedState` acts as a buffer for user edits, isolating them from the `ContextProxy` source-of-truth until the user explicitly clicks "Save". Wiring inputs directly to the live state causes race conditions.
- Changesets: Do NOT create `.changeset` files for each commit or code change. Changesets are managed separately by maintainers and should not be generated by agents during normal development.

## ESLint Suppressions

`src/eslint-suppressions.json` tracks per-file counts of suppressed lint rules. Suppression counts must never increase. When touching a file, prefer reducing its count when the fix is local and low-risk; avoid broad unrelated cleanup.

When writing new code:

- Fix lint violations in the new code rather than suppressing them.
- Avoid `as any`; use typed APIs directly (e.g. `RooCodeEventName.X` constants with typed `on()`/`listenerCount()`), or bracket notation (`obj["privateField"]`) to access private members. Prefer precise test doubles or `unknown` with a type guard over double assertions (`as unknown as T`); use double assertions only as a last resort, with a comment explaining why.
- Avoid floating promises; add `void`, `await`, or `.catch()` as appropriate.
- After editing a file, run `pnpm --dir src exec eslint --prune-suppressions --max-warnings=0 <relative-file>` and confirm the count for that file did not increase.
- If a suppression is truly unavoidable (e.g. `vi.spyOn(Cls.prototype as any, "privateMethod")` where no typed alternative exists), document why in a comment next to the cast.

## Test Placement Guidance

Prefer the narrowest test layer that proves the behavior. This follows standard test-pyramid guidance: keep most coverage in fast, focused tests; add integration tests for cross-module contracts; reserve end-to-end tests for full workflow confidence.
Expand Down
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
# Zoo Code Changelog

## [3.72.0]

### Minor Changes

- Add the Moonshot provider with live model discovery, streaming, model metadata, and a model picker (PR #857 by @grizmin)
- Add the Kimi Code provider with OAuth device-flow authentication (PR #945 by @taltas)
- Add Claude Opus 5 support across all providers (PR #1010 by @app/zoomote)
- Add Kimi K3 to the Moonshot and OpenCode Go providers (#932 by @navedmerchant, PR #996 by @app/zoomote)
- Add Gemini 3.6 Flash model support (PR #975 by @app/zoomote)
- Add MiniMax-M3 model support (#888 by @RayWinter0816, PR #946 by @app/zoomote)
- Add a safe way to abandon interrupted subtasks by severing stale parent-child links and surfacing delegation status (#559 by @edelauna, PR #935 by @edelauna)
- Add Dart support to codebase indexing (#940 by @WebMad, PR #941 by @WebMad)
- Fix codebase indexing for plain-text files (#931 by @tool-buddy, PR #938 by @WebMad)
- Enable image input for DeepSeek V4 models (#964 by @grizmin, PR #963 by @grizmin)
- Fix ChatGPT OAuth requests for GPT-5.6 Luna being rejected by the Codex backend (PR #889 by @taltas)
- Preserve `reasoning_content` for known reasoning model families when using LiteLLM (#891 by @daewoongoh, PR #899 by @daewoongoh)
- Fix task-history cache invalidation races by routing `invalidate()` and `invalidateAll()` through the task-history lock (#698 by @edelauna, PR #912 by @morgan-coded)
- Fix Settings mode changes by synchronizing the local `cachedState` editing buffer (#914 by @easonLiangWorldedtech, PR #925 by @easonLiangWorldedtech)
- Dismiss the welcome screen after successful Zoo Gateway sign-in (#961 by @JohnCanty, PR #962 by @JamesRobert20)
- Add `CompletePromptOptions` to the `completePrompt` API so callers can configure prompt completion (#615 by @edelauna, PR #901 by @easonLiangWorldedtech)
- Centralize provider identifiers into canonical shared types (#951 by @WebMad, PR #952 by @WebMad)
- Refactor provider categories to use canonical provider identifiers (PR #989 by @WebMad)
- Remove obsolete MCP server-creation translations (#895 by @edelauna, PR #943 by @WebMad)
- Add regression coverage for resuming interrupted subtasks (#566 by @myk1yt, PR #911 by @edelauna)
- Upload coverage reports as GitHub Actions artifacts to simplify CI debugging (PR #939 by @app/zoomote)
- Update `esbuild-wasm` to v0.28.1 (PR #829 by @app/renovate)

## [3.70.0]

### Minor Changes
Expand Down
Loading
Loading