Skip to content

Commit f166679

Browse files
committed
Merge remote-tracking branch 'origin/main' into chore/eslint-prefer-const
2 parents 2143789 + e0dd61a commit f166679

568 files changed

Lines changed: 31186 additions & 7199 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/add-glm-5-2-support.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"zoo-code": minor
3+
---
4+
5+
Add GLM-5.2 support with High/Max `reasoning_effort` tiers. The default effort is High (deep reasoning stays opt-in), Max is selected only when the user explicitly picks it, and the parameter is omitted entirely when reasoning is disabled.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
"zoo-code": patch
3+
---
4+
5+
Fix command auto-approval for multi-line shell constructs that must be treated as a single command.
6+
7+
**Quoted multi-line arguments** (`sh -c '...'`, `sh -c $'...'`, `sh -c "..."`): the parser previously split on every newline before handling quotes, so newlines inside a quoted argument were treated as separate commands, defeating allowlist auto-approval. Single-quoted, ANSI-C (`$'...'`), and double-quoted strings are now masked before the newline split so embedded newlines and operators stay within their command.
8+
9+
**Heredocs** (`<< EOF`, `<< 'EOF'`, `<< "EOF"`, `<<- EOF`): the entire heredoc -- opener line, body, and terminator -- is now treated as a single quoted region. Body lines are not split into independent sub-commands. All heredoc delimiter quoting styles (unquoted, single-quoted, double-quoted, backslash-escaped) are supported. An unterminated heredoc (missing terminator) is treated as malformed and returned as a single opaque token.
10+
11+
**Locale quoting** (`$"..."`): treated as a distinct token analogous to ANSI-C quoting, preserving the `$` prefix and preventing the double-quote handler from stripping it.
12+
13+
Quote masking is comment-aware: a quote character inside a `#` comment is not paired with a quote on a later line, so a comment cannot hide a real newline separator and merge two distinct commands. Commands with an unterminated quote are detected with a quote-aware scanner and returned as a single opaque token, preventing a line inside the unclosed quote from surfacing as an independently auto-approvable command. Genuine unquoted newlines still split into separate sub-commands, each of which must be allowlisted for auto-approval.
14+
15+
**Pattern selector (UI)**: the command pattern breakdown shown after execution now uses the same heredoc- and quote-aware parser (`parseCommand`) before extracting patterns, so an unterminated or terminated heredoc no longer produces spurious tokens like `EOF`, body-line words, or `<<` fragments in the allow/deny selector.
16+
17+
Note: this change only prevents _auto-approval_ of fragments from a malformed command; it does not reject malformed commands before execution, which will be addressed in a separate PR to keep the scope focused here.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"zoo-code": patch
3+
---
4+
5+
Forward the active task ID to the LiteLLM proxy as an `X-Zoo-Session-ID` request header so individual conversations can be correlated in LiteLLM logs and spend tracking. The header is only sent when a task ID is present, and follows the `x-<vendor>-session-id` convention used by Claude Code (`x-claude-code-session-id`) and GitHub Copilot (`x-copilot-session-id`).

.github/actions/setup-node-pnpm/action.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@ runs:
2424
using: "composite"
2525
steps:
2626
- name: Install pnpm
27-
uses: pnpm/action-setup@v4
27+
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4
2828
with:
2929
version: ${{ inputs.pnpm-version }}
3030
- name: Get pnpm store directory
3131
shell: bash
3232
run: |
3333
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
3434
- name: Setup pnpm cache
35-
uses: actions/cache@v4
35+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
3636
with:
3737
path: ${{ env.STORE_PATH }}
3838
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
3939
restore-keys: |
4040
${{ runner.os }}-pnpm-store-
4141
- name: Setup Node.js
42-
uses: actions/setup-node@v4
42+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
4343
with:
4444
node-version: ${{ inputs.node-version }}
4545
- name: Install dependencies

.github/workflows/cli-release.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434

3535
steps:
3636
- name: Checkout code
37-
uses: actions/checkout@v4
37+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3838
with:
3939
fetch-depth: 0
4040

@@ -195,7 +195,7 @@ jobs:
195195
rm -rf "$VERIFY_DIR"
196196
197197
- name: Upload artifact
198-
uses: actions/upload-artifact@v4
198+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
199199
with:
200200
name: cli-${{ matrix.platform }}
201201
path: |
@@ -213,7 +213,7 @@ jobs:
213213

214214
steps:
215215
- name: Checkout code
216-
uses: actions/checkout@v4
216+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
217217

218218
- name: Get version
219219
id: version
@@ -227,7 +227,7 @@ jobs:
227227
echo "tag=cli-v$VERSION" >> $GITHUB_OUTPUT
228228
229229
- name: Download all artifacts
230-
uses: actions/download-artifact@v4
230+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
231231
with:
232232
path: artifacts
233233

@@ -373,7 +373,7 @@ jobs:
373373

374374
steps:
375375
- name: Download all artifacts
376-
uses: actions/download-artifact@v4
376+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
377377
with:
378378
path: artifacts
379379

.github/workflows/code-qa.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515
steps:
1616
- name: Checkout code
17-
uses: actions/checkout@v4
17+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
1818
- name: Setup Node.js and pnpm
1919
uses: ./.github/actions/setup-node-pnpm
2020
- name: Verify all translations are complete
@@ -24,7 +24,7 @@ jobs:
2424
runs-on: ubuntu-latest
2525
steps:
2626
- name: Checkout code
27-
uses: actions/checkout@v4
27+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2828
- name: Setup Node.js and pnpm
2929
uses: ./.github/actions/setup-node-pnpm
3030
- name: Run knip checks
@@ -34,7 +34,7 @@ jobs:
3434
runs-on: ubuntu-latest
3535
steps:
3636
- name: Checkout code
37-
uses: actions/checkout@v4
37+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
3838
- name: Setup Node.js and pnpm
3939
uses: ./.github/actions/setup-node-pnpm
4040
- name: Lint
@@ -58,12 +58,12 @@ jobs:
5858
upload-coverage: false
5959
steps:
6060
- name: Checkout code
61-
uses: actions/checkout@v4
61+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
6262
- name: Setup Node.js and pnpm
6363
uses: ./.github/actions/setup-node-pnpm
6464
- name: Restore Turbo cache
6565
id: turbo-cache
66-
uses: actions/cache/restore@v4
66+
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
6767
with:
6868
path: .turbo/cache
6969
key: ${{ runner.os }}-turbo-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.sha }}
@@ -78,7 +78,7 @@ jobs:
7878
run: pnpm turbo run test:coverage:integration --filter="@roo-code/core" --log-order grouped --output-logs new-only
7979
- name: Save Turbo cache
8080
if: steps.turbo-cache.outputs.cache-hit != 'true'
81-
uses: actions/cache/save@v4
81+
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
8282
with:
8383
path: .turbo/cache
8484
key: ${{ steps.turbo-cache.outputs.cache-primary-key }}
@@ -94,7 +94,7 @@ jobs:
9494
# See https://docs.codecov.com/docs/flags
9595
- name: Upload non-core coverage to Codecov
9696
if: matrix.upload-coverage
97-
uses: codecov/codecov-action@v4
97+
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
9898
with:
9999
files: >-
100100
src/coverage/lcov.info,
@@ -107,15 +107,15 @@ jobs:
107107
token: ${{ secrets.CODECOV_TOKEN }}
108108
- name: Upload core unit coverage to Codecov
109109
if: matrix.upload-coverage
110-
uses: codecov/codecov-action@v4
110+
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
111111
with:
112112
files: packages/core/coverage/unit/lcov.info
113113
disable_search: true
114114
flags: ${{ matrix.codecov-flag }},core-unit
115115
token: ${{ secrets.CODECOV_TOKEN }}
116116
- name: Upload core integration coverage to Codecov
117117
if: matrix.upload-coverage
118-
uses: codecov/codecov-action@v4
118+
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
119119
with:
120120
files: packages/core/coverage/integration/lcov.info
121121
disable_search: true

.github/workflows/codeql.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ jobs:
4343
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
4444
steps:
4545
- name: Checkout repository
46-
uses: actions/checkout@v4
46+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
4747

4848
# Initializes the CodeQL tools for scanning.
4949
- name: Initialize CodeQL
50-
uses: github/codeql-action/init@v3
50+
uses: github/codeql-action/init@dd903d2e4f5405488e5ef1422510ee31c8b32357 # v3
5151
with:
5252
languages: ${{ matrix.language }}
5353
build-mode: ${{ matrix.build-mode }}
@@ -75,6 +75,6 @@ jobs:
7575
exit 1
7676
7777
- name: Perform CodeQL Analysis
78-
uses: github/codeql-action/analyze@v3
78+
uses: github/codeql-action/analyze@dd903d2e4f5405488e5ef1422510ee31c8b32357 # v3
7979
with:
8080
category: "/language:${{matrix.language}}"

.github/workflows/e2e.yml

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,6 @@ on:
44
workflow_dispatch:
55
pull_request:
66
types: [opened, reopened, ready_for_review, synchronize]
7-
paths:
8-
- "src/**"
9-
- "webview-ui/**"
10-
- "apps/vscode-e2e/**"
11-
- "packages/core/**"
12-
- "package.json"
13-
- "pnpm-lock.yaml"
14-
- "turbo.json"
15-
- ".github/actions/setup-node-pnpm/**"
167
merge_group:
178
types: [checks_requested]
189

@@ -22,10 +13,41 @@ jobs:
2213
timeout-minutes: 30
2314
steps:
2415
- name: Checkout code
25-
uses: actions/checkout@v4
16+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
17+
18+
- name: Restore mocked E2E pass marker
19+
id: e2e-marker
20+
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
21+
with:
22+
path: .cache/e2e-pass
23+
# packages/** is intentionally broader than the old packages/core/** to avoid false cache hits when any package changes
24+
# base_ref is included to prevent same-repo branches from stuffing a pass marker for a different base
25+
key: ${{ runner.os }}-mocked-e2e-${{ github.base_ref }}-${{ hashFiles('src/**', 'webview-ui/**', 'apps/vscode-e2e/**', 'packages/**', 'package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', 'turbo.json', '.github/workflows/e2e.yml', '.github/actions/setup-node-pnpm/**') }}
26+
27+
- name: Use cached mocked E2E result
28+
if: github.event_name == 'pull_request' && steps.e2e-marker.outputs.cache-hit == 'true'
29+
run: echo "Skipping mocked E2E tests because this source hash already passed."
30+
2631
- name: Setup Node.js and pnpm
32+
if: github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true'
2733
uses: ./.github/actions/setup-node-pnpm
2834
- name: Install xvfb
35+
if: github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true'
2936
run: sudo apt-get install -y xvfb
3037
- name: Run mocked E2E tests
38+
id: run-e2e
39+
# merge_group and workflow_dispatch always run; cache skip is pull_request only
40+
if: github.event_name != 'pull_request' || steps.e2e-marker.outputs.cache-hit != 'true'
3141
run: xvfb-run -a pnpm --filter @roo-code/vscode-e2e test:ci:mock
42+
43+
- name: Write mocked E2E pass marker
44+
if: steps.e2e-marker.outputs.cache-hit != 'true' && steps.run-e2e.outcome == 'success'
45+
run: mkdir -p .cache/e2e-pass && date -u > .cache/e2e-pass/passed
46+
47+
- name: Save mocked E2E pass marker
48+
if: steps.e2e-marker.outputs.cache-hit != 'true' && steps.run-e2e.outcome == 'success'
49+
continue-on-error: true
50+
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
51+
with:
52+
path: .cache/e2e-pass
53+
key: ${{ steps.e2e-marker.outputs.cache-primary-key }}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: Label PR review state
2+
3+
on:
4+
schedule:
5+
- cron: '0 * * * *' # hourly
6+
workflow_dispatch:
7+
8+
permissions:
9+
pull-requests: write
10+
11+
concurrency:
12+
group: label-pr-review-state
13+
cancel-in-progress: false
14+
15+
jobs:
16+
reconcile:
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Reconcile PR review state labels
20+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
21+
with:
22+
script: |
23+
const { owner, repo } = context.repo;
24+
const stateLabels = ['awaiting-author', 'awaiting-review'];
25+
const failures = [];
26+
27+
const prs = await github.paginate(github.rest.pulls.list, {
28+
owner, repo, state: 'open', per_page: 100,
29+
});
30+
31+
for (const pr of prs) {
32+
try {
33+
const reviews = await github.paginate(github.rest.pulls.listReviews, {
34+
owner, repo, pull_number: pr.number, per_page: 100,
35+
});
36+
37+
// Reviews are returned chronologically, so later entries replace
38+
// each reviewer's earlier decision.
39+
const latest = new Map();
40+
for (const r of reviews) {
41+
if (r.state !== 'COMMENTED') {
42+
latest.set(r.user.login, r);
43+
}
44+
}
45+
46+
const changeRequestReviewers = [...latest.entries()]
47+
.filter(([, review]) => review.state === 'CHANGES_REQUESTED')
48+
.map(([login]) => login);
49+
const requestedReviewers = new Set(
50+
pr.requested_reviewers.map(reviewer => reviewer.login),
51+
);
52+
53+
let desiredLabel = null;
54+
if (changeRequestReviewers.length > 0) {
55+
desiredLabel = changeRequestReviewers.every(
56+
reviewer => requestedReviewers.has(reviewer),
57+
)
58+
? 'awaiting-review'
59+
: 'awaiting-author';
60+
}
61+
62+
const currentLabels = new Set(pr.labels.map(label => label.name));
63+
for (const label of stateLabels) {
64+
if (label !== desiredLabel && currentLabels.has(label)) {
65+
await github.rest.issues.removeLabel({
66+
owner, repo, issue_number: pr.number, name: label,
67+
});
68+
}
69+
}
70+
71+
if (desiredLabel && !currentLabels.has(desiredLabel)) {
72+
await github.rest.issues.addLabels({
73+
owner, repo, issue_number: pr.number, labels: [desiredLabel],
74+
});
75+
}
76+
77+
if (
78+
desiredLabel !== 'awaiting-author' &&
79+
currentLabels.has('stale-awaiting-author')
80+
) {
81+
await github.rest.issues.removeLabel({
82+
owner, repo, issue_number: pr.number,
83+
name: 'stale-awaiting-author',
84+
});
85+
}
86+
} catch (error) {
87+
failures.push(`#${pr.number}: ${error.message}`);
88+
core.error(`Failed to reconcile PR #${pr.number}: ${error.message}`);
89+
}
90+
}
91+
92+
if (failures.length > 0) {
93+
core.setFailed(`Failed to reconcile ${failures.length} PR(s): ${failures.join('; ')}`);
94+
}

0 commit comments

Comments
 (0)