Skip to content

feat(gateway): suggest URL from clipboard on Gateway step (issue #18) - #20

Merged
johnnyhuy merged 2 commits into
mainfrom
feat/clipboard-base-url
Jul 30, 2026
Merged

feat(gateway): suggest URL from clipboard on Gateway step (issue #18)#20
johnnyhuy merged 2 commits into
mainfrom
feat/clipboard-base-url

Conversation

@johnnyhuy

Copy link
Copy Markdown
Contributor

Closes #18.

Summary

When the user lands on the Gateway step in the Electron app, Hoist reads the clipboard (renderer-initiated only — main never polls) and offers a one-click "Use this URL" suggestion pill below the Base URL field if the clipboard contains a parseable URL. Single-call, single-click; user editing the input discards the suggestion.

What changed

  • src/shared/channels.ts — new channel clipboard:read

  • src/main/ipc.ts — handler uses clipboard.readText(), trims, truncates at 4096 chars

  • src/preload/api.ts + src/preload/index.ts — typed ClipboardReadResponse + window.hoist.clipboard.read()

  • src/renderer/App.tsx

    • extractBaseUrl() regex: ^https?://[^\s/?#]+ — accepts scheme+host only (no path/query/fragment)
    • GatewayStep calls clipboard.read() on mount
    • "Use this URL" pill below the Base URL input with ✕ dismiss button
    • Editing the Base URL field clears the suggestion (one-shot)
  • scripts/test-extract-base-url.mjs — 10-case smoke test mirroring the App.tsx regex

  • package.jsontest:extractor script

  • .github/workflows/ci.yml — runs npm run test:extractor in the app job between lint and build

Privacy

  • The renderer is the only caller of clipboard.read. Main process never reads the clipboard opportunistically.
  • Reading only happens after the user lands on the Gateway step (one call, gated by mount).
  • Output is truncated to 4096 chars; no autosave, no sharing.
  • Write access never requested (no clipboard.writeText added).

Verification

  • npm run typecheck
  • npm run lint
  • npm run test:extractor ✓ (10/10 cases including wikipedia URL → host-only)
  • npm run build
  • Screenshot above shows the pill with the parsed URL inline, edit clears it, ✕ dismisses it

Test cases that pass

✓ "https://gateway.acme.com"                                           → "https://gateway.acme.com"
✓ "http://localhost:4000/"                                             → "http://localhost:4000"
✓ "https://gateway.ai.cloudflare.com/v1/<account_id>"                 → "https://gateway.ai.cloudflare.com"
✓ "\n  https://api.example.com/v1  \n"                                 → "https://api.example.com"
✓ "mailto:nope@example.com"                                           → null
✓ ""                                                                   → null
✓ "https://"                                                            → null
✓ "api.example.com"                                                    → null
✓ "https://example.com/with/path"                                      → "https://example.com"
✓ "https://en.wikipedia.org/wiki/Claude_(language_model)"              → "https://en.wikipedia.org"

- extractBaseUrl(): pure regex that pulls the scheme+host from arbitrary
  clipboard text (https?://… with no whitespace/path). Tests pass for
  paste-friendly URLs, rejects mailto and bare hosts and fragment-y input.
- GatewayStep calls window.hoist.clipboard.read() once on mount (renderer-
  initiated — main never reads the clipboard opportunistically).
- Below the Base URL input, an "Use this URL" pill appears if the
  clipboard contains a parseable URL.
- Editing the input discards the suggestion (one-shot, no sticky state).
- The pill shows the parsed URL inline and has ✕ to dismiss.

Layout stays consistent at 1280×800; the pill wraps gracefully if the
URL is long.
- scripts/test-extract-base-url.mjs: re-implements extractBaseUrl() in
  plain JS (kept verbatim in sync with the App.tsx version) and asserts
  10 clipboard-shape cases.
- package.json: test:extractor script
- .github/workflows/ci.yml: app job runs npm run test:extractor between
  lint and build, so the regex behavior is exercised on every PR.

10/10 cases pass:
  ✓ https://gateway.acme.comhttps://gateway.acme.com
  ✓ http://localhost:4000/                            → http://localhost:4000
  ✓ https://gateway.ai.cloudflare.com/v1/<account_id> → https://gateway.ai.cloudflare.com
  ✓ \n  https://api.example.com/v1  \n               → https://api.example.com
  ✓ mailto:nope@example.com                          → null
  ✓ (empty)                                          → null
  ✓ https://                                         → null
  ✓ api.example.com                                  → null
  ✓ https://example.com/with/pathhttps://example.comhttps://en.wikipedia.org/wiki/Claude_(...)https://en.wikipedia.org
@johnnyhuy
johnnyhuy merged commit d7efa4e into main Jul 30, 2026
7 checks passed
@johnnyhuy
johnnyhuy deleted the feat/clipboard-base-url branch July 30, 2026 20:35
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.

Pre-fill the gateway Base URL from the clipboard

1 participant