Conversation
External links in chat messages were silently ignored because useArtifactLinkHandler returned early without calling preventDefault. Now intercepts external link clicks and opens them via openUrl from @tauri-apps/plugin-opener. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Streamdown hardcodes target="_blank" on all links, which in Tauri's WKWebView triggers a native new-window request that bypasses the JS click handler entirely. Override the `a` component to omit target so clicks bubble up to useArtifactLinkHandler's delegated handler. Also update tests to mock @tauri-apps/plugin-opener and verify openUrl is called for external links. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Streamdown's built-in linkSafety modal uses window.open() to open external links, which doesn't work in Tauri's WKWebView. Provide a custom renderModal that calls openUrl from @tauri-apps/plugin-opener instead, preserving the existing confirmation dialog UX. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6f22b0da57
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| <span className="font-semibold text-lg">Open external link?</span> | ||
| <p className="text-muted-foreground text-sm"> | ||
| You're about to visit an external website. |
There was a problem hiding this comment.
Localize new link-safety modal strings
This modal introduces user-facing literals ("Open external link?", "You’re about to visit…", button labels, and title="Close") directly in message.tsx, but this file is inside the enforced i18n scope (ui/goose2/scripts/check-i18n-strings.mjs includes src/shared/ui/ai-elements/message.tsx and flags JSX text/title literals). As written, pnpm check will fail on these new strings, so this change is not merge-safe until the copy is moved to translation keys (or narrowly annotated with i18n-check-ignore where truly intentional).
Useful? React with 👍 / 👎.
| useMemo, | ||
| useState, | ||
| } from "react"; | ||
| import { openUrl } from "@tauri-apps/plugin-opener"; |
There was a problem hiding this comment.
Update plugin-opener mocks to export openUrl
Adding openUrl imports here requires every @tauri-apps/plugin-opener Vitest mock in dependent tests to provide that named export; otherwise Vitest throws a missing-export error when loading modules. MessageBubble.test.tsx currently mocks only openPath (lines 9–11), and it imports code paths that now import openUrl, so this change will break that test suite until those mocks are updated.
Useful? React with 👍 / 👎.
The openUrl call was using void which silently swallowed any errors. Add .catch() to log failures so we can diagnose if the Tauri opener plugin is rejecting the call. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0b263ba9c7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (isExternalHref(href)) { | ||
| event.preventDefault(); | ||
| void openUrl(href); | ||
| return; |
There was a problem hiding this comment.
Skip delegated external opener when link safety is active
MessageResponse now enables Streamdown linkSafety (custom modal in message.tsx), but this delegated click handler still opens any external href immediately. Because link clicks bubble to this parent handler, external links inside assistant markdown can be launched before the safety modal is confirmed (and can be triggered twice depending on ordering), which defeats the confirmation flow this commit introduced. Add a guard (for example, return when event.defaultPrevented) or avoid opening external links from this delegated handler when Streamdown is handling them.
Useful? React with 👍 / 👎.
useArtifactLinkHandler was opening external links immediately via openUrl without any confirmation, bypassing Streamdown's linkSafety modal. Remove the external-link handling from the hook so the linkSafety confirmation dialog is the sole path for external URLs. Also extract the custom LinkSafetyModal into its own component file, replace the inline SVG close icon with XIcon from lucide-react, use shared Button primitives, and add Escape key support for accessibility. Signed-off-by: Matt Toohey <contact@matttoohey.com>
Replace the hand-rolled modal with the shared Dialog component built on @radix-ui/react-dialog, which provides focus trapping, aria-modal, portal rendering, animated open/close transitions, and built-in Escape key handling out of the box. Also add .catch() error handling to navigator.clipboard.writeText to prevent unhandled rejections when clipboard permissions are denied. Signed-off-by: Matt Toohey <contact@matttoohey.com>
The copy link button had no visual feedback after clicking, leaving users unsure whether the copy succeeded. Add isCopied state with a 2-second timeout that swaps the button label to "Copied!", matching the pattern used by other copy buttons in the codebase (code-block, terminal, snippet). Also guard against double-clicks while the copied state is active. Resolves review feedback from 550f6bc2. Signed-off-by: Matt Toohey <contact@matttoohey.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c4d608ca85
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| "size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0", | ||
| className, | ||
| )} | ||
| linkSafety={linkSafetyConfig} |
There was a problem hiding this comment.
Preserve local artifact link routing when enabling linkSafety
Enabling linkSafety here changes Streamdown’s link renderer to its intercepted link flow, so markdown links are no longer handled as plain anchors. useArtifactLinkHandler still only matches closest("a"), which means assistant markdown links stop going through resolveMarkdownHref/openResolvedPath; internal artifact paths are then routed through the modal’s openUrl path (or fail), breaking artifact navigation and bypassing the allowed-roots policy.
Useful? React with 👍 / 👎.
Summary