@cluesmith/codev 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -52,6 +52,18 @@ const langMap = {
52
52
  };
53
53
  const lang = langMap[ext] || ext;
54
54
  const isMarkdown = ext === 'md';
55
+ // Image detection
56
+ const imageExtensions = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'];
57
+ const isImage = imageExtensions.includes(ext);
58
+ // MIME type mapping for images
59
+ const imageMimeTypes = {
60
+ png: 'image/png',
61
+ jpg: 'image/jpeg',
62
+ jpeg: 'image/jpeg',
63
+ gif: 'image/gif',
64
+ webp: 'image/webp',
65
+ svg: 'image/svg+xml'
66
+ };
55
67
  // Create server
56
68
  const server = http.createServer((req, res) => {
57
69
  // CORS headers
@@ -67,18 +79,29 @@ const server = http.createServer((req, res) => {
67
79
  if (req.method === 'GET' && (req.url === '/' || req.url === '/index.html')) {
68
80
  try {
69
81
  let template = fs.readFileSync(templatePath, 'utf-8');
70
- const fileContent = fs.readFileSync(fullFilePath, 'utf-8');
82
+ // Get file stats for images
83
+ const fileStats = fs.statSync(fullFilePath);
84
+ const fileSize = fileStats.size;
71
85
  // Replace placeholders
72
86
  template = template.replace(/\{\{BUILDER_ID\}\}/g, '');
73
87
  template = template.replace(/\{\{FILE_PATH\}\}/g, fullFilePath);
74
88
  template = template.replace(/\{\{FILE\}\}/g, displayPath);
75
89
  template = template.replace(/\{\{LANG\}\}/g, lang);
76
90
  template = template.replace(/\{\{IS_MARKDOWN\}\}/g, String(isMarkdown));
77
- // Inject file content
78
- // JSON.stringify escapes quotes but not </script> which would break HTML parsing
79
- // Replace </script> with <\/script> (valid JS, doesn't match HTML closing tag)
80
- const escapedContent = JSON.stringify(fileContent).replace(/<\/script>/gi, '<\\/script>');
81
- template = template.replace('// FILE_CONTENT will be injected by the server', `init(${escapedContent});`);
91
+ template = template.replace(/\{\{IS_IMAGE\}\}/g, String(isImage));
92
+ template = template.replace(/\{\{FILE_SIZE\}\}/g, String(fileSize));
93
+ if (isImage) {
94
+ // For images, don't inject file content - it will be loaded via /api/image
95
+ template = template.replace('// FILE_CONTENT will be injected by the server', `initImage(${fileSize});`);
96
+ }
97
+ else {
98
+ // For text files, inject content as before
99
+ const fileContent = fs.readFileSync(fullFilePath, 'utf-8');
100
+ // JSON.stringify escapes quotes but not </script> which would break HTML parsing
101
+ // Replace </script> with <\/script> (valid JS, doesn't match HTML closing tag)
102
+ const escapedContent = JSON.stringify(fileContent).replace(/<\/script>/gi, '<\\/script>');
103
+ template = template.replace('// FILE_CONTENT will be injected by the server', `init(${escapedContent});`);
104
+ }
82
105
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
83
106
  res.end(template);
84
107
  }
@@ -102,6 +125,30 @@ const server = http.createServer((req, res) => {
102
125
  }
103
126
  return;
104
127
  }
128
+ // Handle image content (GET /api/image)
129
+ // Use startsWith to allow query params like ?t=123 for cache busting
130
+ if (req.method === 'GET' && req.url?.startsWith('/api/image')) {
131
+ if (!isImage) {
132
+ res.writeHead(400, { 'Content-Type': 'text/plain' });
133
+ res.end('Not an image file');
134
+ return;
135
+ }
136
+ try {
137
+ const imageData = fs.readFileSync(fullFilePath);
138
+ const mimeType = imageMimeTypes[ext] || 'application/octet-stream';
139
+ res.writeHead(200, {
140
+ 'Content-Type': mimeType,
141
+ 'Content-Length': imageData.length,
142
+ 'Cache-Control': 'no-cache' // Don't cache, allow reload to work
143
+ });
144
+ res.end(imageData);
145
+ }
146
+ catch (err) {
147
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
148
+ res.end('Error reading image: ' + err.message);
149
+ }
150
+ return;
151
+ }
105
152
  // Handle file save
106
153
  if (req.method === 'POST' && req.url === '/save') {
107
154
  let body = '';
@@ -1 +1 @@
1
- {"version":3,"file":"open-server.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/open-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"open-server.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/open-server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cluesmith/codev",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Codev CLI - AI-assisted software development framework",
5
5
  "type": "module",
6
6
  "bin": {
@@ -284,12 +284,75 @@
284
284
  .annotation-item:hover { background: #2a2a2a; }
285
285
  .annotation-item .line { color: #3b82f6; font-size: 12px; }
286
286
  .annotation-item .text { font-size: 13px; margin-top: 4px; }
287
+
288
+ /* Image Viewer */
289
+ #image-viewer {
290
+ display: none;
291
+ flex-direction: column;
292
+ height: calc(100vh - 80px);
293
+ padding: 15px;
294
+ }
295
+ .image-controls {
296
+ display: flex;
297
+ align-items: center;
298
+ gap: 8px;
299
+ padding: 10px 0;
300
+ flex-shrink: 0;
301
+ }
302
+ .image-controls .btn {
303
+ padding: 6px 12px;
304
+ border-radius: 4px;
305
+ border: none;
306
+ cursor: pointer;
307
+ font-size: 12px;
308
+ background: #444;
309
+ color: #fff;
310
+ }
311
+ .image-controls .btn:hover { opacity: 0.9; }
312
+ .image-controls .btn.active {
313
+ background: #3b82f6;
314
+ }
315
+ #image-info {
316
+ color: #888;
317
+ font-size: 12px;
318
+ margin-left: auto;
319
+ }
320
+ .image-container {
321
+ flex: 1;
322
+ overflow: auto;
323
+ display: flex;
324
+ align-items: center;
325
+ justify-content: center;
326
+ background: #222;
327
+ border-radius: 4px;
328
+ }
329
+ .image-container.zoom-fit img {
330
+ max-width: 100%;
331
+ max-height: 100%;
332
+ width: auto;
333
+ height: auto;
334
+ object-fit: contain;
335
+ }
336
+ .image-container.zoom-100 img,
337
+ .image-container.zoom-custom img {
338
+ max-width: none;
339
+ max-height: none;
340
+ }
341
+ #image-display {
342
+ transition: transform 0.1s ease;
343
+ }
344
+ #image-error {
345
+ color: #ef4444;
346
+ text-align: center;
347
+ padding: 40px;
348
+ }
287
349
  </style>
288
350
  </head>
289
- <body data-builder="{{BUILDER_ID}}" data-file="{{FILE_PATH}}" data-lang="{{LANG}}">
351
+ <body data-builder="{{BUILDER_ID}}" data-file="{{FILE_PATH}}" data-lang="{{LANG}}" data-is-image="{{IS_IMAGE}}" data-file-size="{{FILE_SIZE}}">
290
352
  <div class="header">
291
353
  <h1 class="path">{{FILE_PATH}}</h1>
292
- <div class="subtitle">Click on a line number to leave an annotation.</div>
354
+ <div class="subtitle" id="subtitle">Click on a line number to leave an annotation.</div>
355
+ <div id="image-header-info" style="display: none; color: #888; font-size: 12px; margin-top: 4px;"></div>
293
356
  <div class="actions">
294
357
  <button id="reloadBtn" class="btn btn-secondary" onclick="reloadFile()" title="Reload from disk" aria-label="Reload file from disk">↻</button>
295
358
  <button id="togglePreviewBtn" class="btn btn-secondary" style="display: none;" title="Toggle Preview (Cmd+Shift+P)">
@@ -309,6 +372,22 @@
309
372
  <!-- Markdown preview mode -->
310
373
  <div id="preview-container" style="display: none; padding: 20px; overflow: auto; height: calc(100vh - 80px);"></div>
311
374
 
375
+ <!-- Image viewer mode -->
376
+ <div id="image-viewer">
377
+ <div class="image-controls">
378
+ <button id="zoomFitBtn" class="btn active" onclick="zoomFit()">Fit</button>
379
+ <button id="zoom100Btn" class="btn" onclick="zoom100()">100%</button>
380
+ <button id="zoomInBtn" class="btn" onclick="zoomIn()">+</button>
381
+ <button id="zoomOutBtn" class="btn" onclick="zoomOut()">−</button>
382
+ <span id="zoom-level"></span>
383
+ <span id="image-info"></span>
384
+ </div>
385
+ <div class="image-container zoom-fit" id="image-container">
386
+ <img id="image-display" alt="Image preview" />
387
+ <div id="image-error" style="display: none;"></div>
388
+ </div>
389
+ </div>
390
+
312
391
  <!-- Editor mode -->
313
392
  <textarea id="editor" spellcheck="false"></textarea>
314
393
 
@@ -362,6 +441,13 @@
362
441
  const isMarkdownFile = {{IS_MARKDOWN}};
363
442
  let isPreviewMode = false;
364
443
 
444
+ // Image viewer state
445
+ const isImageFile = {{IS_IMAGE}};
446
+ let currentZoomMode = 'fit'; // 'fit', '100', 'custom'
447
+ let currentZoomLevel = 1.0;
448
+ let imageNaturalWidth = 0;
449
+ let imageNaturalHeight = 0;
450
+
365
451
  // Comment patterns by file extension
366
452
  const COMMENT_PATTERNS = {
367
453
  js: { prefix: '// REVIEW', regex: /^(\s*)\/\/\s*REVIEW(\(@\w+\))?:\s*(.*)$/ },
@@ -403,6 +489,147 @@
403
489
  }
404
490
  }
405
491
 
492
+ // Initialize image viewer
493
+ function initImage(fileSize) {
494
+ // Hide code view elements
495
+ document.getElementById('viewMode').style.display = 'none';
496
+ document.getElementById('editBtn').style.display = 'none';
497
+ document.getElementById('togglePreviewBtn').style.display = 'none';
498
+
499
+ // Update subtitle
500
+ document.querySelector('.subtitle').textContent = 'Image viewer - use zoom controls to adjust view.';
501
+
502
+ // Show image viewer
503
+ const imageViewer = document.getElementById('image-viewer');
504
+ imageViewer.style.display = 'flex';
505
+
506
+ // Load image
507
+ const img = document.getElementById('image-display');
508
+ const imageError = document.getElementById('image-error');
509
+
510
+ img.onload = function() {
511
+ imageNaturalWidth = img.naturalWidth;
512
+ imageNaturalHeight = img.naturalHeight;
513
+ updateImageInfo(fileSize);
514
+ imageError.style.display = 'none';
515
+ img.style.display = 'block';
516
+ };
517
+
518
+ img.onerror = function() {
519
+ imageError.textContent = 'Failed to load image. The file may be corrupted.';
520
+ imageError.style.display = 'block';
521
+ img.style.display = 'none';
522
+ };
523
+
524
+ // Add cache-busting query param to allow reload
525
+ img.src = '/api/image?t=' + Date.now();
526
+ }
527
+
528
+ // Update image info display (in both header and controls)
529
+ function updateImageInfo(fileSize) {
530
+ const sizeStr = formatFileSize(fileSize);
531
+ const infoText = `${imageNaturalWidth} × ${imageNaturalHeight} px · ${sizeStr}`;
532
+
533
+ // Update controls area
534
+ const info = document.getElementById('image-info');
535
+ info.textContent = infoText;
536
+
537
+ // Update header area
538
+ const headerInfo = document.getElementById('image-header-info');
539
+ headerInfo.textContent = infoText;
540
+ headerInfo.style.display = 'block';
541
+ }
542
+
543
+ // Format file size in human-readable form
544
+ function formatFileSize(bytes) {
545
+ if (bytes < 1024) return bytes + ' B';
546
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
547
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
548
+ }
549
+
550
+ // Update zoom level display
551
+ function updateZoomLevelDisplay() {
552
+ const zoomLevelEl = document.getElementById('zoom-level');
553
+ if (currentZoomMode === 'fit') {
554
+ zoomLevelEl.textContent = '';
555
+ } else {
556
+ zoomLevelEl.textContent = Math.round(currentZoomLevel * 100) + '%';
557
+ }
558
+ }
559
+
560
+ // Update active button state
561
+ function updateZoomButtons() {
562
+ document.getElementById('zoomFitBtn').classList.toggle('active', currentZoomMode === 'fit');
563
+ document.getElementById('zoom100Btn').classList.toggle('active', currentZoomMode === '100');
564
+ }
565
+
566
+ // Zoom fit - image fits within container
567
+ function zoomFit() {
568
+ const container = document.getElementById('image-container');
569
+ const img = document.getElementById('image-display');
570
+
571
+ container.className = 'image-container zoom-fit';
572
+ img.style.transform = '';
573
+ img.style.width = '';
574
+ img.style.height = '';
575
+
576
+ currentZoomMode = 'fit';
577
+ currentZoomLevel = 1.0;
578
+ updateZoomButtons();
579
+ updateZoomLevelDisplay();
580
+ }
581
+
582
+ // Zoom 100% - actual pixels
583
+ function zoom100() {
584
+ const container = document.getElementById('image-container');
585
+ const img = document.getElementById('image-display');
586
+
587
+ container.className = 'image-container zoom-100';
588
+ img.style.transform = '';
589
+ img.style.width = imageNaturalWidth + 'px';
590
+ img.style.height = imageNaturalHeight + 'px';
591
+
592
+ currentZoomMode = '100';
593
+ currentZoomLevel = 1.0;
594
+ updateZoomButtons();
595
+ updateZoomLevelDisplay();
596
+ }
597
+
598
+ // Zoom in by 25%
599
+ function zoomIn() {
600
+ if (currentZoomMode === 'fit') {
601
+ // Switch to custom zoom starting at 100%
602
+ currentZoomLevel = 1.0;
603
+ }
604
+ currentZoomLevel = Math.min(currentZoomLevel * 1.25, 10.0); // Max 1000%
605
+ applyCustomZoom();
606
+ }
607
+
608
+ // Zoom out by 20%
609
+ function zoomOut() {
610
+ if (currentZoomMode === 'fit') {
611
+ // Switch to custom zoom starting at 100%
612
+ currentZoomLevel = 1.0;
613
+ }
614
+ currentZoomLevel = Math.max(currentZoomLevel * 0.8, 0.1); // Min 10%
615
+ applyCustomZoom();
616
+ }
617
+
618
+ // Apply custom zoom level
619
+ function applyCustomZoom() {
620
+ const container = document.getElementById('image-container');
621
+ const img = document.getElementById('image-display');
622
+
623
+ container.className = 'image-container zoom-custom';
624
+ img.style.transform = '';
625
+ img.style.width = (imageNaturalWidth * currentZoomLevel) + 'px';
626
+ img.style.height = (imageNaturalHeight * currentZoomLevel) + 'px';
627
+
628
+ currentZoomMode = 'custom';
629
+ updateZoomButtons();
630
+ updateZoomLevelDisplay();
631
+ }
632
+
406
633
  // Toggle between annotated view and preview mode
407
634
  function togglePreviewMode() {
408
635
  // Don't allow preview toggle while in textarea edit mode