[issues/569] Add CMD_BIND_TO_CUSTOM_AI_BY_ID for programmatic custom AI binding#597
Conversation
…m AI binding
## Summary
Adds `rangelink.bindToCustomAiById` command accepting `{ extensionId: string }` to programmatically bind custom AI assistants. Eliminates the picker step, enabling fully automated integration tests for all custom AI paste flows. Previously 6 custom AI tests required human-in-the-loop for binding and manual paste verification.
## Changes
- New `createBindToCustomAiByIdCommand.ts` — resolves extensionId to destination kind via `resolveKindByExtensionId()` and delegates to `PasteDestinationManager.bind()`
- `resolveKindByExtensionId()` in `destinationBuilders.ts` maps extension IDs to built-in or custom AI kinds
- Wiring through `wireSubscriptions.ts`, `createWiringServices.ts`, `commandIds.ts`, `package.json`
- 11 unit tests covering undefined/null/string/array args, missing/empty/number extensionId, unknown extensionId, built-in bind, custom bind, bind error passthrough
- 6 custom AI integration tests converted from `[assisted]` to fully automated using the new command
- 2 manual-paste tests (Tier 3, fallback) now verify toast, clipboard state, and logs without requiring human Cmd+V
- QA YAML: 6 entries updated from `automated: assisted` to `automated: true`
- Contract tests updated for new command and command-palette entry counts
- Documentation: CHANGELOG not needed (dev-facing infrastructure); README not needed (no user-facing changes)
## Test Plan
- [x] All 1947 unit tests pass
- [x] 154/156 automated integration tests pass (2 pre-existing Cursor-specific clipboard-preservation timeouts)
- [x] 11 new unit tests for createBindToCustomAiByIdCommand
- [x] 6 integration tests reworked from human-in-the-loop to fully automated
## Related
- Closes #569
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughAdds rangelink.bindToCustomAiById: a hidden command that resolves extension IDs to built-in or custom assistant destination kinds, validates inputs, and delegates to destinationManager.bind. Exposes parsed customAssistants through wiring; updates unit, wiring, and integration tests and QA YAML; adds log-based clipboard-preservation assertions. ChangesProgrammatic Custom AI Binding Command
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
A new command 'Bind to Custom AI by ID' was added, which requires new test cases to verify its 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: 5
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/__integration-tests__/suite/customAiAssistants.test.ts (1)
356-377:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd at least one log assertion in this behavior test.
This test verifies behavior (clipboard preservation) but currently has no logger assertion, which weakens diagnosability when it fails.
As per coding guidelines, "Include logger assertions in tests that verify method behavior - logging provides critical visibility for debugging. Consolidate with behavior tests, do not create separate logging 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/__integration-tests__/suite/customAiAssistants.test.ts` around lines 356 - 377, Add a logger assertion to this test: after calling rangelink.copyLinkWithRelativePath and ss.settle(), use the existing getLogCapture() marker "before-tier1-clip" to fetch logs produced since that mark and assert that the expected diagnostic log entry appears (for example the clipboard-preservation or copy action message emitted by the extension). Locate getLogCapture() / logCapture.mark('before-tier1-clip') and add a single assertion on logCapture.getEntriesSince(...) (or equivalent helper used elsewhere in tests) to verify the expected log message is present before calling assertClipboardRestored.
🤖 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/src/__integration-tests__/suite/customAiAssistants.test.ts`:
- Around line 268-270: The call to
vscode.commands.executeCommand(CMD_BIND_TO_CUSTOM_AI_BY_ID, {...}) ignores the
command's return value and can hide non-throwing error Results; update each
invocation (including the instances around lines 320-322, 360-362, 383-385,
438-440, 502-504) to capture the returned Result, assert that it indicates
success (or throw/assert with the contained error message when it indicates
failure) so the test fails on bind errors instead of silently succeeding due to
prior state.
In
`@packages/rangelink-vscode-extension/src/__tests__/commands/createBindToCustomAiByIdCommand.test.ts`:
- Around line 167-194: The test is missing assertions that the logger was called
for this new behavior path; update the test that uses
createBindToCustomAiByIdCommand (and the related handler/result) to assert
mockLogger was invoked with the appropriate messages when
destinationBuilders.resolveKindByExtensionId is called and when mockManager.bind
succeeds: add expectations against mockLogger (e.g., mockLogger.info/warn/error
or whichever methods your mock exposes) after calling handler({ extensionId })
to verify a resolve/log entry and a bind/success log entry, referencing
resolveKindByExtensionId and mockManager.bind in your assertions so the test
verifies both behavior and corresponding logs.
- Line 212: The test currently uses a generic expect(result).toBeErr(); —
replace this with the project's Result matcher to assert the actual error using
expect(result).toBeErrWith(...) so the test verifies the error payload; locate
the failing assertion on the "result" variable in
createBindToCustomAiByIdCommand.test.ts and assert the specific error value (or
construct/constant used elsewhere in the test) with toBeErrWith to conform to
the project's Result matcher contract.
In `@packages/rangelink-vscode-extension/src/__tests__/wireSubscriptions.test.ts`:
- Around line 360-371: Add an assertion that the logger was called for this
flow: spy on services.logger (e.g., jest.spyOn(services.logger, 'info') or the
appropriate log level used in the implementation) before invoking
registrar.getHandler(CMD_BIND_TO_CUSTOM_AI_BY_ID), then after the handler runs
assert that the logger was called with a message indicating the extension
resolution and/or bind action (referencing resolveKindByExtensionId,
CMD_BIND_TO_CUSTOM_AI_BY_ID, and destinationManager.bind) and that the
resolveSpy was called as already asserted; keep the logger assertion combined in
this same test rather than in a separate logging test.
In
`@packages/rangelink-vscode-extension/src/errors/RangeLinkExtensionErrorCodes.ts`:
- Line 22: The exported enum value CUSTOM_AI_NOT_FOUND_BY_EXTENSION_ID does not
match the required contract (CUSTOM_AI_NOT_FOUND); update the
RangeLinkExtensionErrorCodes export to use CUSTOM_AI_NOT_FOUND instead, or add
CUSTOM_AI_NOT_FOUND as a stable alias that maps to the same string while keeping
CUSTOM_AI_NOT_FOUND_BY_EXTENSION_ID for backward compatibility; modify the enum
entry in RangeLinkExtensionErrorCodes (and any related references) so consumers
see the canonical CUSTOM_AI_NOT_FOUND identifier.
---
Outside diff comments:
In
`@packages/rangelink-vscode-extension/src/__integration-tests__/suite/customAiAssistants.test.ts`:
- Around line 356-377: Add a logger assertion to this test: after calling
rangelink.copyLinkWithRelativePath and ss.settle(), use the existing
getLogCapture() marker "before-tier1-clip" to fetch logs produced since that
mark and assert that the expected diagnostic log entry appears (for example the
clipboard-preservation or copy action message emitted by the extension). Locate
getLogCapture() / logCapture.mark('before-tier1-clip') and add a single
assertion on logCapture.getEntriesSince(...) (or equivalent helper used
elsewhere in tests) to verify the expected log message is present before calling
assertClipboardRestored.
🪄 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: d6e664d8-eeca-4678-a8df-03b340511b96
📒 Files selected for processing (15)
packages/rangelink-vscode-extension/package.jsonpackages/rangelink-vscode-extension/qa/qa-test-cases-v1.1.0.yamlpackages/rangelink-vscode-extension/src/__integration-tests__/suite/customAiAssistants.test.tspackages/rangelink-vscode-extension/src/__tests__/commands/createBindToCustomAiByIdCommand.test.tspackages/rangelink-vscode-extension/src/__tests__/constants/packageJsonContracts.test.tspackages/rangelink-vscode-extension/src/__tests__/destinations/destinationBuilders.test.tspackages/rangelink-vscode-extension/src/__tests__/extension.test.tspackages/rangelink-vscode-extension/src/__tests__/helpers/createMockWiringServices.tspackages/rangelink-vscode-extension/src/__tests__/wireSubscriptions.test.tspackages/rangelink-vscode-extension/src/commands/createBindToCustomAiByIdCommand.tspackages/rangelink-vscode-extension/src/constants/commandIds.tspackages/rangelink-vscode-extension/src/createWiringServices.tspackages/rangelink-vscode-extension/src/destinations/destinationBuilders.tspackages/rangelink-vscode-extension/src/errors/RangeLinkExtensionErrorCodes.tspackages/rangelink-vscode-extension/src/wireSubscriptions.ts
| await vscode.commands.executeCommand(CMD_BIND_TO_CUSTOM_AI_BY_ID, { | ||
| extensionId: 'rangelink.dummy-ai-extension', | ||
| }); |
There was a problem hiding this comment.
Assert bind command success explicitly in each test.
These executeCommand(CMD_BIND_TO_CUSTOM_AI_BY_ID, ...) calls ignore the command result. If binding returns an error Result (without throwing), a previously bound destination can mask failures and create false positives.
Also applies to: 320-322, 360-362, 383-385, 438-440, 502-504
🤖 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/customAiAssistants.test.ts`
around lines 268 - 270, The call to
vscode.commands.executeCommand(CMD_BIND_TO_CUSTOM_AI_BY_ID, {...}) ignores the
command's return value and can hide non-throwing error Results; update each
invocation (including the instances around lines 320-322, 360-362, 383-385,
438-440, 502-504) to capture the returned Result, assert that it indicates
success (or throw/assert with the contained error message when it indicates
failure) so the test fails on bind errors instead of silently succeeding due to
prior state.
| BOOKMARK_NOT_FOUND = 'BOOKMARK_NOT_FOUND', | ||
| BOOKMARK_SAVE_FAILED = 'BOOKMARK_SAVE_FAILED', | ||
| BOOKMARK_STORE_NOT_AVAILABLE = 'BOOKMARK_STORE_NOT_AVAILABLE', | ||
| CUSTOM_AI_NOT_FOUND_BY_EXTENSION_ID = 'CUSTOM_AI_NOT_FOUND_BY_EXTENSION_ID', |
There was a problem hiding this comment.
Use the required error-code contract name.
At Line 22, the new code is CUSTOM_AI_NOT_FOUND_BY_EXTENSION_ID, but the stated contract for this command is CUSTOM_AI_NOT_FOUND. This mismatch can break consumers that branch on the documented error code. Please align the enum/exported code to the required contract (or add a stable alias if backward compatibility is needed).
🤖 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/errors/RangeLinkExtensionErrorCodes.ts`
at line 22, The exported enum value CUSTOM_AI_NOT_FOUND_BY_EXTENSION_ID does not
match the required contract (CUSTOM_AI_NOT_FOUND); update the
RangeLinkExtensionErrorCodes export to use CUSTOM_AI_NOT_FOUND instead, or add
CUSTOM_AI_NOT_FOUND as a stable alias that maps to the same string while keeping
CUSTOM_AI_NOT_FOUND_BY_EXTENSION_ID for backward compatibility; modify the enum
entry in RangeLinkExtensionErrorCodes (and any related references) so consumers
see the canonical CUSTOM_AI_NOT_FOUND identifier.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Adds missing logger assertions to unit tests and clipboard preservation log assertions to 22 integration tests across four files. Replaces a bare toBeErr() with toBeRangeLinkExtensionErrorErr. Benefits: - Custom-kind bind test now verifies debug logging like its built-in counterpart - Error passthrough test now asserts the specific error code, message, and functionName - Wire delegation test now verifies the debug log emitted by createBindToCustomAiByIdCommand - All 22 integration tests that call assertClipboardRestored now verify both "Clipboard saved" and "Clipboard restored" log entries, proving the full preservation pipeline ran - clipboard-preservation-009 correctly asserts the NEGATIVE case (picker dismissed, no operation ran, so no preservation logs expected) Ignored Feedback: - Asserting executeCommand return values in integration tests: the suite verifies behaviour through log capture, not command return values. Adding return-value assertions would be inconsistent with every other executeCommand call in the test suite. - Renaming CUSTOM_AI_NOT_FOUND_BY_EXTENSION_ID back to CUSTOM_AI_NOT_FOUND: the rename was intentional per prior review — the original name was too vague. This is a new error code on this branch with no existing consumers. Ref: #597 (review)
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/src/__integration-tests__/helpers/clipboardHelpers.ts`:
- Around line 37-44: The current assertClipboardPreservationRan checks only for
presence of "Clipboard saved" and "Clipboard restored" in lines from
logCapture.getLinesSince(markName); update it to also assert the restored entry
occurs after the saved entry by locating their indices in the lines array (use
lines.findIndex for the savedLine and restoredLine) and assert restoredIndex >
savedIndex, including operationLabel in the failure message; keep existing
presence checks (savedLine/restoredLine) but replace or augment them with the
index order check so assertClipboardPreservationRan verifies correct ordering.
🪄 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: d4939dc1-7a71-4a2f-98a1-4156b80fa233
📒 Files selected for processing (7)
packages/rangelink-vscode-extension/src/__integration-tests__/helpers/clipboardHelpers.tspackages/rangelink-vscode-extension/src/__integration-tests__/suite/builtInAiAssistants.test.tspackages/rangelink-vscode-extension/src/__integration-tests__/suite/clipboardPreservation.test.tspackages/rangelink-vscode-extension/src/__integration-tests__/suite/customAiAssistants.test.tspackages/rangelink-vscode-extension/src/__integration-tests__/suite/dirtyBufferWarning.test.tspackages/rangelink-vscode-extension/src/__tests__/commands/createBindToCustomAiByIdCommand.test.tspackages/rangelink-vscode-extension/src/__tests__/wireSubscriptions.test.ts
`assertClipboardPreservationRan` now verifies "Clipboard restored" appears after "Clipboard saved" in the log, not just that both exist. Presence-only assertions could pass if a restored line from a prior operation lingered before the saved line from the current operation. The ordering check proves the save→restore sequence ran within the same operation window. Ref: #597 (review)
❌ CI / Integration Tests (with extensions) — run summary
To re-run failed tests: |
This comment has been minimized.
This comment has been minimized.
❌ CI / Integration Tests (with extensions) — run summary
To re-run failed tests: |
This comment has been minimized.
This comment has been minimized.
…gration tests After the cold paste warmup moves focus to the AI assistant panel, vscode.window.activeTextEditor is stale. Link generation fails silently before withClipboardPreservation runs, so no preservation logs are emitted so the "Clipboard saved" log assertion fails because preservation never ran. Refocusing the editor before the warm selection fixes all three warm paste variants. Ref: #597 (comment)
✅ CI / Integration Tests (with extensions) — run summary
|
✅ CI / Test & Validate — run summary
|
Summary
Adds
rangelink.bindToCustomAiByIdcommand accepting{ extensionId: string }to programmatically bind custom AI assistants. Eliminates the picker step, enabling fully automated integration tests for all custom AI paste flows. Previously 6 custom AI tests required human-in-the-loop for binding and manual paste verification.Changes
createBindToCustomAiByIdCommand.ts— resolves extensionId to destination kind viaresolveKindByExtensionId()and delegates toPasteDestinationManager.bind()resolveKindByExtensionId()indestinationBuilders.tsmaps extension IDs to built-in or custom AI kindswireSubscriptions.ts,createWiringServices.ts,commandIds.ts,package.json[assisted]to fully automated using the new commandautomated: assistedtoautomated: trueTest Plan
Related
Summary by CodeRabbit
New Features
Tests