Skip to content

Commit 494650b

Browse files
authored
Merge branch 'main' into fix/chat-transcript-memory-10ds8iy2mzhqo
2 parents 5b8c98a + c4531d4 commit 494650b

401 files changed

Lines changed: 24091 additions & 5077 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.
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.

.changeset/terminate-process-on-cancel.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

.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@03e4368ac7daa2bd82b3e85262f3bf87ee112f57 # 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@03e4368ac7daa2bd82b3e85262f3bf87ee112f57 # 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 }}

.github/workflows/marketplace-publish.yml

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,59 @@ on:
77
workflow_dispatch:
88

99
jobs:
10+
check-pr-approval:
11+
runs-on: ubuntu-latest
12+
permissions:
13+
pull-requests: read
14+
steps:
15+
- name: Check PR approval status
16+
env:
17+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18+
REPO: ${{ github.repository }}
19+
SHA: ${{ github.sha }}
20+
run: |
21+
pr_number=$(gh api "repos/${REPO}/commits/${SHA}/pulls" \
22+
--header "Accept: application/vnd.github+json" \
23+
--jq '.[0].number // empty')
24+
25+
if [ -z "$pr_number" ]; then
26+
echo "No PR found for commit ${SHA}. Deployment requires an approved PR."
27+
exit 1
28+
fi
29+
30+
review_decision=$(gh api graphql \
31+
-f owner="${REPO%%/*}" \
32+
-f name="${REPO#*/}" \
33+
-F number="$pr_number" \
34+
-f query='
35+
query($owner: String!, $name: String!, $number: Int!) {
36+
repository(owner: $owner, name: $name) {
37+
pullRequest(number: $number) {
38+
reviewDecision
39+
}
40+
}
41+
}' \
42+
--jq '.data.repository.pullRequest.reviewDecision // "NONE"')
43+
44+
echo "PR #${pr_number} review_decision: ${review_decision}"
45+
46+
if [ "$review_decision" != "APPROVED" ]; then
47+
echo "PR #${pr_number} is not approved (state: ${review_decision}). Deployment blocked."
48+
exit 1
49+
fi
50+
51+
echo "PR #${pr_number} is approved. Proceeding."
52+
1053
publish-stable:
54+
needs: [check-pr-approval]
1155
runs-on: ubuntu-latest
56+
environment: marketplace-production
1257
permissions:
1358
contents: write
1459

1560
steps:
1661
- name: Checkout code
17-
uses: actions/checkout@v4
62+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
1863

1964
- name: Setup Node.js and pnpm
2065
uses: ./.github/actions/setup-node-pnpm
@@ -29,6 +74,13 @@ jobs:
2974
test "$package_name" = "zoo-code"
3075
test "$publisher" = "ZooCodeOrganization"
3176
77+
- name: Validate publish ref
78+
run: |
79+
if [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ] && [ "$GITHUB_REF_NAME" != "main" ]; then
80+
echo "Manual stable publishes must run from main, not ${GITHUB_REF_NAME}."
81+
exit 1
82+
fi
83+
3284
- name: Validate release tag
3385
if: github.event_name == 'push'
3486
run: |

.github/workflows/nightly-publish.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ concurrency:
1515
jobs:
1616
publish-prerelease:
1717
runs-on: ubuntu-latest
18+
environment: marketplace-prerelease
1819

1920
steps:
2021
- name: Checkout code
21-
uses: actions/checkout@v4
22+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2223

2324
- name: Setup Node.js and pnpm
2425
uses: ./.github/actions/setup-node-pnpm
@@ -33,6 +34,13 @@ jobs:
3334
test "$package_name" = "zoo-code"
3435
test "$publisher" = "ZooCodeOrganization"
3536
37+
- name: Validate publish ref
38+
run: |
39+
if [ "$GITHUB_REF_NAME" != "main" ]; then
40+
echo "Pre-release publishes must run from main, not ${GITHUB_REF_NAME}."
41+
exit 1
42+
fi
43+
3644
- name: Set pre-release version
3745
id: version
3846
env:

.github/workflows/release-validation.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424

2525
steps:
2626
- name: Checkout code
27-
uses: actions/checkout@v4
27+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2828

2929
- name: Setup Node.js and pnpm
3030
uses: ./.github/actions/setup-node-pnpm

0 commit comments

Comments
 (0)