Intercept clipboard paste events containing images in the terminal, upload them into the Docker container via bollard's tar upload API, and inject the resulting file path into terminal stdin so Claude Code can reference the image. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
93 lines
2.3 KiB
TypeScript
93 lines
2.3 KiB
TypeScript
import { useCallback } from "react";
|
|
import { useShallow } from "zustand/react/shallow";
|
|
import { listen } from "@tauri-apps/api/event";
|
|
import { useAppState } from "../store/appState";
|
|
import * as commands from "../lib/tauri-commands";
|
|
|
|
export function useTerminal() {
|
|
const { sessions, activeSessionId, addSession, removeSession, setActiveSession } =
|
|
useAppState(
|
|
useShallow(s => ({
|
|
sessions: s.sessions,
|
|
activeSessionId: s.activeSessionId,
|
|
addSession: s.addSession,
|
|
removeSession: s.removeSession,
|
|
setActiveSession: s.setActiveSession,
|
|
}))
|
|
);
|
|
|
|
const open = useCallback(
|
|
async (projectId: string, projectName: string) => {
|
|
const sessionId = crypto.randomUUID();
|
|
await commands.openTerminalSession(projectId, sessionId);
|
|
addSession({ id: sessionId, projectId, projectName });
|
|
return sessionId;
|
|
},
|
|
[addSession],
|
|
);
|
|
|
|
const close = useCallback(
|
|
async (sessionId: string) => {
|
|
await commands.closeTerminalSession(sessionId);
|
|
removeSession(sessionId);
|
|
},
|
|
[removeSession],
|
|
);
|
|
|
|
const sendInput = useCallback(
|
|
async (sessionId: string, data: string) => {
|
|
const bytes = Array.from(new TextEncoder().encode(data));
|
|
await commands.terminalInput(sessionId, bytes);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const resize = useCallback(
|
|
async (sessionId: string, cols: number, rows: number) => {
|
|
await commands.terminalResize(sessionId, cols, rows);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const pasteImage = useCallback(
|
|
async (sessionId: string, imageData: Uint8Array) => {
|
|
const bytes = Array.from(imageData);
|
|
return commands.pasteImageToTerminal(sessionId, bytes);
|
|
},
|
|
[],
|
|
);
|
|
|
|
const onOutput = useCallback(
|
|
(sessionId: string, callback: (data: Uint8Array) => void) => {
|
|
const eventName = `terminal-output-${sessionId}`;
|
|
return listen<number[]>(eventName, (event) => {
|
|
callback(new Uint8Array(event.payload));
|
|
});
|
|
},
|
|
[],
|
|
);
|
|
|
|
const onExit = useCallback(
|
|
(sessionId: string, callback: () => void) => {
|
|
const eventName = `terminal-exit-${sessionId}`;
|
|
return listen<void>(eventName, () => {
|
|
callback();
|
|
});
|
|
},
|
|
[],
|
|
);
|
|
|
|
return {
|
|
sessions,
|
|
activeSessionId,
|
|
setActiveSession,
|
|
open,
|
|
close,
|
|
sendInput,
|
|
pasteImage,
|
|
resize,
|
|
onOutput,
|
|
onExit,
|
|
};
|
|
}
|