mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-07-07 06:02:43 +08:00
fix(shell): use c to copy for claude
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import type { MutableRefObject, RefObject } from 'react';
|
import type { MutableRefObject, RefObject } from 'react';
|
||||||
|
import { ClipboardAddon, type IClipboardProvider } from '@xterm/addon-clipboard';
|
||||||
import { FitAddon } from '@xterm/addon-fit';
|
import { FitAddon } from '@xterm/addon-fit';
|
||||||
import { WebLinksAddon } from '@xterm/addon-web-links';
|
import { WebLinksAddon } from '@xterm/addon-web-links';
|
||||||
import { WebglAddon } from '@xterm/addon-webgl';
|
import { WebglAddon } from '@xterm/addon-webgl';
|
||||||
@@ -19,6 +20,43 @@ import {
|
|||||||
import { sendSocketMessage } from '../utils/socket';
|
import { sendSocketMessage } from '../utils/socket';
|
||||||
import { ensureXtermFocusStyles } from '../utils/terminalStyles';
|
import { ensureXtermFocusStyles } from '../utils/terminalStyles';
|
||||||
|
|
||||||
|
// CLIs running inside the pty (e.g. `claude auth login`'s "press c to copy"
|
||||||
|
// device-flow prompt) write to the clipboard via an OSC 52 escape sequence,
|
||||||
|
// not a browser event — xterm.js ignores OSC 52 unless a clipboard addon is
|
||||||
|
// loaded. Routes writes through the same fallback-aware helper the terminal's
|
||||||
|
// own selection-copy shortcut uses, since `navigator.clipboard` is often
|
||||||
|
// unavailable on self-hosted, non-HTTPS deployments.
|
||||||
|
// `ClipboardSelectionType.SYSTEM` is `'c'` (vs. `'p'` for the X11 primary
|
||||||
|
// selection) — compared as a literal since the addon ships it as a const
|
||||||
|
// enum, which isolatedModules builds (esbuild/Vite) can't import as a value.
|
||||||
|
const oscClipboardProvider: IClipboardProvider = {
|
||||||
|
readText: async (selection) => {
|
||||||
|
if (selection !== 'c') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return (await navigator.clipboard?.readText?.()) || '';
|
||||||
|
} catch {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
writeText: async (selection, text) => {
|
||||||
|
if (selection !== 'c') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await copyTextToClipboard(text);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// The addon's published typings declare a single `(provider?)` constructor
|
||||||
|
// param, but the shipped runtime actually takes `(base64?, provider?)` — see
|
||||||
|
// node_modules/@xterm/addon-clipboard/lib/addon-clipboard.js. Cast to call it
|
||||||
|
// the way it's really implemented.
|
||||||
|
const ClipboardAddonCtor = ClipboardAddon as unknown as new (
|
||||||
|
base64?: unknown,
|
||||||
|
provider?: IClipboardProvider,
|
||||||
|
) => ClipboardAddon;
|
||||||
|
|
||||||
type UseShellTerminalOptions = {
|
type UseShellTerminalOptions = {
|
||||||
terminalContainerRef: RefObject<HTMLDivElement>;
|
terminalContainerRef: RefObject<HTMLDivElement>;
|
||||||
terminalRef: MutableRefObject<Terminal | null>;
|
terminalRef: MutableRefObject<Terminal | null>;
|
||||||
@@ -93,6 +131,8 @@ export function useShellTerminal({
|
|||||||
fitAddonRef.current = nextFitAddon;
|
fitAddonRef.current = nextFitAddon;
|
||||||
nextTerminal.loadAddon(nextFitAddon);
|
nextTerminal.loadAddon(nextFitAddon);
|
||||||
|
|
||||||
|
nextTerminal.loadAddon(new ClipboardAddonCtor(undefined, oscClipboardProvider));
|
||||||
|
|
||||||
// Avoid wrapped partial links in compact login flows.
|
// Avoid wrapped partial links in compact login flows.
|
||||||
if (!minimal) {
|
if (!minimal) {
|
||||||
nextTerminal.loadAddon(new WebLinksAddon());
|
nextTerminal.loadAddon(new WebLinksAddon());
|
||||||
|
|||||||
Reference in New Issue
Block a user