Skip to content

[issues/621] Merge bind+send status bar messages into a single notification#667

Merged
couimet merged 2 commits into
mainfrom
issues/621
Jun 19, 2026
Merged

[issues/621] Merge bind+send status bar messages into a single notification#667
couimet merged 2 commits into
mainfrom
issues/621

Conversation

@couimet

@couimet couimet commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Summary

When no destination is bound and the picker resolves to a bind during a send operation (R-V, R-L, R-F), the user sees one status bar message instead of two back-to-back toasts. The merge is achieved by threading bind context through the feedback layer, introducing a ResolveResult discriminated union, and adding a BindContext type shared across senders.

Changes

  • Destination picker send flows now produce a single merged status bar message ("Bound to Terminal — RangeLink sent") instead of separate bind and send toasts. The bind-only toast from showPickerAndBind() is suppressed via the existing StatusBarOptions.skipMessage flag.
  • ResolveResult discriminated union replaces the boolean return of resolveDestination(), encoding whether a bind was performed and the destination name when applicable. Callers no longer need to infer bind state from a bare boolean.
  • New BindContext type ({ readonly destinationName: string }) shared across SendRouter, OperationFeedbackProvider, LinkGenerator, and four sender services, replacing an inline { destinationName: string } type duplicated at each call site.
  • Standalone toBindContext(result: ResolveResult) utility extracts BindContext from the discriminated union, eliminating a 4× copy-pasted ternary.
  • BindingFeedback interface gains notifyRebound(newDestinationName, previousDestinationName) as a first-class method, splitting the rebind notification from notifyBound(destinationName). The replacedName optional param is removed.
  • commitBind options restructured: suppressAutoPaste and StatusBarOptions are nested under a single bindOptions parameter, keeping bind behavior and UI feedback concerns separated.
  • CI: CI action for install-deps added.

Key Discoveries

  • The replacedName path in notifyBound was the only place where rebind and fresh-bind messages could be confused. Splitting into notifyRebound eliminates that ambiguity and structurally guarantees rebind messages never leak into the send-feedback path.
  • The four senders (TextSelectionPaster, LinkGenerator, FilePathPaster, TerminalSelectionService) had nearly identical resolveResult → bindContext construction logic. Extracting toBindContext as a standalone utility with its own test file (100% branch coverage) cleaned up the duplication.

Test Plan

  • All 2099 existing tests pass
  • New unit tests: toBindContext.test.ts (3 tests, 100% branch), OperationFeedbackProvider.test.ts (+11 tests covering notifyBound, notifyRebound, notifyAlreadyBound, notifyBindFailedEditor, notifyBindFailedNotAvailable, notifyBackgroundTabOpened, notifyUnbound, notifyNothingToUnbind, notifyJumpFocused, notifyJumpFailed), PasteDestinationManager.test.ts (+5 tests for buildCommitBindOptions via as-any cast)
  • Existing unit tests updated: SendRouter.test.ts, LinkGenerator.test.ts, FilePathPaster.test.ts, TextSelectionPaster.test.ts, TerminalSelectionService.test.ts — all now assert exact FormattedLink objects and ResolveResult shapes instead of expect.any(Object) or bare booleans

Related

Summary by CodeRabbit

  • New Features

    • Single consolidated status bar message when binding and sending in one step via the destination picker (e.g., "Bound to Terminal — File path sent") instead of separate sequential notifications
  • Tests

    • Added integration test coverage for unbound file path operations in Explorer and Editor tab context menus

@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 750622d9-0ad5-42f0-8cb8-7d27d32a07e9

📥 Commits

Reviewing files that changed from the base of the PR and between f63cf12 and 14961cf.

📒 Files selected for processing (31)
  • packages/rangelink-vscode-extension/CHANGELOG.md
  • packages/rangelink-vscode-extension/qa/qa-test-cases.yaml
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/contextMenuEditorTab.test.ts
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/contextMenuExplorer.test.ts
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/contextMenuTerminal.test.ts
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/dirtyBufferWarning.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/destinations/PasteDestinationManager.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/feedback/OperationFeedbackProvider.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/helpers/createMockOperationFeedbackProvider.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/FilePathPaster.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/LinkGenerator.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/SendRouter.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/TerminalSelectionService.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/TextSelectionPaster.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/toBindContext.test.ts
  • packages/rangelink-vscode-extension/src/destinations/DestinationBinder.ts
  • packages/rangelink-vscode-extension/src/destinations/PasteDestinationManager.ts
  • packages/rangelink-vscode-extension/src/feedback/BindingFeedback.ts
  • packages/rangelink-vscode-extension/src/feedback/OperationFeedbackProvider.ts
  • packages/rangelink-vscode-extension/src/i18n/messages.en.ts
  • packages/rangelink-vscode-extension/src/services/FilePathPaster.ts
  • packages/rangelink-vscode-extension/src/services/LinkGenerator.ts
  • packages/rangelink-vscode-extension/src/services/SendRouter.ts
  • packages/rangelink-vscode-extension/src/services/TerminalSelectionService.ts
  • packages/rangelink-vscode-extension/src/services/TextSelectionPaster.ts
  • packages/rangelink-vscode-extension/src/services/toBindContext.ts
  • packages/rangelink-vscode-extension/src/services/types/ResolveResult.ts
  • packages/rangelink-vscode-extension/src/services/types/index.ts
  • packages/rangelink-vscode-extension/src/types/BindContext.ts
  • packages/rangelink-vscode-extension/src/types/MessageCode.ts
  • packages/rangelink-vscode-extension/src/types/index.ts
✅ Files skipped from review due to trivial changes (5)
  • packages/rangelink-vscode-extension/src/types/index.ts
  • packages/rangelink-vscode-extension/CHANGELOG.md
  • packages/rangelink-vscode-extension/src/services/types/index.ts
  • packages/rangelink-vscode-extension/src/integration-tests/suite/contextMenuTerminal.test.ts
  • packages/rangelink-vscode-extension/src/integration-tests/suite/dirtyBufferWarning.test.ts
🚧 Files skipped from review as they are similar to previous changes (22)
  • packages/rangelink-vscode-extension/src/tests/services/toBindContext.test.ts
  • packages/rangelink-vscode-extension/src/feedback/BindingFeedback.ts
  • packages/rangelink-vscode-extension/src/services/toBindContext.ts
  • packages/rangelink-vscode-extension/src/types/BindContext.ts
  • packages/rangelink-vscode-extension/src/types/MessageCode.ts
  • packages/rangelink-vscode-extension/src/services/TerminalSelectionService.ts
  • packages/rangelink-vscode-extension/src/services/LinkGenerator.ts
  • packages/rangelink-vscode-extension/src/services/types/ResolveResult.ts
  • packages/rangelink-vscode-extension/src/services/TextSelectionPaster.ts
  • packages/rangelink-vscode-extension/src/i18n/messages.en.ts
  • packages/rangelink-vscode-extension/src/tests/services/TerminalSelectionService.test.ts
  • packages/rangelink-vscode-extension/src/destinations/DestinationBinder.ts
  • packages/rangelink-vscode-extension/src/services/FilePathPaster.ts
  • packages/rangelink-vscode-extension/src/tests/services/TextSelectionPaster.test.ts
  • packages/rangelink-vscode-extension/src/tests/feedback/OperationFeedbackProvider.test.ts
  • packages/rangelink-vscode-extension/src/tests/services/FilePathPaster.test.ts
  • packages/rangelink-vscode-extension/src/tests/services/LinkGenerator.test.ts
  • packages/rangelink-vscode-extension/src/services/SendRouter.ts
  • packages/rangelink-vscode-extension/src/tests/services/SendRouter.test.ts
  • packages/rangelink-vscode-extension/src/feedback/OperationFeedbackProvider.ts
  • packages/rangelink-vscode-extension/src/destinations/PasteDestinationManager.ts
  • packages/rangelink-vscode-extension/src/tests/destinations/PasteDestinationManager.test.ts

Walkthrough

Introduces a ResolveResult discriminated union replacing resolveDestination()'s boolean return, a BindContext interface, and a toBindContext helper. When a user picks a destination via the quick-pick and immediately sends, PasteDestinationManager.bind() suppresses the standalone bind notification via a new StatusBarOptions.skipMessage flag, and OperationFeedbackProvider.provideSendFeedback() emits a single merged "Bound to X — Y sent" status bar message instead of two sequential messages.

Changes

Merged bind+send status bar notification

Layer / File(s) Summary
New types and i18n strings
src/types/BindContext.ts, src/types/index.ts, src/services/types/ResolveResult.ts, src/services/types/index.ts, src/types/MessageCode.ts, src/i18n/messages.en.ts
Introduces the BindContext interface, ResolveResult discriminated union (canProceed / bindPerformed / destinationName), two new STATUS_BAR_DESTINATION_BOUND_AND_SENT / STATUS_BAR_DESTINATION_BOUND_PREFIX MessageCode members, and matching English message templates. Updates both type barrel exports.
Bind suppression via StatusBarOptions
src/feedback/BindingFeedback.ts, src/destinations/DestinationBinder.ts, src/destinations/PasteDestinationManager.ts
Extends DestinationBinder.bind() and all PasteDestinationManager bind paths to accept optional StatusBarOptions; commitBind guards notifyBound/notifyRebound behind skipMessage. Refactors BindingFeedback to separate notifyBound (destination-name-only) from new notifyRebound. Adds buildCommitBindOptions helper.
OperationFeedbackProvider merged messaging
src/feedback/OperationFeedbackProvider.ts
Adds optional bindContext parameter to provideSendFeedback(); rewrites the outcome.kind switch to compose "Bound to X — Y" status messages when bindContext is present. Implements notifyRebound. Adds private helpers for bound-prefix and clipboard-status composition.
SendRouter: ResolveResult return and bindContext threading
src/services/SendRouter.ts
Replaces resolveDestination() Promise<boolean> with Promise<ResolveResult>. sendToDestination() gains optional bindContext forwarded to provideSendFeedback. showPickerAndBind() calls binder.bind() with { skipMessage: true }.
toBindContext helper and service caller updates
src/services/toBindContext.ts, src/services/FilePathPaster.ts, src/services/LinkGenerator.ts, src/services/TerminalSelectionService.ts, src/services/TextSelectionPaster.ts
New toBindContext utility converts ResolveResult to optional BindContext. All four paste/send services updated to await resolveResult, guard on canProceed, derive bindContext via toBindContext, and pass it as second argument to sendToDestination.
Unit tests for new contracts
src/__tests__/services/toBindContext.test.ts, src/__tests__/helpers/createMockOperationFeedbackProvider.ts, src/__tests__/feedback/OperationFeedbackProvider.test.ts, src/__tests__/destinations/PasteDestinationManager.test.ts, src/__tests__/services/SendRouter.test.ts, src/__tests__/services/FilePathPaster.test.ts, src/__tests__/services/LinkGenerator.test.ts, src/__tests__/services/TerminalSelectionService.test.ts, src/__tests__/services/TextSelectionPaster.test.ts
Adds toBindContext test suite; extends mock with notifyRebound; adds provideSendFeedback with-bindContext and all notify* tests; updates PasteDestinationManager tests for skipMessage suppression, buildCommitBindOptions, notifyRebound/notifyBound call signature; aligns all resolveDestination mocks to ResolveResult shape and sendToDestination assertions to include second argument.
Integration tests and QA updated to single message
src/__integration-tests__/suite/contextMenuEditorTab.test.ts, src/__integration-tests__/suite/contextMenuExplorer.test.ts, src/__integration-tests__/suite/contextMenuTerminal.test.ts, src/__integration-tests__/suite/dirtyBufferWarning.test.ts, qa/qa-test-cases.yaml, CHANGELOG.md
Adds new integration tests for unbound editor-tab and explorer "Send File Path"/"Send Relative File Path" picker flows. Updates existing terminal, explorer, editor-tab, and dirty-buffer tests to assert a single merged "Bound to X — Y sent" message. Adds QA entries and a CHANGELOG note.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Service as FilePathPaster / TextSelectionPaster / LinkGenerator
  participant SendRouter
  participant PasteDestinationManager
  participant OperationFeedbackProvider
  participant StatusBar

  User->>Service: paste/send command (no destination bound)
  Service->>SendRouter: resolveDestination(logCtx)
  SendRouter->>SendRouter: showPickerAndBind() — user selects terminal
  SendRouter->>PasteDestinationManager: bind(options, { skipMessage: true })
  PasteDestinationManager-->>SendRouter: BindSuccessInfo (notifyBound suppressed)
  SendRouter-->>Service: ResolveResult { canProceed: true, bindPerformed: true, destinationName }
  Service->>Service: toBindContext(resolveResult) → BindContext
  Service->>SendRouter: sendToDestination(payload, bindContext)
  SendRouter->>OperationFeedbackProvider: provideSendFeedback(ctx, outcome, bindContext)
  OperationFeedbackProvider->>StatusBar: "✓ RangeLink: Bound to Terminal (name) — File path sent"
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • couimet/rangeLink#493: Introduced the extracted paste services (FilePathPaster, LinkGenerator, TerminalSelectionService, TextSelectionPaster) and the SendRouter-based destination resolution pattern that this PR directly refactors.
  • couimet/rangeLink#614: Introduced OperationFeedbackProvider and SendRouter with strict status-bar/toast verification — the same feedback and routing contracts that this PR extends with bindContext and ResolveResult.
  • couimet/rangeLink#620: Directly touched BindingFeedback/OperationFeedbackProvider and the bound-session-driven send flow that this PR builds upon to produce the merged status bar message.

Poem

🐇 Hop! No more double dings when I bind and send,
One crisp little message — a tidy blend!
"Bound to Terminal — File path sent" it reads,
A single soft chime is all this bunny needs.
✓ RangeLink hops forward, clean as can be! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and concisely describes the main change: merging bind+send status bar messages into a single notification, which is the core objective of issue #621.
Linked Issues check ✅ Passed All code changes comprehensively implement the three core technical requirements from issue #621: ResolveResult discriminated union, StatusBarOptions.skipMessage flag, and BindContext threading through the feedback layer.
Out of Scope Changes check ✅ Passed All changes are directly tied to issue #621 objectives. The refactorings (BindContext type, toBindContext utility, BindingFeedback.notifyRebound separation) are supporting implementations necessary for the core feature, not tangential additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issues/621

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 19, 2026

Copy link
Copy Markdown

QA Coverage OK

The PR introduces a new single status bar message format for binding and sending in one step, and fixes the R-F command to work with various active tabs. New test cases have been added to the QA YAML to cover these changes.


Generated by QA Gap Check (GPT-4o-mini via GitHub Models)

@github-actions

Copy link
Copy Markdown

❌ CI / Integration Tests (with overrides) — run summary

Duration: 0m 48s

QA TC IDs: 2 exercised across 0 features

Report: View run & artifacts

Reproduce locally: ./scripts/run-integration-tests.sh --label needs-override --exclude-label cursor --exclude-assisted

Feature breakdown
Feature TCs IDs

To re-run failed tests:

./scripts/run-integration-tests.sh --label "needs-override" --exclude-label "cursor" --exclude-assisted --with-extensions --use-overrides --grep "custom-ai-assistant-018"

++RESULTS_JSON_START++
{
"passing": 1,
"failing": 1,
"total": 2,
"failed_ids": [
  "custom-ai-assistant-018"
],
"report_complete_at": "2026-06-19T12:09:28Z"
}
++RESULTS_JSON_END++
/home/runner/work/rangeLink/rangeLink/packages/rangelink-vscode-extension:
 ERR_PNPM_RECURSIVE_RUN_FIRST_FAIL  rangelink-vscode-extension@2.0.0 test:release:with-extensions: `./scripts/run-integration-tests.sh --with-extensions --use-overrides --exclude-assisted --exclude-label cursor`
Exit status 1
 ELIFECYCLE  Command failed with exit code 1.

@github-actions

Copy link
Copy Markdown

❌ CI / Integration Tests (automated) — run summary

Duration: 1m 6s

\342\232\240\357\270\217 Integration test report missing: Runner may have crashed

QA TC IDs: 163 exercised across 0 features

Report: View run & artifacts

Reproduce locally: ./scripts/run-integration-tests.sh --exclude-label requires-extensions --exclude-label cursor --automated

Feature breakdown
Feature TCs IDs

@github-actions

Copy link
Copy Markdown

❌ CI / Integration Tests (with extensions) — run summary

Duration: 1m 5s

Unit tests: Ran in separate Test & Validate job

\342\232\240\357\270\217 Integration test report missing: Runner may have crashed

QA TC IDs: 195 exercised across 0 features

Report: View run & artifacts

Reproduce locally: ./scripts/run-integration-tests.sh --exclude-label cursor --exclude-label needs-override --exclude-assisted

Feature breakdown
Feature TCs IDs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 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/CHANGELOG.md`:
- Line 14: Add QA test cases to the qa-test-cases-*.yaml files to cover the
merged bind+send status bar notification behavior. Create test cases with schema
fields (id, feature: status_bar_feedback, scenario, preconditions, steps,
expected_result, automated) for four scenarios: unbound picker send
(R-V/R-L/R-F) producing exactly one merged message in the format "Bound to
<destination> — <link> sent", already-bound send preserving the existing
send-only message behavior, bind-only action preserving the bind-only message,
and rebind paths ensuring no send text appears in bind-only contexts. Use id
naming like qa-bind-send-merged-001, qa-bind-send-merged-002, etc. for each test
case.

In
`@packages/rangelink-vscode-extension/src/__integration-tests__/suite/contextMenuEditorTab.test.ts`:
- Around line 27-29: The test assertions for already-bound terminal flows are
expecting the wrong status bar message. In scenarios where the terminal is
pre-bound using CMD_BIND_TO_TERMINAL_HERE, the expectStatusBarMessages assertion
should expect send-only feedback messages, not combined bind+send messages.
Update the expectStatusBarMessages calls in both test cases (the one at lines
27-29 and the one at lines 76-78) to assert for the appropriate send-only
feedback message instead of the merged "Bound to Terminal... — File path sent"
message, which should only appear in fresh-bind scenarios.

In
`@packages/rangelink-vscode-extension/src/__integration-tests__/suite/contextMenuExplorer.test.ts`:
- Around line 28-30: The expectStatusBarMessages assertion in the test is
validating the wrong status message. Since the terminal is already bound before
the send action occurs, the status bar should only display the send-only
message, not the combined bind-and-send message. Update the
expectStatusBarMessages call around lines 28-30 to assert only the send-only
status text instead of the combined "Bound to Terminal ... — File path sent"
message. Also apply the same fix to the similar assertion mentioned at lines
74-76.
🪄 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: b3ac3e4d-619f-4814-ba59-7edda64f7f2b

📥 Commits

Reviewing files that changed from the base of the PR and between 26fc2b4 and f63cf12.

📒 Files selected for processing (31)
  • packages/rangelink-vscode-extension/CHANGELOG.md
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/contextMenuEditorTab.test.ts
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/contextMenuExplorer.test.ts
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/contextMenuTerminal.test.ts
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/customAiAssistants.test.ts
  • packages/rangelink-vscode-extension/src/__integration-tests__/suite/dirtyBufferWarning.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/destinations/PasteDestinationManager.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/feedback/OperationFeedbackProvider.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/helpers/createMockOperationFeedbackProvider.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/FilePathPaster.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/LinkGenerator.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/SendRouter.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/TerminalSelectionService.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/TextSelectionPaster.test.ts
  • packages/rangelink-vscode-extension/src/__tests__/services/toBindContext.test.ts
  • packages/rangelink-vscode-extension/src/destinations/DestinationBinder.ts
  • packages/rangelink-vscode-extension/src/destinations/PasteDestinationManager.ts
  • packages/rangelink-vscode-extension/src/feedback/BindingFeedback.ts
  • packages/rangelink-vscode-extension/src/feedback/OperationFeedbackProvider.ts
  • packages/rangelink-vscode-extension/src/i18n/messages.en.ts
  • packages/rangelink-vscode-extension/src/services/FilePathPaster.ts
  • packages/rangelink-vscode-extension/src/services/LinkGenerator.ts
  • packages/rangelink-vscode-extension/src/services/SendRouter.ts
  • packages/rangelink-vscode-extension/src/services/TerminalSelectionService.ts
  • packages/rangelink-vscode-extension/src/services/TextSelectionPaster.ts
  • packages/rangelink-vscode-extension/src/services/toBindContext.ts
  • packages/rangelink-vscode-extension/src/services/types/ResolveResult.ts
  • packages/rangelink-vscode-extension/src/services/types/index.ts
  • packages/rangelink-vscode-extension/src/types/BindContext.ts
  • packages/rangelink-vscode-extension/src/types/MessageCode.ts
  • packages/rangelink-vscode-extension/src/types/index.ts


### Changed

- **Single status bar message when binding and sending in one step via the destination picker**, instead of two back-to-back messages. The merged message reads "Bound to &lt;destination&gt; — &lt;link&gt; sent". (#621)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Potential QA coverage gap for the merged bind+send UX

This PR changes user-visible notification behavior, but no QA YAML updates are present in the reviewed changes. Please add/confirm QA cases in packages/rangelink-vscode-extension/qa/qa-test-cases-*.yaml for:

  • unbound picker send (R-V/R-L/R-F) → exactly one merged status bar message,
  • already-bound send → existing send-only behavior preserved,
  • bind-only action → bind-only message preserved,
  • rebind paths → no merged send text leakage.

Suggested schema examples:

  • id: qa-bind-send-merged-001, feature: status_bar_feedback, scenario: unbound picker send merges bind+send, preconditions, steps, expected_result, automated.
  • id: qa-bind-send-merged-002, feature: status_bar_feedback, scenario: already-bound send remains send-only, ...

As per coding guidelines, "When reviewing changes in the VS Code extension source code... Flag a potential QA coverage gap if ... user-visible behavior changes and QA YAML is not updated."

🤖 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/CHANGELOG.md` at line 14, Add QA test
cases to the qa-test-cases-*.yaml files to cover the merged bind+send status bar
notification behavior. Create test cases with schema fields (id, feature:
status_bar_feedback, scenario, preconditions, steps, expected_result, automated)
for four scenarios: unbound picker send (R-V/R-L/R-F) producing exactly one
merged message in the format "Bound to <destination> — <link> sent",
already-bound send preserving the existing send-only message behavior, bind-only
action preserving the bind-only message, and rebind paths ensuring no send text
appears in bind-only contexts. Use id naming like qa-bind-send-merged-001,
qa-bind-send-merged-002, etc. for each test case.

Source: Coding guidelines

Comment on lines 27 to 29
ss.expectStatusBarMessages([
'✓ RangeLink: Bound to Terminal ("rl-ctxmenu-tab-001")',
'✓ RangeLink: File path sent to Terminal ("rl-ctxmenu-tab-001")',
'✓ RangeLink: Bound to Terminal ("rl-ctxmenu-tab-001") — File path sent',
]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Already-bound scenarios should assert send-only feedback, not merged bind+send

Both tests pre-bind via CMD_BIND_TO_TERMINAL_HERE before triggering “Send File Path”. That makes these already-bound flows, so expecting Bound to ... — File path sent likely contradicts the intended contract for non-picker sends.

Suggested assertion adjustment
-    ss.expectStatusBarMessages([
-      '✓ RangeLink: Bound to Terminal ("rl-ctxmenu-tab-001") — File path sent',
-    ]);
+    ss.expectStatusBarMessages([
+      '✓ RangeLink: File path sent to Terminal ("rl-ctxmenu-tab-001")',
+    ]);

-    ss.expectStatusBarMessages([
-      '✓ RangeLink: Bound to Terminal ("rl-ctxmenu-tab-002") — File path sent',
-    ]);
+    ss.expectStatusBarMessages([
+      '✓ RangeLink: File path sent to Terminal ("rl-ctxmenu-tab-002")',
+    ]);

Also applies to: 76-78

🤖 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/contextMenuEditorTab.test.ts`
around lines 27 - 29, The test assertions for already-bound terminal flows are
expecting the wrong status bar message. In scenarios where the terminal is
pre-bound using CMD_BIND_TO_TERMINAL_HERE, the expectStatusBarMessages assertion
should expect send-only feedback messages, not combined bind+send messages.
Update the expectStatusBarMessages calls in both test cases (the one at lines
27-29 and the one at lines 76-78) to assert for the appropriate send-only
feedback message instead of the merged "Bound to Terminal... — File path sent"
message, which should only appear in fresh-bind scenarios.

Comment on lines 28 to 30
ss.expectStatusBarMessages([
'✓ RangeLink: Bound to Terminal ("rl-ctxmenu-exp-001")',
'✓ RangeLink: File path sent to Terminal ("rl-ctxmenu-exp-001")',
'✓ RangeLink: Bound to Terminal ("rl-ctxmenu-exp-001") — File path sent',
]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

These Explorer tests also appear to assert the wrong message contract for pre-bound sends

Since the terminal is bound before the send action, these cases should validate send-only status text. The merged Bound to ... — File path sent expectation is generally for picker-bind+send in one flow.

Suggested assertion adjustment
-    ss.expectStatusBarMessages([
-      '✓ RangeLink: Bound to Terminal ("rl-ctxmenu-exp-001") — File path sent',
-    ]);
+    ss.expectStatusBarMessages([
+      '✓ RangeLink: File path sent to Terminal ("rl-ctxmenu-exp-001")',
+    ]);

-    ss.expectStatusBarMessages([
-      '✓ RangeLink: Bound to Terminal ("rl-ctxmenu-exp-002") — File path sent',
-    ]);
+    ss.expectStatusBarMessages([
+      '✓ RangeLink: File path sent to Terminal ("rl-ctxmenu-exp-002")',
+    ]);

Also applies to: 74-76

🤖 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/contextMenuExplorer.test.ts`
around lines 28 - 30, The expectStatusBarMessages assertion in the test is
validating the wrong status message. Since the terminal is already bound before
the send action occurs, the status bar should only display the send-only
message, not the combined bind-and-send message. Update the
expectStatusBarMessages call around lines 28-30 to assert only the send-only
status text instead of the combined "Bound to Terminal ... — File path sent"
message. Also apply the same fix to the similar assertion mentioned at lines
74-76.

couimet added 2 commits June 19, 2026 08:27
…cation

When no destination is bound and the picker resolves to a bind during a send operation (R-V, R-L, R-F), the user sees one status bar message instead of two back-to-back toasts. The merge is achieved by threading bind context through the feedback layer, introducing a `ResolveResult` discriminated union, and adding a `BindContext` type shared across senders.

- Destination picker send flows now produce a single merged status bar message ("Bound to Terminal — RangeLink sent") instead of separate bind and send toasts. The bind-only toast from `showPickerAndBind()` is suppressed via the existing `StatusBarOptions.skipMessage` flag.
- `ResolveResult` discriminated union replaces the boolean return of `resolveDestination()`, encoding whether a bind was performed and the destination name when applicable. Callers no longer need to infer bind state from a bare boolean.
- New `BindContext` type (`{ readonly destinationName: string }`) shared across `SendRouter`, `OperationFeedbackProvider`, `LinkGenerator`, and four sender services, replacing an inline `{ destinationName: string }` type duplicated at each call site.
- Standalone `toBindContext(result: ResolveResult)` utility extracts `BindContext` from the discriminated union, eliminating a 4× copy-pasted ternary.
- `BindingFeedback` interface gains `notifyRebound(newDestinationName, previousDestinationName)` as a first-class method, splitting the rebind notification from `notifyBound(destinationName)`. The `replacedName` optional param is removed.
- `commitBind` options restructured: `suppressAutoPaste` and `StatusBarOptions` are nested under a single `bindOptions` parameter, keeping bind behavior and UI feedback concerns separated.
- CI: CI action for install-deps added.

- The `replacedName` path in `notifyBound` was the only place where rebind and fresh-bind messages could be confused. Splitting into `notifyRebound` eliminates that ambiguity and structurally guarantees rebind messages never leak into the send-feedback path.
- The four senders (`TextSelectionPaster`, `LinkGenerator`, `FilePathPaster`, `TerminalSelectionService`) had nearly identical `resolveResult → bindContext` construction logic. Extracting `toBindContext` as a standalone utility with its own test file (100% branch coverage) cleaned up the duplication.

- [x] All 2099 existing tests pass
- [x] New unit tests: `toBindContext.test.ts` (3 tests, 100% branch), `OperationFeedbackProvider.test.ts` (+11 tests covering `notifyBound`, `notifyRebound`, `notifyAlreadyBound`, `notifyBindFailedEditor`, `notifyBindFailedNotAvailable`, `notifyBackgroundTabOpened`, `notifyUnbound`, `notifyNothingToUnbind`, `notifyJumpFocused`, `notifyJumpFailed`), `PasteDestinationManager.test.ts` (+5 tests for `buildCommitBindOptions` via as-any cast)
- [x] Existing unit tests updated: `SendRouter.test.ts`, `LinkGenerator.test.ts`, `FilePathPaster.test.ts`, `TextSelectionPaster.test.ts`, `TerminalSelectionService.test.ts` — all now assert exact `FormattedLink` objects and `ResolveResult` shapes instead of `expect.any(Object)` or bare booleans

- Closes #621
@github-actions

Copy link
Copy Markdown

✅ CI / Integration Tests (with overrides) — run summary

Duration: 0m 51s

QA TC IDs: 2 exercised across 0 features

Report: View run & artifacts

Reproduce locally: ./scripts/run-integration-tests.sh --label needs-override --exclude-label cursor --exclude-assisted

Feature breakdown
Feature TCs IDs

@github-actions

Copy link
Copy Markdown

✅ CI / Integration Tests (automated) — run summary

Duration: 11m 24s

QA TC IDs: 163 exercised across 0 features

Report: View run & artifacts

Reproduce locally: ./scripts/run-integration-tests.sh --exclude-label requires-extensions --exclude-label cursor --automated

Feature breakdown
Feature TCs IDs

@github-actions

Copy link
Copy Markdown

✅ CI / Integration Tests (with extensions) — run summary

Duration: 12m 37s

Unit tests: Ran in separate Test & Validate job

QA TC IDs: 195 exercised across 0 features

Report: View run & artifacts

Reproduce locally: ./scripts/run-integration-tests.sh --exclude-label cursor --exclude-label needs-override --exclude-assisted

Feature breakdown
Feature TCs IDs

@couimet couimet merged commit 5cb3aba into main Jun 19, 2026
7 checks passed
@couimet couimet deleted the issues/621 branch June 19, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Merge bind+send status bar messages into a single notification

1 participant