@@ -30,60 +30,28 @@ export const SUPPORTED_IMAGE_EXTENSIONS = new Set([
3030
3131// Size limits - balanced to prevent message truncation while allowing reasonable images
3232const MAX_FILE_SIZE = 2 * 1024 * 1024 // 2MB - allow larger files for compression
33- const MAX_TOTAL_SIZE = 5 * 1024 * 1024 // 5MB total
3433const MAX_BASE64_SIZE = 150 * 1024 // 150KB max for base64 (backend limit ~760KB, so safe margin)
3534
35+ /**
36+ * Normalizes a user-provided file path by handling escape sequences.
37+ * Handles:
38+ * - Shell-escaped special characters: "my\ file.png" -> "my file.png"
39+ * - Unicode escapes: "\u{202f}" or "\u202f" -> actual unicode char (from terminal copy/paste)
40+ */
3641function normalizeUserProvidedPath ( filePath : string ) : string {
3742 let normalized = filePath
3843
39- normalized = normalized . replace (
40- / \\ u \{ ( [ 0 - 9 a - f A - F ] + ) \} / g,
41- ( match , codePoint ) => {
42- const value = Number . parseInt ( codePoint , 16 )
43- if ( Number . isNaN ( value ) ) {
44- return match
45- }
46- try {
47- return String . fromCodePoint ( value )
48- } catch {
49- return match
50- }
51- } ,
52- )
53-
54- normalized = normalized . replace (
55- / \\ u ( [ 0 - 9 a - f A - F ] { 4 } ) / g,
56- ( match , codePoint ) => {
57- const value = Number . parseInt ( codePoint , 16 )
58- if ( Number . isNaN ( value ) ) {
59- return match
60- }
61- try {
62- return String . fromCodePoint ( value )
63- } catch {
64- return match
65- }
66- } ,
67- )
68-
69- normalized = normalized . replace (
70- / \\ x ( [ 0 - 9 a - f A - F ] { 2 } ) / g,
71- ( match , codePoint ) => {
72- const value = Number . parseInt ( codePoint , 16 )
73- if ( Number . isNaN ( value ) ) {
74- return match
75- }
76- return String . fromCharCode ( value )
77- } ,
78- )
79-
80- normalized = normalized . replace ( / \\ ( [ \t " ' ( ) { } \[ \] ] ) / g, ( match , char ) => {
81- if ( char === '\\' ) {
82- return '\\'
83- }
84- return char
44+ // Handle unicode escape sequences (e.g., from terminal copy/paste)
45+ // Format: \u{XXXX} or \uXXXX
46+ normalized = normalized . replace ( / \\ u \{ ( [ 0 - 9 a - f A - F ] + ) \} | \\ u ( [ 0 - 9 a - f A - F ] { 4 } ) / g, ( _ , bracedCode , shortCode ) => {
47+ const code = bracedCode || shortCode
48+ const value = Number . parseInt ( code , 16 )
49+ return Number . isNaN ( value ) ? _ : String . fromCodePoint ( value )
8550 } )
8651
52+ // Handle shell-escaped special characters (e.g., spaces in paths)
53+ normalized = normalized . replace ( / \\ ( [ \t " ' ( ) { } \[ \] ] ) / g, '$1' )
54+
8755 return normalized
8856}
8957
@@ -138,10 +106,10 @@ export function resolveFilePath(filePath: string, cwd: string): string {
138106/**
139107 * Processes an image file and converts it to base64 for upload
140108 */
141- export async function processImageFile (
109+ export function processImageFile (
142110 filePath : string ,
143111 cwd : string ,
144- ) : Promise < ImageUploadResult > {
112+ ) : ImageUploadResult {
145113 try {
146114 const resolvedPath = resolveFilePath ( filePath , cwd )
147115
@@ -257,27 +225,6 @@ export async function processImageFile(
257225 }
258226}
259227
260- /**
261- * Validates total size of multiple images
262- */
263- export function validateTotalImageSize ( imageParts : Array < { size ?: number } > ) : {
264- valid : boolean
265- error ?: string
266- } {
267- const totalSize = imageParts . reduce ( ( sum , part ) => sum + ( part . size || 0 ) , 0 )
268-
269- if ( totalSize > MAX_TOTAL_SIZE ) {
270- const totalMB = ( totalSize / ( 1024 * 1024 ) ) . toFixed ( 1 )
271- const maxMB = ( MAX_TOTAL_SIZE / ( 1024 * 1024 ) ) . toFixed ( 1 )
272- return {
273- valid : false ,
274- error : `Total image size too large: ${ totalMB } MB (max ${ maxMB } MB)` ,
275- }
276- }
277-
278- return { valid : true }
279- }
280-
281228/**
282229 * Extracts image file paths from user input using @path syntax and auto-detection
283230 */
0 commit comments