@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
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
package/templates/open.html
CHANGED
|
@@ -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
|