@@ -3,6 +3,7 @@ import { ClipboardService, ImageData } from '../services/clipboard';
33import { FileManagerService , ImageFile } from '../services/fileManager' ;
44import { ProgressService , ProgressPatterns , ProgressSteps } from '../services/progress' ;
55import { ConfigurationService } from '../services/configuration' ;
6+ import { Logger } from '../services/logging' ;
67import { Result , success , failure , ExtensionResult , ClipboardError , FileSystemError } from '../common/result' ;
78
89export type InsertDestination = 'editor' | 'terminal' ;
@@ -16,15 +17,78 @@ export interface CommandDependencies {
1617 fileManager : FileManagerService ;
1718 progress : ProgressService ;
1819 config : ConfigurationService ;
20+ logger : Logger ;
21+ }
22+
23+ function delay ( ms : number ) : Promise < void > {
24+ return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
25+ }
26+
27+ function asBracketedPaste ( text : string ) : string {
28+ return `\x1b[200~${ text } \x1b[201~` ;
29+ }
30+
31+ async function pasteTextIntoActiveTerminal ( text : string , logger : Logger ) : Promise < ExtensionResult < void > > {
32+ const activeTerminal = vscode . window . activeTerminal ;
33+ if ( ! activeTerminal ) {
34+ logger . error ( 'No active terminal available for insertion' ) ;
35+ return failure ( new FileSystemError ( 'No active terminal available' ) ) ;
36+ }
37+
38+ try {
39+ logger . info ( 'Attempting terminal insertion' , {
40+ textLength : text . length ,
41+ terminalName : activeTerminal . name
42+ } ) ;
43+ activeTerminal . show ( false ) ;
44+ await vscode . commands . executeCommand ( 'workbench.action.terminal.focus' ) ;
45+ await delay ( 100 ) ;
46+ await vscode . env . clipboard . writeText ( text ) ;
47+ await vscode . commands . executeCommand ( 'workbench.action.terminal.paste' ) ;
48+ logger . info ( 'VS Code terminal paste command completed' , {
49+ textLength : text . length
50+ } ) ;
51+ vscode . window . showInformationMessage ( 'Claudeboard Local: attempted VS Code terminal paste command' ) ;
52+ return success ( undefined ) ;
53+ } catch ( pasteCommandError ) {
54+ logger . warn ( 'VS Code terminal paste command failed' , { pasteCommandError } ) ;
55+ try {
56+ activeTerminal . sendText ( asBracketedPaste ( text ) , false ) ;
57+ logger . warn ( 'Bracketed paste sendText fallback completed' , {
58+ textLength : text . length
59+ } ) ;
60+ vscode . window . showWarningMessage ( 'Claudeboard Local: terminal paste command failed; used bracketed sendText fallback' ) ;
61+ return success ( undefined ) ;
62+ } catch ( bracketedPasteError ) {
63+ await vscode . env . clipboard . writeText ( text ) ;
64+ logger . error ( 'Terminal paste and bracketed sendText both failed' , {
65+ pasteCommandError,
66+ bracketedPasteError,
67+ textLength : text . length
68+ } ) ;
69+ return failure ( new FileSystemError (
70+ 'Failed to insert image URL into terminal. The path was copied to the clipboard; press Cmd+V/Ctrl+V in the terminal.' ,
71+ { pasteCommandError, bracketedPasteError, text }
72+ ) ) ;
73+ }
74+ }
1975}
2076
2177class ImageUploadCommand implements UploadImageCommand {
2278 constructor ( private readonly deps : CommandDependencies ) { }
2379
2480 async execute ( destination : InsertDestination ) : Promise < ExtensionResult < string > > {
81+ this . deps . logger . info ( 'Upload command started' , {
82+ destination,
83+ remoteName : vscode . env . remoteName
84+ } ) ;
2585 // Validate remote connection first
2686 const remoteCheck = this . validateRemoteConnection ( ) ;
2787 if ( Result . isFailure ( remoteCheck ) ) {
88+ this . deps . logger . error ( 'Remote validation failed' , {
89+ destination,
90+ error : remoteCheck . error
91+ } ) ;
2892 return remoteCheck ;
2993 }
3094
@@ -49,14 +113,25 @@ class ImageUploadCommand implements UploadImageCommand {
49113
50114 private async checkClipboard ( ) : Promise < ExtensionResult < ImageData > > {
51115 try {
116+ const hasImage = await this . deps . clipboard . hasImage ( ) . catch ( error => {
117+ this . deps . logger . debug ( 'hasImage probe failed before getImage' , { error } ) ;
118+ return false ;
119+ } ) ;
120+ this . deps . logger . info ( 'Clipboard probe before getImage' , { hasImage } ) ;
52121 const imageData = await this . deps . clipboard . getImage ( ) ;
53122
54123 if ( ! imageData ) {
124+ this . deps . logger . warn ( 'getImage returned null' ) ;
55125 return failure ( new ClipboardError ( 'No image found in clipboard' ) ) ;
56126 }
57127
128+ this . deps . logger . info ( 'Clipboard image retrieved' , {
129+ format : imageData . format ,
130+ bytes : imageData . buffer . length
131+ } ) ;
58132 return success ( imageData ) ;
59133 } catch ( error ) {
134+ this . deps . logger . error ( 'Clipboard access failed' , { error } ) ;
60135 return failure ( new ClipboardError (
61136 'Failed to access clipboard' ,
62137 { originalError : error }
@@ -69,17 +144,20 @@ class ImageUploadCommand implements UploadImageCommand {
69144 reporter : any
70145 ) : Promise < ExtensionResult < string > > {
71146 reporter . report ( ProgressSteps . preparing ( ) ) ;
147+ this . deps . logger . debug ( 'Upload and insert start' , { destination } ) ;
72148
73149 try {
74150 // Get image from previous step's result - this is a simplified approach
75151 // In a more complex implementation, we'd pass results between steps
76152 const imageData = await this . deps . clipboard . getImage ( ) ;
77153 if ( ! imageData ) {
154+ this . deps . logger . warn ( 'Image disappeared between clipboard check and upload' ) ;
78155 return failure ( new ClipboardError ( 'Image no longer available in clipboard' ) ) ;
79156 }
80157
81158 // Cleanup old images based on user configuration
82159 const retentionDays = this . deps . config . getRetentionDays ( ) ;
160+ this . deps . logger . debug ( 'Cleaning old images' , { retentionDays } ) ;
83161 await this . deps . fileManager . cleanupOldImages ( retentionDays ) ;
84162
85163 reporter . report ( ProgressSteps . uploading ( ) ) ;
@@ -89,12 +167,22 @@ class ImageUploadCommand implements UploadImageCommand {
89167 imageData . buffer ,
90168 imageData . format
91169 ) ;
170+ this . deps . logger . info ( 'Image file created' , {
171+ imagePath : imageFile . getPath ( ) ,
172+ format : imageData . format ,
173+ bytes : imageData . buffer . length
174+ } ) ;
92175
93176 reporter . report ( ProgressSteps . inserting ( ) ) ;
94177
95178 // Insert URL into editor/terminal
96179 const insertResult = await this . insertImageUrl ( imageFile . getPath ( ) , destination ) ;
97180 if ( Result . isFailure ( insertResult ) ) {
181+ this . deps . logger . error ( 'Insertion failed after file creation' , {
182+ destination,
183+ imagePath : imageFile . getPath ( ) ,
184+ error : insertResult . error
185+ } ) ;
98186 imageFile . dispose ( ) ;
99187 return insertResult ;
100188 }
@@ -104,16 +192,22 @@ class ImageUploadCommand implements UploadImageCommand {
104192 // Clear clipboard if configured to do so
105193 if ( this . deps . config . getClearClipboardAfterUpload ( ) ) {
106194 await this . deps . clipboard . clear ( ) ;
195+ this . deps . logger . debug ( 'Clipboard cleared after upload' ) ;
107196 }
108197
109198 const imageUrl = imageFile . getPath ( ) ;
110199
111200 // Show success message
112201 vscode . window . showInformationMessage ( `Image uploaded: ${ imageUrl } ` ) ;
202+ this . deps . logger . info ( 'Upload command completed successfully' , {
203+ destination,
204+ imageUrl
205+ } ) ;
113206
114207 return success ( imageUrl ) ;
115208
116209 } catch ( error ) {
210+ this . deps . logger . error ( 'Upload and insert threw' , { error, destination } ) ;
117211 return failure ( new FileSystemError (
118212 'Failed to upload image' ,
119213 { originalError : error , destination }
@@ -133,13 +227,9 @@ class ImageUploadCommand implements UploadImageCommand {
133227 await activeEditor . edit ( editBuilder => {
134228 editBuilder . insert ( position , url ) ;
135229 } ) ;
230+ this . deps . logger . info ( 'Inserted image path into editor' , { url } ) ;
136231 } else if ( destination === 'terminal' ) {
137- const activeTerminal = vscode . window . activeTerminal ;
138- if ( ! activeTerminal ) {
139- return failure ( new FileSystemError ( 'No active terminal available' ) ) ;
140- }
141-
142- activeTerminal . sendText ( url , false ) ;
232+ return await pasteTextIntoActiveTerminal ( url , this . deps . logger ) ;
143233 }
144234
145235 return success ( undefined ) ;
@@ -157,9 +247,17 @@ class OptimizedImageUploadCommand implements UploadImageCommand {
157247 constructor ( private readonly deps : CommandDependencies ) { }
158248
159249 async execute ( destination : InsertDestination ) : Promise < ExtensionResult < string > > {
250+ this . deps . logger . info ( 'Optimized upload command started' , {
251+ destination,
252+ remoteName : vscode . env . remoteName
253+ } ) ;
160254 // Validate remote connection first
161255 const remoteCheck = this . validateRemoteConnection ( ) ;
162256 if ( Result . isFailure ( remoteCheck ) ) {
257+ this . deps . logger . error ( 'Remote validation failed' , {
258+ destination,
259+ error : remoteCheck . error
260+ } ) ;
163261 return remoteCheck ;
164262 }
165263
@@ -170,6 +268,10 @@ class OptimizedImageUploadCommand implements UploadImageCommand {
170268 ) ;
171269
172270 if ( Result . isFailure ( clipboardResult ) ) {
271+ this . deps . logger . warn ( 'Clipboard check failed in optimized command' , {
272+ destination,
273+ error : clipboardResult . error
274+ } ) ;
173275 vscode . window . showWarningMessage ( clipboardResult . error . message ) ;
174276 return clipboardResult ;
175277 }
@@ -193,14 +295,25 @@ class OptimizedImageUploadCommand implements UploadImageCommand {
193295
194296 private async checkClipboard ( ) : Promise < ExtensionResult < ImageData > > {
195297 try {
298+ const hasImage = await this . deps . clipboard . hasImage ( ) . catch ( error => {
299+ this . deps . logger . debug ( 'hasImage probe failed before getImage' , { error } ) ;
300+ return false ;
301+ } ) ;
302+ this . deps . logger . info ( 'Clipboard probe before getImage' , { hasImage } ) ;
196303 const imageData = await this . deps . clipboard . getImage ( ) ;
197304
198305 if ( ! imageData ) {
306+ this . deps . logger . warn ( 'getImage returned null' ) ;
199307 return failure ( new ClipboardError ( 'No image found in clipboard' ) ) ;
200308 }
201309
310+ this . deps . logger . info ( 'Clipboard image retrieved' , {
311+ format : imageData . format ,
312+ bytes : imageData . buffer . length
313+ } ) ;
202314 return success ( imageData ) ;
203315 } catch ( error ) {
316+ this . deps . logger . error ( 'Clipboard access failed' , { error } ) ;
204317 return failure ( new ClipboardError (
205318 'Failed to access clipboard' ,
206319 { originalError : error }
@@ -215,9 +328,15 @@ class OptimizedImageUploadCommand implements UploadImageCommand {
215328 ) : Promise < ExtensionResult < string > > {
216329 try {
217330 reporter . report ( ProgressSteps . preparing ( ) ) ;
331+ this . deps . logger . debug ( 'Optimized upload and insert start' , {
332+ destination,
333+ format : imageData . format ,
334+ bytes : imageData . buffer . length
335+ } ) ;
218336
219337 // Cleanup old images first based on user configuration
220338 const retentionDays = this . deps . config . getRetentionDays ( ) ;
339+ this . deps . logger . debug ( 'Cleaning old images' , { retentionDays } ) ;
221340 await this . deps . fileManager . cleanupOldImages ( retentionDays ) ;
222341
223342 reporter . report ( ProgressSteps . uploading ( ) ) ;
@@ -227,12 +346,22 @@ class OptimizedImageUploadCommand implements UploadImageCommand {
227346 imageData . buffer ,
228347 imageData . format
229348 ) ;
349+ this . deps . logger . info ( 'Image file created' , {
350+ imagePath : imageFile . getPath ( ) ,
351+ format : imageData . format ,
352+ bytes : imageData . buffer . length
353+ } ) ;
230354
231355 reporter . report ( ProgressSteps . inserting ( ) ) ;
232356
233357 // Insert URL into editor/terminal
234358 const insertResult = await this . insertImageUrl ( imageFile . getPath ( ) , destination ) ;
235359 if ( Result . isFailure ( insertResult ) ) {
360+ this . deps . logger . error ( 'Insertion failed after file creation' , {
361+ destination,
362+ imagePath : imageFile . getPath ( ) ,
363+ error : insertResult . error
364+ } ) ;
236365 imageFile . dispose ( ) ;
237366 return insertResult ;
238367 }
@@ -242,16 +371,22 @@ class OptimizedImageUploadCommand implements UploadImageCommand {
242371 // Clear clipboard if configured to do so
243372 if ( this . deps . config . getClearClipboardAfterUpload ( ) ) {
244373 await this . deps . clipboard . clear ( ) ;
374+ this . deps . logger . debug ( 'Clipboard cleared after upload' ) ;
245375 }
246376
247377 const imageUrl = imageFile . getPath ( ) ;
248378
249379 // Show success message
250380 vscode . window . showInformationMessage ( `Image uploaded: ${ imageUrl } ` ) ;
381+ this . deps . logger . info ( 'Optimized upload command completed successfully' , {
382+ destination,
383+ imageUrl
384+ } ) ;
251385
252386 return success ( imageUrl ) ;
253387
254388 } catch ( error ) {
389+ this . deps . logger . error ( 'Optimized upload and insert threw' , { error, destination } ) ;
255390 return failure ( new FileSystemError (
256391 'Failed to upload image' ,
257392 { originalError : error , destination }
@@ -271,13 +406,9 @@ class OptimizedImageUploadCommand implements UploadImageCommand {
271406 await activeEditor . edit ( editBuilder => {
272407 editBuilder . insert ( position , url ) ;
273408 } ) ;
409+ this . deps . logger . info ( 'Inserted image path into editor' , { url } ) ;
274410 } else if ( destination === 'terminal' ) {
275- const activeTerminal = vscode . window . activeTerminal ;
276- if ( ! activeTerminal ) {
277- return failure ( new FileSystemError ( 'No active terminal available' ) ) ;
278- }
279-
280- activeTerminal . sendText ( url , false ) ;
411+ return await pasteTextIntoActiveTerminal ( url , this . deps . logger ) ;
281412 }
282413
283414 return success ( undefined ) ;
@@ -304,6 +435,17 @@ export async function handleUploadCommand(
304435 const result = await command . execute ( destination ) ;
305436
306437 if ( Result . isFailure ( result ) ) {
438+ deps . logger . error ( 'Command handler returning failure' , {
439+ destination,
440+ error : result . error
441+ } ) ;
442+ deps . logger . show ( true ) ;
307443 vscode . window . showErrorMessage ( `Upload error: ${ result . error . message } ` ) ;
444+ return ;
308445 }
309- }
446+
447+ deps . logger . info ( 'Command handler returning success' , {
448+ destination,
449+ imageUrl : result . data
450+ } ) ;
451+ }
0 commit comments