Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
473e0af
feat(scm): add generate commit message action in source control input…
1220moritz Nov 2, 2026
ce2e38c
fix(scm): disambiguate commit message action icon and title for multi…
1220moritz Nov 2, 2026
c03fcdd
fix(scm): address CodeRabbit review findings for generate commit mess…
1220moritz Nov 2, 2026
fef189b
fix: address CodeRabbit review comments on commit message generator
1220moritz Nov 2, 2026
b1d43b3
fix(scm): use explicit separator literals for cross-platform path mat…
1220moritz Nov 2, 2026
2c957db
fix(scm): address CodeRabbit review round 2
1220moritz Nov 3, 2026
0b58879
style(scm): run prettier on commitMessageGenerator.ts
1220moritz Nov 3, 2026
9c6b0ae
fix(scm): address CodeRabbit review round 3 for commit message genera…
1220moritz Nov 10, 2026
7a778b3
fix(scm): redact the full quoted credential value
1220moritz Nov 10, 2026
d5928a8
fix(scm): address CodeRabbit review round 4 for commit message genera…
1220moritz Nov 10, 2026
35c09ab
fix(scm): address CodeRabbit pre-merge checks for commit message gene…
1220moritz Nov 11, 2026
9f22164
fix(scm): redact standalone token assignments in commit message diffs
1220moritz Nov 11, 2026
9b5825a
fix(scm): redact unquoted token values that do not look like code
1220moritz Nov 11, 2026
8d16bd3
fix(scm): narrow code-like token values and key the stale-write guard…
1220moritz Nov 11, 2026
0ff66cd
fix(scm): let credential keys decide redaction regardless of value shape
1220moritz Nov 11, 2026
775623e
feat(api): abort signal support for Zoo Gateway completePrompt
1220moritz Nov 11, 2026
81511ac
test(e2e): add Extension Host visual scene for the SCM commit message…
1220moritz Nov 11, 2026
cbbe298
fix(scm): redact whole credential values and hold retries behind canc…
1220moritz Nov 11, 2026
bcb3008
test(e2e): use a relative locator to find the SCM header that holds t…
1220moritz Nov 11, 2026
0c1a8bb
fix(scm): match webhook hosts and bearer tokens in any case; tighten …
1220moritz Nov 11, 2026
366d15c
test(e2e): add SCM title bar baseline from the pinned CI runner
1220moritz Nov 11, 2026
cf0002c
fix(scm): redact alphabetic bearer tokens; never overlap a still-runn…
1220moritz Nov 11, 2026
116596d
fix(scm): one provider request per repository; redact multi-line XML …
1220moritz Nov 11, 2026
d7d0649
fix(scm): scan XML and YAML credential values per diff side; split ou…
1220moritz Nov 11, 2026
fcdd857
fix(scm): stream-scan XML credential values in XML files; redact pair…
1220moritz Nov 11, 2026
e2bed66
fix(scm): scan both diff sides from the original lines; XML in every …
1220moritz Nov 11, 2026
ba62e5c
fix(scm): parse YAML mappings by key column and scan flat records for…
1220moritz Nov 11, 2026
0521c56
refactor(scm): move secret redaction to @roo-code/core; scan nested r…
1220moritz Nov 11, 2026
437392b
refactor(scm): replace secret parsers with line and file rules
1220moritz Nov 11, 2026
b0c62a5
fix(scm): read escaped Git paths and track code blocks per diff side
1220moritz Nov 11, 2026
d44cdc8
fix(scm): check both paths of a renamed file and keep outer credentia…
1220moritz Nov 12, 2026
dbeefd2
fix(scm): redact combined diffs and more sensitive file names
1220moritz Nov 13, 2026
21ad363
refactor(scm): respect .rooignore instead of heuristic secret redaction
1220moritz Nov 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions apps/vscode-e2e/src/visual/electron.visual.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
attachFailureArtifacts,
CHAT_RESULT,
extensionDevelopmentPath,
SCM_ACTION_TITLE,
startScene,
stopScene,
vscodeVersion,
Expand Down Expand Up @@ -119,3 +120,32 @@ for (const scenario of scenarios) {
}
})
}

const scmScenario: VisualScenario = {
name: "scm-title-dark",
scene: "scm",
themeId: "Default Dark Modern",
landmark: SCM_ACTION_TITLE,
}

test("renders the Generate Commit Message action in the Source Control title bar", async ({
browserName: _browserName,
}, testInfo) => {
const running = await startScene(vscodeExecutablePath, scmScenario, testInfo)
try {
// Keep the pointer away from the sidebar so no action shows a hover state or tooltip.
await running.page.mouse.move(900, 400)
// `has` takes a locator relative to each header, so it names only the action itself.
const header = running.page
.locator(".part.sidebar .pane-header")
.filter({ has: running.page.locator(`[aria-label="${SCM_ACTION_TITLE}"]`) })
await expect(header).toHaveCount(1)
await expect(header.locator(`[aria-label="${SCM_ACTION_TITLE}"]`)).toBeVisible()
await expect(header).toHaveScreenshot("electron-scm-title-dark-header.png")
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
} catch (error) {
await attachFailureArtifacts(running, testInfo)
throw error
} finally {
await stopScene(running, testInfo)
}
})
24 changes: 23 additions & 1 deletion apps/vscode-e2e/src/visual/electronHarness.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { execFile } from "child_process"
import fs from "fs/promises"
import { readFileSync } from "fs"
import os from "os"
import path from "path"
import { promisify } from "util"

import { LLMock } from "@copilotkit/aimock"
import { _electron, expect, type ElectronApplication, type Page, type TestInfo } from "@playwright/test"
Expand All @@ -18,10 +20,26 @@ export const vscodeVersion = packageJson.devDependencies["@types/vscode"]

const CHAT_PROMPT = "electron-visual-smoke: render a deterministic completion"
export const CHAT_RESULT = "Electron visual smoke response rendered inside the real VS Code webview."
export const SCM_ACTION_TITLE = "Generate Commit Message (Zoo Code)"

const execFileAsync = promisify(execFile)

/**
* Makes the workspace a Git repository with one staged file, so the Source Control view shows the
* Git provider and its title actions. The branch name, author, and file are fixed for a stable scene.
*/
async function initGitWorkspace(workspacePath: string) {
const git = (...args: string[]) => execFileAsync("git", args, { cwd: workspacePath })
await git("init", "--initial-branch=main")
await git("config", "user.name", "Zoo Code Visual")
await git("config", "user.email", "visual@example.invalid")
await fs.writeFile(path.join(workspacePath, "notes.md"), "# Notes\n", "utf8")
await git("add", "notes.md")
}

export interface VisualScenario {
name: string
scene: "welcome" | "chat"
scene: "welcome" | "chat" | "scm"
themeId: "Default Dark Modern" | "Default High Contrast"
landmark: string
webviewSnapshot?: string
Expand Down Expand Up @@ -105,6 +123,9 @@ export async function startScene(
for (const result of directories) {
if (result.status === "rejected") throw result.reason
}
if (scenario.scene === "scm") {
await initGitWorkspace(workspacePath)
}
if (scenario.startMock) {
mock = new LLMock({ port: 0 })
mock.addFixture({
Expand Down Expand Up @@ -147,6 +168,7 @@ export async function startScene(
ROO_CODE_VISUAL_READY_PATH: readyPath,
ROO_CODE_VISUAL_SCENE: scenario.scene,
ROO_CODE_VISUAL_THEME: scenario.themeId,
ROO_CODE_VISUAL_SCM_ACTION_TITLE: SCM_ACTION_TITLE,
ROO_CODE_THEME_FIXTURE_PROBE: "1",
},
locale: "en-US",
Expand Down
28 changes: 27 additions & 1 deletion apps/vscode-e2e/src/visual/sceneController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import {
import { isCompletedAsk } from "../suite/utils"

const POLL_INTERVAL_MS = 100

/** The parts of the built-in Git extension API (`vscode.git`, version 1) that the scm scene reads. */
interface GitExtension {
getAPI(version: 1): { repositories: Array<{ state: { indexChanges: unknown[] } }> }
}
const SCENE_TIMEOUT_MS = 60_000

const themeKinds: Record<string, vscode.ColorThemeKind> = {
Expand Down Expand Up @@ -68,7 +73,9 @@ export async function run(): Promise<void> {
}
const log = (message: string) => fs.appendFile(logPath, `${message}\n`, "utf8")
await log(`scene=${scene} theme=${themeId}`)
if (scene !== "welcome" && scene !== "chat") throw new Error(`Unknown Electron visual scene: ${scene}`)
if (scene !== "welcome" && scene !== "chat" && scene !== "scm") {
throw new Error(`Unknown Electron visual scene: ${scene}`)
}
if (!themeKinds[themeId]) throw new Error(`Unsupported Electron visual theme: ${themeId}`)

const extension = vscode.extensions.getExtension<RooCodeTestAPI>("ZooCodeOrganization.zoo-code")
Expand Down Expand Up @@ -145,6 +152,25 @@ export async function run(): Promise<void> {
landmark = result
}

if (scene === "scm") {
// Show view title actions without hover, so the screenshot does not depend on the pointer.
await vscode.workspace
.getConfiguration("workbench.view")
.update("alwaysShowHeaderActions", true, vscode.ConfigurationTarget.Global)
const gitExtension = vscode.extensions.getExtension<GitExtension>("vscode.git")
if (!gitExtension) throw new Error("The built-in Git extension is not available")
const git = (gitExtension.isActive ? gitExtension.exports : await gitExtension.activate()).getAPI(1)
await poll(
async () => git.repositories.map((repository) => repository.state.indexChanges.length),
(stagedCounts) => stagedCounts.length === 1 && stagedCounts[0] === 1,
"one Git repository with one staged file",
)
await vscode.commands.executeCommand("workbench.view.scm")
await log("scm-ready")
landmark = process.env.ROO_CODE_VISUAL_SCM_ACTION_TITLE ?? ""
if (!landmark) throw new Error("The Source Control action title is required for the scm scene")
}

await fs.writeFile(
readyPath,
`${JSON.stringify({ scene, themeId, landmark, themeFixture, taskIds: api.getCurrentTaskStack() }, null, 2)}\n`,
Expand Down
2 changes: 2 additions & 0 deletions packages/types/src/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export const commandIds = [
"retryWebviewRecovery",
"toggleAutoApprove",

"generateGitCommitMessage",

"showRipgrepDiagnostic",
"createDiagnosticsReport",
] as const
Expand Down
30 changes: 30 additions & 0 deletions src/activate/__tests__/registerCommands.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ vi.mock("../../services/diagnostics", () => ({
createDiagnosticsReport: vi.fn().mockResolvedValue(undefined),
}))

vi.mock("../../services/git/commitMessageGenerator", () => ({
generateCommitMessage: vi.fn().mockResolvedValue(undefined),
}))

describe("getVisibleProviderOrLog", () => {
let mockOutputChannel: vscode.OutputChannel

Expand Down Expand Up @@ -282,6 +286,32 @@ describe("registerCommands handlers", () => {
})
})

it("generateGitCommitMessage calls generateCommitMessage with visible provider and context", async () => {
const { generateCommitMessage } = await import("../../services/git/commitMessageGenerator")
const mockScmContext = { rootUri: { fsPath: "/mock/repo" } }

await handlers["zoo-code.generateGitCommitMessage"](mockScmContext)

expect(generateCommitMessage).toHaveBeenCalledWith({
provider: mockVisibleProviderInstance,
outputChannel: mockOutputChannel,
context: mockScmContext,
})
})

it("generateGitCommitMessage falls back to default provider when no visible provider", async () => {
const { generateCommitMessage } = await import("../../services/git/commitMessageGenerator")
;(ClineProvider.getVisibleInstance as Mock).mockReturnValue(undefined)

await handlers["zoo-code.generateGitCommitMessage"]()

expect(generateCommitMessage).toHaveBeenCalledWith({
provider: mockProvider,
outputChannel: mockOutputChannel,
context: undefined,
})
})

it("settingsButtonClicked posts both settingsButtonClicked and didBecomeVisible actions", () => {
handlers["zoo-code.settingsButtonClicked"]()

Expand Down
9 changes: 9 additions & 0 deletions src/activate/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { importSettingsWithFeedback } from "../core/config/importExport"
import { MdmService } from "../services/mdm/MdmService"
import { registerRipgrepDiagnosticCommand } from "../services/ripgrep/diagnostic"
import { createDiagnosticsReport } from "../services/diagnostics"
import { generateCommitMessage } from "../services/git/commitMessageGenerator"

/**
* Helper to get the visible ClineProvider instance or log if not found.
Expand Down Expand Up @@ -225,6 +226,14 @@ const getCommandsMap = ({
outputChannel.appendLine(`[toggleAutoApprove] postMessageToWebview failed: ${error}`)
}
},
generateGitCommitMessage: async (context?: unknown) => {
const visibleProvider = ClineProvider.getVisibleInstance() ?? provider
await generateCommitMessage({
provider: visibleProvider,
outputChannel,
context,
})
},
})

type OpenClineInNewTabOptions = {
Expand Down
12 changes: 12 additions & 0 deletions src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,21 @@
"command": "zoo-code.toggleAutoApprove",
"title": "%command.toggleAutoApprove.title%",
"category": "%configuration.title%"
},
{
"command": "zoo-code.generateGitCommitMessage",
"title": "%command.generateGitCommitMessage.title%",
"icon": "$(wand)"
}
],
"menus": {
"scm/title": [
{
"command": "zoo-code.generateGitCommitMessage",
"group": "navigation",
"when": "scmProvider == git"
}
],
"editor/context": [
{
"submenu": "zoo-code.contextMenu",
Expand Down
1 change: 1 addition & 0 deletions src/package.nls.ca.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.de.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.es.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.fr.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.hi.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.id.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.it.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.ja.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"command.showRipgrepDiagnostic.title": "Show Ripgrep Diagnostic",
"command.createDiagnosticsReport.title": "Create Diagnostics Report",
"command.toggleAutoApprove.title": "Toggle Auto-Approve",
"command.generateGitCommitMessage.title": "Generate Commit Message (Zoo Code)",
"configuration.title": "Zoo Code",
"commands.allowedCommands.description": "Commands that can be auto-executed when 'Always approve execute operations' is enabled",
"commands.deniedCommands.description": "Command prefixes that will be automatically denied without asking for approval. In case of conflicts with allowed commands, the longest prefix match takes precedence. Add * to deny all commands.",
Expand Down
1 change: 1 addition & 0 deletions src/package.nls.ko.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.nl.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.pl.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.pt-BR.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.ru.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.tr.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.vi.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.zh-CN.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/package.nls.zh-TW.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading