[issues/529] Add Gemini Code Assist as built-in AI assistant destination#538
[issues/529] Add Gemini Code Assist as built-in AI assistant destination#538couimet wants to merge 9 commits into
Conversation
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughAdds Gemini Code Assist as a built-in AI assistant destination across types, availability detection, focus/paste cold-start/refocus, picker ordering, clipboard/paste flow, commands/wiring, tests, QA, README/CHANGELOG, and test-run support for running with marketplace extensions. ChangesGemini Code Assist Integration
Sequence Diagram(s)sequenceDiagram
participant User
participant Wire as wireSubscriptions
participant Manager as PasteDestinationManager
participant Availability as isGeminiCodeAssistAvailable
participant Gemini as Gemini Extension / Chat View
User->>Wire: invoke "Bind to Gemini Code Assist" command
Wire->>Manager: bind(kind: 'gemini-code-assist')
Manager->>Availability: isGeminiCodeAssistAvailable(ideAdapter, logger)
Availability->>Gemini: check extension presence/active
alt available
Manager->>Gemini: execute focus command(s)
Manager->>Gemini: paste payload into chat view
Gemini-->>User: chat receives pasted RangeLink + selection
else not available
Manager-->>User: show not-available/info message
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
✨ Finishing Touches🧪 Generate unit tests (beta)
|
|
The PR introduces new integrations with Gemini Code Assist and Claude Code, along with new configurable settings for cold-start timing. These changes require additional test cases to verify their functionality. Suggested test cases:
Generated by QA Gap Check (GPT-4o-mini via GitHub Models) |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.ts (1)
36-45:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdding
gemini-code-assistshiftsgithub-copilot-chatpast theslice(0, 3)boundary — it now appears after custom AI assistants in the picker.The custom-AI insertion at lines 93–97 (unchanged) splits
DESTINATION_PICKER_SEQUENCEusing a hardcoded index of3. With the previous 3-item AI block this was correct; now that there are 4 built-in AI assistants the split falls betweencursor-ai(index 2) andgithub-copilot-chat(index 3), placing Copilot Chat after any configured custom AI assistants infullSequence.For a user with custom AI assistants and GitHub Copilot Chat installed the picker renders:
Claude Code ← slice(0,3) Gemini Code Assist Cursor AI [custom AI assistants] GitHub Copilot Chat ← WRONG: slice(3) now starts here🐛 Proposed fix — update magic index from 3 → 4
// buildDestinationQuickPickItems.ts (lines 93-97, unchanged in this PR) const fullSequence: PickerSequenceKey[] = [ - ...DESTINATION_PICKER_SEQUENCE.slice(0, 3), + ...DESTINATION_PICKER_SEQUENCE.slice(0, 4), ...(customAiKinds as PickerSequenceKey[]), - ...DESTINATION_PICKER_SEQUENCE.slice(3), + ...DESTINATION_PICKER_SEQUENCE.slice(4), ];A more future-proof alternative imports
AI_ASSISTANT_KINDSand derives the count:import { type BindableQuickPickItem, DESTINATION_KINDS, + AI_ASSISTANT_KINDS, ... } from '../../types'; +const BUILTIN_AI_COUNT = AI_ASSISTANT_KINDS.length; const fullSequence: PickerSequenceKey[] = [ - ...DESTINATION_PICKER_SEQUENCE.slice(0, 3), + ...DESTINATION_PICKER_SEQUENCE.slice(0, BUILTIN_AI_COUNT), ...(customAiKinds as PickerSequenceKey[]), - ...DESTINATION_PICKER_SEQUENCE.slice(3), + ...DESTINATION_PICKER_SEQUENCE.slice(BUILTIN_AI_COUNT), ];This automatically stays in sync with
AI_ASSISTANT_KINDSfor any future built-in additions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.ts` around lines 36 - 45, The hardcoded split index (slice(0, 3) / slice(3)) that partitions DESTINATION_PICKER_SEQUENCE must be replaced with a derived count so built-in AI assistants stay grouped; import AI_ASSISTANT_KINDS (or otherwise compute the number of built-in AI assistants) in buildDestinationQuickPickItems.ts and replace the magic 3 with const aiCount = AI_ASSISTANT_KINDS.length (or the computed count) and use slice(0, aiCount) and slice(aiCount) when inserting custom AI assistants into fullSequence (update any references to the old slices around DESTINATION_PICKER_SEQUENCE and the custom-AI insertion block).
🧹 Nitpick comments (1)
packages/rangelink-vscode-extension/src/__tests__/helpers/createMockDestinationRegistry.ts (1)
21-27: 💤 Low valueConsider adding
'gemini-code-assist'to mock destinations for consistency.The
DEFAULT_DISPLAY_NAMESincludes'gemini-code-assist', butMockDestinationRegistryOptions.destinationsand the default destinations object don't include it. Tests that callcreate({ kind: 'gemini-code-assist' })on this mock will receiveundefined.If this is intentional (tests should provide custom
createImpl), the current state is fine. Otherwise, consider adding the missing entry for completeness.Also applies to: 63-73
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/rangelink-vscode-extension/src/__tests__/helpers/createMockDestinationRegistry.ts` around lines 21 - 27, The mock destination registry is missing a 'gemini-code-assist' entry causing create({ kind: 'gemini-code-assist' }) to return undefined; update the MockDestinationRegistryOptions.destinations type and the default destinations object in createMockDestinationRegistry to include 'gemini-code-assist' as a jest.Mocked<PasteDestination> (match the shape used for 'claude-code'/'cursor-ai'), and add a default mock implementation in the same defaults block so DEFAULT_DISPLAY_NAMES and the mock registry remain consistent with each other.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/rangelink-vscode-extension/qa/qa-test-cases-v1.1.0-003.yaml`:
- Around line 2992-2995: Update the QA test cases that assert "link + selected
code snippet" for the Cmd/Ctrl+R Cmd/Ctrl+L shortcut so they instead verify only
that the Claude Code chat opens and contains a RangeLink payload for the
selected range (not the pasted snippet); specifically change the expected_result
value from 'Claude Code chat opens and contains the RangeLink and selected code
snippet' to something like 'Claude Code chat opens and contains the RangeLink
payload for the selected range' for the test block containing the shortcut
string 'Cmd+R Cmd+L (Mac) / Ctrl+R Ctrl+L (Win/Linux)' and apply the same edit
to the other analogous test cases in this file that use that shortcut.
In `@packages/rangelink-vscode-extension/README.md`:
- Around line 148-151: Reorder the built-in assistants and any command rows in
the README so they follow the canonical sequence "Claude Code → Gemini Code
Assist → Cursor AI → GitHub Copilot Chat"; update the list items that currently
show "Cursor AI" before "Gemini Code Assist" (the lines containing the text for
Claude Code Extension, Gemini Code Assist, Cursor AI, and GitHub Copilot Chat)
and also apply the same corrected order to the corresponding command rows
mentioned around the other occurrence (lines referenced as also applies to
286-289).
In
`@packages/rangelink-vscode-extension/src/__tests__/constants/packageJsonContracts.test.ts`:
- Around line 480-482: Add a dedicated test for the
rangelink.bindToGeminiCodeAssist entry in the "destination binding commands"
suite: locate the tests referencing the commands array (in
packageJsonContracts.test.ts) and add an it() that finds the command object with
command === 'rangelink.bindToGeminiCodeAssist' and asserts its shape equals the
expected { command, title, category, icon } values (matching the other bind
tests like rangelink.bindToCursorAI, rangelink.bindToClaudeCode,
rangelink.bindToGitHubCopilotChat). Ensure the test uses the same assertion
style (e.g., expect(found).toEqual({...})) so future accidental
title/icon/category changes are caught.
In `@packages/rangelink-vscode-extension/src/types/MessageCode.ts`:
- Around line 68-69: The enum entry
MessageCode.ERROR_GEMINI_CODE_ASSIST_NOT_AVAILABLE is out of alphabetical order
relative to MessageCode.ERROR_FILE_PATH_NAVIGATION_FAILED; move the
ERROR_GEMINI_CODE_ASSIST_NOT_AVAILABLE line so it appears after
ERROR_FILE_PATH_NAVIGATION_FAILED in MessageCode.ts, and apply the same
transposition in messages.en.ts by moving the
[MessageCode.ERROR_GEMINI_CODE_ASSIST_NOT_AVAILABLE] message block to follow the
[MessageCode.ERROR_FILE_PATH_NAVIGATION_FAILED] block so both files maintain
consistent alphabetical ordering.
In
`@packages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGeminiCodeAssistAvailable.test.ts`:
- Around line 71-74: The test currently uses loose matchers for the logger
assertion; update the assertion in isGeminiCodeAssistAvailable.test.ts to assert
exact values: replace expect.objectContaining({ detectionMethod: 'command' })
with the exact object literal { detectionMethod: 'command' } and replace
expect.any(String) with the exact string literal that the code logs (the second
argument passed to mockLogger.debug). Modify the mockLogger.debug expectation to
use toHaveBeenCalledWith({ detectionMethod: 'command' }, '<exact log message>')
so the test asserts precise values.
- Around line 55-58: Replace the loose Jest matchers in the test assertion for
mockLogger.debug with an exact equality check: instead of
expect.objectContaining({ detectionMethod: 'command' }) and expect.any(String),
call expect(mockLogger.debug).toHaveBeenCalledWith(<exactExpectedMetaObject>,
'<exactExpectedMessage>'); locate the existing full expected meta object used
earlier in this test (the one asserted in lines ~31-38) and reuse that exact
object as the first argument and the exact expected log string as the second
argument so the assertion uses precise values for mockLogger.debug.
---
Outside diff comments:
In
`@packages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.ts`:
- Around line 36-45: The hardcoded split index (slice(0, 3) / slice(3)) that
partitions DESTINATION_PICKER_SEQUENCE must be replaced with a derived count so
built-in AI assistants stay grouped; import AI_ASSISTANT_KINDS (or otherwise
compute the number of built-in AI assistants) in
buildDestinationQuickPickItems.ts and replace the magic 3 with const aiCount =
AI_ASSISTANT_KINDS.length (or the computed count) and use slice(0, aiCount) and
slice(aiCount) when inserting custom AI assistants into fullSequence (update any
references to the old slices around DESTINATION_PICKER_SEQUENCE and the
custom-AI insertion block).
---
Nitpick comments:
In
`@packages/rangelink-vscode-extension/src/__tests__/helpers/createMockDestinationRegistry.ts`:
- Around line 21-27: The mock destination registry is missing a
'gemini-code-assist' entry causing create({ kind: 'gemini-code-assist' }) to
return undefined; update the MockDestinationRegistryOptions.destinations type
and the default destinations object in createMockDestinationRegistry to include
'gemini-code-assist' as a jest.Mocked<PasteDestination> (match the shape used
for 'claude-code'/'cursor-ai'), and add a default mock implementation in the
same defaults block so DEFAULT_DISPLAY_NAMES and the mock registry remain
consistent with each other.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7d9508af-c448-43e3-8037-beb39163ee99
📒 Files selected for processing (28)
packages/rangelink-vscode-extension/CHANGELOG.mdpackages/rangelink-vscode-extension/README.mdpackages/rangelink-vscode-extension/package.jsonpackages/rangelink-vscode-extension/qa/qa-test-cases-v1.1.0-003.yamlpackages/rangelink-vscode-extension/src/__integration-tests__/suite/bindToDestination.test.tspackages/rangelink-vscode-extension/src/__tests__/constants/packageJsonContracts.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/DestinationRegistry.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/destinationBuilders.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/utils/buildDestinationQuickPickItems.test.tspackages/rangelink-vscode-extension/src/__tests__/extension.test.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockBindableQuickPickItem.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockDestinationRegistry.tspackages/rangelink-vscode-extension/src/__tests__/wireSubscriptions.test.tspackages/rangelink-vscode-extension/src/constants/commandIds.tspackages/rangelink-vscode-extension/src/destinations/DestinationAvailabilityService.tspackages/rangelink-vscode-extension/src/destinations/DestinationRegistry.tspackages/rangelink-vscode-extension/src/destinations/PasteDestinationManager.tspackages/rangelink-vscode-extension/src/destinations/aiAssistantFocusCommands.tspackages/rangelink-vscode-extension/src/destinations/destinationBuilders.tspackages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.tspackages/rangelink-vscode-extension/src/i18n/messages.en.tspackages/rangelink-vscode-extension/src/types/BindOptions.tspackages/rangelink-vscode-extension/src/types/DestinationKind.tspackages/rangelink-vscode-extension/src/types/MessageCode.tspackages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGeminiCodeAssistAvailable.test.tspackages/rangelink-vscode-extension/src/utils/aiAssistants/index.tspackages/rangelink-vscode-extension/src/utils/aiAssistants/isGeminiCodeAssistAvailable.tspackages/rangelink-vscode-extension/src/wireSubscriptions.ts
…eview The most critical finding was a real user-visible bug: the hardcoded `slice(0, 3)` / `slice(3)` split in `buildDestinationQuickPickItems` placed GitHub Copilot Chat after any configured custom AI assistants once Gemini was added as the fourth built-in. The fix derives the split index from `AI_ASSISTANT_KINDS.length` and adds a behavioral guard test so the same regression can't recur silently on the next built-in addition. The remaining items close gaps that the original implementation left open: alphabetical ordering violations in `MessageCode` and `messages.en.ts`, loose matchers that violated rule T004, a QA expected-result that misrepresented what `Cmd+R Cmd+L` actually sends (link only, not code), README ordering inconsistency, a missing `package.json` contract test for the new bind command, and missing Gemini mock helpers / `PasteDestinationManager` test scenarios that every other AI assistant already had. Also adds `--with-extensions` mode to `test-release-run.sh` via a new `.vscode-test.with-extensions.mjs` config that installs `google.geminicodeassist` and `anthropic.claude-code` from the marketplace before running integration tests, enabling future graduation of Gemini/Claude Code QA tests from `automated: false` to `automated: assisted`. Benefits: - Picker ordering is now correct for users with custom AI assistants and GitHub Copilot Chat installed simultaneously - `BUILTIN_AI_COUNT` and the exhaustive `packageJsonContracts` guard both break loudly when a fifth built-in AI assistant is added without updating the corresponding tests and commands - Gemini mock helpers (`Paradigm A` + `Paradigm B`) and `PasteDestinationManager` scenarios bring Gemini to the same test coverage depth as Claude Code, Cursor AI, and GitHub Copilot Chat - Extension-install infrastructure is opt-in and isolated to a separate VS Code test config, so the default `test:release` run is unaffected Ref: #538 (review)
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/rangelink-vscode-extension/src/__tests__/destinations/PasteDestinationManager.test.ts (1)
421-441: ⚡ Quick winMissing
mockLogger.infoassertion in the bind success test.The
should bind to gemini-code-assist when availabletest omits themockLogger.infoassertion thatcommitBindemits on success. Theshould bind to github-copilot-chat when availabletest at lines 483–490 includes this assertion and serves as the correct reference. As per coding guidelines, "include logger assertions in tests that verify method behavior."🛠️ Proposed addition
expectContextKeys(mockAdapter.__getVscodeInstance(), { 'rangelink.isBound': true }); + expect(mockLogger.info).toHaveBeenCalledWith( + { + fn: 'PasteDestinationManager.commitBind', + kind: 'gemini-code-assist', + displayName: 'Gemini Code Assist', + }, + 'Successfully bound to "Gemini Code Assist"', + ); });As per coding guidelines: "Include logger assertions in tests that verify method behavior - consolidate logging checks with behavior tests, never create separate logging-only tests."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/rangelink-vscode-extension/src/__tests__/destinations/PasteDestinationManager.test.ts` around lines 421 - 441, The test "should bind to gemini-code-assist when available" is missing the logger assertion; after calling manager.bind({ kind: 'gemini-code-assist' }) add an assertion that mockLogger.info was called once for the successful bind (the same check used in the github-copilot-chat test). Specifically, locate the test that uses createMockGeminiCodeAssistDestination and mockRegistry.create, and add an expectation on mockLogger.info (the commitBind/info call emitted by the bind flow) verifying it was invoked with the bind success message/details (include destination name 'Gemini Code Assist' and kind 'gemini-code-assist' or use an assertion consistent with the existing github-copilot-chat test).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@packages/rangelink-vscode-extension/src/__tests__/destinations/PasteDestinationManager.test.ts`:
- Around line 421-441: The test "should bind to gemini-code-assist when
available" is missing the logger assertion; after calling manager.bind({ kind:
'gemini-code-assist' }) add an assertion that mockLogger.info was called once
for the successful bind (the same check used in the github-copilot-chat test).
Specifically, locate the test that uses createMockGeminiCodeAssistDestination
and mockRegistry.create, and add an expectation on mockLogger.info (the
commitBind/info call emitted by the bind flow) verifying it was invoked with the
bind success message/details (include destination name 'Gemini Code Assist' and
kind 'gemini-code-assist' or use an assertion consistent with the existing
github-copilot-chat test).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6e271deb-42f7-4acf-b601-08f61b72f741
📒 Files selected for processing (17)
package.jsonpackages/rangelink-vscode-extension/.vscode-test.with-extensions.mjspackages/rangelink-vscode-extension/README.mdpackages/rangelink-vscode-extension/package.jsonpackages/rangelink-vscode-extension/qa/qa-test-cases-v1.1.0-003.yamlpackages/rangelink-vscode-extension/scripts/test-release-run.shpackages/rangelink-vscode-extension/src/__tests__/constants/packageJsonContracts.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/PasteDestinationManager.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/utils/buildDestinationQuickPickItems.test.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockDestinationRegistry.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockGeminiCodeAssistComposableDestination.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockGeminiCodeAssistDestination.tspackages/rangelink-vscode-extension/src/__tests__/helpers/index.tspackages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.tspackages/rangelink-vscode-extension/src/i18n/messages.en.tspackages/rangelink-vscode-extension/src/types/MessageCode.tspackages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGeminiCodeAssistAvailable.test.ts
✅ Files skipped from review due to trivial changes (6)
- packages/rangelink-vscode-extension/src/tests/helpers/index.ts
- packages/rangelink-vscode-extension/src/tests/helpers/createMockGeminiCodeAssistDestination.ts
- packages/rangelink-vscode-extension/README.md
- packages/rangelink-vscode-extension/src/i18n/messages.en.ts
- packages/rangelink-vscode-extension/qa/qa-test-cases-v1.1.0-003.yaml
- packages/rangelink-vscode-extension/src/types/MessageCode.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/rangelink-vscode-extension/src/utils/tests/aiAssistants/isGeminiCodeAssistAvailable.test.ts
- packages/rangelink-vscode-extension/package.json
- packages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.ts
|
@coderabbitai Is the rate-limited comment in #538 (comment) still accurate ? Did you fully review 9958b14 (my latest push on this PR) ? |
🧩 Analysis chain🏁 Script executed: Length of output: 46190
Is the rate-limited comment still accurate? Was commit From what I can see in the commit diff, the change is clean test-hardening: it adds symmetric Would you like me to trigger a full review of the PR now? ✅ Actions performedReview triggered.
|
|
@coderabbitai Yes, trigger a full review of the PR now |
|
Tip For best results, initiate chat on the files or code changes.
[full_review] |
## Summary Adds Google Gemini Code Assist (`google.geminicodeassist`) as a fourth built-in AI assistant destination alongside Claude Code, Cursor AI, and GitHub Copilot Chat. The integration follows the established pattern for built-in AI assistants: a typed destination kind, focus command wiring, availability detection, picker ordering, and a dedicated bind command. Gemini is inserted between Claude Code and Cursor AI in picker order, matching the product's stated ordering priority. ## Changes - **New destination kind** — `'gemini-code-assist'` added to `DESTINATION_KINDS` and `AI_ASSISTANT_KINDS` in `DestinationKind.ts`; `GeminiCodeAssistBindOptions` interface added to `BindOptions.ts` union - **Five new message codes** — display name, error, info-not-available, user-instructions, and status-bar jump success added to `MessageCode.ts` and wired into `messages.en.ts` - **Detection utility** — `isGeminiCodeAssistAvailable.ts` created under `src/utils/aiAssistants/`, checking command availability first then falling back to extension presence; exported from `index.ts`; 191-line unit test suite with 100% coverage - **Focus command + builder** — `GEMINI_CODE_ASSIST_FOCUS_COMMANDS` registered in `aiAssistantFocusCommands.ts`; `BUILTIN_AI_ASSISTANTS` entry added in `destinationBuilders.ts` keyed by `'google.geminicodeassist'`; display-name map entry added to `DestinationRegistry.ts` - **Availability & routing** — not-available info map and send-path switch updated in `DestinationAvailabilityService.ts` and `PasteDestinationManager.ts` - **Picker ordering** — `'gemini-code-assist'` inserted between `'claude-code'` and `'cursor-ai'` in `DESTINATION_PICKER_SEQUENCE`; group map entry added in `buildDestinationQuickPickItems.ts` - **Command wiring** — `CMD_BIND_TO_GEMINI_CODE_ASSIST = 'rangelink.bindToGeminiCodeAssist'` added to `commandIds.ts`; registered in `wireSubscriptions.ts`; `"Bind to Gemini Code Assist"` command contributed in `package.json` - **Test updates** — all exhaustive kind/sequence assertions updated across 7 test files; integration test coverage updated in `bindToDestination.test.ts` - **QA** — 10 new test cases appended to `qa-test-cases-v1.1.0-003.yaml` covering bind, availability, focus, and picker ordering scenarios - **Documentation** — CHANGELOG `[Unreleased]` entry added; README updated with Gemini entry in assistant list, commands table, and inline prose sequences; all new entries marked `<sup>Unreleased</sup>` ## Test Plan - [x] All existing tests pass (108 suites, 1887 tests) - [x] New unit tests added for `isGeminiCodeAssistAvailable.ts` (100% coverage) - [x] QA YAML updated with 10 new test cases (IDs `bind-to-destination-029` through `bind-to-destination-038`) - [ ] Manual testing: bind to Gemini Code Assist and verify auto-send behavior with the extension installed ## Related Closes #529
…eview The most critical finding was a real user-visible bug: the hardcoded `slice(0, 3)` / `slice(3)` split in `buildDestinationQuickPickItems` placed GitHub Copilot Chat after any configured custom AI assistants once Gemini was added as the fourth built-in. The fix derives the split index from `AI_ASSISTANT_KINDS.length` and adds a behavioral guard test so the same regression can't recur silently on the next built-in addition. The remaining items close gaps that the original implementation left open: alphabetical ordering violations in `MessageCode` and `messages.en.ts`, loose matchers that violated rule T004, a QA expected-result that misrepresented what `Cmd+R Cmd+L` actually sends (link only, not code), README ordering inconsistency, a missing `package.json` contract test for the new bind command, and missing Gemini mock helpers / `PasteDestinationManager` test scenarios that every other AI assistant already had. Also adds `--with-extensions` mode to `test-release-run.sh` via a new `.vscode-test.with-extensions.mjs` config that installs `google.geminicodeassist` and `anthropic.claude-code` from the marketplace before running integration tests, enabling future graduation of Gemini/Claude Code QA tests from `automated: false` to `automated: assisted`. Benefits: - Picker ordering is now correct for users with custom AI assistants and GitHub Copilot Chat installed simultaneously - `BUILTIN_AI_COUNT` and the exhaustive `packageJsonContracts` guard both break loudly when a fifth built-in AI assistant is added without updating the corresponding tests and commands - Gemini mock helpers (`Paradigm A` + `Paradigm B`) and `PasteDestinationManager` scenarios bring Gemini to the same test coverage depth as Claude Code, Cursor AI, and GitHub Copilot Chat - Extension-install infrastructure is opt-in and isolated to a separate VS Code test config, so the default `test:release` run is unaffected Ref: #538 (review)
…hitecture cleanup Gemini Code Assist's webview panel needs time to initialise on first use — and the right duration varies by machine speed. The hardcoded 2500ms/300ms defaults work for most setups but leave slower machines without recourse. Two new user-facing settings (`rangelink.destinations.gemini.*`) let users tune the cold-start window without restarting VS Code, and runtime validation prevents misconfiguration. The architecture was reworked so cold-start config is read fresh on every focus() call — no more stale values after a settings change — and ConfigReader was encapsulated into DestinationBuilderContext instead of being threaded through three function layers as a separate parameter. Benefits: - Users on slow machines can increase coldStartDelayMs without editing code or restarting - Settings read at bind time, no restart required to apply changes - Cross-field validation (delayMs > intervalMs) prevents silent refocus-loop failure - ConfigReader on DestinationBuilderContext eliminates threaded param through registerAllDestinationBuilders → createBuiltinAiAssistantBuilder → buildBuiltinAiAssistantDestination - getColdRefocus hook mirrors isAvailable signature for API symmetry - ColdRefocusConfig and LazyResolvedFocusCapability added to capabilities barrel
Claude Code Extension's chat panel has the same cold-start initialization behavior as Gemini Code Assist — the panel needs time to become ready on first use. Two new settings (`rangelink.destinations.claudeCode.coldStartDelayMs` and `coldRefocusIntervalMs`) let users tune the cold-start window, with runtime validation ensuring delayMs > intervalMs. Follows the exact same architecture established for Gemini: setting keys and defaults in the single-source-of-truth files, getColdRefocus hook on the BuiltinAiAssistantDef, fresh config read on every focus() call, and full contract test coverage for package.json schema and default values.
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/rangelink-vscode-extension/README.md (1)
373-373:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winStale count: "three built-in AI tools" should now be "four".
With Gemini Code Assist added, this sentence undercounts the built-in assistants.
📝 Proposed fix
-Define custom AI assistants to extend RangeLink beyond the three built-in AI tools. +Define custom AI assistants to extend RangeLink beyond the four built-in AI tools.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/rangelink-vscode-extension/README.md` at line 373, Update the README sentence that undercounts built-in assistants: locate the line containing "Define custom AI assistants to extend RangeLink beyond the three built-in AI tools." and change "three" to "four" so it reads "four built-in AI tools" to account for the added Gemini Code Assist.
🧹 Nitpick comments (4)
packages/rangelink-vscode-extension/src/__tests__/extension.test.ts (1)
624-629: ⚡ Quick winAvoid hardcoded command count drift in subscription assertions.
COMMAND_COUNT = 51is brittle and already required manual updates in this PR. Consider deriving it from a shared expected command list constant (or centralized command-id source) to prevent future false negatives/positives.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/rangelink-vscode-extension/src/__tests__/extension.test.ts` around lines 624 - 629, The test hardcodes COMMAND_COUNT = 51 which is brittle; change the test to derive the command count from the authoritative command list instead of a magic number: import or reference the shared expected commands array/constant used by the extension (e.g., the exported command IDs list or COMMANDS constant) and set COMMAND_COUNT = sharedCommands.length, then recompute EXPECTED_SUBSCRIPTION_COUNT using that derived value along with INFRASTRUCTURE_COUNT, PROVIDER_COUNT, and DESTINATION_MANAGER_LISTENERS so the assertion stays correct when commands change.packages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGeminiCodeAssistAvailable.test.ts (1)
79-111: ⚡ Quick winAdd logger assertions to behavior-verifying edge case tests.
The three edge-case tests verify method behavior (return value) but omit
mockLogger.debugassertions. All three code paths log a debug message, and the guideline requires logger assertions to be consolidated with behavior tests.📝 Proposed additions
it('should not match other Google extensions', async () => { mockAdapter = createMockVscodeAdapter({ extensionsOptions: [{ id: 'GoogleCloudTools.cloudcode', isActive: true }], }); const result = await isGeminiCodeAssistAvailable(mockAdapter, mockLogger); expect(result).toBe(false); + expect(mockLogger.debug).toHaveBeenCalledWith( + { + fn: 'isGeminiCodeAssistAvailable', + extensionId: 'google.geminicodeassist', + extensionFound: false, + extensionActive: false, + }, + 'Gemini Code Assist not available (not installed or not active)', + ); }); it('should handle mixed extensions list', async () => { ... expect(result).toBe(true); + expect(mockLogger.debug).toHaveBeenCalledWith( + { + fn: 'isGeminiCodeAssistAvailable', + extensionId: 'google.geminicodeassist', + extensionFound: true, + extensionActive: true, + }, + 'Gemini Code Assist detected and active', + ); }); it('should use exact extension ID match', async () => { ... expect(result).toBe(false); + expect(mockLogger.debug).toHaveBeenCalledWith( + { + fn: 'isGeminiCodeAssistAvailable', + extensionId: 'google.geminicodeassist', + extensionFound: false, + extensionActive: false, + }, + 'Gemini Code Assist not available (not installed or not active)', + ); });As per coding guidelines: "Include logger assertions in tests that verify method behavior - consolidate logging checks with behavior tests, never create separate logging-only tests".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGeminiCodeAssistAvailable.test.ts` around lines 79 - 111, Update the three edge-case tests for isGeminiCodeAssistAvailable to also assert the logger calls: in the "should not match other Google extensions", "should handle mixed extensions list", and "should use exact extension ID match" tests add expectations that mockLogger.debug was invoked (or invoked with the expected diagnostic message) appropriate to the code path after calling isGeminiCodeAssistAvailable; reference the isGeminiCodeAssistAvailable function and the existing mockAdapter configurations (extensionsOptions / EXTENSION_ID_GEMINI_CODE_ASSIST) to locate where to add mockLogger.debug assertions so logging checks are consolidated with the behavior assertions.packages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.ts (1)
21-21: ⚡ Quick winConsider deriving
BUILTIN_AI_COUNTfromAI_ASSISTANT_KINDS.lengthto eliminate manual sync.The test already asserts
BUILTIN_AI_COUNT === AI_ASSISTANT_KINDS.length, meaning they must stay in sync. If a future AI destination is added toAI_ASSISTANT_KINDSbutBUILTIN_AI_COUNTisn't updated,fullSequencewill incorrectly split the built-in AI block — silently inserting custom AI kinds in the wrong position.♻️ Proposed refactor
+import { AI_ASSISTANT_KINDS } from '../../types'; -export const BUILTIN_AI_COUNT = 4; +export const BUILTIN_AI_COUNT = AI_ASSISTANT_KINDS.length;This makes
BUILTIN_AI_COUNTa derived constant, keeps the test assertion valid as documentation, and removes the synchronization burden entirely.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.ts` at line 21, BUILTIN_AI_COUNT is a brittle hard-coded value that must match AI_ASSISTANT_KINDS.length; change the code to derive the count from the array instead of a manual constant — replace the exported constant BUILTIN_AI_COUNT with a derived value using AI_ASSISTANT_KINDS.length (or remove the constant and use AI_ASSISTANT_KINDS.length where fullSequence and related logic reference BUILTIN_AI_COUNT) so the built-in AI block splitting in fullSequence stays correct and the test asserting equality remains valid.packages/rangelink-vscode-extension/src/__integration-tests__/suite/clipboardPreservation.test.ts (1)
382-397: ⚡ Quick winAlso assert the warning toast path in TC-010.
The test verifies the failure log and clipboard outcome, but not the user-facing warning mentioned in the scenario steps. Adding a toast-log assertion would protect UX regressions.
Suggested patch
const focusFailLog = lines010.find((line) => line.includes('Focus failed, cannot paste link')); assert.ok( focusFailLog, 'Expected "Focus failed, cannot paste link" log — the focus command should have thrown', ); + const warningToastLog = lines010.find( + (line) => + line.includes('VscodeAdapter.showWarningMessage') && + line.toLowerCase().includes('paste'), + ); + assert.ok( + warningToastLog, + 'Expected warning toast log instructing manual paste after focus failure', + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/rangelink-vscode-extension/src/__integration-tests__/suite/clipboardPreservation.test.ts` around lines 382 - 397, After confirming focus failure (using lines010 and focusFailLog) add an assertion that the user-facing warning toast was shown by searching the same lines010 for a toast/warning log entry (e.g., find a line that includes both "toast" and "warning" or the exact scenario message text), failing the test if it's not present; place this new assertion after the focusFailLog check and before the clipboard assertion so the test verifies the UX toast path as well (use the existing logCapture.getLinesSince('before-010') and lines010.find(...) pattern and keep the assertion style consistent with the surrounding asserts and assertClipboardChanged call).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@packages/rangelink-vscode-extension/scripts/setup-integration-test-settings-with-extensions.js`:
- Around line 59-66: The inline comment incorrectly names the property as
focusPasteCommands while the actual key used is focusAndPasteCommands; update
the comment to reference focusAndPasteCommands (or otherwise match the settings
schema) so it accurately describes the bogus property for the Gemini entry
(extensionId: 'google.geminicodeassist', focusAndPasteCommands:
['nonexistent.gemini.focusPaste']).
- Around line 7-9: Update the two comment occurrences of the old test ID
"TC-011" in the setup-integration-test-settings-with-extensions.js script to the
canonical "clipboard-preservation-010"; locate the comment that describes the
Gemini Code Assist override using a bogus focusPasteCommands (and the other
comment referencing the clipboard preservation test) and replace "TC-011" with
"clipboard-preservation-010" so the script's comments match the QA/integration
test identifiers.
- Around line 13-16: Update the incorrect test ID comments from "TC-011" to
"clipboard-preservation-010" where referenced and correct the comment that
mentions "bogus focusPasteCommands" to match the actual property name
focusAndPasteCommands; in addition, resolve the os.tmpdir() portability mismatch
around SETTINGS_DIR (the constant SETTINGS_DIR using os.tmpdir()) by either
hardcoding the path to "/tmp/rl-vscode-test-with-ext/User" to match the
documented test host or by adding a short runtime verification/coordination step
so the test runner and this script use the same temp directory (choose one
approach and apply consistently); make these edits around the SETTINGS_DIR
declaration and the comments that reference the test ID and
focusAndPasteCommands.
In
`@packages/rangelink-vscode-extension/src/__integration-tests__/suite/bindToDestination.test.ts`:
- Around line 335-337: The numbered steps in the test's instruction array are
duplicated (two "1." entries) which breaks the manual flow; update the three
strings so they read sequentially ("1. Press Cmd+R Cmd+D and select any built-in
AI assistant (e.g., Claude Code Chat)", "2. Press Cmd+R Cmd+D and select any
built-in AI assistant (e.g., Gemini Code Assist)", "3. Press Cmd+R Cmd+D again")
— locate the instruction array in the bindToDestination.test.ts integration test
(the test/suite or variable holding the steps) and change the second and third
string prefixes from "1." and "2." to "2." and "3." respectively.
In
`@packages/rangelink-vscode-extension/src/destinations/capabilities/AIAssistantFocusCapability.ts`:
- Around line 65-68: The loop in AIAssistantFocusCapability that uses
refocus.intervalMs can hang if intervalMs is zero or negative because waitMs
becomes non-positive and elapsed doesn't advance; update the refocus handling
(where elapsed, waitMs and refocus.totalMs are used) to guard intervalMs by
validating or normalizing it before the loop (e.g., require intervalMs > 0 and
throw or clamp to a sensible minimum like 1ms), or compute waitMs as Math.max(1,
Math.min(refocus.intervalMs, refocus.totalMs - elapsed)) so elapsed always
progresses and the loop terminates.
In
`@packages/rangelink-vscode-extension/src/utils/aiAssistants/isGitHubCopilotChatAvailable.ts`:
- Around line 15-16: The code currently only checks the first entry
(chatCommand) of GITHUB_COPILOT_CHAT_FOCUS_COMMANDS which can miss the fallback;
update isGitHubCopilotChatAvailable to test the entire
GITHUB_COPILOT_CHAT_FOCUS_COMMANDS array (e.g., use Array.prototype.some or
equivalent) against the registered commands list instead of only using
GITHUB_COPILOT_CHAT_FOCUS_COMMANDS[0], so commandExists reflects any matching
focus command.
---
Outside diff comments:
In `@packages/rangelink-vscode-extension/README.md`:
- Line 373: Update the README sentence that undercounts built-in assistants:
locate the line containing "Define custom AI assistants to extend RangeLink
beyond the three built-in AI tools." and change "three" to "four" so it reads
"four built-in AI tools" to account for the added Gemini Code Assist.
---
Nitpick comments:
In
`@packages/rangelink-vscode-extension/src/__integration-tests__/suite/clipboardPreservation.test.ts`:
- Around line 382-397: After confirming focus failure (using lines010 and
focusFailLog) add an assertion that the user-facing warning toast was shown by
searching the same lines010 for a toast/warning log entry (e.g., find a line
that includes both "toast" and "warning" or the exact scenario message text),
failing the test if it's not present; place this new assertion after the
focusFailLog check and before the clipboard assertion so the test verifies the
UX toast path as well (use the existing logCapture.getLinesSince('before-010')
and lines010.find(...) pattern and keep the assertion style consistent with the
surrounding asserts and assertClipboardChanged call).
In `@packages/rangelink-vscode-extension/src/__tests__/extension.test.ts`:
- Around line 624-629: The test hardcodes COMMAND_COUNT = 51 which is brittle;
change the test to derive the command count from the authoritative command list
instead of a magic number: import or reference the shared expected commands
array/constant used by the extension (e.g., the exported command IDs list or
COMMANDS constant) and set COMMAND_COUNT = sharedCommands.length, then recompute
EXPECTED_SUBSCRIPTION_COUNT using that derived value along with
INFRASTRUCTURE_COUNT, PROVIDER_COUNT, and DESTINATION_MANAGER_LISTENERS so the
assertion stays correct when commands change.
In
`@packages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.ts`:
- Line 21: BUILTIN_AI_COUNT is a brittle hard-coded value that must match
AI_ASSISTANT_KINDS.length; change the code to derive the count from the array
instead of a manual constant — replace the exported constant BUILTIN_AI_COUNT
with a derived value using AI_ASSISTANT_KINDS.length (or remove the constant and
use AI_ASSISTANT_KINDS.length where fullSequence and related logic reference
BUILTIN_AI_COUNT) so the built-in AI block splitting in fullSequence stays
correct and the test asserting equality remains valid.
In
`@packages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGeminiCodeAssistAvailable.test.ts`:
- Around line 79-111: Update the three edge-case tests for
isGeminiCodeAssistAvailable to also assert the logger calls: in the "should not
match other Google extensions", "should handle mixed extensions list", and
"should use exact extension ID match" tests add expectations that
mockLogger.debug was invoked (or invoked with the expected diagnostic message)
appropriate to the code path after calling isGeminiCodeAssistAvailable;
reference the isGeminiCodeAssistAvailable function and the existing mockAdapter
configurations (extensionsOptions / EXTENSION_ID_GEMINI_CODE_ASSIST) to locate
where to add mockLogger.debug assertions so logging checks are consolidated with
the behavior assertions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9e11cbaf-0c0a-470e-bf2a-cd8364610f5a
📒 Files selected for processing (67)
package.jsonpackages/rangelink-vscode-extension/.vscode-test.with-extensions.mjspackages/rangelink-vscode-extension/CHANGELOG.mdpackages/rangelink-vscode-extension/README.mdpackages/rangelink-vscode-extension/package.jsonpackages/rangelink-vscode-extension/qa/qa-test-cases-v1.1.0-003.yamlpackages/rangelink-vscode-extension/scripts/setup-integration-test-settings-with-extensions.jspackages/rangelink-vscode-extension/scripts/setup-integration-test-settings.jspackages/rangelink-vscode-extension/scripts/test-release-run.shpackages/rangelink-vscode-extension/src/__integration-tests__/suite/bindToDestination.test.tspackages/rangelink-vscode-extension/src/__integration-tests__/suite/clipboardPreservation.test.tspackages/rangelink-vscode-extension/src/__integration-tests__/suite/commandRegistration.test.tspackages/rangelink-vscode-extension/src/__integration-tests__/suite/customAiAssistants.test.tspackages/rangelink-vscode-extension/src/__tests__/constants/packageJsonContracts.test.tspackages/rangelink-vscode-extension/src/__tests__/constants/settingDefaults.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/ComposablePasteDestination.integration.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/DestinationRegistry.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/PasteDestinationManager.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/capabilities/AIAssistantFocusCapability.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/capabilities/FocusCapabilityFactory.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/capabilities/insertFactories/aiAssistantInsertFactory.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/destinationBuilders.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/utils/buildDestinationQuickPickItems.test.tspackages/rangelink-vscode-extension/src/__tests__/extension.test.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockBindableQuickPickItem.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockDestinationRegistry.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockFocusCapabilityFactory.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockGeminiCodeAssistComposableDestination.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockGeminiCodeAssistDestination.tspackages/rangelink-vscode-extension/src/__tests__/helpers/index.tspackages/rangelink-vscode-extension/src/__tests__/helpers/spyOnIsGeminiCodeAssistAvailable.tspackages/rangelink-vscode-extension/src/__tests__/services/ClipboardRouter.test.tspackages/rangelink-vscode-extension/src/__tests__/wireSubscriptions.test.tspackages/rangelink-vscode-extension/src/constants/chatPasteConstants.tspackages/rangelink-vscode-extension/src/constants/commandIds.tspackages/rangelink-vscode-extension/src/constants/settingDefaults.tspackages/rangelink-vscode-extension/src/constants/settingKeys.tspackages/rangelink-vscode-extension/src/createWiringServices.tspackages/rangelink-vscode-extension/src/destinations/DestinationAvailabilityService.tspackages/rangelink-vscode-extension/src/destinations/DestinationRegistry.tspackages/rangelink-vscode-extension/src/destinations/PasteDestinationManager.tspackages/rangelink-vscode-extension/src/destinations/aiAssistantFocusCommands.tspackages/rangelink-vscode-extension/src/destinations/capabilities/AIAssistantFocusCapability.tspackages/rangelink-vscode-extension/src/destinations/capabilities/ColdRefocusConfig.tspackages/rangelink-vscode-extension/src/destinations/capabilities/FocusCapabilityFactory.tspackages/rangelink-vscode-extension/src/destinations/capabilities/index.tspackages/rangelink-vscode-extension/src/destinations/capabilities/insertFactories/aiAssistantInsertFactory.tspackages/rangelink-vscode-extension/src/destinations/destinationBuilders.tspackages/rangelink-vscode-extension/src/destinations/index.tspackages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.tspackages/rangelink-vscode-extension/src/i18n/messages.en.tspackages/rangelink-vscode-extension/src/services/ClipboardRouter.tspackages/rangelink-vscode-extension/src/types/BindOptions.tspackages/rangelink-vscode-extension/src/types/DestinationKind.tspackages/rangelink-vscode-extension/src/types/MessageCode.tspackages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isClaudeCodeAvailable.test.tspackages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isCursorIDEDetected.test.tspackages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGeminiCodeAssistAvailable.test.tspackages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGitHubCopilotChatAvailable.test.tspackages/rangelink-vscode-extension/src/utils/aiAssistants/builtInAiAssistants.tspackages/rangelink-vscode-extension/src/utils/aiAssistants/index.tspackages/rangelink-vscode-extension/src/utils/aiAssistants/isClaudeCodeAvailable.tspackages/rangelink-vscode-extension/src/utils/aiAssistants/isGeminiCodeAssistAvailable.tspackages/rangelink-vscode-extension/src/utils/aiAssistants/isGitHubCopilotChatAvailable.tspackages/rangelink-vscode-extension/src/wireSubscriptions.tspackages/rangelink-vscode-extension/test-fixtures/dummy-ai-extension/extension.jspackages/rangelink-vscode-extension/test-fixtures/dummy-ai-extension/package.json
💤 Files with no reviewable changes (1)
- packages/rangelink-vscode-extension/src/destinations/capabilities/insertFactories/aiAssistantInsertFactory.ts
✅ Files skipped from review due to trivial changes (14)
- packages/rangelink-vscode-extension/src/integration-tests/suite/commandRegistration.test.ts
- packages/rangelink-vscode-extension/src/constants/commandIds.ts
- packages/rangelink-vscode-extension/src/destinations/capabilities/ColdRefocusConfig.ts
- packages/rangelink-vscode-extension/src/tests/helpers/spyOnIsGeminiCodeAssistAvailable.ts
- packages/rangelink-vscode-extension/src/destinations/index.ts
- packages/rangelink-vscode-extension/src/tests/helpers/createMockFocusCapabilityFactory.ts
- packages/rangelink-vscode-extension/src/utils/aiAssistants/index.ts
- packages/rangelink-vscode-extension/src/constants/chatPasteConstants.ts
- packages/rangelink-vscode-extension/src/utils/tests/aiAssistants/isCursorIDEDetected.test.ts
- packages/rangelink-vscode-extension/src/utils/aiAssistants/builtInAiAssistants.ts
- packages/rangelink-vscode-extension/src/tests/helpers/createMockBindableQuickPickItem.ts
- packages/rangelink-vscode-extension/src/constants/settingDefaults.ts
- packages/rangelink-vscode-extension/src/types/MessageCode.ts
- packages/rangelink-vscode-extension/src/tests/destinations/capabilities/AIAssistantFocusCapability.test.ts
🚧 Files skipped from review as they are similar to previous changes (25)
- package.json
- packages/rangelink-vscode-extension/src/destinations/aiAssistantFocusCommands.ts
- packages/rangelink-vscode-extension/src/tests/helpers/index.ts
- packages/rangelink-vscode-extension/src/wireSubscriptions.ts
- packages/rangelink-vscode-extension/src/tests/wireSubscriptions.test.ts
- packages/rangelink-vscode-extension/src/types/BindOptions.ts
- packages/rangelink-vscode-extension/CHANGELOG.md
- packages/rangelink-vscode-extension/src/destinations/DestinationAvailabilityService.ts
- packages/rangelink-vscode-extension/src/tests/helpers/createMockGeminiCodeAssistComposableDestination.ts
- packages/rangelink-vscode-extension/src/destinations/PasteDestinationManager.ts
- packages/rangelink-vscode-extension/src/i18n/messages.en.ts
- packages/rangelink-vscode-extension/.vscode-test.with-extensions.mjs
- packages/rangelink-vscode-extension/src/tests/destinations/DestinationRegistry.test.ts
- packages/rangelink-vscode-extension/src/tests/destinations/utils/buildDestinationQuickPickItems.test.ts
- packages/rangelink-vscode-extension/qa/qa-test-cases-v1.1.0-003.yaml
- packages/rangelink-vscode-extension/src/tests/helpers/createMockDestinationRegistry.ts
- packages/rangelink-vscode-extension/package.json
- packages/rangelink-vscode-extension/src/tests/destinations/destinationBuilders.test.ts
- packages/rangelink-vscode-extension/src/tests/helpers/createMockGeminiCodeAssistDestination.ts
- packages/rangelink-vscode-extension/src/destinations/destinationBuilders.ts
- packages/rangelink-vscode-extension/scripts/test-release-run.sh
- packages/rangelink-vscode-extension/src/tests/constants/packageJsonContracts.test.ts
- packages/rangelink-vscode-extension/src/tests/destinations/PasteDestinationManager.test.ts
- packages/rangelink-vscode-extension/src/utils/aiAssistants/isGeminiCodeAssistAvailable.ts
- packages/rangelink-vscode-extension/src/types/DestinationKind.ts
Fixes across four categories: - Doc: update README built-in AI tool count from three to four (A) - Defensive: guard intervalMs <= 0 in AIAssistantFocusCapability to prevent infinite loops (H); check all focus commands in isGitHubCopilotChatAvailable instead of only index 0 (I) - Correctness: derive BUILTIN_AI_COUNT from AI_ASSISTANT_KINDS.length (C); derive COMMAND_COUNT from the command list instead of hardcoding 51 (E); fix stale TC-011 IDs, rename focusPasteCommands->focusAndPasteCommands, and replace os.tmpdir() with /tmp in integration-test setup script (F) - Test hygiene: add logger assertions to 3 edge-case tests in isGeminiCodeAssistAvailable.test.ts (B); add toast assertion in TC-010 clipboardPreservation.test.ts (D); fix duplicated step numbering in bindToDestination.test.ts (G) Ref: #538 (review)
|
@coderabbitai review -- I was rate-limited in #538 (comment) . I don't believe you reviewed since my last push |
|
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGitHubCopilotChatAvailable.test.ts (1)
194-207: ⚡ Quick winAdd logger assertion in this behavior test for consistency.
This case asserts availability but not the emitted log payload, unlike the other behavior tests in this suite.
Suggested test addition
it('should handle multiple extensions when Copilot Chat is active', async () => { mockAdapter = createMockVscodeAdapter({ commandsOptions: { availableCommands: [] }, extensionsOptions: [ { id: 'other.extension', isActive: true }, { id: EXTENSION_ID_GITHUB_COPILOT_CHAT, isActive: true }, { id: 'another.extension', isActive: false }, ], }); const result = await isGitHubCopilotChatAvailable(mockAdapter, mockLogger); expect(result).toBe(true); + expect(mockLogger.debug).toHaveBeenCalledWith( + { + fn: 'isGitHubCopilotChatAvailable', + extensionId: 'github.copilot-chat', + extensionFound: true, + extensionActive: true, + detectionMethod: 'extension', + }, + 'GitHub Copilot Chat detected via extension', + ); });As per coding guidelines, "Include logger assertions in tests that verify method behavior - consolidate logging checks with behavior tests, never create separate logging-only tests".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGitHubCopilotChatAvailable.test.ts` around lines 194 - 207, Add the logger assertion to this behavior test: after calling isGitHubCopilotChatAvailable(mockAdapter, mockLogger) assert that mockLogger.info was invoked with the same payload/format used in the other availability tests (i.e., the same message/structure used to indicate GitHub Copilot Chat is available). Locate the test "should handle multiple extensions when Copilot Chat is active" and add an expectation against mockLogger (mockLogger.info) consistent with the other tests in this suite so the logging check is consolidated with the behavior assertion for isGitHubCopilotChatAvailable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In
`@packages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGitHubCopilotChatAvailable.test.ts`:
- Around line 194-207: Add the logger assertion to this behavior test: after
calling isGitHubCopilotChatAvailable(mockAdapter, mockLogger) assert that
mockLogger.info was invoked with the same payload/format used in the other
availability tests (i.e., the same message/structure used to indicate GitHub
Copilot Chat is available). Locate the test "should handle multiple extensions
when Copilot Chat is active" and add an expectation against mockLogger
(mockLogger.info) consistent with the other tests in this suite so the logging
check is consolidated with the behavior assertion for
isGitHubCopilotChatAvailable.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2b237d31-a20a-40ac-a8cd-4d8d5e69ed67
📒 Files selected for processing (11)
packages/rangelink-vscode-extension/README.mdpackages/rangelink-vscode-extension/scripts/setup-integration-test-settings-with-extensions.jspackages/rangelink-vscode-extension/src/__integration-tests__/suite/bindToDestination.test.tspackages/rangelink-vscode-extension/src/__integration-tests__/suite/clipboardPreservation.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/capabilities/AIAssistantFocusCapability.test.tspackages/rangelink-vscode-extension/src/__tests__/extension.test.tspackages/rangelink-vscode-extension/src/destinations/capabilities/AIAssistantFocusCapability.tspackages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.tspackages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGeminiCodeAssistAvailable.test.tspackages/rangelink-vscode-extension/src/utils/__tests__/aiAssistants/isGitHubCopilotChatAvailable.test.tspackages/rangelink-vscode-extension/src/utils/aiAssistants/isGitHubCopilotChatAvailable.ts
✅ Files skipped from review due to trivial changes (1)
- packages/rangelink-vscode-extension/README.md
🚧 Files skipped from review as they are similar to previous changes (8)
- packages/rangelink-vscode-extension/src/destinations/utils/buildDestinationQuickPickItems.ts
- packages/rangelink-vscode-extension/scripts/setup-integration-test-settings-with-extensions.js
- packages/rangelink-vscode-extension/src/tests/destinations/capabilities/AIAssistantFocusCapability.test.ts
- packages/rangelink-vscode-extension/src/integration-tests/suite/clipboardPreservation.test.ts
- packages/rangelink-vscode-extension/src/utils/tests/aiAssistants/isGeminiCodeAssistAvailable.test.ts
- packages/rangelink-vscode-extension/src/destinations/capabilities/AIAssistantFocusCapability.ts
- packages/rangelink-vscode-extension/src/utils/aiAssistants/isGitHubCopilotChatAvailable.ts
- packages/rangelink-vscode-extension/src/integration-tests/suite/bindToDestination.test.ts
…nsion test The test "should handle multiple extensions when Copilot Chat is active" was the only behavior test in the suite without a mockLogger.debug assertion. All other tests in the same describe block already verify the log payload per T007. Benefits: - Consistent logging assertions across all isGitHubCopilotChatAvailable tests - Prevents regression where the log payload silently breaks Ref: #538 (review)
Summary
Adds Google Gemini Code Assist (
google.geminicodeassist) as a fourth built-in AI assistant destination alongside Claude Code, Cursor AI, and GitHub Copilot Chat. The integration follows the established pattern for built-in AI assistants: a typed destination kind, focus command wiring, availability detection, picker ordering, and a dedicated bind command. Gemini is inserted between Claude Code and Cursor AI in picker order, matching the product's stated ordering priority.Changes
'gemini-code-assist'added toDESTINATION_KINDSandAI_ASSISTANT_KINDSinDestinationKind.ts;GeminiCodeAssistBindOptionsinterface added toBindOptions.tsunionMessageCode.tsand wired intomessages.en.tsisGeminiCodeAssistAvailable.tscreated undersrc/utils/aiAssistants/, checking command availability first then falling back to extension presence; exported fromindex.ts; 191-line unit test suite with 100% coverageGEMINI_CODE_ASSIST_FOCUS_COMMANDSregistered inaiAssistantFocusCommands.ts;BUILTIN_AI_ASSISTANTSentry added indestinationBuilders.tskeyed by'google.geminicodeassist'; display-name map entry added toDestinationRegistry.tsDestinationAvailabilityService.tsandPasteDestinationManager.ts'gemini-code-assist'inserted between'claude-code'and'cursor-ai'inDESTINATION_PICKER_SEQUENCE; group map entry added inbuildDestinationQuickPickItems.tsCMD_BIND_TO_GEMINI_CODE_ASSIST = 'rangelink.bindToGeminiCodeAssist'added tocommandIds.ts; registered inwireSubscriptions.ts;"Bind to Gemini Code Assist"command contributed inpackage.jsonbindToDestination.test.tsqa-test-cases-v1.1.0-003.yamlcovering bind, availability, focus, and picker ordering scenarios[Unreleased]entry added; README updated with Gemini entry in assistant list, commands table, and inline prose sequences; all new entries marked<sup>Unreleased</sup>Test Plan
isGeminiCodeAssistAvailable.ts(100% coverage)bind-to-destination-029throughbind-to-destination-038)Related
Closes #529
Summary by CodeRabbit
New Features
Documentation
Tests
Chores