Skip to content

Commit 55edc17

Browse files
authored
Merge branch 'main' into issue-958-canonical-extension-provider-identifiers
2 parents 76574a4 + c52f118 commit 55edc17

48 files changed

Lines changed: 3761 additions & 318 deletions

Some content is hidden

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

.github/pull_request_template.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,35 @@ Detail the steps to test your changes. This helps reviewers verify your work.
3838
- [ ] **Scope**: My changes are focused on the linked issue (one major feature/fix per PR).
3939
- [ ] **Self-Review**: I have performed a thorough self-review of my code.
4040
- [ ] **Testing**: New and/or updated tests have been added to cover my changes (if applicable).
41+
- [ ] **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".
4142
- [ ] **Documentation Impact**: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
4243
- [ ] **Contribution Guidelines**: I have read and agree to the [Contributor Guidelines](/CONTRIBUTING.md).
4344

44-
### Screenshots / Videos
45+
### Visual Snapshots
4546

4647
<!--
47-
For UI changes, please provide before-and-after screenshots or a short video of the *actual results*.
48-
This greatly helps in understanding the visual impact of your changes.
48+
For UI changes to static rendered state, the primary artifact is a committed
49+
Playwright CT snapshot (`*.visual.tsx` in `webview-ui/`) — that baseline
50+
becomes durable regression coverage for the surface. See
51+
`webview-ui/AGENTS.md` for what deserves a snapshot.
52+
53+
Before/after screenshots pasted here are welcome as a review aid but are not a
54+
substitute for the committed baseline. If a snapshot is possible, prefer the
55+
snapshot.
56+
-->
57+
58+
### Videos (interaction / animation only)
59+
60+
<!--
61+
Snapshots cannot capture motion or multi-step flows. Attach a short screen
62+
recording here when reviewers need to see:
63+
- A new interactive flow (dropdown, form, dialog progression)
64+
- Animation, transition, or timing behavior
65+
- A regression that only manifests during interaction
66+
67+
Videos are a review aid, not regression coverage. If the *result* of the
68+
interaction has a distinct rendered state worth protecting, still commit a
69+
`*.visual.tsx` snapshot of that end-state alongside the video.
4970
-->
5071

5172
### Documentation Updates

.github/workflows/code-qa.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,25 +135,32 @@ jobs:
135135
# lanes for behavioral confidence, but duplicating coverage uploads
136136
# there mostly adds Codecov overhead without changing pass/fail
137137
# behavior.
138-
# Coverage is uploaded in three separate steps so each LCOV gets the
138+
# Coverage is uploaded in separate steps so each LCOV gets the
139139
# correct flag set. Codecov double-counts overlapping lines when a
140140
# single upload carries multiple flags whose paths overlap, so the
141-
# two core lanes (which both cover packages/core/src/**) must be
142-
# uploaded individually with their own lane flag.
141+
# core lanes and webview lane must be uploaded individually with
142+
# their own flag.
143143
# See https://docs.codecov.com/docs/flags
144144
- name: Upload non-core coverage to Codecov
145145
if: matrix.upload-coverage
146146
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
147147
with:
148148
files: >-
149149
src/coverage/lcov.info,
150-
webview-ui/coverage/lcov.info,
151150
packages/cloud/coverage/lcov.info,
152151
packages/telemetry/coverage/lcov.info,
153152
apps/cli/coverage/lcov.info
154153
disable_search: true
155154
flags: ${{ matrix.codecov-flag }}
156155
token: ${{ secrets.CODECOV_TOKEN }}
156+
- name: Upload webview JSDOM coverage to Codecov
157+
if: matrix.upload-coverage
158+
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
159+
with:
160+
files: webview-ui/coverage/lcov.info
161+
disable_search: true
162+
flags: webview-ui
163+
token: ${{ secrets.CODECOV_TOKEN }}
157164
- name: Upload core unit coverage to Codecov
158165
if: matrix.upload-coverage
159166
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Webview Visual Regression
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
types: [opened, reopened, ready_for_review, synchronize]
7+
paths:
8+
- "webview-ui/**"
9+
- "src/shared/**"
10+
- "package.json"
11+
- "pnpm-lock.yaml"
12+
- ".github/workflows/visual-regression.yml"
13+
merge_group:
14+
types: [checks_requested]
15+
16+
concurrency:
17+
group: ${{ github.workflow }}-${{ github.ref }}
18+
cancel-in-progress: true
19+
20+
permissions:
21+
contents: read
22+
23+
jobs:
24+
webview-visual:
25+
runs-on: ubuntu-latest
26+
timeout-minutes: 10
27+
container:
28+
image: mcr.microsoft.com/playwright:v1.60.0-noble@sha256:9bd26ad900bb5e0f4dee75839e957a89ae89c2b7ab1e76050e559790e946b948
29+
options: --ipc=host
30+
steps:
31+
- name: Checkout code
32+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
33+
with:
34+
persist-credentials: false
35+
- name: Setup Node.js and pnpm
36+
uses: ./.github/actions/setup-node-pnpm
37+
with:
38+
install-args: "--frozen-lockfile"
39+
- name: Run webview visual tests
40+
run: pnpm --filter @roo-code/vscode-webview test:visual
41+
- name: Upload visual test coverage to Codecov
42+
if: always()
43+
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
44+
with:
45+
files: webview-ui/coverage-ct/lcov.info
46+
disable_search: true
47+
flags: webview-ui-ct
48+
token: ${{ secrets.CODECOV_TOKEN }}
49+
- name: Upload visual test artifacts
50+
if: failure()
51+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
52+
with:
53+
name: webview-visual-regression
54+
path: |
55+
webview-ui/playwright-report
56+
webview-ui/test-results
57+
if-no-files-found: ignore

codecov.yml

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,33 @@ coverage:
66
default:
77
target: auto # never regress below current baseline
88
threshold: 1%
9+
webview:
10+
target: auto # webview project ratchet: never drop below current baseline
11+
threshold: 0.5%
12+
flags:
13+
- webview-ui
14+
- webview-ui-ct
915
patch:
1016
default:
1117
target: 80% # new lines must be 80% covered
1218
threshold: 0%
19+
webview-patch:
20+
target: 70% # new lines in webview must be 70% covered
21+
threshold: 0%
22+
flags:
23+
- webview-ui
24+
- webview-ui-ct
1325

1426
flag_management:
1527
individual_flags:
28+
- name: webview-ui
29+
paths:
30+
- webview-ui/src/
31+
carryforward: true
32+
- name: webview-ui-ct
33+
paths:
34+
- webview-ui/src/
35+
carryforward: true
1636
- name: core-unit
1737
paths:
1838
- packages/core/src/
@@ -22,6 +42,18 @@ flag_management:
2242
- packages/core/src/
2343
carryforward: true
2444

45+
component_management:
46+
individual_components:
47+
- component_id: webview_components
48+
name: "Webview UI Components"
49+
paths:
50+
- webview-ui/src/components/
51+
- component_id: webview_state
52+
name: "Webview State & Context"
53+
paths:
54+
- webview-ui/src/context/
55+
- webview-ui/src/state/
56+
2557
comment:
26-
layout: "diff, flags"
58+
layout: "diff, flags, components"
2759
behavior: default

knip.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
{
22
"$schema": "https://unpkg.com/knip@5/schema.json",
33
"ignore": ["**/__tests__/**", "apps/vscode-e2e/**", "scripts/**", "apps/cli/scripts/**"],
4-
"ignoreDependencies": ["lint-staged", "ovsx"],
4+
"ignoreDependencies": ["lint-staged"],
55
"ignoreExportsUsedInFile": true,
6+
"playwright": false,
7+
"playwright-ct": false,
68
"workspaces": {
79
"src": {
810
"entry": ["extension.ts", "extension/api.ts", "workers/countTokens.ts"],
@@ -30,7 +32,7 @@
3032
"source-map",
3133
"tailwindcss",
3234
"tailwindcss-animate",
33-
"vscode"
35+
"monocart-reporter"
3436
]
3537
},
3638
"apps/cli": {

packages/config-eslint/base.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import js from "@eslint/js"
22
import eslintConfigPrettier from "eslint-config-prettier"
33
import turboPlugin from "eslint-plugin-turbo"
44
import tseslint from "typescript-eslint"
5-
import onlyWarn from "eslint-plugin-only-warn"
6-
75
/**
86
* A shared ESLint configuration for the repository.
97
*
@@ -21,11 +19,6 @@ export const config = [
2119
"turbo/no-undeclared-env-vars": "off",
2220
},
2321
},
24-
{
25-
plugins: {
26-
onlyWarn,
27-
},
28-
},
2922
{
3023
ignores: ["dist/**"],
3124
},

packages/config-eslint/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
"@next/eslint-plugin-next": "15.5.20",
1313
"eslint": "9.39.4",
1414
"eslint-config-prettier": "10.1.8",
15-
"eslint-plugin-only-warn": "1.2.1",
1615
"eslint-plugin-react": "7.37.5",
1716
"eslint-plugin-react-hooks": "5.2.0",
1817
"eslint-plugin-turbo": "2.10.0",
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import type { ProviderName } from "../provider-settings.js"
2+
3+
vi.mock("../provider-identifiers.js", async (importOriginal) => {
4+
const actual = await importOriginal<typeof import("../provider-identifiers.js")>()
5+
6+
return {
7+
...actual,
8+
providerIdentifiers: {
9+
...actual.providerIdentifiers,
10+
openrouter: "canonical-openrouter-test-value",
11+
},
12+
}
13+
})
14+
15+
import { providerIdentifiers } from "../provider-identifiers.js"
16+
import {
17+
anthropicDefaultModelId,
18+
getProviderDefaultModelId,
19+
internationalZAiDefaultModelId,
20+
kimiCodeDefaultModelId,
21+
mainlandZAiDefaultModelId,
22+
openRouterDefaultModelId,
23+
vscodeLlmDefaultModelId,
24+
zooGatewayDefaultModelId,
25+
} from "../providers/index.js"
26+
27+
describe("getProviderDefaultModelId", () => {
28+
it("selects a static default through the canonical provider identifier", () => {
29+
expect(getProviderDefaultModelId(providerIdentifiers.openrouter as ProviderName)).toBe(openRouterDefaultModelId)
30+
})
31+
32+
it("triangulates static selection with another provider category", () => {
33+
expect(getProviderDefaultModelId(providerIdentifiers.vscodeLm)).toBe(vscodeLlmDefaultModelId)
34+
})
35+
36+
it.each([
37+
[providerIdentifiers.kimiCode, kimiCodeDefaultModelId],
38+
[providerIdentifiers.zooGateway, zooGatewayDefaultModelId],
39+
])("preserves the %s default added on main", (provider, expectedModelId) => {
40+
expect(getProviderDefaultModelId(provider)).toBe(expectedModelId)
41+
})
42+
43+
it("preserves region-dependent defaults", () => {
44+
// These defaults currently share the same model ID, so the assertions document
45+
// both branches but cannot detect swapped ternary arms until the IDs diverge.
46+
expect(getProviderDefaultModelId(providerIdentifiers.zai, { isChina: true })).toBe(mainlandZAiDefaultModelId)
47+
expect(getProviderDefaultModelId(providerIdentifiers.zai)).toBe(internationalZAiDefaultModelId)
48+
})
49+
50+
it.each([providerIdentifiers.openai, providerIdentifiers.ollama, providerIdentifiers.lmstudio])(
51+
"returns an empty default for custom or locally selected models from %s",
52+
(provider) => {
53+
expect(getProviderDefaultModelId(provider)).toBe("")
54+
},
55+
)
56+
57+
it.each([providerIdentifiers.anthropic, providerIdentifiers.geminiCli, providerIdentifiers.fakeAi])(
58+
"preserves the Anthropic fallback for %s",
59+
(provider) => {
60+
expect(getProviderDefaultModelId(provider)).toBe(anthropicDefaultModelId)
61+
},
62+
)
63+
})

packages/types/src/mode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export const DEFAULT_MODES: readonly ModeConfig[] = [
182182
description: "Plan and design before implementation",
183183
groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "mcp"],
184184
customInstructions:
185-
"1. Do some information gathering (using provided tools) to get more context about the task.\n\n2. You should also ask the user clarifying questions to get a better understanding of the task.\n\n3. Once you've gained more context about the user's request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:\n - Specific and actionable\n - Listed in logical execution order\n - Focused on a single, well-defined outcome\n - Clear enough that another mode could execute it independently\n\n **Note:** If the `update_todo_list` tool is not available, write the plan to a markdown file (e.g., `plan.md` or `todo.md`) instead.\n\n4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.\n\n5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list.\n\n6. Include Mermaid diagrams if they help clarify complex workflows or system architecture. Please avoid using double quotes (\"\") and parentheses () inside square brackets ([]) in Mermaid diagrams, as this can cause parsing errors.\n\n7. Use the switch_mode tool to request that the user switch to another mode to implement the solution.\n\n**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**\n\n**CRITICAL: Never provide level of effort time estimates (e.g., hours, days, weeks) for tasks. Focus solely on breaking down the work into clear, actionable steps without estimating how long they will take.**\n\nUnless told otherwise, if you want to save a plan file, put it in the /plans directory",
185+
'1. Do some information gathering (using provided tools) to get more context about the task.\n\n2. You should also ask the user clarifying questions to get a better understanding of the task.\n\n3. Once you\'ve gained more context about the user\'s request, break down the task into clear, actionable steps and create a todo list using the `update_todo_list` tool. Each todo item should be:\n - Specific and actionable\n - Listed in logical execution order\n - Focused on a single, well-defined outcome\n - Clear enough that another mode could execute it independently\n\n **Note:** If the `update_todo_list` tool is not available, write the plan to a markdown file (e.g., `plan.md` or `todo.md`) instead.\n\n4. As you gather more information or discover new requirements, update the todo list to reflect the current understanding of what needs to be accomplished.\n\n5. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and refine the todo list.\n\n6. Include Mermaid diagrams if they help clarify complex workflows or system architecture. Please avoid using double quotes ("") and parentheses () inside square brackets ([]) in Mermaid diagrams, as this can cause parsing errors.\n\n7. Use the switch_mode tool to request that the user switch to another mode to implement the solution.\n\n**IMPORTANT: Focus on creating clear, actionable todo lists rather than lengthy markdown documents. Use the todo list as your primary planning tool to track and organize the work that needs to be done.**\n\n**CRITICAL: Never provide level of effort time estimates (e.g., hours, days, weeks) for tasks. Focus solely on breaking down the work into clear, actionable steps without estimating how long they will take.**\n\nUnless told otherwise, if you want to save a plan file, put it in the ./plans directory (a directory named "plans" relative to the workspace root, not the absolute filesystem path /plans)',
186186
},
187187
{
188188
slug: "code",

0 commit comments

Comments
 (0)