diff --git a/package.json b/package.json index 7af8996..a4fcbf8 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.1.23", "@anthropic-ai/claude-code": "^2.0.24", + "@anthropic-ai/sdk": "^0.67.0", "@effect/platform": "^0.92.1", "@effect/platform-node": "^0.98.4", "@hono/node-server": "^1.19.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08b441a..2cf647b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@anthropic-ai/claude-code': specifier: ^2.0.24 version: 2.0.24 + '@anthropic-ai/sdk': + specifier: ^0.67.0 + version: 0.67.0(zod@4.1.12) '@effect/platform': specifier: ^0.92.1 version: 0.92.1(effect@3.18.4) @@ -231,6 +234,15 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + '@anthropic-ai/sdk@0.67.0': + resolution: {integrity: sha512-Buxbf6jYJ+pPtfCgXe1pcFtZmdXPrbdqhBjiscFt9irS1G0hCsmR/fPA+DwKTk4GPjqeNnnCYNecXH6uVZ4G/A==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -3210,6 +3222,10 @@ packages: resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} engines: {node: ^18.17.0 || >=20.5.0} + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} @@ -4280,6 +4296,9 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -4611,6 +4630,12 @@ snapshots: '@img/sharp-linux-x64': 0.33.5 '@img/sharp-win32-x64': 0.33.5 + '@anthropic-ai/sdk@0.67.0(zod@4.1.12)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 4.1.12 + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -7544,6 +7569,11 @@ snapshots: json-parse-even-better-errors@4.0.0: {} + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.28.4 + ts-algebra: 2.0.0 + json-schema-traverse@1.0.0: {} json5@2.2.3: {} @@ -8863,6 +8893,8 @@ snapshots: trough@2.2.0: {} + ts-algebra@2.0.0: {} + tslib@2.8.1: {} tsx@4.20.6: diff --git a/src/app/projects/[projectId]/components/chatForm/ChatInput.tsx b/src/app/projects/[projectId]/components/chatForm/ChatInput.tsx index f3bf548..e2924b1 100644 --- a/src/app/projects/[projectId]/components/chatForm/ChatInput.tsx +++ b/src/app/projects/[projectId]/components/chatForm/ChatInput.tsx @@ -2,8 +2,10 @@ import { Trans, useLingui } from "@lingui/react"; import { AlertCircleIcon, LoaderIcon, + PaperclipIcon, SendIcon, SparklesIcon, + XIcon, } from "lucide-react"; import { type FC, useCallback, useId, useRef, useState } from "react"; import { Button } from "../../../../../components/ui/button"; @@ -11,11 +13,18 @@ import { Textarea } from "../../../../../components/ui/textarea"; import { useConfig } from "../../../../hooks/useConfig"; import type { CommandCompletionRef } from "./CommandCompletion"; import type { FileCompletionRef } from "./FileCompletion"; +import type { DocumentBlock, ImageBlock } from "./fileUtils"; import { InlineCompletion } from "./InlineCompletion"; +export interface MessageInput { + text: string; + images?: ImageBlock[]; + documents?: DocumentBlock[]; +} + export interface ChatInputProps { projectId: string; - onSubmit: (message: string) => Promise; + onSubmit: (input: MessageInput) => Promise; isPending: boolean; error?: Error | null; placeholder: string; @@ -40,6 +49,9 @@ export const ChatInput: FC = ({ }) => { const { i18n } = useLingui(); const [message, setMessage] = useState(""); + const [attachedFiles, setAttachedFiles] = useState< + Array<{ file: File; id: string }> + >([]); const [cursorPosition, setCursorPosition] = useState<{ relative: { top: number; left: number }; absolute: { top: number; left: number }; @@ -47,15 +59,63 @@ export const ChatInput: FC = ({ const containerRef = useRef(null); const textareaRef = useRef(null); + const fileInputRef = useRef(null); const commandCompletionRef = useRef(null); const fileCompletionRef = useRef(null); const helpId = useId(); const { config } = useConfig(); const handleSubmit = async () => { - if (!message.trim()) return; - await onSubmit(message.trim()); + if (!message.trim() && attachedFiles.length === 0) return; + + const { processFile } = await import("./fileUtils"); + + const images: ImageBlock[] = []; + const documents: DocumentBlock[] = []; + let additionalText = ""; + + for (const { file } of attachedFiles) { + const result = await processFile(file); + + if (result.type === "text") { + additionalText += `\n\nFile: ${file.name}\n${result.content}`; + } else if (result.type === "image") { + images.push(result.block); + } else if (result.type === "document") { + documents.push(result.block); + } + } + + const finalText = message.trim() + additionalText; + + await onSubmit({ + text: finalText, + images: images.length > 0 ? images : undefined, + documents: documents.length > 0 ? documents : undefined, + }); + setMessage(""); + setAttachedFiles([]); + }; + + const handleFileSelect = (e: React.ChangeEvent) => { + const files = e.target.files; + if (!files) return; + + const newFiles = Array.from(files).map((file) => ({ + file, + id: `${file.name}-${Date.now()}-${Math.random()}`, + })); + + setAttachedFiles((prev) => [...prev, ...newFiles]); + + if (fileInputRef.current) { + fileInputRef.current.value = ""; + } + }; + + const handleRemoveFile = (id: string) => { + setAttachedFiles((prev) => prev.filter((f) => f.id !== id)); }; const handleKeyDown = (e: React.KeyboardEvent) => { @@ -159,7 +219,7 @@ export const ChatInput: FC = ({ textareaRef.current?.focus(); }; - const handleFileSelect = (filePath: string) => { + const handleFilePathSelect = (filePath: string) => { setMessage(filePath); textareaRef.current?.focus(); }; @@ -216,8 +276,50 @@ export const ChatInput: FC = ({ /> + {attachedFiles.length > 0 && ( +
+ {attachedFiles.map(({ file, id }) => ( +
+ {file.name} + +
+ ))} +
+ )} +
+ + = ({
diff --git a/src/app/projects/[projectId]/components/chatForm/fileUtils.ts b/src/app/projects/[projectId]/components/chatForm/fileUtils.ts new file mode 100644 index 0000000..7d6df50 --- /dev/null +++ b/src/app/projects/[projectId]/components/chatForm/fileUtils.ts @@ -0,0 +1,148 @@ +/** + * File utilities for file upload and encoding + */ + +export type FileType = "text" | "image" | "pdf"; + +export type ImageBlock = { + type: "image"; + source: { + type: "base64"; + media_type: "image/png" | "image/jpeg" | "image/gif" | "image/webp"; + data: string; + }; +}; + +export type DocumentBlock = { + type: "document"; + source: { + type: "base64"; + media_type: "application/pdf"; + data: string; + }; +}; + +/** + * Determine file type based on MIME type + */ +export const determineFileType = (mimeType: string): FileType => { + if (mimeType.startsWith("image/")) { + return "image"; + } + if (mimeType === "application/pdf") { + return "pdf"; + } + return "text"; +}; + +/** + * Check if MIME type is supported + */ +export const isSupportedMimeType = (mimeType: string): boolean => { + const supportedImageTypes = [ + "image/png", + "image/jpeg", + "image/gif", + "image/webp", + ]; + const supportedDocumentTypes = ["application/pdf"]; + const supportedTextTypes = ["text/plain"]; + + return ( + supportedImageTypes.includes(mimeType) || + supportedDocumentTypes.includes(mimeType) || + supportedTextTypes.includes(mimeType) + ); +}; + +/** + * Convert File to base64 encoded string (without data URL prefix) + */ +export const fileToBase64 = (file: File): Promise => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const result = reader.result; + if (typeof result === "string") { + // Remove data URL prefix (e.g., "data:image/png;base64,") + const base64 = result.split(",")[1]; + resolve(base64 ?? ""); + } else { + reject(new Error("Failed to read file as base64")); + } + }; + reader.onerror = () => { + reject(new Error("Failed to read file")); + }; + reader.readAsDataURL(file); + }); +}; + +/** + * Convert File to plain text + */ +export const fileToText = (file: File): Promise => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => { + const result = reader.result; + if (typeof result === "string") { + resolve(result); + } else { + reject(new Error("Failed to read file as text")); + } + }; + reader.onerror = () => { + reject(new Error("Failed to read file")); + }; + reader.readAsText(file); + }); +}; + +/** + * Process a file and return appropriate block structure + */ +export const processFile = async ( + file: File, +): Promise< + | { type: "text"; content: string } + | { type: "image"; block: ImageBlock } + | { type: "document"; block: DocumentBlock } +> => { + const fileType = determineFileType(file.type); + + if (fileType === "text") { + const content = await fileToText(file); + return { type: "text", content }; + } + + const base64Data = await fileToBase64(file); + + if (fileType === "image") { + const mediaType = file.type as ImageBlock["source"]["media_type"]; + return { + type: "image", + block: { + type: "image", + source: { + type: "base64", + media_type: mediaType, + data: base64Data, + }, + }, + }; + } + + // PDF + return { + type: "document", + block: { + type: "document", + source: { + type: "base64", + media_type: "application/pdf", + data: base64Data, + }, + }, + }; +}; diff --git a/src/app/projects/[projectId]/components/chatForm/index.ts b/src/app/projects/[projectId]/components/chatForm/index.ts index bb31081..630e6ed 100644 --- a/src/app/projects/[projectId]/components/chatForm/index.ts +++ b/src/app/projects/[projectId]/components/chatForm/index.ts @@ -1,4 +1,4 @@ -export type { ChatInputProps } from "./ChatInput"; +export type { ChatInputProps, MessageInput } from "./ChatInput"; export { ChatInput } from "./ChatInput"; export type { CommandCompletionRef } from "./CommandCompletion"; export { CommandCompletion } from "./CommandCompletion"; diff --git a/src/app/projects/[projectId]/components/chatForm/useChatMutations.ts b/src/app/projects/[projectId]/components/chatForm/useChatMutations.ts index 4f4c803..444437a 100644 --- a/src/app/projects/[projectId]/components/chatForm/useChatMutations.ts +++ b/src/app/projects/[projectId]/components/chatForm/useChatMutations.ts @@ -1,6 +1,7 @@ import { useMutation } from "@tanstack/react-query"; import { useNavigate } from "@tanstack/react-router"; import { honoClient } from "../../../../../lib/api/client"; +import type { MessageInput } from "./ChatInput"; export const useCreateSessionProcessMutation = ( projectId: string, @@ -10,7 +11,7 @@ export const useCreateSessionProcessMutation = ( return useMutation({ mutationFn: async (options: { - message: string; + input: MessageInput; baseSessionId?: string; }) => { const response = await honoClient.api.cc["session-processes"].$post( @@ -18,7 +19,7 @@ export const useCreateSessionProcessMutation = ( json: { projectId, baseSessionId: options.baseSessionId, - message: options.message, + input: options.input, }, }, { @@ -53,7 +54,7 @@ export const useContinueSessionProcessMutation = ( ) => { return useMutation({ mutationFn: async (options: { - message: string; + input: MessageInput; sessionProcessId: string; }) => { const response = await honoClient.api.cc["session-processes"][ @@ -64,7 +65,7 @@ export const useContinueSessionProcessMutation = ( json: { projectId: projectId, baseSessionId: baseSessionId, - continueMessage: options.message, + input: options.input, }, }, { diff --git a/src/app/projects/[projectId]/components/newChat/NewChat.tsx b/src/app/projects/[projectId]/components/newChat/NewChat.tsx index 7d1f9ae..9838fa5 100644 --- a/src/app/projects/[projectId]/components/newChat/NewChat.tsx +++ b/src/app/projects/[projectId]/components/newChat/NewChat.tsx @@ -1,7 +1,11 @@ import { Trans, useLingui } from "@lingui/react"; import type { FC } from "react"; import { useConfig } from "../../../../hooks/useConfig"; -import { ChatInput, useCreateSessionProcessMutation } from "../chatForm"; +import { + ChatInput, + type MessageInput, + useCreateSessionProcessMutation, +} from "../chatForm"; export const NewChat: FC<{ projectId: string; @@ -14,8 +18,8 @@ export const NewChat: FC<{ ); const { config } = useConfig(); - const handleSubmit = async (message: string) => { - await createSessionProcess.mutateAsync({ message }); + const handleSubmit = async (input: MessageInput) => { + await createSessionProcess.mutateAsync({ input }); }; const getPlaceholder = () => { diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx index 760a4ba..1f3e63e 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx @@ -1,14 +1,23 @@ import { Trans } from "@lingui/react"; -import { AlertCircle, Image as ImageIcon } from "lucide-react"; +import { + AlertCircle, + ChevronDown, + FileText, + Image as ImageIcon, +} from "lucide-react"; import type { FC } from "react"; import { Badge } from "@/components/ui/badge"; import { Card, - CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; +import { + Collapsible, + CollapsibleContent, + CollapsibleTrigger, +} from "@/components/ui/collapsible"; import type { UserMessageContent } from "@/lib/conversation-schema/message/UserMessageSchema"; import { UserTextContent } from "./UserTextContent"; @@ -28,38 +37,39 @@ export const UserConversationContent: FC<{ if (content.source.type === "base64") { return ( - -
- - - - - - {content.source.media_type} - -
- - - -
- -
- User uploaded content -
-
+ + +
+
+ + + + + + {content.source.media_type} + + +
+
+
+ +
+
+ User uploaded content +
+
+
+
); } @@ -93,6 +103,124 @@ export const UserConversationContent: FC<{ ); } + if (content.type === "document") { + if (content.source.type === "base64") { + // PDFの場合 + if (content.source.media_type === "application/pdf") { + return ( + + + +
+
+ + + + + + {content.source.media_type} + + +
+
+
+ +
+
+ +
+
+
+
+
+ ); + } + } + + if (content.source.type === "text") { + // テキストファイルの場合 + return ( + + + +
+
+ + + + + + {content.source.media_type} + + +
+
+
+ +
+
+
+                    {content.source.data}
+                  
+
+
+
+
+
+ ); + } + + return ( + + +
+ + + + + + + +
+ + + +
+
+ ); + } + if (content.type === "tool_result") { // ツール結果は Assistant の呼び出し側に添えるので return null; diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/resumeChat/ContinueChat.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/resumeChat/ContinueChat.tsx index 818a8d2..f078afe 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/resumeChat/ContinueChat.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/resumeChat/ContinueChat.tsx @@ -3,6 +3,7 @@ import type { FC } from "react"; import { useConfig } from "../../../../../../hooks/useConfig"; import { ChatInput, + type MessageInput, useContinueSessionProcessMutation, } from "../../../../components/chatForm"; @@ -18,8 +19,8 @@ export const ContinueChat: FC<{ ); const { config } = useConfig(); - const handleSubmit = async (message: string) => { - await continueSessionProcess.mutateAsync({ message, sessionProcessId }); + const handleSubmit = async (input: MessageInput) => { + await continueSessionProcess.mutateAsync({ input, sessionProcessId }); }; const getPlaceholder = () => { diff --git a/src/app/projects/[projectId]/sessions/[sessionId]/components/resumeChat/ResumeChat.tsx b/src/app/projects/[projectId]/sessions/[sessionId]/components/resumeChat/ResumeChat.tsx index 9245b4d..f14bb31 100644 --- a/src/app/projects/[projectId]/sessions/[sessionId]/components/resumeChat/ResumeChat.tsx +++ b/src/app/projects/[projectId]/sessions/[sessionId]/components/resumeChat/ResumeChat.tsx @@ -3,6 +3,7 @@ import type { FC } from "react"; import { useConfig } from "../../../../../../hooks/useConfig"; import { ChatInput, + type MessageInput, useCreateSessionProcessMutation, } from "../../../../components/chatForm"; @@ -14,9 +15,9 @@ export const ResumeChat: FC<{ const createSessionProcess = useCreateSessionProcessMutation(projectId); const { config } = useConfig(); - const handleSubmit = async (message: string) => { + const handleSubmit = async (input: MessageInput) => { await createSessionProcess.mutateAsync({ - message, + input, baseSessionId: sessionId, }); }; diff --git a/src/lib/conversation-schema/content/DocumentContentSchema.ts b/src/lib/conversation-schema/content/DocumentContentSchema.ts new file mode 100644 index 0000000..e842019 --- /dev/null +++ b/src/lib/conversation-schema/content/DocumentContentSchema.ts @@ -0,0 +1,17 @@ +import { z } from "zod"; + +export const DocumentContentSchema = z.object({ + type: z.literal("document"), + source: z.union([ + z.object({ + media_type: z.literal("text/plain"), + type: z.literal("text"), + data: z.string(), + }), + z.object({ + media_type: z.enum(["application/pdf"]), + type: z.literal("base64"), + data: z.string(), + }), + ]), +}); diff --git a/src/lib/conversation-schema/content/ImageContentSchema.ts b/src/lib/conversation-schema/content/ImageContentSchema.ts index d9ffd2b..14d84cc 100644 --- a/src/lib/conversation-schema/content/ImageContentSchema.ts +++ b/src/lib/conversation-schema/content/ImageContentSchema.ts @@ -5,6 +5,6 @@ export const ImageContentSchema = z.object({ source: z.object({ type: z.literal("base64"), data: z.string(), - media_type: z.enum(["image/png"]), + media_type: z.enum(["image/png", "image/jpeg", "image/gif", "image/webp"]), }), }); diff --git a/src/lib/conversation-schema/message/UserMessageSchema.ts b/src/lib/conversation-schema/message/UserMessageSchema.ts index 129fb72..233a93a 100644 --- a/src/lib/conversation-schema/message/UserMessageSchema.ts +++ b/src/lib/conversation-schema/message/UserMessageSchema.ts @@ -1,4 +1,5 @@ import { z } from "zod"; +import { DocumentContentSchema } from "../content/DocumentContentSchema"; import { ImageContentSchema } from "../content/ImageContentSchema"; import { TextContentSchema } from "../content/TextContentSchema"; import { ToolResultContentSchema } from "../content/ToolResultContentSchema"; @@ -8,6 +9,7 @@ const UserMessageContentSchema = z.union([ TextContentSchema, ToolResultContentSchema, ImageContentSchema, + DocumentContentSchema, ]); export type UserMessageContent = z.infer; diff --git a/src/lib/i18n/locales/en/messages.json b/src/lib/i18n/locales/en/messages.json index c7cbfb1..88a8354 100644 --- a/src/lib/i18n/locales/en/messages.json +++ b/src/lib/i18n/locales/en/messages.json @@ -772,7 +772,7 @@ "origin": [["src/components/scheduler/CronExpressionBuilder.tsx", 183]] }, "user.content.image": { - "message": "Image", + "message": "Attached Image", "placeholders": {}, "comments": [], "origin": [ @@ -781,7 +781,7 @@ 39 ] ], - "translation": "Image" + "translation": "Attached Image" }, "assistant.tool.input_parameters": { "message": "Input Parameters", @@ -1569,7 +1569,7 @@ "translation": "Unsupported Media" }, "user.content.image.description": { - "message": "User uploaded image content", + "message": "Image attached by user", "placeholders": {}, "comments": [], "origin": [ @@ -1578,7 +1578,55 @@ 49 ] ], - "translation": "User uploaded image content" + "translation": "Image attached by user" + }, + "user.content.document.pdf": { + "message": "PDF Document", + "placeholders": {}, + "comments": [], + "origin": [ + [ + "src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx", + 121 + ] + ], + "translation": "PDF Document" + }, + "user.content.document.text": { + "message": "Text Document", + "placeholders": {}, + "comments": [], + "origin": [ + [ + "src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx", + 163 + ] + ], + "translation": "Text Document" + }, + "user.content.unsupported_document": { + "message": "Unsupported Document", + "placeholders": {}, + "comments": [], + "origin": [ + [ + "src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx", + 200 + ] + ], + "translation": "Unsupported Document" + }, + "user.content.unsupported_document.description": { + "message": "Document type not supported for display", + "placeholders": {}, + "comments": [], + "origin": [ + [ + "src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx", + 210 + ] + ], + "translation": "Document type not supported for display" }, "system_info.feature.agent_sdk.description": { "message": "Uses Claude Agent SDK instead of Claude Code SDK (v1.0.125+)", diff --git a/src/lib/i18n/locales/en/messages.ts b/src/lib/i18n/locales/en/messages.ts index d9e03cc..e1badd9 100644 --- a/src/lib/i18n/locales/en/messages.ts +++ b/src/lib/i18n/locales/en/messages.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Available commands\":[\"Available commands\"],\"Available files and directories\":[\"Available files and directories\"],\"Close sidebar\":[\"Close sidebar\"],\"Compare from\":[\"Compare from\"],\"Compare to\":[\"Compare to\"],\"Failed to commit\":[\"Failed to commit\"],\"Failed to commit and push\":[\"Failed to commit and push\"],\"Failed to push\":[\"Failed to push\"],\"Message input with completion support\":[\"Message input with completion support\"],\"Reload MCP servers\":[\"Reload MCP servers\"],\"Retry Push\":[\"Retry Push\"],\"Select enter key behavior\":[\"Select enter key behavior\"],\"Select language\":[\"Select language\"],\"Select permission mode\":[\"Select permission mode\"],\"Select theme\":[\"Select theme\"],\"Type your message here... (Start with / for commands, @ for files, Command+Enter to send)\":[\"Type your message here... (Start with / for commands, @ for files, Command+Enter to send)\"],\"Type your message here... (Start with / for commands, @ for files, Enter to send)\":[\"Type your message here... (Start with / for commands, @ for files, Enter to send)\"],\"Type your message here... (Start with / for commands, @ for files, Shift+Enter to send)\":[\"Type your message here... (Start with / for commands, @ for files, Shift+Enter to send)\"],\"Type your message... (Start with / for commands, @ for files, Command+Enter to send)\":[\"Type your message... (Start with / for commands, @ for files, Command+Enter to send)\"],\"Type your message... (Start with / for commands, @ for files, Enter to send)\":[\"Type your message... (Start with / for commands, @ for files, Enter to send)\"],\"Type your message... (Start with / for commands, @ for files, Shift+Enter to send)\":[\"Type your message... (Start with / for commands, @ for files, Shift+Enter to send)\"],\"Uncommitted changes\":[\"Uncommitted changes\"],\"assistant.thinking\":[\"Thinking\"],\"assistant.tool.input_parameters\":[\"Input Parameters\"],\"assistant.tool.message_count\":[[\"count\"],\" messages\"],\"assistant.tool.result\":[\"Tool Result\"],\"assistant.tool.task_id\":[\"Task ID\"],\"assistant.tool.tool_id\":[\"Tool ID\"],\"assistant.tool.view_task\":[\"View Task\"],\"assistant.tool.view_task_details\":[\"View Task\"],\"chat.autocomplete.active\":[\"Autocomplete active\"],\"chat.button.start\":[\"Start Chat\"],\"chat.error.send_failed\":[\"Failed to send message. Please try again.\"],\"chat.modal.title\":[\"Start New Chat\"],\"chat.resume\":[\"Resume\"],\"chat.send\":[\"Send\"],\"chat.status.processing\":[\"Processing...\"],\"common.action.cancel\":[\"Cancel\"],\"common.error\":[\"Error\"],\"common.loading\":[\"Loading...\"],\"conversation.error.raw_content\":[\"Raw Content:\"],\"conversation.error.report_issue\":[\"Report this issue\"],\"conversation.error.schema\":[\"Schema Error\"],\"conversation.error.schema_validation\":[\"Schema Validation Error\"],\"conversation.error.schema_validation.description\":[\"This conversation entry failed to parse correctly. This might indicate a format change or parsing issue.\"],\"cron_builder.cron_expression\":[\"Cron Expression\"],\"cron_builder.custom\":[\"Custom\"],\"cron_builder.daily\":[\"Daily\"],\"cron_builder.day_of_week\":[\"Day of Week\"],\"cron_builder.expression\":[\"Expression\"],\"cron_builder.friday\":[\"Friday\"],\"cron_builder.hour\":[\"Hour (0-23)\"],\"cron_builder.hourly\":[\"Hourly\"],\"cron_builder.minute\":[\"Minute (0-59)\"],\"cron_builder.monday\":[\"Monday\"],\"cron_builder.preview\":[\"Preview\"],\"cron_builder.saturday\":[\"Saturday\"],\"cron_builder.schedule_type\":[\"Schedule Type\"],\"cron_builder.sunday\":[\"Sunday\"],\"cron_builder.thursday\":[\"Thursday\"],\"cron_builder.tuesday\":[\"Tuesday\"],\"cron_builder.wednesday\":[\"Wednesday\"],\"cron_builder.weekly\":[\"Weekly\"],\"diff.commit\":[\"Commit\"],\"diff.commit.changes\":[\"Commit Changes\"],\"diff.commit.message\":[\"Commit message\"],\"diff.commit.push\":[\"Commit & Push\"],\"diff.committing\":[\"Committing...\"],\"diff.committing.pushing\":[\"Committing & Pushing...\"],\"diff.deselect.all\":[\"Deselect All\"],\"diff.enter.message\":[\"Enter a commit message\"],\"diff.files\":[\"files\"],\"diff.files.changed\":[\"files changed\"],\"diff.loading\":[\"Loading diff...\"],\"diff.push\":[\"Push\"],\"diff.pushing\":[\"Pushing...\"],\"diff.select.all\":[\"Select All\"],\"diff.select.file\":[\"Select at least one file\"],\"directory_picker.current\":[\"Current:\"],\"directory_picker.loading\":[\"Loading...\"],\"directory_picker.no_directories\":[\"No directories found\"],\"directory_picker.select\":[\"Select This Directory\"],\"mcp.error.load_failed\":[\"Failed to load MCP servers: \",[\"error\"]],\"mcp.no.servers\":[\"No MCP servers found\"],\"mcp.title\":[\"MCP Servers\"],\"notfound.button.go_home\":[\"Go to Home\"],\"notfound.default.description\":[\"The page you are looking for does not exist or has been moved.\"],\"notfound.default.title\":[\"Page Not Found\"],\"notfound.project.description\":[\"The project you are looking for does not exist.\"],\"notfound.project.title\":[\"Project Not Found\"],\"notfound.session.description\":[\"The session you are looking for does not exist.\"],\"notfound.session.title\":[\"Session Not Found\"],\"notification.beep\":[\"Beep\"],\"notification.chime\":[\"Chime\"],\"notification.description\":[\"Select a sound to play when a task completes\"],\"notification.none\":[\"None\"],\"notification.ping\":[\"Ping\"],\"notification.pop\":[\"Pop\"],\"notification.test\":[\"Test\"],\"project.create.action.create\":[\"Create Project\"],\"project.create.action.creating\":[\"Creating...\"],\"project.create.description\":[\"Select a directory to initialize as a Claude Code project. This will run <0>/init in the selected directory.\"],\"project.create.selected_directory\":[\"Selected directory:\"],\"project.create.title\":[\"Create New Project\"],\"project.error.back_to_projects\":[\"Back to Projects\"],\"project.error.description\":[\"We encountered an error while loading this project\"],\"project.error.details_title\":[\"Error Details\"],\"project.error.error_id\":[\"Error ID:\"],\"project.error.title\":[\"Failed to load project\"],\"project.error.try_again\":[\"Try Again\"],\"project.new\":[\"New Project\"],\"project.not_found.back_to_projects\":[\"Back to Projects\"],\"project.not_found.description\":[\"The project you are looking for does not exist or has been removed\"],\"project.not_found.title\":[\"Project Not Found\"],\"project_list.last_modified\":[\"Last modified:\"],\"project_list.messages\":[\"Messages:\"],\"project_list.no_projects.description\":[\"No Claude Code projects found in your ~/.claude/projects directory. Start a conversation with Claude Code to create your first project.\"],\"project_list.no_projects.title\":[\"No projects found\"],\"project_list.view_conversations\":[\"View Conversations\"],\"projects.page.description\":[\"Browse your Claude Code conversation history and project interactions\"],\"projects.page.loading\":[\"Loading projects...\"],\"projects.page.title\":[\"Your Projects\"],\"session.conversation.abort\":[\"Abort\"],\"session.conversation.in.progress\":[\"Conversation is in progress...\"],\"session.conversation.paused\":[\"Conversation is paused...\"],\"session.processing\":[\"Claude Code is processing...\"],\"session.status.paused\":[\"Paused\"],\"session.status.running\":[\"Running\"],\"sessions.load.more\":[\"Load More\"],\"sessions.new\":[\"New\"],\"sessions.title\":[\"Sessions\"],\"sessions.total\":[\"total\"],\"settings.description\":[\"Display and behavior preferences\"],\"settings.input.enter_key_behavior\":[\"Enter Key Behavior\"],\"settings.input.enter_key_behavior.command_enter\":[\"Command+Enter to send\"],\"settings.input.enter_key_behavior.description\":[\"Choose how the Enter key behaves in message input\"],\"settings.input.enter_key_behavior.enter\":[\"Enter to send\"],\"settings.input.enter_key_behavior.shift_enter\":[\"Shift+Enter to send (default)\"],\"settings.loading\":[\"Loading settings...\"],\"settings.locale\":[\"Language\"],\"settings.locale.description\":[\"Choose your preferred language\"],\"settings.locale.en\":[\"English\"],\"settings.locale.ja\":[\"日本語\"],\"settings.notifications\":[\"Notifications\"],\"settings.permission.mode\":[\"Permission Mode\"],\"settings.permission.mode.accept_edits\":[\"Accept Edits (Auto-approve file edits)\"],\"settings.permission.mode.bypass_permissions\":[\"Bypass Permissions (No prompts)\"],\"settings.permission.mode.default\":[\"Default (Ask permission)\"],\"settings.permission.mode.description\":[\"Control how Claude Code handles permission requests for file operations\"],\"settings.permission.mode.plan\":[\"Plan Mode (Planning only)\"],\"settings.section.notifications\":[\"Notifications\"],\"settings.section.session_display\":[\"Session Display\"],\"settings.section.system_info\":[\"System Information\"],\"settings.session.display\":[\"Session Display\"],\"settings.session.hide_no_user_message\":[\"Hide sessions without user messages\"],\"settings.session.hide_no_user_message.description\":[\"Only show sessions that contain user commands or messages\"],\"settings.session.unify_same_title\":[\"Unify sessions with same title\"],\"settings.session.unify_same_title.description\":[\"Show only the latest session when multiple sessions have the same title\"],\"settings.tab.title\":[\"Settings for display and notifications\"],\"settings.theme\":[\"Theme\"],\"settings.theme.dark\":[\"Dark\"],\"settings.theme.description\":[\"Choose your preferred color theme\"],\"settings.theme.light\":[\"Light\"],\"settings.theme.system\":[\"System\"],\"settings.title\":[\"Settings\"],\"sidebar.back.to.projects\":[\"Back to projects\"],\"sidebar.show.mcp.settings\":[\"Show MCP server settings\"],\"sidebar.show.session.list\":[\"Show session list\"],\"system.info.tab.title\":[\"Show system information\"],\"system_info.available_features\":[\"Available Features\"],\"system_info.claude_code\":[\"Claude Code\"],\"system_info.description\":[\"Version and feature information\"],\"system_info.executable_path\":[\"Executable\"],\"system_info.feature.agent_sdk.description\":[\"Uses Claude Agent SDK instead of Claude Code SDK (v1.0.125+)\"],\"system_info.feature.agent_sdk.title\":[\"Claude Agent SDK\"],\"system_info.feature.can_use_tool.description\":[\"Dynamically control tool usage permissions and request user approval before tool execution (v1.0.82+)\"],\"system_info.feature.can_use_tool.title\":[\"Tool Use Permission Control\"],\"system_info.feature.unknown.description\":[\"Feature information not available\"],\"system_info.feature.uuid_on_sdk_message.description\":[\"Adds unique identifiers to SDK messages for better tracking (v1.0.86+)\"],\"system_info.feature.uuid_on_sdk_message.title\":[\"Message UUID Support\"],\"system_info.loading\":[\"Loading system information...\"],\"system_info.title\":[\"System Information\"],\"system_info.unknown\":[\"Unknown\"],\"system_info.version_label\":[\"Version\"],\"system_info.viewer_version\":[\"Claude Code Viewer\"],\"user.content.image\":[\"Image\"],\"user.content.image.description\":[\"User uploaded image content\"],\"user.content.unsupported_media\":[\"Unsupported Media\"],\"user.content.unsupported_media.description\":[\"Media type not supported for display\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Available commands\":[\"Available commands\"],\"Available files and directories\":[\"Available files and directories\"],\"Close sidebar\":[\"Close sidebar\"],\"Compare from\":[\"Compare from\"],\"Compare to\":[\"Compare to\"],\"Failed to commit\":[\"Failed to commit\"],\"Failed to commit and push\":[\"Failed to commit and push\"],\"Failed to push\":[\"Failed to push\"],\"Message input with completion support\":[\"Message input with completion support\"],\"Reload MCP servers\":[\"Reload MCP servers\"],\"Retry Push\":[\"Retry Push\"],\"Select enter key behavior\":[\"Select enter key behavior\"],\"Select language\":[\"Select language\"],\"Select permission mode\":[\"Select permission mode\"],\"Select theme\":[\"Select theme\"],\"Type your message here... (Start with / for commands, @ for files, Command+Enter to send)\":[\"Type your message here... (Start with / for commands, @ for files, Command+Enter to send)\"],\"Type your message here... (Start with / for commands, @ for files, Enter to send)\":[\"Type your message here... (Start with / for commands, @ for files, Enter to send)\"],\"Type your message here... (Start with / for commands, @ for files, Shift+Enter to send)\":[\"Type your message here... (Start with / for commands, @ for files, Shift+Enter to send)\"],\"Type your message... (Start with / for commands, @ for files, Command+Enter to send)\":[\"Type your message... (Start with / for commands, @ for files, Command+Enter to send)\"],\"Type your message... (Start with / for commands, @ for files, Enter to send)\":[\"Type your message... (Start with / for commands, @ for files, Enter to send)\"],\"Type your message... (Start with / for commands, @ for files, Shift+Enter to send)\":[\"Type your message... (Start with / for commands, @ for files, Shift+Enter to send)\"],\"Uncommitted changes\":[\"Uncommitted changes\"],\"assistant.thinking\":[\"Thinking\"],\"assistant.tool.input_parameters\":[\"Input Parameters\"],\"assistant.tool.message_count\":[[\"count\"],\" messages\"],\"assistant.tool.result\":[\"Tool Result\"],\"assistant.tool.task_id\":[\"Task ID\"],\"assistant.tool.tool_id\":[\"Tool ID\"],\"assistant.tool.view_task\":[\"View Task\"],\"assistant.tool.view_task_details\":[\"View Task\"],\"chat.autocomplete.active\":[\"Autocomplete active\"],\"chat.button.start\":[\"Start Chat\"],\"chat.error.send_failed\":[\"Failed to send message. Please try again.\"],\"chat.modal.title\":[\"Start New Chat\"],\"chat.resume\":[\"Resume\"],\"chat.send\":[\"Send\"],\"chat.status.processing\":[\"Processing...\"],\"common.action.cancel\":[\"Cancel\"],\"common.error\":[\"Error\"],\"common.loading\":[\"Loading...\"],\"conversation.error.raw_content\":[\"Raw Content:\"],\"conversation.error.report_issue\":[\"Report this issue\"],\"conversation.error.schema\":[\"Schema Error\"],\"conversation.error.schema_validation\":[\"Schema Validation Error\"],\"conversation.error.schema_validation.description\":[\"This conversation entry failed to parse correctly. This might indicate a format change or parsing issue.\"],\"cron_builder.cron_expression\":[\"Cron Expression\"],\"cron_builder.custom\":[\"Custom\"],\"cron_builder.daily\":[\"Daily\"],\"cron_builder.day_of_week\":[\"Day of Week\"],\"cron_builder.expression\":[\"Expression\"],\"cron_builder.friday\":[\"Friday\"],\"cron_builder.hour\":[\"Hour (0-23)\"],\"cron_builder.hourly\":[\"Hourly\"],\"cron_builder.minute\":[\"Minute (0-59)\"],\"cron_builder.monday\":[\"Monday\"],\"cron_builder.preview\":[\"Preview\"],\"cron_builder.saturday\":[\"Saturday\"],\"cron_builder.schedule_type\":[\"Schedule Type\"],\"cron_builder.sunday\":[\"Sunday\"],\"cron_builder.thursday\":[\"Thursday\"],\"cron_builder.tuesday\":[\"Tuesday\"],\"cron_builder.wednesday\":[\"Wednesday\"],\"cron_builder.weekly\":[\"Weekly\"],\"diff.commit\":[\"Commit\"],\"diff.commit.changes\":[\"Commit Changes\"],\"diff.commit.message\":[\"Commit message\"],\"diff.commit.push\":[\"Commit & Push\"],\"diff.committing\":[\"Committing...\"],\"diff.committing.pushing\":[\"Committing & Pushing...\"],\"diff.deselect.all\":[\"Deselect All\"],\"diff.enter.message\":[\"Enter a commit message\"],\"diff.files\":[\"files\"],\"diff.files.changed\":[\"files changed\"],\"diff.loading\":[\"Loading diff...\"],\"diff.push\":[\"Push\"],\"diff.pushing\":[\"Pushing...\"],\"diff.select.all\":[\"Select All\"],\"diff.select.file\":[\"Select at least one file\"],\"directory_picker.current\":[\"Current:\"],\"directory_picker.loading\":[\"Loading...\"],\"directory_picker.no_directories\":[\"No directories found\"],\"directory_picker.select\":[\"Select This Directory\"],\"mcp.error.load_failed\":[\"Failed to load MCP servers: \",[\"error\"]],\"mcp.no.servers\":[\"No MCP servers found\"],\"mcp.title\":[\"MCP Servers\"],\"notfound.button.go_home\":[\"Go to Home\"],\"notfound.default.description\":[\"The page you are looking for does not exist or has been moved.\"],\"notfound.default.title\":[\"Page Not Found\"],\"notfound.project.description\":[\"The project you are looking for does not exist.\"],\"notfound.project.title\":[\"Project Not Found\"],\"notfound.session.description\":[\"The session you are looking for does not exist.\"],\"notfound.session.title\":[\"Session Not Found\"],\"notification.beep\":[\"Beep\"],\"notification.chime\":[\"Chime\"],\"notification.description\":[\"Select a sound to play when a task completes\"],\"notification.none\":[\"None\"],\"notification.ping\":[\"Ping\"],\"notification.pop\":[\"Pop\"],\"notification.test\":[\"Test\"],\"project.create.action.create\":[\"Create Project\"],\"project.create.action.creating\":[\"Creating...\"],\"project.create.description\":[\"Select a directory to initialize as a Claude Code project. This will run <0>/init in the selected directory.\"],\"project.create.selected_directory\":[\"Selected directory:\"],\"project.create.title\":[\"Create New Project\"],\"project.error.back_to_projects\":[\"Back to Projects\"],\"project.error.description\":[\"We encountered an error while loading this project\"],\"project.error.details_title\":[\"Error Details\"],\"project.error.error_id\":[\"Error ID:\"],\"project.error.title\":[\"Failed to load project\"],\"project.error.try_again\":[\"Try Again\"],\"project.new\":[\"New Project\"],\"project.not_found.back_to_projects\":[\"Back to Projects\"],\"project.not_found.description\":[\"The project you are looking for does not exist or has been removed\"],\"project.not_found.title\":[\"Project Not Found\"],\"project_list.last_modified\":[\"Last modified:\"],\"project_list.messages\":[\"Messages:\"],\"project_list.no_projects.description\":[\"No Claude Code projects found in your ~/.claude/projects directory. Start a conversation with Claude Code to create your first project.\"],\"project_list.no_projects.title\":[\"No projects found\"],\"project_list.view_conversations\":[\"View Conversations\"],\"projects.page.description\":[\"Browse your Claude Code conversation history and project interactions\"],\"projects.page.loading\":[\"Loading projects...\"],\"projects.page.title\":[\"Your Projects\"],\"session.conversation.abort\":[\"Abort\"],\"session.conversation.in.progress\":[\"Conversation is in progress...\"],\"session.conversation.paused\":[\"Conversation is paused...\"],\"session.processing\":[\"Claude Code is processing...\"],\"session.status.paused\":[\"Paused\"],\"session.status.running\":[\"Running\"],\"sessions.load.more\":[\"Load More\"],\"sessions.new\":[\"New\"],\"sessions.title\":[\"Sessions\"],\"sessions.total\":[\"total\"],\"settings.description\":[\"Display and behavior preferences\"],\"settings.input.enter_key_behavior\":[\"Enter Key Behavior\"],\"settings.input.enter_key_behavior.command_enter\":[\"Command+Enter to send\"],\"settings.input.enter_key_behavior.description\":[\"Choose how the Enter key behaves in message input\"],\"settings.input.enter_key_behavior.enter\":[\"Enter to send\"],\"settings.input.enter_key_behavior.shift_enter\":[\"Shift+Enter to send (default)\"],\"settings.loading\":[\"Loading settings...\"],\"settings.locale\":[\"Language\"],\"settings.locale.description\":[\"Choose your preferred language\"],\"settings.locale.en\":[\"English\"],\"settings.locale.ja\":[\"日本語\"],\"settings.notifications\":[\"Notifications\"],\"settings.permission.mode\":[\"Permission Mode\"],\"settings.permission.mode.accept_edits\":[\"Accept Edits (Auto-approve file edits)\"],\"settings.permission.mode.bypass_permissions\":[\"Bypass Permissions (No prompts)\"],\"settings.permission.mode.default\":[\"Default (Ask permission)\"],\"settings.permission.mode.description\":[\"Control how Claude Code handles permission requests for file operations\"],\"settings.permission.mode.plan\":[\"Plan Mode (Planning only)\"],\"settings.section.notifications\":[\"Notifications\"],\"settings.section.session_display\":[\"Session Display\"],\"settings.section.system_info\":[\"System Information\"],\"settings.session.display\":[\"Session Display\"],\"settings.session.hide_no_user_message\":[\"Hide sessions without user messages\"],\"settings.session.hide_no_user_message.description\":[\"Only show sessions that contain user commands or messages\"],\"settings.session.unify_same_title\":[\"Unify sessions with same title\"],\"settings.session.unify_same_title.description\":[\"Show only the latest session when multiple sessions have the same title\"],\"settings.tab.title\":[\"Settings for display and notifications\"],\"settings.theme\":[\"Theme\"],\"settings.theme.dark\":[\"Dark\"],\"settings.theme.description\":[\"Choose your preferred color theme\"],\"settings.theme.light\":[\"Light\"],\"settings.theme.system\":[\"System\"],\"settings.title\":[\"Settings\"],\"sidebar.back.to.projects\":[\"Back to projects\"],\"sidebar.show.mcp.settings\":[\"Show MCP server settings\"],\"sidebar.show.session.list\":[\"Show session list\"],\"system.info.tab.title\":[\"Show system information\"],\"system_info.available_features\":[\"Available Features\"],\"system_info.claude_code\":[\"Claude Code\"],\"system_info.description\":[\"Version and feature information\"],\"system_info.executable_path\":[\"Executable\"],\"system_info.feature.agent_sdk.description\":[\"Uses Claude Agent SDK instead of Claude Code SDK (v1.0.125+)\"],\"system_info.feature.agent_sdk.title\":[\"Claude Agent SDK\"],\"system_info.feature.can_use_tool.description\":[\"Dynamically control tool usage permissions and request user approval before tool execution (v1.0.82+)\"],\"system_info.feature.can_use_tool.title\":[\"Tool Use Permission Control\"],\"system_info.feature.unknown.description\":[\"Feature information not available\"],\"system_info.feature.uuid_on_sdk_message.description\":[\"Adds unique identifiers to SDK messages for better tracking (v1.0.86+)\"],\"system_info.feature.uuid_on_sdk_message.title\":[\"Message UUID Support\"],\"system_info.loading\":[\"Loading system information...\"],\"system_info.title\":[\"System Information\"],\"system_info.unknown\":[\"Unknown\"],\"system_info.version_label\":[\"Version\"],\"system_info.viewer_version\":[\"Claude Code Viewer\"],\"user.content.image\":[\"Attached Image\"],\"user.content.image.description\":[\"Image attached by user\"],\"user.content.unsupported_media\":[\"Unsupported Media\"],\"user.content.unsupported_media.description\":[\"Media type not supported for display\"]}")as Messages; \ No newline at end of file diff --git a/src/lib/i18n/locales/ja/messages.json b/src/lib/i18n/locales/ja/messages.json index 1d37d10..7b669f2 100644 --- a/src/lib/i18n/locales/ja/messages.json +++ b/src/lib/i18n/locales/ja/messages.json @@ -772,7 +772,7 @@ "origin": [["src/components/scheduler/CronExpressionBuilder.tsx", 183]] }, "user.content.image": { - "message": "Image", + "message": "Attached Image", "placeholders": {}, "comments": [], "origin": [ @@ -781,7 +781,7 @@ 39 ] ], - "translation": "画像" + "translation": "添付画像" }, "assistant.tool.input_parameters": { "message": "Input Parameters", @@ -1569,7 +1569,7 @@ "translation": "サポートされていないメディア" }, "user.content.image.description": { - "message": "User uploaded image content", + "message": "Image attached by user", "placeholders": {}, "comments": [], "origin": [ @@ -1578,7 +1578,55 @@ 49 ] ], - "translation": "ユーザーがアップロードした画像コンテンツ" + "translation": "ユーザーが添付した画像" + }, + "user.content.document.pdf": { + "message": "PDF Document", + "placeholders": {}, + "comments": [], + "origin": [ + [ + "src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx", + 121 + ] + ], + "translation": "PDF文書" + }, + "user.content.document.text": { + "message": "Text Document", + "placeholders": {}, + "comments": [], + "origin": [ + [ + "src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx", + 163 + ] + ], + "translation": "テキスト文書" + }, + "user.content.unsupported_document": { + "message": "Unsupported Document", + "placeholders": {}, + "comments": [], + "origin": [ + [ + "src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx", + 200 + ] + ], + "translation": "サポートされていない文書" + }, + "user.content.unsupported_document.description": { + "message": "Document type not supported for display", + "placeholders": {}, + "comments": [], + "origin": [ + [ + "src/app/projects/[projectId]/sessions/[sessionId]/components/conversationList/UserConversationContent.tsx", + 210 + ] + ], + "translation": "文書タイプは表示がサポートされていません" }, "system_info.feature.agent_sdk.description": { "message": "Uses Claude Agent SDK instead of Claude Code SDK (v1.0.125+)", diff --git a/src/lib/i18n/locales/ja/messages.ts b/src/lib/i18n/locales/ja/messages.ts index 45ef674..5432f65 100644 --- a/src/lib/i18n/locales/ja/messages.ts +++ b/src/lib/i18n/locales/ja/messages.ts @@ -1 +1 @@ -/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Available commands\":[\"利用可能なコマンド\"],\"Available files and directories\":[\"利用可能なファイルとディレクトリ\"],\"Close sidebar\":[\"サイドバーを閉じる\"],\"Compare from\":[\"比較元\"],\"Compare to\":[\"比較先\"],\"Failed to commit\":[\"コミットに失敗しました\"],\"Failed to commit and push\":[\"コミットとプッシュに失敗しました\"],\"Failed to push\":[\"プッシュに失敗しました\"],\"Message input with completion support\":[\"補完機能付きメッセージ入力\"],\"Reload MCP servers\":[\"MCPサーバーを再読み込み\"],\"Retry Push\":[\"プッシュを再試行\"],\"Select enter key behavior\":[\"Enterキーの動作を選択\"],\"Select language\":[\"言語を選択\"],\"Select permission mode\":[\"権限モードを選択\"],\"Select theme\":[\"テーマを選択\"],\"Type your message here... (Start with / for commands, @ for files, Command+Enter to send)\":[\"ここにメッセージを入力... (/でコマンド、@でファイル、Command+Enterで送信)\"],\"Type your message here... (Start with / for commands, @ for files, Enter to send)\":[\"ここにメッセージを入力... (/でコマンド、@でファイル、Enterで送信)\"],\"Type your message here... (Start with / for commands, @ for files, Shift+Enter to send)\":[\"ここにメッセージを入力... (/でコマンド、@でファイル、Shift+Enterで送信)\"],\"Type your message... (Start with / for commands, @ for files, Command+Enter to send)\":[\"メッセージを入力... (/でコマンド、@でファイル、Command+Enterで送信)\"],\"Type your message... (Start with / for commands, @ for files, Enter to send)\":[\"メッセージを入力... (/でコマンド、@でファイル、Enterで送信)\"],\"Type your message... (Start with / for commands, @ for files, Shift+Enter to send)\":[\"メッセージを入力... (/でコマンド、@でファイル、Shift+Enterで送信)\"],\"Uncommitted changes\":[\"未コミットの変更\"],\"assistant.thinking\":[\"思考中\"],\"assistant.tool.input_parameters\":[\"入力パラメータ\"],\"assistant.tool.message_count\":[[\"count\"],\"件のメッセージ\"],\"assistant.tool.result\":[\"ツール実行結果\"],\"assistant.tool.task_id\":[\"タスクID\"],\"assistant.tool.tool_id\":[\"ツールID\"],\"assistant.tool.view_task\":[\"タスクを表示\"],\"assistant.tool.view_task_details\":[\"タスクを確認\"],\"chat.autocomplete.active\":[\"オートコンプリート有効\"],\"chat.button.start\":[\"チャット開始\"],\"chat.error.send_failed\":[\"メッセージの送信に失敗しました。もう一度お試しください。\"],\"chat.modal.title\":[\"新しいチャットを開始\"],\"chat.resume\":[\"再開\"],\"chat.send\":[\"送信\"],\"chat.status.processing\":[\"処理中...\"],\"common.action.cancel\":[\"キャンセル\"],\"common.error\":[\"エラー\"],\"common.loading\":[\"読み込み中...\"],\"conversation.error.raw_content\":[\"生データ:\"],\"conversation.error.report_issue\":[\"この問題を報告\"],\"conversation.error.schema\":[\"スキーマエラー\"],\"conversation.error.schema_validation\":[\"スキーマ検証エラー\"],\"conversation.error.schema_validation.description\":[\"この会話エントリの解析に失敗しました。フォーマットの変更または解析の問題が考えられます。\"],\"cron_builder.cron_expression\":[\"Cron式\"],\"cron_builder.custom\":[\"カスタム\"],\"cron_builder.daily\":[\"毎日\"],\"cron_builder.day_of_week\":[\"曜日\"],\"cron_builder.expression\":[\"Cron式\"],\"cron_builder.friday\":[\"金曜日\"],\"cron_builder.hour\":[\"時 (0-23)\"],\"cron_builder.hourly\":[\"毎時\"],\"cron_builder.minute\":[\"分 (0-59)\"],\"cron_builder.monday\":[\"月曜日\"],\"cron_builder.preview\":[\"プレビュー\"],\"cron_builder.saturday\":[\"土曜日\"],\"cron_builder.schedule_type\":[\"スケジュールタイプ\"],\"cron_builder.sunday\":[\"日曜日\"],\"cron_builder.thursday\":[\"木曜日\"],\"cron_builder.tuesday\":[\"火曜日\"],\"cron_builder.wednesday\":[\"水曜日\"],\"cron_builder.weekly\":[\"毎週\"],\"diff.commit\":[\"コミット\"],\"diff.commit.changes\":[\"変更をコミット\"],\"diff.commit.message\":[\"コミットメッセージ\"],\"diff.commit.push\":[\"コミット&プッシュ\"],\"diff.committing\":[\"コミット中...\"],\"diff.committing.pushing\":[\"コミット&プッシュ中...\"],\"diff.deselect.all\":[\"すべて選択解除\"],\"diff.enter.message\":[\"コミットメッセージを入力\"],\"diff.files\":[\"ファイル\"],\"diff.files.changed\":[\"ファイルが変更されました\"],\"diff.loading\":[\"差分を読み込み中...\"],\"diff.push\":[\"プッシュ\"],\"diff.pushing\":[\"プッシュ中...\"],\"diff.select.all\":[\"すべて選択\"],\"diff.select.file\":[\"少なくとも1つのファイルを選択してください\"],\"directory_picker.current\":[\"現在:\"],\"directory_picker.loading\":[\"読み込み中...\"],\"directory_picker.no_directories\":[\"ディレクトリが見つかりません\"],\"directory_picker.select\":[\"このディレクトリを選択\"],\"mcp.error.load_failed\":[\"MCPサーバーの読み込みに失敗しました: \",[\"error\"]],\"mcp.no.servers\":[\"MCPサーバーが見つかりません\"],\"mcp.title\":[\"MCPサーバー\"],\"notfound.button.go_home\":[\"ホームに戻る\"],\"notfound.default.description\":[\"お探しのページは存在しないか、移動されました。\"],\"notfound.default.title\":[\"ページが見つかりません\"],\"notfound.project.description\":[\"お探しのプロジェクトは存在しません。\"],\"notfound.project.title\":[\"プロジェクトが見つかりません\"],\"notfound.session.description\":[\"お探しのセッションは存在しません。\"],\"notfound.session.title\":[\"セッションが見つかりません\"],\"notification.beep\":[\"ビープ音\"],\"notification.chime\":[\"チャイム\"],\"notification.description\":[\"Claude Code のタスクが完了した時に再生する音を選択してください\"],\"notification.none\":[\"なし\"],\"notification.ping\":[\"ピン\"],\"notification.pop\":[\"ポップ\"],\"notification.test\":[\"テスト\"],\"project.create.action.create\":[\"プロジェクトを作成\"],\"project.create.action.creating\":[\"作成中...\"],\"project.create.description\":[\"Claude Codeプロジェクトとして初期化するディレクトリを選択してください。選択したディレクトリで<0>/initが実行されます。\"],\"project.create.selected_directory\":[\"選択したディレクトリ:\"],\"project.create.title\":[\"新規プロジェクトを作成\"],\"project.error.back_to_projects\":[\"プロジェクト一覧に戻る\"],\"project.error.description\":[\"このプロジェクトの読み込み中にエラーが発生しました\"],\"project.error.details_title\":[\"エラー詳細\"],\"project.error.error_id\":[\"エラーID:\"],\"project.error.title\":[\"プロジェクトの読み込みに失敗しました\"],\"project.error.try_again\":[\"再試行\"],\"project.new\":[\"新規プロジェクト\"],\"project.not_found.back_to_projects\":[\"プロジェクト一覧に戻る\"],\"project.not_found.description\":[\"お探しのプロジェクトは存在しないか、削除されています\"],\"project.not_found.title\":[\"プロジェクトが見つかりません\"],\"project_list.last_modified\":[\"最終更新:\"],\"project_list.messages\":[\"メッセージ:\"],\"project_list.no_projects.description\":[\"~/.claude/projectsディレクトリにClaude Codeプロジェクトが見つかりません。Claude Codeとの会話を開始して、最初のプロジェクトを作成してください。\"],\"project_list.no_projects.title\":[\"プロジェクトが見つかりません\"],\"project_list.view_conversations\":[\"会話を表示\"],\"projects.page.description\":[\"Claude Codeの会話履歴とプロジェクトの操作を閲覧\"],\"projects.page.loading\":[\"プロジェクトを読み込み中...\"],\"projects.page.title\":[\"プロジェクト\"],\"session.conversation.abort\":[\"中止\"],\"session.conversation.in.progress\":[\"会話を進行中...\"],\"session.conversation.paused\":[\"会話を一時停止中...\"],\"session.processing\":[\"Claude Codeが処理中...\"],\"session.status.paused\":[\"一時停止\"],\"session.status.running\":[\"実行中\"],\"sessions.load.more\":[\"さらに読み込む\"],\"sessions.new\":[\"新規\"],\"sessions.title\":[\"セッション\"],\"sessions.total\":[\"合計\"],\"settings.description\":[\"表示と動作の設定\"],\"settings.input.enter_key_behavior\":[\"Enterキーの動作\"],\"settings.input.enter_key_behavior.command_enter\":[\"Command+Enterで送信\"],\"settings.input.enter_key_behavior.description\":[\"メッセージ入力でのEnterキーの動作を選択\"],\"settings.input.enter_key_behavior.enter\":[\"Enterで送信\"],\"settings.input.enter_key_behavior.shift_enter\":[\"Shift+Enterで送信(デフォルト)\"],\"settings.loading\":[\"設定を読み込み中...\"],\"settings.locale\":[\"言語\"],\"settings.locale.description\":[\"お好みの言語を選択\"],\"settings.locale.en\":[\"English\"],\"settings.locale.ja\":[\"日本語\"],\"settings.notifications\":[\"通知\"],\"settings.permission.mode\":[\"権限モード\"],\"settings.permission.mode.accept_edits\":[\"編集を承認(ファイル編集を自動承認)\"],\"settings.permission.mode.bypass_permissions\":[\"権限をバイパス(プロンプトなし)\"],\"settings.permission.mode.default\":[\"デフォルト(権限を確認)\"],\"settings.permission.mode.description\":[\"ファイル操作の権限リクエストの処理方法を制御\"],\"settings.permission.mode.plan\":[\"プランモード(計画のみ)\"],\"settings.section.notifications\":[\"通知\"],\"settings.section.session_display\":[\"セッション表示\"],\"settings.section.system_info\":[\"システム情報\"],\"settings.session.display\":[\"セッション表示\"],\"settings.session.hide_no_user_message\":[\"ユーザーメッセージのないセッションを非表示\"],\"settings.session.hide_no_user_message.description\":[\"ユーザーコマンドまたはメッセージを含むセッションのみを表示\"],\"settings.session.unify_same_title\":[\"同じタイトルのセッションを統合\"],\"settings.session.unify_same_title.description\":[\"同じタイトルの複数のセッションがある場合、最新のセッションのみを表示\"],\"settings.tab.title\":[\"表示と通知の設定\"],\"settings.theme\":[\"テーマ\"],\"settings.theme.dark\":[\"ダーク\"],\"settings.theme.description\":[\"お好みのカラーテーマを選択\"],\"settings.theme.light\":[\"ライト\"],\"settings.theme.system\":[\"システム\"],\"settings.title\":[\"設定\"],\"sidebar.back.to.projects\":[\"プロジェクト一覧に戻る\"],\"sidebar.show.mcp.settings\":[\"MCPサーバー設定を表示\"],\"sidebar.show.session.list\":[\"セッション一覧を表示\"],\"system.info.tab.title\":[\"システム情報を表示\"],\"system_info.available_features\":[\"利用可能機能\"],\"system_info.claude_code\":[\"Claude Code\"],\"system_info.description\":[\"バージョンと機能情報\"],\"system_info.executable_path\":[\"実行ファイル\"],\"system_info.feature.agent_sdk.description\":[\"Claude Code SDKではなくClaude Agent SDKを使用 (v1.0.125+)\"],\"system_info.feature.agent_sdk.title\":[\"Claude Agent SDK\"],\"system_info.feature.can_use_tool.description\":[\"動的にツールの使用許可を制御し、ツール実行前にユーザーの承認を求めることができます (v1.0.82+)\"],\"system_info.feature.can_use_tool.title\":[\"ツール使用権限制御\"],\"system_info.feature.unknown.description\":[\"機能情報は利用できません\"],\"system_info.feature.uuid_on_sdk_message.description\":[\"SDKメッセージに一意の識別子を追加して追跡を改善します (v1.0.86+)\"],\"system_info.feature.uuid_on_sdk_message.title\":[\"メッセージUUIDサポート\"],\"system_info.loading\":[\"システム情報を読み込んでいます...\"],\"system_info.title\":[\"システム情報\"],\"system_info.unknown\":[\"不明\"],\"system_info.version_label\":[\"バージョン\"],\"system_info.viewer_version\":[\"Claude Code Viewer\"],\"user.content.image\":[\"画像\"],\"user.content.image.description\":[\"ユーザーがアップロードした画像コンテンツ\"],\"user.content.unsupported_media\":[\"サポートされていないメディア\"],\"user.content.unsupported_media.description\":[\"表示がサポートされていないメディア形式です\"]}")as Messages; \ No newline at end of file +/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Available commands\":[\"利用可能なコマンド\"],\"Available files and directories\":[\"利用可能なファイルとディレクトリ\"],\"Close sidebar\":[\"サイドバーを閉じる\"],\"Compare from\":[\"比較元\"],\"Compare to\":[\"比較先\"],\"Failed to commit\":[\"コミットに失敗しました\"],\"Failed to commit and push\":[\"コミットとプッシュに失敗しました\"],\"Failed to push\":[\"プッシュに失敗しました\"],\"Message input with completion support\":[\"補完機能付きメッセージ入力\"],\"Reload MCP servers\":[\"MCPサーバーを再読み込み\"],\"Retry Push\":[\"プッシュを再試行\"],\"Select enter key behavior\":[\"Enterキーの動作を選択\"],\"Select language\":[\"言語を選択\"],\"Select permission mode\":[\"権限モードを選択\"],\"Select theme\":[\"テーマを選択\"],\"Type your message here... (Start with / for commands, @ for files, Command+Enter to send)\":[\"ここにメッセージを入力... (/でコマンド、@でファイル、Command+Enterで送信)\"],\"Type your message here... (Start with / for commands, @ for files, Enter to send)\":[\"ここにメッセージを入力... (/でコマンド、@でファイル、Enterで送信)\"],\"Type your message here... (Start with / for commands, @ for files, Shift+Enter to send)\":[\"ここにメッセージを入力... (/でコマンド、@でファイル、Shift+Enterで送信)\"],\"Type your message... (Start with / for commands, @ for files, Command+Enter to send)\":[\"メッセージを入力... (/でコマンド、@でファイル、Command+Enterで送信)\"],\"Type your message... (Start with / for commands, @ for files, Enter to send)\":[\"メッセージを入力... (/でコマンド、@でファイル、Enterで送信)\"],\"Type your message... (Start with / for commands, @ for files, Shift+Enter to send)\":[\"メッセージを入力... (/でコマンド、@でファイル、Shift+Enterで送信)\"],\"Uncommitted changes\":[\"未コミットの変更\"],\"assistant.thinking\":[\"思考中\"],\"assistant.tool.input_parameters\":[\"入力パラメータ\"],\"assistant.tool.message_count\":[[\"count\"],\"件のメッセージ\"],\"assistant.tool.result\":[\"ツール実行結果\"],\"assistant.tool.task_id\":[\"タスクID\"],\"assistant.tool.tool_id\":[\"ツールID\"],\"assistant.tool.view_task\":[\"タスクを表示\"],\"assistant.tool.view_task_details\":[\"タスクを確認\"],\"chat.autocomplete.active\":[\"オートコンプリート有効\"],\"chat.button.start\":[\"チャット開始\"],\"chat.error.send_failed\":[\"メッセージの送信に失敗しました。もう一度お試しください。\"],\"chat.modal.title\":[\"新しいチャットを開始\"],\"chat.resume\":[\"再開\"],\"chat.send\":[\"送信\"],\"chat.status.processing\":[\"処理中...\"],\"common.action.cancel\":[\"キャンセル\"],\"common.error\":[\"エラー\"],\"common.loading\":[\"読み込み中...\"],\"conversation.error.raw_content\":[\"生データ:\"],\"conversation.error.report_issue\":[\"この問題を報告\"],\"conversation.error.schema\":[\"スキーマエラー\"],\"conversation.error.schema_validation\":[\"スキーマ検証エラー\"],\"conversation.error.schema_validation.description\":[\"この会話エントリの解析に失敗しました。フォーマットの変更または解析の問題が考えられます。\"],\"cron_builder.cron_expression\":[\"Cron式\"],\"cron_builder.custom\":[\"カスタム\"],\"cron_builder.daily\":[\"毎日\"],\"cron_builder.day_of_week\":[\"曜日\"],\"cron_builder.expression\":[\"Cron式\"],\"cron_builder.friday\":[\"金曜日\"],\"cron_builder.hour\":[\"時 (0-23)\"],\"cron_builder.hourly\":[\"毎時\"],\"cron_builder.minute\":[\"分 (0-59)\"],\"cron_builder.monday\":[\"月曜日\"],\"cron_builder.preview\":[\"プレビュー\"],\"cron_builder.saturday\":[\"土曜日\"],\"cron_builder.schedule_type\":[\"スケジュールタイプ\"],\"cron_builder.sunday\":[\"日曜日\"],\"cron_builder.thursday\":[\"木曜日\"],\"cron_builder.tuesday\":[\"火曜日\"],\"cron_builder.wednesday\":[\"水曜日\"],\"cron_builder.weekly\":[\"毎週\"],\"diff.commit\":[\"コミット\"],\"diff.commit.changes\":[\"変更をコミット\"],\"diff.commit.message\":[\"コミットメッセージ\"],\"diff.commit.push\":[\"コミット&プッシュ\"],\"diff.committing\":[\"コミット中...\"],\"diff.committing.pushing\":[\"コミット&プッシュ中...\"],\"diff.deselect.all\":[\"すべて選択解除\"],\"diff.enter.message\":[\"コミットメッセージを入力\"],\"diff.files\":[\"ファイル\"],\"diff.files.changed\":[\"ファイルが変更されました\"],\"diff.loading\":[\"差分を読み込み中...\"],\"diff.push\":[\"プッシュ\"],\"diff.pushing\":[\"プッシュ中...\"],\"diff.select.all\":[\"すべて選択\"],\"diff.select.file\":[\"少なくとも1つのファイルを選択してください\"],\"directory_picker.current\":[\"現在:\"],\"directory_picker.loading\":[\"読み込み中...\"],\"directory_picker.no_directories\":[\"ディレクトリが見つかりません\"],\"directory_picker.select\":[\"このディレクトリを選択\"],\"mcp.error.load_failed\":[\"MCPサーバーの読み込みに失敗しました: \",[\"error\"]],\"mcp.no.servers\":[\"MCPサーバーが見つかりません\"],\"mcp.title\":[\"MCPサーバー\"],\"notfound.button.go_home\":[\"ホームに戻る\"],\"notfound.default.description\":[\"お探しのページは存在しないか、移動されました。\"],\"notfound.default.title\":[\"ページが見つかりません\"],\"notfound.project.description\":[\"お探しのプロジェクトは存在しません。\"],\"notfound.project.title\":[\"プロジェクトが見つかりません\"],\"notfound.session.description\":[\"お探しのセッションは存在しません。\"],\"notfound.session.title\":[\"セッションが見つかりません\"],\"notification.beep\":[\"ビープ音\"],\"notification.chime\":[\"チャイム\"],\"notification.description\":[\"Claude Code のタスクが完了した時に再生する音を選択してください\"],\"notification.none\":[\"なし\"],\"notification.ping\":[\"ピン\"],\"notification.pop\":[\"ポップ\"],\"notification.test\":[\"テスト\"],\"project.create.action.create\":[\"プロジェクトを作成\"],\"project.create.action.creating\":[\"作成中...\"],\"project.create.description\":[\"Claude Codeプロジェクトとして初期化するディレクトリを選択してください。選択したディレクトリで<0>/initが実行されます。\"],\"project.create.selected_directory\":[\"選択したディレクトリ:\"],\"project.create.title\":[\"新規プロジェクトを作成\"],\"project.error.back_to_projects\":[\"プロジェクト一覧に戻る\"],\"project.error.description\":[\"このプロジェクトの読み込み中にエラーが発生しました\"],\"project.error.details_title\":[\"エラー詳細\"],\"project.error.error_id\":[\"エラーID:\"],\"project.error.title\":[\"プロジェクトの読み込みに失敗しました\"],\"project.error.try_again\":[\"再試行\"],\"project.new\":[\"新規プロジェクト\"],\"project.not_found.back_to_projects\":[\"プロジェクト一覧に戻る\"],\"project.not_found.description\":[\"お探しのプロジェクトは存在しないか、削除されています\"],\"project.not_found.title\":[\"プロジェクトが見つかりません\"],\"project_list.last_modified\":[\"最終更新:\"],\"project_list.messages\":[\"メッセージ:\"],\"project_list.no_projects.description\":[\"~/.claude/projectsディレクトリにClaude Codeプロジェクトが見つかりません。Claude Codeとの会話を開始して、最初のプロジェクトを作成してください。\"],\"project_list.no_projects.title\":[\"プロジェクトが見つかりません\"],\"project_list.view_conversations\":[\"会話を表示\"],\"projects.page.description\":[\"Claude Codeの会話履歴とプロジェクトの操作を閲覧\"],\"projects.page.loading\":[\"プロジェクトを読み込み中...\"],\"projects.page.title\":[\"プロジェクト\"],\"session.conversation.abort\":[\"中止\"],\"session.conversation.in.progress\":[\"会話を進行中...\"],\"session.conversation.paused\":[\"会話を一時停止中...\"],\"session.processing\":[\"Claude Codeが処理中...\"],\"session.status.paused\":[\"一時停止\"],\"session.status.running\":[\"実行中\"],\"sessions.load.more\":[\"さらに読み込む\"],\"sessions.new\":[\"新規\"],\"sessions.title\":[\"セッション\"],\"sessions.total\":[\"合計\"],\"settings.description\":[\"表示と動作の設定\"],\"settings.input.enter_key_behavior\":[\"Enterキーの動作\"],\"settings.input.enter_key_behavior.command_enter\":[\"Command+Enterで送信\"],\"settings.input.enter_key_behavior.description\":[\"メッセージ入力でのEnterキーの動作を選択\"],\"settings.input.enter_key_behavior.enter\":[\"Enterで送信\"],\"settings.input.enter_key_behavior.shift_enter\":[\"Shift+Enterで送信(デフォルト)\"],\"settings.loading\":[\"設定を読み込み中...\"],\"settings.locale\":[\"言語\"],\"settings.locale.description\":[\"お好みの言語を選択\"],\"settings.locale.en\":[\"English\"],\"settings.locale.ja\":[\"日本語\"],\"settings.notifications\":[\"通知\"],\"settings.permission.mode\":[\"権限モード\"],\"settings.permission.mode.accept_edits\":[\"編集を承認(ファイル編集を自動承認)\"],\"settings.permission.mode.bypass_permissions\":[\"権限をバイパス(プロンプトなし)\"],\"settings.permission.mode.default\":[\"デフォルト(権限を確認)\"],\"settings.permission.mode.description\":[\"ファイル操作の権限リクエストの処理方法を制御\"],\"settings.permission.mode.plan\":[\"プランモード(計画のみ)\"],\"settings.section.notifications\":[\"通知\"],\"settings.section.session_display\":[\"セッション表示\"],\"settings.section.system_info\":[\"システム情報\"],\"settings.session.display\":[\"セッション表示\"],\"settings.session.hide_no_user_message\":[\"ユーザーメッセージのないセッションを非表示\"],\"settings.session.hide_no_user_message.description\":[\"ユーザーコマンドまたはメッセージを含むセッションのみを表示\"],\"settings.session.unify_same_title\":[\"同じタイトルのセッションを統合\"],\"settings.session.unify_same_title.description\":[\"同じタイトルの複数のセッションがある場合、最新のセッションのみを表示\"],\"settings.tab.title\":[\"表示と通知の設定\"],\"settings.theme\":[\"テーマ\"],\"settings.theme.dark\":[\"ダーク\"],\"settings.theme.description\":[\"お好みのカラーテーマを選択\"],\"settings.theme.light\":[\"ライト\"],\"settings.theme.system\":[\"システム\"],\"settings.title\":[\"設定\"],\"sidebar.back.to.projects\":[\"プロジェクト一覧に戻る\"],\"sidebar.show.mcp.settings\":[\"MCPサーバー設定を表示\"],\"sidebar.show.session.list\":[\"セッション一覧を表示\"],\"system.info.tab.title\":[\"システム情報を表示\"],\"system_info.available_features\":[\"利用可能機能\"],\"system_info.claude_code\":[\"Claude Code\"],\"system_info.description\":[\"バージョンと機能情報\"],\"system_info.executable_path\":[\"実行ファイル\"],\"system_info.feature.agent_sdk.description\":[\"Claude Code SDKではなくClaude Agent SDKを使用 (v1.0.125+)\"],\"system_info.feature.agent_sdk.title\":[\"Claude Agent SDK\"],\"system_info.feature.can_use_tool.description\":[\"動的にツールの使用許可を制御し、ツール実行前にユーザーの承認を求めることができます (v1.0.82+)\"],\"system_info.feature.can_use_tool.title\":[\"ツール使用権限制御\"],\"system_info.feature.unknown.description\":[\"機能情報は利用できません\"],\"system_info.feature.uuid_on_sdk_message.description\":[\"SDKメッセージに一意の識別子を追加して追跡を改善します (v1.0.86+)\"],\"system_info.feature.uuid_on_sdk_message.title\":[\"メッセージUUIDサポート\"],\"system_info.loading\":[\"システム情報を読み込んでいます...\"],\"system_info.title\":[\"システム情報\"],\"system_info.unknown\":[\"不明\"],\"system_info.version_label\":[\"バージョン\"],\"system_info.viewer_version\":[\"Claude Code Viewer\"],\"user.content.image\":[\"添付画像\"],\"user.content.image.description\":[\"ユーザーが添付した画像\"],\"user.content.unsupported_media\":[\"サポートされていないメディア\"],\"user.content.unsupported_media.description\":[\"表示がサポートされていないメディア形式です\"]}")as Messages; \ No newline at end of file diff --git a/src/server/core/claude-code/functions/createMessageGenerator.ts b/src/server/core/claude-code/functions/createMessageGenerator.ts index 7928c8e..b2e3923 100644 --- a/src/server/core/claude-code/functions/createMessageGenerator.ts +++ b/src/server/core/claude-code/functions/createMessageGenerator.ts @@ -2,8 +2,18 @@ import type { SDKMessage, SDKUserMessage, } from "@anthropic-ai/claude-agent-sdk"; +import type { + DocumentBlockParam, + ImageBlockParam, +} from "@anthropic-ai/sdk/resources"; import { controllablePromise } from "../../../../lib/controllablePromise"; +export type UserMessageInput = { + text: string; + images?: readonly ImageBlockParam[]; + documents?: readonly DocumentBlockParam[]; +}; + export type OnMessage = (message: SDKMessage) => void | Promise; export type MessageGenerator = () => AsyncGenerator< @@ -14,37 +24,61 @@ export type MessageGenerator = () => AsyncGenerator< export const createMessageGenerator = (): { generateMessages: MessageGenerator; - setNextMessage: (message: string) => void; + setNextMessage: (input: UserMessageInput) => void; setHooks: (hooks: { - onNextMessageSet?: (message: string) => void | Promise; - onNewUserMessageResolved?: (message: string) => void | Promise; + onNextMessageSet?: (input: UserMessageInput) => void | Promise; + onNewUserMessageResolved?: ( + input: UserMessageInput, + ) => void | Promise; }) => void; } => { - let sendMessagePromise = controllablePromise(); + let sendMessagePromise = controllablePromise(); let registeredHooks: { - onNextMessageSet: ((message: string) => void | Promise)[]; - onNewUserMessageResolved: ((message: string) => void | Promise)[]; + onNextMessageSet: ((input: UserMessageInput) => void | Promise)[]; + onNewUserMessageResolved: (( + input: UserMessageInput, + ) => void | Promise)[]; } = { onNextMessageSet: [], onNewUserMessageResolved: [], }; - const createMessage = (message: string): SDKUserMessage => { + const createMessage = (input: UserMessageInput): SDKUserMessage => { + const { images = [], documents = [] } = input; + + if (images.length === 0 && documents.length === 0) { + return { + type: "user", + message: { + role: "user", + content: input.text, + }, + parent_tool_use_id: null, + } satisfies Omit as SDKUserMessage; + } + return { type: "user", message: { role: "user", - content: message, + content: [ + { + type: "text", + text: input.text, + }, + ...images, + ...documents, + ], }, } as SDKUserMessage; }; async function* generateMessages(): ReturnType { - sendMessagePromise = controllablePromise(); + sendMessagePromise = controllablePromise(); while (true) { const message = await sendMessagePromise.promise; - sendMessagePromise = controllablePromise(); + sendMessagePromise = controllablePromise(); void Promise.allSettled( registeredHooks.onNewUserMessageResolved.map((hook) => hook(message)), ); @@ -53,16 +87,18 @@ export const createMessageGenerator = (): { } } - const setNextMessage = (message: string) => { - sendMessagePromise.resolve(message); + const setNextMessage = (input: UserMessageInput) => { + sendMessagePromise.resolve(input); void Promise.allSettled( - registeredHooks.onNextMessageSet.map((hook) => hook(message)), + registeredHooks.onNextMessageSet.map((hook) => hook(input)), ); }; const setHooks = (hooks: { - onNextMessageSet?: (message: string) => void | Promise; - onNewUserMessageResolved?: (message: string) => void | Promise; + onNextMessageSet?: (input: UserMessageInput) => void | Promise; + onNewUserMessageResolved?: ( + input: UserMessageInput, + ) => void | Promise; }) => { registeredHooks = { onNextMessageSet: [ diff --git a/src/server/core/claude-code/models/CCSessionProcess.ts b/src/server/core/claude-code/models/CCSessionProcess.ts index 6843ae8..6605214 100644 --- a/src/server/core/claude-code/models/CCSessionProcess.ts +++ b/src/server/core/claude-code/models/CCSessionProcess.ts @@ -1,5 +1,6 @@ import { Effect } from "effect"; import type { UserEntry } from "../../../../lib/conversation-schema/entry/UserEntrySchema"; +import type { UserMessageInput } from "../functions/createMessageGenerator"; import type { InitMessageContext } from "../types"; import * as ClaudeCode from "./ClaudeCode"; import type * as CCTask from "./ClaudeCodeTask"; @@ -10,7 +11,7 @@ export type CCSessionProcessDef = { projectId: string; cwd: string; abortController: AbortController; - setNextMessage: (message: string) => void; + setNextMessage: (input: UserMessageInput) => void; }; type CCSessionProcessStateBase = { diff --git a/src/server/core/claude-code/presentation/ClaudeCodeSessionProcessController.ts b/src/server/core/claude-code/presentation/ClaudeCodeSessionProcessController.ts index 1e741c5..fcb6327 100644 --- a/src/server/core/claude-code/presentation/ClaudeCodeSessionProcessController.ts +++ b/src/server/core/claude-code/presentation/ClaudeCodeSessionProcessController.ts @@ -4,6 +4,7 @@ import type { ControllerResponse } from "../../../lib/effect/toEffectResponse"; import type { InferEffect } from "../../../lib/effect/types"; import { UserConfigService } from "../../platform/services/UserConfigService"; import { ProjectRepository } from "../../project/infrastructure/ProjectRepository"; +import type { UserMessageInput } from "../functions/createMessageGenerator"; import { ClaudeCodeLifeCycleService } from "../services/ClaudeCodeLifeCycleService"; const LayerImpl = Effect.gen(function* () { @@ -33,11 +34,11 @@ const LayerImpl = Effect.gen(function* () { const createSessionProcess = (options: { projectId: string; - message: string; + input: UserMessageInput; baseSessionId?: string | undefined; }) => Effect.gen(function* () { - const { projectId, message, baseSessionId } = options; + const { projectId, input, baseSessionId } = options; const { project } = yield* projectRepository.getProject(projectId); const userConfig = yield* userConfigService.getUserConfig(); @@ -56,7 +57,7 @@ const LayerImpl = Effect.gen(function* () { sessionId: baseSessionId, }, userConfig, - message, + input, }); const { sessionId } = yield* result.yieldSessionInitialized(); @@ -75,13 +76,12 @@ const LayerImpl = Effect.gen(function* () { const continueSessionProcess = (options: { projectId: string; - continueMessage: string; + input: UserMessageInput; baseSessionId: string; sessionProcessId: string; }) => Effect.gen(function* () { - const { projectId, continueMessage, baseSessionId, sessionProcessId } = - options; + const { projectId, input, baseSessionId, sessionProcessId } = options; const { project } = yield* projectRepository.getProject(projectId); @@ -94,7 +94,7 @@ const LayerImpl = Effect.gen(function* () { const result = yield* claudeCodeLifeCycleService.continueTask({ sessionProcessId, - message: continueMessage, + input, baseSessionId, }); diff --git a/src/server/core/claude-code/schema.ts b/src/server/core/claude-code/schema.ts new file mode 100644 index 0000000..0f096ac --- /dev/null +++ b/src/server/core/claude-code/schema.ts @@ -0,0 +1,36 @@ +import { z } from "zod"; + +/** + * Schema for image block parameter + */ +const imageBlockSchema = z.object({ + type: z.literal("image"), + source: z.object({ + type: z.literal("base64"), + media_type: z.enum(["image/png", "image/jpeg", "image/gif", "image/webp"]), + data: z.string(), + }), +}); + +/** + * Schema for document block parameter + */ +const documentBlockSchema = z.object({ + type: z.literal("document"), + source: z.object({ + type: z.literal("base64"), + media_type: z.enum(["application/pdf"]), + data: z.string(), + }), +}); + +/** + * Schema for user message input with optional images and documents + */ +export const userMessageInputSchema = z.object({ + text: z.string().min(1), + images: z.array(imageBlockSchema).optional(), + documents: z.array(documentBlockSchema).optional(), +}); + +export type UserMessageInputSchema = z.infer; diff --git a/src/server/core/claude-code/services/ClaudeCodeLifeCycleService.ts b/src/server/core/claude-code/services/ClaudeCodeLifeCycleService.ts index ac317c7..e435d28 100644 --- a/src/server/core/claude-code/services/ClaudeCodeLifeCycleService.ts +++ b/src/server/core/claude-code/services/ClaudeCodeLifeCycleService.ts @@ -14,7 +14,10 @@ import type { EnvService } from "../../platform/services/EnvService"; import { SessionRepository } from "../../session/infrastructure/SessionRepository"; import { VirtualConversationDatabase } from "../../session/infrastructure/VirtualConversationDatabase"; import type { SessionMetaService } from "../../session/services/SessionMetaService"; -import { createMessageGenerator } from "../functions/createMessageGenerator"; +import { + createMessageGenerator, + type UserMessageInput, +} from "../functions/createMessageGenerator"; import * as CCSessionProcess from "../models/CCSessionProcess"; import * as ClaudeCode from "../models/ClaudeCode"; import { ClaudeCodePermissionService } from "./ClaudeCodePermissionService"; @@ -46,9 +49,9 @@ const LayerImpl = Effect.gen(function* () { const continueTask = (options: { sessionProcessId: string; baseSessionId: string; - message: string; + input: UserMessageInput; }) => { - const { sessionProcessId, baseSessionId, message } = options; + const { sessionProcessId, baseSessionId, input } = options; return Effect.gen(function* () { const { sessionProcess, task } = @@ -65,7 +68,7 @@ const LayerImpl = Effect.gen(function* () { const virtualConversation = yield* CCSessionProcess.createVirtualConversation(sessionProcess, { sessionId: baseSessionId, - userMessage: message, + userMessage: input.text, }); yield* virtualConversationDatabase.createVirtualConversation( @@ -74,7 +77,7 @@ const LayerImpl = Effect.gen(function* () { [virtualConversation], ); - sessionProcess.def.setNextMessage(message); + sessionProcess.def.setNextMessage(input); return { sessionProcess, task, @@ -89,9 +92,9 @@ const LayerImpl = Effect.gen(function* () { projectId: string; sessionId?: string; }; - message: string; + input: UserMessageInput; }) => { - const { baseSession, message, userConfig } = options; + const { baseSession, input, userConfig } = options; return Effect.gen(function* () { const { @@ -131,11 +134,11 @@ const LayerImpl = Effect.gen(function* () { }>(); setMessageGeneratorHooks({ - onNewUserMessageResolved: async (message) => { + onNewUserMessageResolved: async (input) => { Effect.runFork( sessionProcessService.toNotInitializedState({ sessionProcessId: sessionProcess.def.sessionProcessId, - rawUserMessage: message, + rawUserMessage: input.text, }), ); }, @@ -276,7 +279,7 @@ const LayerImpl = Effect.gen(function* () { }), ); - setNextMessage(message); + setNextMessage(input); try { for await (const message of messageIter) { diff --git a/src/server/core/project/presentation/ProjectController.ts b/src/server/core/project/presentation/ProjectController.ts index 4fb2708..bf237ce 100644 --- a/src/server/core/project/presentation/ProjectController.ts +++ b/src/server/core/project/presentation/ProjectController.ts @@ -138,7 +138,9 @@ const LayerImpl = Effect.gen(function* () { sessionId: undefined, }, userConfig, - message: "/init", + input: { + text: "/init", + }, }); const { sessionId } = yield* result.yieldSessionFileCreated(); diff --git a/src/server/core/scheduler/domain/Job.ts b/src/server/core/scheduler/domain/Job.ts index b985677..d9d2d41 100644 --- a/src/server/core/scheduler/domain/Job.ts +++ b/src/server/core/scheduler/domain/Job.ts @@ -27,7 +27,9 @@ export const executeJob = (job: SchedulerJob) => sessionId: message.baseSessionId ?? undefined, }, userConfig, - message: message.content, + input: { + text: message.content, + }, }); }); diff --git a/src/server/hono/route.ts b/src/server/hono/route.ts index 1970f3e..715e6da 100644 --- a/src/server/hono/route.ts +++ b/src/server/hono/route.ts @@ -9,6 +9,7 @@ import packageJson from "../../../package.json" with { type: "json" }; import { ClaudeCodeController } from "../core/claude-code/presentation/ClaudeCodeController"; import { ClaudeCodePermissionController } from "../core/claude-code/presentation/ClaudeCodePermissionController"; import { ClaudeCodeSessionProcessController } from "../core/claude-code/presentation/ClaudeCodeSessionProcessController"; +import { userMessageInputSchema } from "../core/claude-code/schema"; import { ClaudeCodeLifeCycleService } from "../core/claude-code/services/ClaudeCodeLifeCycleService"; import { TypeSafeSSE } from "../core/events/functions/typeSafeSSE"; import { SSEController } from "../core/events/presentation/SSEController"; @@ -356,7 +357,7 @@ export const routes = (app: HonoAppType) => "json", z.object({ projectId: z.string(), - message: z.string(), + input: userMessageInputSchema, baseSessionId: z.string().optional(), }), ), @@ -378,7 +379,7 @@ export const routes = (app: HonoAppType) => "json", z.object({ projectId: z.string(), - continueMessage: z.string(), + input: userMessageInputSchema, baseSessionId: z.string(), }), ),