Skip to content

COP-46 - Tools launch bug#131

Merged
dantheuber merged 4 commits into
mainfrom
tools-launch-bug
Jun 28, 2026
Merged

COP-46 - Tools launch bug#131
dantheuber merged 4 commits into
mainfrom
tools-launch-bug

Conversation

@dantheuber

Copy link
Copy Markdown
Owner

Fix: tools launcher hotkey scans live clipboard, not stale stored clip (COP-46)

Summary

The "open tools launcher for latest clip" hotkey scanned the most recently
stored clip from history instead of what is actually on the system clipboard
right now. When the user copied something and immediately fired the hotkey (window
unfocused), the launcher showed results for the previous clip.

This fixes it by having the main process read the live clipboard directly and pass
that content to the launcher.

Root cause

HotkeyActions.openToolsLauncher() read storage.getClips()[0].clip.content.
clips[0] is the most recent clip in stored history, which trails the real
clipboard: history only updates through an async pipeline (250ms main-process poll
-> clipboard-changed IPC -> renderer dedup/add -> save-back via IPC). Firing the
hotkey inside that window meant storage.getClips()[0] was still the previous clip,
so the launcher scanned stale content.

The launcher renderer (ToolsLauncher.tsx -> QuickClipsScanner) only consumes a
content: string and has no dependency on history, so passing the live clipboard
content directly fully fixes the scan.

Approach (Option A)

Read the live clipboard in the main process and pass it straight to the launcher --
no forced history update, no new IPC handshake, no renderer roundtrip.

  • openToolsLauncher() now calls getCurrentClipboardData() (already exposed) for
    the current { type, content } and passes that content to
    createToolsLauncherWindow().
  • Falls back to storage.getClips()[0].clip.content only when the live read returns
    null/empty (e.g. empty clipboard or an unsupported format).
  • History continues to update on its own via the normal 250ms poll one tick later.

Rejected alternative (Option B): drive the renderer to ingest the live clipboard and
wait for the save before opening. Rejected because add-to-history logic (dedup,
locking, language detection, max-clips, echo guards, storage save) is owned by the
renderer; driving it from the hotkey handler requires a new request/response IPC
handshake, gates the launcher open on an async roundtrip, and is sensitive to
hidden-window backgroundThrottling.

Changes

  • src/main/hotkeys/actions.ts -- openToolsLauncher() reads live clipboard via
    getCurrentClipboardData(), falls back to the most recent stored clip when the
    live read is empty.
  • src/main/hotkeys/actions.test.ts -- new unit coverage (see below).

Housekeeping (incidental)

  • Bump version 1.8.6 -> 1.8.7.
  • Add graphify tooling docs to CLAUDE.md and ignore graphify-out/ in
    .gitignore.

Testing

  • Unit: live clipboard content beats a stale stored clip; launcher does not touch
    stored history when live has content; fallback to stored clip when the live read
    is null; fallback when live content is empty; no-op when live read is null and no
    history; no-op when first stored clip is null; error handled gracefully.
  • npm run lint and npm run typecheck -- zero errors/warnings.
  • npx vitest run --coverage -- 411 tests pass, 100% statements/branches/functions/lines.
  • npx playwright test -- 18/18 e2e pass.

Acceptance criteria

  • Window hidden/unfocused: copy new text, fire hotkey -> launcher scans the
    just-copied text, not the previous clip.
  • openToolsLauncher() sources content from the live clipboard
    (getCurrentClipboardData()), not storage.getClips()[0].
  • Live read null/empty falls back to the most recent stored clip (no crash, no
    empty launcher when history has content).
  • Focused-window behavior with current history is unchanged.
  • Unit test: launcher opens with live content even when storage.getClips()[0]
    is stale.
  • Unit test: fallback to stored clip when live read is null.
  • Lint, typecheck, unit tests pass at 100% coverage; e2e suite passes.

@github-actions

Copy link
Copy Markdown

📊 Coverage Report

Metric Coverage
Statements 100%
Branches 100%
Functions 100%
Lines 100%

@github-actions

Copy link
Copy Markdown

🧪 E2E Test Results

18 passed, 0 failed, 0 skipped

Test Suite Result
App Launch
Clipboard
Context Menu
Image Clipboard
Quick Clips
Settings
Theme
Settings — Search Terms CRUD
Settings — Quick Tools CRUD
Settings — Templates CRUD
Tools Launcher — Pattern Scanning
Tools Launcher — Clip Templates

@dantheuber dantheuber merged commit a0a1a2a into main Jun 28, 2026
3 checks passed
@dantheuber dantheuber deleted the tools-launch-bug branch June 28, 2026 21:59
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.

1 participant