claude-dev-server 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.
@@ -158,10 +158,10 @@ html, body {
158
158
  font-family: monospace;
159
159
  white-space: nowrap;
160
160
  }
161
- /* Portrait mode */
161
+ /* Portrait mode - dev on top, ttyd on bottom */
162
162
  @media (orientation: portrait) {
163
163
  .claude-dev-server-container {
164
- flex-direction: column;
164
+ flex-direction: column-reverse;
165
165
  }
166
166
  .claude-dev-server-divider {
167
167
  width: 100%;
@@ -172,9 +172,16 @@ html, body {
172
172
  width: 100%;
173
173
  min-width: unset;
174
174
  max-width: unset;
175
- height: 50%;
175
+ height: 70%;
176
176
  min-height: 200px;
177
177
  }
178
+ .claude-dev-server-left {
179
+ width: 100%;
180
+ min-width: unset;
181
+ max-width: unset;
182
+ height: 30%;
183
+ min-height: 150px;
184
+ }
178
185
  }
179
186
  </style>
180
187
  </head>
@@ -484,13 +491,19 @@ html, body {
484
491
  }
485
492
 
486
493
  function setupDraggable(divider) {
487
- let startX = 0;
488
- let startWidth = 0;
489
- let containerWidth = 0;
494
+ let startValue = 0;
495
+ let startSize = 0;
496
+ let containerSize = 0;
497
+ let isPortrait = window.matchMedia('(orientation: portrait)').matches;
490
498
 
491
499
  divider.addEventListener('mousedown', startDrag);
492
500
  divider.addEventListener('touchstart', startDrag);
493
501
 
502
+ // Listen for orientation changes
503
+ window.matchMedia('(orientation: portrait)').addEventListener('change', (e) => {
504
+ isPortrait = e.matches;
505
+ });
506
+
494
507
  function startDrag(e) {
495
508
  isDragging = true;
496
509
  divider.classList.add('dragging');
@@ -499,14 +512,17 @@ html, body {
499
512
  iframes.forEach(iframe => iframe.style.pointerEvents = 'none');
500
513
 
501
514
  const clientX = e.touches ? e.touches[0].clientX : e.clientX;
502
- startX = clientX;
515
+ const clientY = e.touches ? e.touches[0].clientY : e.clientY;
516
+
517
+ // Use X for landscape (horizontal drag), Y for portrait (vertical drag)
518
+ startValue = isPortrait ? clientY : clientX;
503
519
 
504
520
  const container = document.querySelector('.claude-dev-server-container');
505
521
  const leftPanelEl = document.querySelector('.claude-dev-server-left');
506
522
 
507
523
  if (container && leftPanelEl) {
508
- containerWidth = container.offsetWidth;
509
- startWidth = leftPanelEl.offsetWidth;
524
+ containerSize = isPortrait ? container.offsetHeight : container.offsetWidth;
525
+ startSize = isPortrait ? leftPanelEl.offsetHeight : leftPanelEl.offsetWidth;
510
526
  }
511
527
 
512
528
  e.preventDefault();
@@ -521,16 +537,28 @@ html, body {
521
537
  }
522
538
 
523
539
  const clientX = e.touches ? e.touches[0].clientX : e.clientX;
524
- const deltaX = clientX - startX;
540
+ const clientY = e.touches ? e.touches[0].clientY : e.clientY;
525
541
 
526
- let newWidth = startWidth + deltaX;
527
- let percentage = (newWidth / containerWidth) * 100;
542
+ // Use appropriate axis based on orientation
543
+ const currentValue = isPortrait ? clientY : clientX;
544
+ const delta = currentValue - startValue;
545
+
546
+ let newSize = startSize + delta;
547
+ let percentage = (newSize / containerSize) * 100;
528
548
  const clamped = Math.max(20, Math.min(80, percentage));
529
549
 
530
550
  const leftPanelEl = document.querySelector('.claude-dev-server-left');
531
551
  if (leftPanelEl) {
532
552
  leftPanelEl.style.flex = 'none';
533
- leftPanelEl.style.width = clamped + '%';
553
+ if (isPortrait) {
554
+ // Portrait: adjust height
555
+ leftPanelEl.style.height = clamped + '%';
556
+ leftPanelEl.style.width = '';
557
+ } else {
558
+ // Landscape: adjust width
559
+ leftPanelEl.style.width = clamped + '%';
560
+ leftPanelEl.style.height = '';
561
+ }
534
562
  }
535
563
  }
536
564
 
@@ -348,10 +348,10 @@ html, body {
348
348
  font-family: monospace;
349
349
  white-space: nowrap;
350
350
  }
351
- /* Portrait mode */
351
+ /* Portrait mode - dev on top, ttyd on bottom */
352
352
  @media (orientation: portrait) {
353
353
  .claude-dev-server-container {
354
- flex-direction: column;
354
+ flex-direction: column-reverse;
355
355
  }
356
356
  .claude-dev-server-divider {
357
357
  width: 100%;
@@ -362,9 +362,16 @@ html, body {
362
362
  width: 100%;
363
363
  min-width: unset;
364
364
  max-width: unset;
365
- height: 50%;
365
+ height: 70%;
366
366
  min-height: 200px;
367
367
  }
368
+ .claude-dev-server-left {
369
+ width: 100%;
370
+ min-width: unset;
371
+ max-width: unset;
372
+ height: 30%;
373
+ min-height: 150px;
374
+ }
368
375
  }
369
376
  </style>
370
377
  `;
@@ -1085,9 +1092,10 @@ var CLIENT_SCRIPT = `
1085
1092
  }
1086
1093
 
1087
1094
  function setupDraggable(divider) {
1088
- let startX = 0
1089
- let startWidth = 0
1090
- let containerWidth = 0
1095
+ let startValue = 0
1096
+ let startSize = 0
1097
+ let containerSize = 0
1098
+ let isPortrait = window.matchMedia('(orientation: portrait)').matches
1091
1099
 
1092
1100
  // Remove existing listeners to avoid duplicates
1093
1101
  divider.removeEventListener('mousedown', startDrag)
@@ -1096,6 +1104,11 @@ var CLIENT_SCRIPT = `
1096
1104
  divider.addEventListener('mousedown', startDrag)
1097
1105
  divider.addEventListener('touchstart', startDrag)
1098
1106
 
1107
+ // Listen for orientation changes
1108
+ window.matchMedia('(orientation: portrait)').addEventListener('change', (e) => {
1109
+ isPortrait = e.matches
1110
+ })
1111
+
1099
1112
  function startDrag(e) {
1100
1113
  isDragging = true
1101
1114
  divider.classList.add('dragging')
@@ -1105,14 +1118,17 @@ var CLIENT_SCRIPT = `
1105
1118
  iframes.forEach(iframe => iframe.style.pointerEvents = 'none')
1106
1119
 
1107
1120
  const clientX = e.touches ? e.touches[0].clientX : e.clientX
1108
- startX = clientX
1121
+ const clientY = e.touches ? e.touches[0].clientY : e.clientY
1122
+
1123
+ // Use X for landscape (horizontal drag), Y for portrait (vertical drag)
1124
+ startValue = isPortrait ? clientY : clientX
1109
1125
 
1110
1126
  const container = document.querySelector('.claude-dev-server-container')
1111
1127
  const leftPanelEl = document.querySelector('.claude-dev-server-left')
1112
1128
 
1113
1129
  if (container && leftPanelEl) {
1114
- containerWidth = container.offsetWidth
1115
- startWidth = leftPanelEl.offsetWidth
1130
+ containerSize = isPortrait ? container.offsetHeight : container.offsetWidth
1131
+ startSize = isPortrait ? leftPanelEl.offsetHeight : leftPanelEl.offsetWidth
1116
1132
  }
1117
1133
 
1118
1134
  e.preventDefault()
@@ -1128,11 +1144,15 @@ var CLIENT_SCRIPT = `
1128
1144
  }
1129
1145
 
1130
1146
  const clientX = e.touches ? e.touches[0].clientX : e.clientX
1131
- const deltaX = clientX - startX
1147
+ const clientY = e.touches ? e.touches[0].clientY : e.clientY
1148
+
1149
+ // Use appropriate axis based on orientation
1150
+ const currentValue = isPortrait ? clientY : clientX
1151
+ const delta = currentValue - startValue
1132
1152
 
1133
- // Calculate new width in pixels, then convert to percentage
1134
- let newWidth = startWidth + deltaX
1135
- let percentage = (newWidth / containerWidth) * 100
1153
+ // Calculate new size in pixels, then convert to percentage
1154
+ let newSize = startSize + delta
1155
+ let percentage = (newSize / containerSize) * 100
1136
1156
 
1137
1157
  // Clamp between 20% and 80%
1138
1158
  const clamped = Math.max(20, Math.min(80, percentage))
@@ -1140,7 +1160,15 @@ var CLIENT_SCRIPT = `
1140
1160
  const leftPanelEl = document.querySelector('.claude-dev-server-left')
1141
1161
  if (leftPanelEl) {
1142
1162
  leftPanelEl.style.flex = 'none'
1143
- leftPanelEl.style.width = clamped + '%'
1163
+ if (isPortrait) {
1164
+ // Portrait: adjust height
1165
+ leftPanelEl.style.height = clamped + '%'
1166
+ leftPanelEl.style.width = ''
1167
+ } else {
1168
+ // Landscape: adjust width
1169
+ leftPanelEl.style.width = clamped + '%'
1170
+ leftPanelEl.style.height = ''
1171
+ }
1144
1172
  }
1145
1173
  }
1146
1174
 
@@ -1865,5 +1893,5 @@ function injectScripts(html, wsPort, projectRoot) {
1865
1893
  }
1866
1894
 
1867
1895
  export { startUniversalServer };
1868
- //# sourceMappingURL=chunk-PAE5WTS2.js.map
1869
- //# sourceMappingURL=chunk-PAE5WTS2.js.map
1896
+ //# sourceMappingURL=chunk-PZVR2URG.js.map
1897
+ //# sourceMappingURL=chunk-PZVR2URG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/pty.ts","../src/server/source-map.ts","../src/server/websocket.ts","../src/client/injection.js","../src/universal/index.ts"],"names":["resolve","__filename","spawn","SourceMapConsumer"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAuLtB,IAAM,aAAA,GAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","file":"chunk-PZVR2URG.js","sourcesContent":["import { spawn } from 'child_process'\nimport { randomBytes } from 'crypto'\n\nexport interface PtyOptions {\n cwd: string\n claudePath: string\n args: string[]\n env?: Record<string, string>\n}\n\nexport function spawnClaudeCode(options: PtyOptions) {\n // Generate a random port for ttyd\n const port = 50000 + Math.floor(Math.random() * 10000)\n\n // Start ttyd with claude command\n const ttydProc = spawn('ttyd', [\n '--port', String(port),\n '--interface', '127.0.0.1',\n '--writable',\n options.claudePath,\n ...options.args,\n ], {\n cwd: options.cwd,\n env: {\n ...process.env,\n ...options.env,\n TERM: 'xterm-256color',\n FORCE_COLOR: '1',\n },\n })\n\n ttydProc.on('exit', (code) => {\n console.log(`[claude-dev-server] ttyd exited - code: ${code}`)\n })\n\n ttydProc.on('error', (err) => {\n console.error(`[claude-dev-server] ttyd error: ${err.message}`)\n })\n\n // Wait a bit for ttyd to start, then return the WebSocket URL\n return new Promise<{ wsUrl: string; process: typeof ttydProc; port: number }>((resolve, reject) => {\n ttydProc.stdout?.on('data', (data: Buffer) => {\n const msg = data.toString()\n console.log(`[ttyd] ${msg}`)\n })\n\n ttydProc.stderr?.on('data', (data: Buffer) => {\n const msg = data.toString()\n console.error(`[ttyd stderr] ${msg}`)\n })\n\n // Give ttyd a moment to start\n setTimeout(() => {\n resolve({\n wsUrl: `ws://127.0.0.1:${port}`,\n process: ttydProc,\n port,\n })\n }, 500)\n\n ttydProc.on('error', reject)\n })\n}\n","import { SourceMapConsumer } from 'source-map'\n\nexport interface SourcePosition {\n source: string\n line: number\n column: number\n name?: string\n}\n\nexport interface CodeLocation {\n file: string\n line: number\n column: number\n content?: string\n}\n\n// Store source maps by generated file path\nconst sourceMapCache = new Map<string, SourceMapConsumer>()\n\nexport async function parseSourceMap(sourceMapUrl: string, content: string): Promise<void> {\n try {\n const consumer = await new SourceMapConsumer(content)\n sourceMapCache.set(sourceMapUrl, consumer)\n } catch (err) {\n console.error('Failed to parse source map:', err)\n }\n}\n\nexport async function findOriginalPosition(\n generatedFile: string,\n line: number,\n column: number\n): Promise<SourcePosition | null> {\n const consumer = sourceMapCache.get(generatedFile)\n if (!consumer) {\n return null\n }\n\n try {\n const position = consumer.originalPositionFor({ line, column })\n if (position.source) {\n return {\n source: position.source,\n line: position.line || 1,\n column: position.column || 0,\n name: position.name,\n }\n }\n } catch (err) {\n console.error('Failed to find original position:', err)\n }\n\n return null\n}\n\nexport function generateVSCodeURI(location: CodeLocation): string {\n // Generate VS Code URI scheme for opening files\n // vscode://file/{path}:{line}:{col}\n const filePath = location.file.replace(/\\\\/g, '/')\n return `vscode://file/${filePath}:${location.line}:${location.column}`\n}\n\nexport function formatCodeContext(location: CodeLocation): string {\n return `\n📍 Code Location:\n File: ${location.file}\n Line: ${location.line}\n Column: ${location.column}\n`\n}\n\nexport function clearCache() {\n sourceMapCache.clear()\n}\n","import { WebSocketServer, WebSocket } from 'ws'\nimport { spawnClaudeCode } from './pty.js'\nimport { findOriginalPosition, parseSourceMap, CodeLocation, formatCodeContext } from './source-map.js'\nimport { readFile } from 'fs/promises'\nimport { resolve } from 'path'\n\nexport interface WebSocketServerOptions {\n port?: number\n projectRoot: string\n claudePath: string\n claudeArgs: string[]\n}\n\nexport function createWebSocketServer(options: WebSocketServerOptions) {\n let wss: WebSocketServer | null = null\n let port = options.port || 0\n let ttydInfo: { wsUrl: string; process: any; port: number } | null = null\n\n const start = async (): Promise<{ wsPort: number; ttydPort: number }> => {\n // Start ttyd first\n console.log('[claude-dev-server] Starting ttyd...')\n ttydInfo = await spawnClaudeCode({\n cwd: options.projectRoot,\n claudePath: options.claudePath,\n args: options.claudeArgs,\n })\n console.log(`[claude-dev-server] ttyd running at ${ttydInfo.wsUrl}`)\n\n // Also start a simple WebSocket server for inspect functionality\n return new Promise((resolve, reject) => {\n wss = new WebSocketServer({ port, host: '127.0.0.1' })\n\n wss.on('listening', () => {\n const address = wss!.address()\n if (address && typeof address === 'object') {\n port = address.port\n resolve({ wsPort: port, ttydPort: ttydInfo!.port })\n }\n })\n\n wss.on('error', (err) => {\n reject(err)\n })\n\n wss.on('connection', (ws: WebSocket) => {\n ws.on('message', async (message: Buffer) => {\n try {\n const msg = JSON.parse(message.toString())\n\n if (msg.type === 'inspect') {\n await handleInspect(msg, ws, options.projectRoot)\n } else if (msg.type === 'loadSourceMap') {\n await handleLoadSourceMap(msg, ws, options.projectRoot)\n }\n } catch (err) {\n // Ignore\n }\n })\n\n // Send ready message with ttyd URL\n ws.send(JSON.stringify({\n type: 'ready',\n ttydUrl: ttydInfo!.wsUrl\n }))\n })\n })\n }\n\n const stop = () => {\n ttydInfo?.process.kill()\n wss?.close()\n }\n\n return { start, stop }\n}\n\nasync function handleLoadSourceMap(\n msg: any,\n ws: WebSocket,\n projectRoot: string\n) {\n const { sourceMapUrl } = msg\n try {\n const mapPath = resolve(projectRoot, sourceMapUrl.replace(/^\\//, ''))\n const content = await readFile(mapPath, 'utf-8')\n await parseSourceMap(sourceMapUrl, content)\n ws.send(JSON.stringify({\n type: 'sourceMapLoaded',\n sourceMapUrl,\n success: true\n }))\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'sourceMapLoaded',\n sourceMapUrl,\n success: false,\n error: (err as Error).message\n }))\n }\n}\n\nasync function handleInspect(\n msg: any,\n ws: WebSocket,\n projectRoot: string\n) {\n const { url, line, column, sourceMapUrl } = msg\n\n let location: CodeLocation | null = null\n\n if (sourceMapUrl) {\n const original = await findOriginalPosition(sourceMapUrl, line, column)\n if (original) {\n location = {\n file: resolve(projectRoot, original.source),\n line: original.line,\n column: original.column,\n }\n }\n }\n\n if (!location) {\n const match = url.match(/\\/@fs\\/(.+?)(?:\\?|$)|\\/@vite\\/(.+?)(?:\\?|$)/)\n if (match) {\n location = {\n file: decodeURIComponent(match[1] || match[2]),\n line,\n column,\n }\n }\n }\n\n ws.send(JSON.stringify({\n type: 'inspectResult',\n location: location ? {\n file: location.file,\n line: location.line,\n column: location.column,\n context: formatCodeContext(location)\n } : null\n }))\n}\n","// Client-side script - pure JavaScript (no TypeScript)\n// This file will be injected into the browser\n\n// STYLES FOR SPLIT LAYOUT\nexport const CLIENT_STYLES = `\n<style id=\"claude-dev-server-styles\">\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\nhtml, body {\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: transparent;\n}\n.claude-dev-server-container {\n display: flex;\n width: 100vw;\n height: 100vh;\n overflow: hidden;\n background: transparent;\n}\n.claude-dev-server-left {\n width: 40%;\n min-width: 300px;\n max-width: 60%;\n overflow: hidden;\n position: relative;\n background: #fff;\n display: flex;\n flex-direction: column;\n}\n.claude-dev-server-left iframe {\n width: 100%;\n height: 100%;\n border: none;\n}\n.claude-dev-server-divider {\n width: 6px;\n background: #3e3e3e;\n position: relative;\n cursor: col-resize;\n transition: background 0.2s;\n flex-shrink: 0;\n}\n.claude-dev-server-divider:hover,\n.claude-dev-server-divider.dragging {\n background: #d97757;\n}\n.claude-dev-server-right {\n flex: 1;\n min-width: 300px;\n overflow: hidden;\n position: relative;\n display: flex;\n flex-direction: column;\n}\n.claude-dev-server-terminal {\n flex: 1;\n overflow: hidden;\n position: relative;\n background: #000;\n}\n.claude-dev-server-terminal iframe,\n.claude-dev-server-terminal-iframe {\n width: 100%;\n height: 100%;\n border: none;\n}\n.claude-dev-server-dev-iframe {\n width: 100%;\n height: 100%;\n border: none;\n}\n.claude-dev-server-terminal-header {\n padding: 8px 12px;\n background: #2d2d2d;\n border-bottom: 1px solid #3e3e3e;\n display: flex;\n justify-content: space-between;\n align-items: center;\n user-select: none;\n min-height: 40px;\n}\n.claude-dev-server-title {\n font-weight: 600;\n color: #fff;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Consolas', monospace;\n}\n.claude-dev-server-title svg {\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n}\n.claude-dev-server-actions {\n display: flex;\n gap: 6px;\n}\n.claude-dev-server-btn {\n background: #d97757;\n border: none;\n color: #fff;\n cursor: pointer;\n font-family: inherit;\n font-size: 11px;\n padding: 4px 10px;\n border-radius: 3px;\n transition: background 0.15s;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.claude-dev-server-btn:hover {\n background: #c96a4a;\n}\n.claude-dev-server-btn.active {\n background: #b85d3f;\n color: #fff;\n}\n.claude-dev-server-inspect-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n z-index: 2147483646;\n display: none;\n}\n.claude-dev-server-inspect-overlay.active {\n display: block;\n}\n.claude-dev-server-highlight {\n position: absolute;\n border: 2px solid #007acc;\n background: rgba(0, 122, 204, 0.1);\n pointer-events: none;\n transition: all 0.1s ease;\n}\n.claude-dev-server-highlight::after {\n content: attr(data-element);\n position: absolute;\n top: -20px;\n left: 0;\n background: #007acc;\n color: #fff;\n font-size: 10px;\n padding: 2px 4px;\n border-radius: 2px 2px 0 0;\n font-family: monospace;\n white-space: nowrap;\n}\n/* Portrait mode - dev on top, ttyd on bottom */\n@media (orientation: portrait) {\n .claude-dev-server-container {\n flex-direction: column-reverse;\n }\n .claude-dev-server-divider {\n width: 100%;\n height: 6px;\n cursor: row-resize;\n }\n .claude-dev-server-right {\n width: 100%;\n min-width: unset;\n max-width: unset;\n height: 70%;\n min-height: 200px;\n }\n .claude-dev-server-left {\n width: 100%;\n min-width: unset;\n max-width: unset;\n height: 30%;\n min-height: 150px;\n }\n}\n</style>\n`\n\n// NEW CLIENT SCRIPT FOR SPLIT LAYOUT\nexport const CLIENT_SCRIPT = `\n(() => {\n let ws = null\n let ttydIframe = null\n let devIframe = null\n let overlay = null\n let isInspectMode = false\n let ttydWsUrl = null\n let leftPanel = null\n let divider = null\n let rightPanel = null\n let isDragging = false\n let inspectListenersRegistered = false\n\n // Fetch the WebSocket port from the server\n async function getWsPort() {\n const res = await fetch('/@claude-port')\n const data = await res.json()\n return data.port\n }\n\n async function initWhenReady() {\n try {\n const port = await getWsPort()\n connect(port)\n } catch (err) {\n console.error('[Claude Dev Server] Failed to get port:', err)\n setTimeout(initWhenReady, 1000)\n return\n }\n // Create overlay first before split layout\n createOverlay()\n createSplitLayout()\n }\n\n function createSplitLayout() {\n // IMPORTANT: Only create layout in the top-level window, not in iframes\n // This prevents infinite nesting when the dev iframe loads\n if (window.top !== window.self) {\n console.log('[Claude Dev Server] Not in top window, skipping layout creation')\n return\n }\n\n // Check if already created\n if (document.querySelector('.claude-dev-server-container')) return\n // Also check if we're already in an injected page\n if (window.__CLAUDE_SPLIT_LAYOUT_CREATED__) return\n window.__CLAUDE_SPLIT_LAYOUT_CREATED__ = true\n\n // Get original HTML from window variable (set by server)\n // The HTML is Base64 encoded to avoid any escaping issues\n let originalHtml\n if (window.__CLAUDE_ORIGINAL_HTML_BASE64__) {\n // Decode Base64\n try {\n const decoded = atob(window.__CLAUDE_ORIGINAL_HTML_BASE64__)\n // Handle UTF-8 encoding\n const bytes = new Uint8Array(decoded.length)\n for (let i = 0; i < decoded.length; i++) {\n bytes[i] = decoded.charCodeAt(i)\n }\n originalHtml = new TextDecoder().decode(bytes)\n } catch (e) {\n console.error('[Claude Dev Server] Failed to decode Base64 HTML:', e)\n originalHtml = document.documentElement.outerHTML\n }\n } else {\n originalHtml = document.documentElement.outerHTML\n }\n\n // Create container\n const container = document.createElement('div')\n container.className = 'claude-dev-server-container'\n\n // Left panel - terminal (Claude)\n leftPanel = document.createElement('div')\n leftPanel.className = 'claude-dev-server-left'\n\n // Terminal header\n const header = document.createElement('div')\n header.className = 'claude-dev-server-terminal-header'\n header.innerHTML = \\`\n <span class=\"claude-dev-server-title\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M11.376 24L10.776 23.544L10.44 22.8L10.776 21.312L11.16 19.392L11.472 17.856L11.76 15.96L11.928 15.336L11.904 15.288L11.784 15.312L10.344 17.28L8.16 20.232L6.432 22.056L6.024 22.224L5.304 21.864L5.376 21.192L5.784 20.616L8.16 17.568L9.6 15.672L10.536 14.592L10.512 14.448H10.464L4.128 18.576L3 18.72L2.496 18.264L2.568 17.52L2.808 17.28L4.704 15.96L9.432 13.32L9.504 13.08L9.432 12.96H9.192L8.4 12.912L5.712 12.84L3.384 12.744L1.104 12.624L0.528 12.504L0 11.784L0.048 11.424L0.528 11.112L1.224 11.16L2.736 11.28L5.016 11.424L6.672 11.52L9.12 11.784H9.504L9.552 11.616L9.432 11.52L9.336 11.424L6.96 9.84L4.416 8.16L3.072 7.176L2.352 6.672L1.992 6.216L1.848 5.208L2.496 4.488L3.384 4.56L3.6 4.608L4.488 5.304L6.384 6.768L8.88 8.616L9.24 8.904L9.408 8.808V8.736L9.24 8.472L7.896 6.024L6.456 3.528L5.808 2.496L5.64 1.872C5.576 1.656 5.544 1.416 5.544 1.152L6.288 0.144001L6.696 0L7.704 0.144001L8.112 0.504001L8.736 1.92L9.72 4.152L11.28 7.176L11.736 8.088L11.976 8.904L12.072 9.168H12.24V9.024L12.36 7.296L12.6 5.208L12.84 2.52L12.912 1.752L13.296 0.840001L14.04 0.360001L14.616 0.624001L15.096 1.32L15.024 1.752L14.76 3.6L14.184 6.504L13.824 8.472H14.04L14.28 8.208L15.264 6.912L16.92 4.848L17.64 4.032L18.504 3.12L19.056 2.688H20.088L20.832 3.816L20.496 4.992L19.44 6.336L18.552 7.464L17.28 9.168L16.512 10.536L16.584 10.632H16.752L19.608 10.008L21.168 9.744L22.992 9.432L23.832 9.816L23.928 10.2L23.592 11.016L21.624 11.496L19.32 11.952L15.888 12.768L15.84 12.792L15.888 12.864L17.424 13.008L18.096 13.056H19.728L22.752 13.272L23.544 13.8L24 14.424L23.928 14.928L22.704 15.528L21.072 15.144L17.232 14.232L15.936 13.92H15.744V14.016L16.848 15.096L18.84 16.896L21.36 19.224L21.48 19.8L21.168 20.28L20.832 20.232L18.624 18.552L17.76 17.808L15.84 16.2H15.72V16.368L16.152 17.016L18.504 20.544L18.624 21.624L18.456 21.96L17.832 22.176L17.184 22.056L15.792 20.136L14.376 17.952L13.224 16.008L13.104 16.104L12.408 23.352L12.096 23.712L11.376 24Z\" fill=\"#d97757\"/>\n </svg>\n Claude Code\n </span>\n <div class=\"claude-dev-server-actions\">\n <button class=\"claude-dev-server-btn claude-dev-server-btn-inspect\" title=\"Inspect Element\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M19 11V4a2 2 0 00-2-2H4a2 2 0 00-2 2v13a2 2 0 002 2h7\"/>\n <path d=\"M12 12l4.166 10 1.48-4.355L22 16.166 12 12z\"/>\n <path d=\"M18 18l3 3\"/>\n </svg>\n Inspect\n </button>\n </div>\n \\`\n\n const inspectBtn = header.querySelector('.claude-dev-server-btn-inspect')\n inspectBtn.addEventListener('click', () => {\n if (isInspectMode) {\n disableInspectMode()\n } else {\n enableInspectMode()\n }\n })\n\n // Terminal container\n const terminal = document.createElement('div')\n terminal.className = 'claude-dev-server-terminal'\n\n // Ttyd iframe\n ttydIframe = document.createElement('iframe')\n ttydIframe.className = 'claude-dev-server-terminal-iframe'\n ttydIframe.allow = 'clipboard-read; clipboard-write'\n\n terminal.appendChild(ttydIframe)\n leftPanel.appendChild(header)\n leftPanel.appendChild(terminal)\n\n // Divider - draggable\n divider = document.createElement('div')\n divider.className = 'claude-dev-server-divider'\n setupDraggable(divider)\n\n // Right panel - dev server\n rightPanel = document.createElement('div')\n rightPanel.className = 'claude-dev-server-right'\n\n // Create dev server iframe with srcdoc\n devIframe = document.createElement('iframe')\n devIframe.className = 'claude-dev-server-dev-iframe'\n // The HTML already has inspect script injected by server\n devIframe.srcdoc = originalHtml\n\n rightPanel.appendChild(devIframe)\n\n // Assemble layout: Claude (left) | divider | dev server (right)\n container.appendChild(leftPanel)\n container.appendChild(divider)\n container.appendChild(rightPanel)\n\n // Replace body content\n document.body.innerHTML = ''\n document.body.appendChild(container)\n document.body.appendChild(overlay)\n\n // Wait for iframe to load before setting up communication\n devIframe.onload = () => {\n console.log('[Claude Dev Server] Dev iframe loaded')\n // Setup inspect mode communication\n setupInspectCommunication()\n }\n }\n\n function setupInspectCommunication() {\n // Inspect mode is now handled entirely in the outer layer\n // We'll access the iframe's document directly\n }\n\n function setupIframeInspectListeners() {\n if (!devIframe || !devIframe.contentDocument) return\n\n // Prevent duplicate listener registration\n if (inspectListenersRegistered) {\n return\n }\n\n const iframeDoc = devIframe.contentDocument\n const iframeWindow = devIframe.contentWindow\n\n const inspectHandler = (e) => {\n if (!isInspectMode) return\n\n e.preventDefault()\n e.stopPropagation()\n\n if (e.type === 'click') {\n const el = e.target\n const rect = el.getBoundingClientRect()\n const className = el.className ? String(el.className) : ''\n // Limit classnames to first 2-3 to avoid overly long selectors\n const classNames = className.split(' ').filter(c => c).slice(0, 3)\n const selector = el.tagName.toLowerCase() +\n (el.id ? '#' + el.id : '') +\n (classNames.length ? '.' + classNames.join('.') : '')\n\n // Highlight element\n if (overlay) {\n overlay.innerHTML = ''\n\n // Get iframe position on page\n const iframeRect = devIframe.getBoundingClientRect()\n\n // Calculate highlight position relative to main document\n // Element rect is relative to iframe viewport, need to add iframe position\n const highlightTop = iframeRect.top + rect.top\n const highlightLeft = iframeRect.left + rect.left\n\n const highlight = document.createElement('div')\n highlight.className = 'claude-dev-server-highlight'\n highlight.style.top = highlightTop + 'px'\n highlight.style.left = highlightLeft + 'px'\n highlight.style.width = rect.width + 'px'\n highlight.style.height = rect.height + 'px'\n highlight.dataset.element = selector\n overlay.appendChild(highlight)\n }\n\n // Get source location and send to terminal\n getSourceLocationFromElement(el).then(location => {\n if (location) {\n sendToTerminal(location)\n }\n disableInspectMode()\n })\n } else if (e.type === 'mousemove') {\n const el = e.target\n const rect = el.getBoundingClientRect()\n const className = el.className ? String(el.className) : ''\n // Limit classnames to first 2-3 to avoid overly long selectors\n const classNames = className.split(' ').filter(c => c).slice(0, 3)\n const selector = el.tagName.toLowerCase() +\n (el.id ? '#' + el.id : '') +\n (classNames.length ? '.' + classNames.join('.') : '')\n\n if (overlay) {\n overlay.innerHTML = ''\n\n // Get iframe position on page\n const iframeRect = devIframe.getBoundingClientRect()\n\n // Calculate highlight position relative to main document\n const highlightTop = iframeRect.top + rect.top\n const highlightLeft = iframeRect.left + rect.left\n\n const highlight = document.createElement('div')\n highlight.className = 'claude-dev-server-highlight'\n highlight.style.top = highlightTop + 'px'\n highlight.style.left = highlightLeft + 'px'\n highlight.style.width = rect.width + 'px'\n highlight.style.height = rect.height + 'px'\n highlight.dataset.element = selector\n overlay.appendChild(highlight)\n }\n }\n }\n\n // Store handler reference for later removal\n iframeDoc._claudeInspectHandler = inspectHandler\n\n // Add event listeners in capture phase\n iframeDoc.addEventListener('click', inspectHandler, true)\n iframeDoc.addEventListener('mousemove', inspectHandler, true)\n\n // Mark listeners as registered\n inspectListenersRegistered = true\n }\n\n async function handleInspectElement(elementInfo) {\n // This is now handled directly in setupIframeInspectListeners\n }\n\n async function getSourceLocationFromElement(element) {\n // Access the iframe's document to detect Next.js chunks\n const iframeDoc = devIframe?.contentDocument || document\n\n // Early check: detect Next.js by checking for _next/static chunks\n const hasNextJsChunks = Array.from(iframeDoc.querySelectorAll('script[src]'))\n .some(script => script.getAttribute('src')?.includes('/_next/static/chunks/'))\n\n if (hasNextJsChunks) {\n console.log('[Claude Dev Server] Next.js Turbopack detected, using specialized lookup')\n\n const pagePath = window.location.pathname\n console.log('[Claude Dev Server] Looking up source for page:', pagePath)\n\n try {\n const params = new URLSearchParams({\n page: pagePath,\n framework: 'nextjs'\n })\n const lookupUrl = '/@sourcemap-lookup?' + params.toString()\n console.log('[Claude Dev Server] Fetching:', lookupUrl)\n\n const response = await fetch(lookupUrl)\n console.log('[Claude Dev Server] Response status:', response.status)\n\n if (response.ok) {\n const result = await response.json()\n console.log('[Claude Dev Server] Lookup result:', result)\n if (result.file) {\n const elClassName = element.className ? String(element.className) : ''\n // Limit classnames to first 2-3 to avoid overly long selectors\n const classNames = elClassName.split(' ').filter(c => c).slice(0, 3)\n const selector = element.tagName.toLowerCase() +\n (element.id ? '#' + element.id : '') +\n (classNames.length ? '.' + classNames.join('.') : '')\n\n // Extract text content from element\n let textContent = ''\n if (element.nodeType === Node.TEXT_NODE) {\n textContent = element.textContent ? element.textContent.trim().substring(0, 50) : ''\n } else if (element.childNodes.length === 1 && element.childNodes[0].nodeType === Node.TEXT_NODE) {\n textContent = element.childNodes[0].textContent ? element.childNodes[0].textContent.trim().substring(0, 50) : ''\n } else {\n for (const child of element.childNodes) {\n if (child.nodeType === Node.TEXT_NODE && child.textContent && child.textContent.trim()) {\n textContent = child.textContent.trim().substring(0, 50)\n break\n }\n }\n }\n if (textContent && textContent.length >= 50) {\n textContent += '...'\n }\n\n return {\n url: result.file,\n line: result.line || undefined,\n column: result.column || undefined,\n selector: selector,\n text: textContent,\n hint: 'File: ' + result.file\n }\n }\n }\n } catch (e) {\n console.log('[Claude Dev Server] Next.js lookup failed:', e)\n }\n // If Next.js lookup failed, continue with normal flow\n }\n\n let sourceFile = null\n let sourceLine = 1\n let sourceColumn = 1\n\n // Try to get original line number using source map\n // Use server-side source map resolution with source-map library\n async function resolveSourceMap(filePath, line, column) {\n try {\n console.log('[Claude Dev Server] Calling server source map resolution for:', filePath, line, column)\n\n // Convert absolute file path to URL path for Vite\n let urlPath = filePath\n if (filePath.startsWith('/Users/')) {\n // Convert /Users/.../src/App.jsx to /src/App.jsx\n const parts = filePath.split('/')\n const srcIndex = parts.indexOf('src')\n if (srcIndex >= 0) {\n urlPath = '/' + parts.slice(srcIndex).join('/')\n }\n }\n\n console.log('[Claude Dev Server] Converted path to URL path:', urlPath)\n\n // Use the server-side source map resolution with URL path\n const params = new URLSearchParams({\n file: urlPath,\n line: String(line),\n col: String(column)\n })\n\n const response = await fetch('/@sourcemap?' + params.toString())\n if (!response.ok) {\n console.log('[Claude Dev Server] Source map request failed:', response.status)\n return null\n }\n\n const result = await response.json()\n console.log('[Claude Dev Server] Source map result:', result)\n\n if (result.error) {\n console.log('[Claude Dev Server] Source map error:', result.error)\n return null\n }\n\n if (result.file) {\n return {\n file: result.file,\n line: result.line,\n column: result.column\n }\n }\n\n return null\n } catch (e) {\n console.log('[Claude Dev Server] Source map lookup failed:', e.message)\n return null\n }\n }\n\n // Try to extract jsxDEV source location from React Fiber\n function extractJsxDevLocation(fiber) {\n try {\n // The jsxDEV location is stored in the element type's _debugInfo or _source\n // React 18 stores it differently - let's check multiple locations\n const elementType = fiber.elementType || fiber.type\n\n // Check if this is a jsxDEV call by looking at the string representation\n if (elementType && typeof elementType === 'function') {\n const fnStr = elementType.toString()\n // jsxDEV functions have a specific pattern\n if (fnStr.includes('jsxDEV') || fnStr.includes('jsx')) {\n console.log('[Claude Dev Server] Found jsxDEV element type')\n }\n }\n\n // Try to get _debugSource which might have jsxDEV metadata\n const debugSource = fiber._debugSource || fiber._debugInfo\n if (debugSource) {\n // For jsxDEV, check if there's a _source object with fileName/lineNumber\n const source = debugSource._source || debugSource.source || debugSource\n if (source && source.fileName && source.lineNumber !== undefined) {\n console.log('[Claude Dev Server] Found _debugSource with source location:', source)\n // NOTE: Don't use this directly! The lineNumber might be from transpiled code\n // We'll let the source map resolver handle it\n return null\n }\n }\n\n // Check the memoizedState or other properties for source location\n if (fiber.memoizedState) {\n // React might store jsxDEV location in memoizedState\n console.log('[Claude Dev Server] Checking memoizedState:', fiber.memoizedState)\n }\n\n // Check the memoizedProps or other properties for source location\n if (fiber.memoizedProps && fiber.memoizedProps.__source) {\n const source = fiber.memoizedProps.__source\n console.log('[Claude Dev Server] Found __source in memoizedProps:', source)\n return {\n file: source.fileName,\n line: source.lineNumber,\n column: source.columnNumber || 1\n }\n }\n\n // Check pendingProps for __source\n if (fiber.pendingProps && fiber.pendingProps.__source) {\n const source = fiber.pendingProps.__source\n console.log('[Claude Dev Server] Found __source in pendingProps:', source)\n return {\n file: source.fileName,\n line: source.lineNumber,\n column: source.columnNumber || 1\n }\n }\n } catch (e) {\n console.log('[Claude Dev Server] Error extracting jsxDEV location:', e)\n }\n return null\n }\n\n // Try React DevTools - handle React 18's randomized suffix\n const elKeys = Object.keys(element)\n let fiberKey = elKeys.find(k => k === '__reactFiber__' || k === '__reactInternalInstance' || k.indexOf('__reactFiber') === 0)\n let propsKey = elKeys.find(k => k === '__reactProps__' || k.indexOf('__reactProps') === 0)\n\n if (fiberKey) {\n const fiber = element[fiberKey]\n console.log('[Claude Dev Server] Found fiber at key:', fiberKey)\n\n // Log fiber structure for debugging\n console.log('[Claude Dev Server] Fiber structure:', {\n _debugSource: fiber._debugSource,\n elementType: fiber.elementType,\n type: fiber.type,\n memoizedProps: fiber.memoizedProps,\n pendingProps: fiber.pendingProps\n })\n\n // Log _debugSource details\n if (fiber._debugSource) {\n console.log('[Claude Dev Server] _debugSource details:', JSON.stringify(fiber._debugSource, null, 2))\n }\n\n // For Next.js, try to get component name from elementType\n if (!fiber._debugSource && fiber.elementType) {\n const elementType = fiber.elementType\n console.log('[Claude Dev Server] elementType:', elementType)\n console.log('[Claude Dev Server] elementType.name:', elementType.name)\n console.log('[Claude Dev Server] elementType.displayName:', elementType.displayName)\n\n // Try to get the function string to find component name\n if (typeof elementType === 'function') {\n const fnStr = elementType.toString()\n console.log('[Claude Dev Server] elementType function:', fnStr.substring(0, 200))\n }\n }\n\n // First, try to extract jsxDEV source location\n const jsxDevLocation = extractJsxDevLocation(fiber)\n if (jsxDevLocation) {\n sourceFile = jsxDevLocation.file\n sourceLine = jsxDevLocation.line\n sourceColumn = jsxDevLocation.column\n\n // Convert absolute path to relative path\n if (sourceFile.startsWith('/')) {\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n if (projectRoot && sourceFile.startsWith(projectRoot)) {\n sourceFile = sourceFile.substring(projectRoot.length + 1)\n if (sourceFile.startsWith('/')) {\n sourceFile = sourceFile.substring(1)\n }\n }\n }\n console.log('[Claude Dev Server] Using jsxDEV location:', sourceFile, sourceLine)\n } else {\n // Fall back to _debugSource\n const debugSource = fiber._debugSource || fiber.elementType?._debugSource || fiber.type?._debugSource || fiber.alternate?._debugSource\n if (debugSource && debugSource.fileName) {\n sourceFile = debugSource.fileName\n sourceLine = debugSource.lineNumber || 1\n sourceColumn = debugSource.columnNumber || 1\n\n // Convert relative path to absolute path for source map resolution\n let absolutePath = sourceFile\n if (!sourceFile.startsWith('/')) {\n // Relative path - resolve relative to project root\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n absolutePath = projectRoot + '/' + sourceFile\n }\n\n console.log('[Claude Dev Server] Resolving source map for:', absolutePath, 'at line:', sourceLine)\n\n // Use server-side source map resolution\n const original = await resolveSourceMap(absolutePath, sourceLine, sourceColumn)\n if (original) {\n sourceFile = original.file\n sourceLine = original.line\n sourceColumn = original.column\n console.log('[Claude Dev Server] Original location from source map:', sourceFile, sourceLine)\n } else {\n // Source map resolution failed, use the original file\n // Convert absolute path back to relative\n if (absolutePath.startsWith('/')) {\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n if (projectRoot && absolutePath.startsWith(projectRoot)) {\n sourceFile = absolutePath.substring(projectRoot.length + 1)\n if (sourceFile.startsWith('/')) {\n sourceFile = sourceFile.substring(1)\n }\n }\n }\n }\n console.log('[Claude Dev Server] Final React source:', sourceFile, sourceLine)\n } else {\n // Try going up the fiber tree\n let currentFiber = fiber\n let depth = 0\n while (currentFiber && depth < 20) {\n const jsxDevLoc = extractJsxDevLocation(currentFiber)\n if (jsxDevLoc) {\n sourceFile = jsxDevLoc.file\n sourceLine = jsxDevLoc.line\n sourceColumn = jsxDevLoc.column\n\n if (sourceFile.startsWith('/')) {\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n if (projectRoot && sourceFile.startsWith(projectRoot)) {\n sourceFile = sourceFile.substring(projectRoot.length + 1)\n if (sourceFile.startsWith('/')) {\n sourceFile = sourceFile.substring(1)\n }\n }\n }\n console.log('[Claude Dev Server] Found jsxDEV location at depth', depth, ':', sourceFile, sourceLine)\n break\n }\n\n const ds = currentFiber._debugSource || currentFiber.elementType?._debugSource || currentFiber.type?._debugSource\n if (ds && ds.fileName) {\n sourceFile = ds.fileName\n sourceLine = ds.lineNumber || 1\n sourceColumn = ds.columnNumber || 1\n\n // Use server-side source map resolution\n const original = await resolveSourceMap(sourceFile, sourceLine, sourceColumn)\n if (original) {\n sourceFile = original.file\n sourceLine = original.line\n sourceColumn = original.column\n } else {\n // Convert absolute path to relative path using project root\n if (sourceFile.startsWith('/')) {\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n if (projectRoot && sourceFile.startsWith(projectRoot)) {\n sourceFile = sourceFile.substring(projectRoot.length + 1)\n if (sourceFile.startsWith('/')) {\n sourceFile = sourceFile.substring(1)\n }\n }\n }\n }\n console.log('[Claude Dev Server] Found React source at depth', depth, ':', sourceFile, sourceLine)\n break\n }\n currentFiber = currentFiber.return || currentFiber.alternate\n depth++\n }\n }\n }\n }\n\n // Try Vue component\n if (!sourceFile) {\n const vueComponent = element.__vueParentComponent || element.__vnode\n if (vueComponent) {\n const type = vueComponent.type || vueComponent.component\n if (type && type.__file) {\n sourceFile = type.__file\n console.log('[Claude Dev Server] Found Vue source:', sourceFile)\n }\n }\n }\n\n // Try Vite's HMR source map\n if (!sourceFile) {\n // Look for data-vite-dev-id or similar attributes\n const viteId = element.getAttribute('data-vite-dev-id')\n if (viteId) {\n // Extract file path from viteId (remove query params if any)\n const queryIndex = viteId.indexOf('?')\n sourceFile = '/' + (queryIndex >= 0 ? viteId.substring(0, queryIndex) : viteId)\n console.log('[Claude Dev Server] Found Vite ID:', viteId)\n }\n }\n\n // Check for inline script\n if (!sourceFile) {\n const inlineScripts = iframeDoc.querySelectorAll('script:not([src])')\n if (inlineScripts.length > 0) {\n const pathParts = window.location.pathname.split('/')\n const fileName = pathParts[pathParts.length - 1] || 'index.html'\n sourceFile = '/' + fileName\n\n const html = iframeDoc.documentElement.outerHTML\n const elId = element.id ? element.id : ''\n const elClass = element.className ? element.className : ''\n let elPattern\n if (elId) {\n elPattern = 'id=\"' + elId + '\"'\n } else if (elClass) {\n elPattern = 'class=\"' + elClass.split(' ')[0] + '\"'\n } else {\n elPattern = element.tagName.toLowerCase()\n }\n\n const matchIndex = html.indexOf(elPattern)\n if (matchIndex !== -1) {\n const beforeElement = html.substring(0, matchIndex)\n sourceLine = beforeElement.split('\\\\n').length\n }\n }\n }\n\n // Find main script\n if (!sourceFile) {\n const scripts = iframeDoc.querySelectorAll('script[src]')\n for (const script of scripts) {\n const src = script.getAttribute('src')\n if (src && !src.includes('cdn') && !src.includes('node_modules') &&\n (src.includes('/src/') || src.includes('/app.') || src.includes('/main.'))) {\n sourceFile = src\n break\n }\n }\n }\n\n // Fallback\n if (!sourceFile) {\n const pathParts = window.location.pathname.split('/')\n const fileName = pathParts[pathParts.length - 1] || 'index.html'\n sourceFile = '/' + fileName\n }\n\n const elClassName = element.className ? String(element.className) : ''\n // Limit classnames to first 2-3 to avoid overly long selectors\n const classNames = elClassName.split(' ').filter(c => c).slice(0, 3)\n const selector = element.tagName.toLowerCase() +\n (element.id ? '#' + element.id : '') +\n (classNames.length ? '.' + classNames.join('.') : '')\n\n // Get text content for better context\n let textContent = ''\n if (element.nodeType === Node.TEXT_NODE) {\n textContent = element.textContent ? element.textContent.trim().substring(0, 50) : ''\n } else if (element.childNodes.length === 1 && element.childNodes[0].nodeType === Node.TEXT_NODE) {\n textContent = element.childNodes[0].textContent ? element.childNodes[0].textContent.trim().substring(0, 50) : ''\n } else {\n // Try to get first text node from children\n for (const child of element.childNodes) {\n if (child.nodeType === Node.TEXT_NODE && child.textContent && child.textContent.trim()) {\n textContent = child.textContent.trim().substring(0, 50)\n break\n }\n }\n }\n if (textContent && textContent.length >= 50) {\n textContent += '...'\n }\n\n return {\n url: sourceFile,\n line: sourceLine,\n column: sourceColumn,\n selector: selector,\n text: textContent,\n hint: sourceFile ? 'File: ' + sourceFile : 'Element: ' + selector\n }\n }\n\n function setupDraggable(divider) {\n let startValue = 0\n let startSize = 0\n let containerSize = 0\n let isPortrait = window.matchMedia('(orientation: portrait)').matches\n\n // Remove existing listeners to avoid duplicates\n divider.removeEventListener('mousedown', startDrag)\n divider.removeEventListener('touchstart', startDrag)\n\n divider.addEventListener('mousedown', startDrag)\n divider.addEventListener('touchstart', startDrag)\n\n // Listen for orientation changes\n window.matchMedia('(orientation: portrait)').addEventListener('change', (e) => {\n isPortrait = e.matches\n })\n\n function startDrag(e) {\n isDragging = true\n divider.classList.add('dragging')\n\n // Disable pointer events on iframes to prevent interference\n const iframes = document.querySelectorAll('iframe')\n iframes.forEach(iframe => iframe.style.pointerEvents = 'none')\n\n const clientX = e.touches ? e.touches[0].clientX : e.clientX\n const clientY = e.touches ? e.touches[0].clientY : e.clientY\n\n // Use X for landscape (horizontal drag), Y for portrait (vertical drag)\n startValue = isPortrait ? clientY : clientX\n\n const container = document.querySelector('.claude-dev-server-container')\n const leftPanelEl = document.querySelector('.claude-dev-server-left')\n\n if (container && leftPanelEl) {\n containerSize = isPortrait ? container.offsetHeight : container.offsetWidth\n startSize = isPortrait ? leftPanelEl.offsetHeight : leftPanelEl.offsetWidth\n }\n\n e.preventDefault()\n }\n\n function drag(e) {\n if (!isDragging) return\n\n // Safety check: if mouse button is not pressed, end drag\n if (e.buttons === 0 && !e.touches) {\n endDrag()\n return\n }\n\n const clientX = e.touches ? e.touches[0].clientX : e.clientX\n const clientY = e.touches ? e.touches[0].clientY : e.clientY\n\n // Use appropriate axis based on orientation\n const currentValue = isPortrait ? clientY : clientX\n const delta = currentValue - startValue\n\n // Calculate new size in pixels, then convert to percentage\n let newSize = startSize + delta\n let percentage = (newSize / containerSize) * 100\n\n // Clamp between 20% and 80%\n const clamped = Math.max(20, Math.min(80, percentage))\n\n const leftPanelEl = document.querySelector('.claude-dev-server-left')\n if (leftPanelEl) {\n leftPanelEl.style.flex = 'none'\n if (isPortrait) {\n // Portrait: adjust height\n leftPanelEl.style.height = clamped + '%'\n leftPanelEl.style.width = ''\n } else {\n // Landscape: adjust width\n leftPanelEl.style.width = clamped + '%'\n leftPanelEl.style.height = ''\n }\n }\n }\n\n function endDrag() {\n if (isDragging) {\n isDragging = false\n divider.classList.remove('dragging')\n\n // Re-enable pointer events on iframes\n const iframes = document.querySelectorAll('iframe')\n iframes.forEach(iframe => iframe.style.pointerEvents = '')\n }\n }\n\n // Use capture phase to ensure events are caught\n // Remove old listeners first to prevent duplicates\n document.removeEventListener('mousemove', drag, true)\n document.removeEventListener('touchmove', drag, true)\n document.removeEventListener('mouseup', endDrag, true)\n document.removeEventListener('touchend', endDrag, true)\n\n document.addEventListener('mousemove', drag, true)\n document.addEventListener('touchmove', drag, { passive: false, capture: true })\n document.addEventListener('mouseup', endDrag, true)\n document.addEventListener('touchend', endDrag, true)\n }\n\n function createOverlay() {\n if (overlay) return\n overlay = document.createElement('div')\n overlay.className = 'claude-dev-server-inspect-overlay'\n document.body.appendChild(overlay)\n }\n\n function enableInspectMode() {\n isInspectMode = true\n if (overlay) overlay.classList.add('active')\n // Setup inspect listeners on the iframe\n setupIframeInspectListeners()\n // Change cursor in iframe\n if (devIframe && devIframe.contentDocument && devIframe.contentDocument.body) {\n devIframe.contentDocument.body.style.cursor = 'crosshair'\n }\n const btn = document.querySelector('.claude-dev-server-btn-inspect')\n if (btn) btn.classList.add('active')\n }\n\n function disableInspectMode() {\n isInspectMode = false\n if (overlay) {\n overlay.classList.remove('active')\n overlay.innerHTML = ''\n }\n // Restore cursor in iframe\n if (devIframe && devIframe.contentDocument && devIframe.contentDocument.body) {\n devIframe.contentDocument.body.style.cursor = ''\n }\n const btn = document.querySelector('.claude-dev-server-btn-inspect')\n if (btn) btn.classList.remove('active')\n\n // Remove inspect listeners to free up resources\n removeIframeInspectListeners()\n }\n\n function removeIframeInspectListeners() {\n if (!devIframe || !devIframe.contentDocument) return\n\n const iframeDoc = devIframe.contentDocument\n const existingHandler = iframeDoc._claudeInspectHandler\n\n if (existingHandler) {\n iframeDoc.removeEventListener('click', existingHandler, true)\n iframeDoc.removeEventListener('mousemove', existingHandler, true)\n delete iframeDoc._claudeInspectHandler\n inspectListenersRegistered = false\n }\n }\n\n async function sendToTerminal(location) {\n // Use format: @filename <selector> \"text content\" (without line number)\n const filePath = location.url || location.file || 'unknown'\n\n // Build selector - handle Tailwind CSS classes by limiting\n const tagName = location.selector ? location.selector.split(/[.#]/)[0] : 'div'\n let selector = location.selector || tagName\n\n // Get text content for better context\n let textContent = ''\n if (location.text) {\n textContent = location.text\n } else if (location.hint && location.hint.includes('File:')) {\n // No text content available\n }\n\n // Format: @filename <selector> \"text content\" (no line number)\n let prompt = \\`@\\${filePath} <\\${selector}>\\`\n if (textContent) {\n prompt += \\` \"\\${textContent}\"\\`\n }\n\n console.log('[Claude Dev Server] Sending to terminal:', prompt)\n\n // Store the interval ID so we can clear it if needed\n if (!window._claudeSendRetryInterval) {\n window._claudeSendRetryInterval = null\n }\n\n // Clear any existing retry interval\n if (window._claudeSendRetryInterval) {\n clearInterval(window._claudeSendRetryInterval)\n window._claudeSendRetryInterval = null\n }\n\n // Send to terminal with retry logic\n const sendToTerminalInternal = () => {\n if (!ttydIframe || !ttydIframe.contentWindow) {\n return false\n }\n\n const win = ttydIframe.contentWindow\n if (win.sendToTerminal) {\n win.sendToTerminal(prompt)\n console.log('[Claude Dev Server] Sent via sendToTerminal:', prompt)\n // Clear interval on success\n if (window._claudeSendRetryInterval) {\n clearInterval(window._claudeSendRetryInterval)\n window._claudeSendRetryInterval = null\n }\n return true\n }\n\n return false\n }\n\n // Try immediately\n if (sendToTerminalInternal()) {\n return\n }\n\n // If not ready, wait and retry\n let attempts = 0\n const maxAttempts = 50\n window._claudeSendRetryInterval = setInterval(() => {\n attempts++\n if (sendToTerminalInternal() || attempts >= maxAttempts) {\n clearInterval(window._claudeSendRetryInterval)\n window._claudeSendRetryInterval = null\n if (attempts >= maxAttempts) {\n console.warn('[Claude Dev Server] Could not send to terminal after retries')\n }\n }\n }, 100)\n }\n\n function loadTerminalIframe(ttydUrl) {\n if (!ttydIframe) return\n ttydWsUrl = ttydUrl\n ttydIframe.src = '/ttyd/index.html?ws=' + encodeURIComponent(ttydUrl)\n ttydIframe.onload = () => {\n console.log('[Claude Dev Server] Terminal iframe loaded')\n }\n }\n\n function connect(port) {\n const WS_URL = 'ws://localhost:' + port\n ws = new WebSocket(WS_URL)\n\n ws.onopen = () => {\n console.log('[Claude Dev Server] Connected to control server')\n }\n\n ws.onmessage = (e) => {\n try {\n const msg = JSON.parse(e.data)\n console.log('[Claude Dev Server] Received message:', msg.type, msg)\n if (msg.type === 'ready' && msg.ttydUrl) {\n loadTerminalIframe(msg.ttydUrl)\n }\n } catch (err) {\n console.error('[Claude Dev Server] Message parse error:', err)\n }\n }\n\n ws.onclose = () => {\n console.log('[Claude Dev Server] Control WebSocket disconnected, reconnecting...')\n setTimeout(() => connect(port), 2000)\n }\n\n ws.onerror = (err) => {\n console.error('[Claude Dev Server] Control WebSocket error:', err)\n }\n }\n\n initWhenReady()\n\n document.addEventListener('keydown', (e) => {\n if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === 'I') {\n e.preventDefault()\n if (isInspectMode) {\n disableInspectMode()\n } else {\n enableInspectMode()\n }\n }\n if (e.key === 'Escape' && isInspectMode) {\n disableInspectMode()\n }\n })\n})()\n`\n","import { spawn } from 'child_process'\nimport { existsSync, readFileSync } from 'fs'\nimport { createHash } from 'crypto'\nimport { join, dirname, relative, sep } from 'path'\nimport http, { IncomingMessage } from 'http'\nimport { fileURLToPath } from 'url'\nimport { createProxyMiddleware } from 'http-proxy-middleware'\nimport { WebSocketServer } from 'ws'\nimport { createConnection } from 'net'\nimport { SourceMapConsumer } from 'source-map'\nimport { createWebSocketServer } from '../server/websocket.js'\nimport { CLIENT_SCRIPT, CLIENT_STYLES } from '../client/injection.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\nexport interface UniversalServerOptions {\n port?: number\n claudePath?: string\n claudeArgs?: string[]\n cwd?: string\n server?: {\n type?: 'vite' | 'next' | 'webpack' | 'custom'\n command?: string\n port?: number\n }\n}\n\nexport async function startUniversalServer(options: UniversalServerOptions = {}) {\n const cwd = options.cwd || process.cwd()\n const port = options.port || 3000\n\n // 1. 检测项目类型\n const projectType = options.server?.type || detectProjectType(cwd)\n const targetCommand = options.server?.command || getDefaultCommand(projectType)\n\n console.log(`[Claude Dev Server] Detected project type: ${projectType}`)\n console.log(`[Claude Dev Server] Starting target server...`)\n\n // 2. 启动目标 dev server(不预设端口)\n const targetServer = spawnTargetServer(targetCommand, cwd)\n\n // 3. 等待并检测目标服务器实际监听的端口\n console.log(`[Claude Dev Server] Waiting for target server to start (PID: ${targetServer.pid})...`)\n const targetPort = await detectServerPort(targetServer, 30000)\n\n if (!targetPort) {\n throw new Error('Failed to detect target server port. Please check if the dev server started successfully.')\n }\n\n console.log(`[Claude Dev Server] Target server is running on port ${targetPort}`)\n\n // 4. 启动控制 WebSocket 服务器(ttyd + Claude)\n const wsServer = createWebSocketServer({\n port: 0, // 自动分配端口\n projectRoot: cwd,\n claudePath: options.claudePath || 'claude',\n claudeArgs: options.claudeArgs || [],\n })\n\n const { wsPort, ttydPort } = await wsServer.start()\n console.log(`[Claude Dev Server] Control server running on ws://localhost:${wsPort}`)\n console.log(`[Claude Dev Server] ttyd running on ws://localhost:${ttydPort}`)\n\n // 5. 启动 HTTP 代理服务器\n const proxyServer = createProxyServer(targetPort, wsPort, cwd)\n proxyServer.listen(port)\n console.log(`[Claude Dev Server] Proxy server running on http://localhost:${port}`)\n console.log(`\\n🚀 Ready! Open http://localhost:${port} in your browser`)\n\n // 清理处理\n const cleanup = () => {\n console.log('[Claude Dev Server] Shutting down...')\n targetServer.kill()\n wsServer.stop()\n proxyServer.close()\n process.exit(0)\n }\n\n process.on('SIGINT', cleanup)\n process.on('SIGTERM', cleanup)\n\n return { proxyServer, targetServer, wsServer }\n}\n\nfunction detectProjectType(cwd: string): 'vite' | 'next' | 'webpack' | 'custom' {\n if (existsSync(join(cwd, 'vite.config.ts')) || existsSync(join(cwd, 'vite.config.js'))) {\n return 'vite'\n }\n if (existsSync(join(cwd, 'next.config.js')) || existsSync(join(cwd, 'next.config.mjs'))) {\n return 'next'\n }\n if (existsSync(join(cwd, 'webpack.config.js')) || existsSync(join(cwd, 'webpack.config.ts'))) {\n return 'webpack'\n }\n return 'custom'\n}\n\nfunction getDefaultCommand(projectType: string): string {\n switch (projectType) {\n case 'vite': return 'npm run dev'\n case 'next': return 'npm run dev'\n case 'webpack': return 'npm run dev'\n default: return 'npm run dev'\n }\n}\n\nfunction spawnTargetServer(command: string, cwd: string) {\n const [cmd, ...args] = command.split(' ')\n const child = spawn(cmd, args, {\n cwd,\n stdio: 'pipe',\n env: process.env,\n })\n\n // Forward child's stdout/stderr to parent so user can see dev server output\n child.stdout?.pipe(process.stdout)\n child.stderr?.pipe(process.stderr)\n\n return child\n}\n\n/**\n * Detect the port that the dev server is listening on by parsing stdout.\n * Most dev servers announce their port on startup like: \"Local: http://localhost:5173\"\n */\nasync function detectServerPort(childProcess: any, timeout: number): Promise<number | null> {\n return new Promise((resolve) => {\n const timeoutId = setTimeout(() => {\n cleanup()\n resolve(null)\n }, timeout)\n\n let stdout = ''\n\n const onData = (chunk: Buffer) => {\n stdout += chunk.toString()\n\n // Match common port announcement patterns:\n // Vite: \"Local: http://localhost:5173/\"\n // Next.js: \"Local: http://localhost:3000\"\n // Webpack: \"http://localhost:8080/\"\n const patterns = [\n /localhost:(\\d{4,5})/,\n /127\\.0\\.0\\.1:(\\d{4,5})/,\n /0\\.0\\.0\\.0:(\\d{4,5})/,\n ]\n\n for (const pattern of patterns) {\n const match = stdout.match(pattern)\n if (match) {\n const port = parseInt(match[1], 10)\n console.log(`[Claude Dev Server] Detected port from stdout: ${port}`)\n cleanup()\n resolve(port)\n return\n }\n }\n }\n\n const cleanup = () => {\n clearTimeout(timeoutId)\n childProcess.stdout?.off('data', onData)\n }\n\n childProcess.stdout?.on('data', onData)\n })\n}\n\n/**\n * Handle source map resolution request.\n * Given a compiled file path and line/column, find the original source position.\n */\nasync function handleSourceMapRequest(\n projectRoot: string,\n filePath: string,\n line: number,\n column: number,\n targetPort?: number\n): Promise<{ file?: string; line?: number; column?: number; original?: any; error?: string }> {\n try {\n let content: string\n let fullPath = filePath\n\n // If filePath starts with / and looks like a URL path, fetch from Vite\n if (filePath.startsWith('/') && targetPort) {\n // console.log('[Claude Dev Server] Fetching from Vite:', filePath)\n try {\n const response = await fetch(`http://localhost:${targetPort}${filePath}`)\n if (!response.ok) {\n console.log('[Claude Dev Server] Failed to fetch from Dev Server:', response.status)\n return { error: 'Failed to fetch from Dev Server' }\n }\n content = await response.text()\n console.log('[Claude Dev Server] Fetched', content.length, 'chars from Dev Server')\n } catch (e) {\n console.log('[Claude Dev Server] Fetch error:', e)\n return { error: 'Fetch error: ' + (e as Error).message }\n }\n } else {\n // If filePath is absolute, check if it's within projectRoot\n if (!filePath.startsWith('/')) {\n fullPath = join(projectRoot, filePath)\n }\n\n // Check if the file exists\n if (!existsSync(fullPath)) {\n console.log('[Claude Dev Server] File not found:', fullPath)\n return { error: 'File not found' }\n }\n\n // Read the file content\n content = readFileSync(fullPath, 'utf-8')\n\n console.log('[Claude Dev Server] Resolving source map for:', fullPath, 'at line:', line)\n }\n\n // Look for sourceMappingURL comment\n // Format: //# sourceMappingURL=filename.js.map or /*# sourceMappingURL=filename.js.map */\n // Or inline: //# sourceMappingURL=data:application/json;base64,...\n let sourceMapUrl: string | null = null\n const patterns = [\n /\\/\\/[@#]\\s*sourceMappingURL=([^\\s]+)/,\n /\\/\\*[@#]\\s*sourceMappingURL=([^\\s]+)\\s*\\*\\//\n ]\n\n for (const pattern of patterns) {\n const match = content.match(pattern)\n if (match) {\n sourceMapUrl = match[1]\n console.log('[Claude Dev Server] Found sourceMappingURL:', sourceMapUrl.substring(0, 100) + '...')\n break\n }\n }\n\n if (!sourceMapUrl) {\n console.log('[Claude Dev Server] No source map found in:', fullPath)\n return { file: relative(projectRoot, fullPath), line, column }\n }\n\n let sourceMapContent: string\n let sourceMap: any\n\n // Check if it's an inline source map (data URL)\n if (sourceMapUrl.startsWith('data:application/json;base64,') ||\n sourceMapUrl.startsWith('data:application/json;charset=utf-8;base64,')) {\n console.log('[Claude Dev Server] Found inline source map')\n // Extract base64 content\n const base64Data = sourceMapUrl.split(',', 2)[1]\n sourceMapContent = Buffer.from(base64Data, 'base64').toString('utf-8')\n try {\n sourceMap = JSON.parse(sourceMapContent)\n } catch (e) {\n console.log('[Claude Dev Server] Failed to parse inline source map:', e)\n return { file: relative(projectRoot, fullPath), line, column }\n }\n } else if (sourceMapUrl.startsWith('http://') || sourceMapUrl.startsWith('https://')) {\n // Remote source map - try to fetch via proxy\n console.log('[Claude Dev Server] Remote source map not supported:', sourceMapUrl)\n return { file: relative(projectRoot, fullPath), line, column }\n } else {\n // External source map file\n let sourceMapPath: string\n if (sourceMapUrl.startsWith('/')) {\n // Absolute path\n sourceMapPath = sourceMapUrl\n } else {\n // Relative path - resolve relative to the file\n sourceMapPath = join(dirname(fullPath), sourceMapUrl)\n }\n\n console.log('[Claude Dev Server] Reading external source map:', sourceMapPath)\n\n // Read the source map\n if (!existsSync(sourceMapPath)) {\n console.log('[Claude Dev Server] Source map file not found:', sourceMapPath)\n return { file: relative(projectRoot, fullPath), line, column }\n }\n\n sourceMapContent = readFileSync(sourceMapPath, 'utf-8')\n sourceMap = JSON.parse(sourceMapContent)\n }\n\n // console.log('[Claude Dev Server] Source map loaded, sources:', sourceMap.sources?.length, 'mappings:', sourceMap.mappings?.substring(0, 50) + '...')\n // console.log('[Claude Dev Server] Source map sources:', sourceMap.sources)\n\n // Use source-map library to find original position\n const consumer = await new SourceMapConsumer(sourceMap)\n const original = consumer.originalPositionFor({\n line: line,\n column: column\n })\n consumer.destroy()\n\n // console.log('[Claude Dev Server] Source map result:', {\n // generated: { line, column },\n // original: original\n // })\n\n if (original.source && original.line !== null) {\n // Convert source path to be relative to project root\n let originalFile = original.source\n if (originalFile.startsWith('webpack://')) {\n // Remove webpack:// prefix\n originalFile = originalFile.replace(/^webpack:\\/\\/[\\/\\\\]?/, '')\n }\n // For Vite and other bundlers, source might be just a filename\n if (!originalFile.startsWith('/')) {\n // Try to resolve relative to project root to verify the file exists\n const possiblePath = join(projectRoot, originalFile)\n if (existsSync(possiblePath)) {\n // Keep the original source path as-is (preserves directory structure)\n // originalFile is already correct (e.g., 'src/App.jsx')\n } else {\n // File doesn't exist at the given path\n // Check if it's just a filename (no directory separators)\n const fileName = originalFile.split('/').pop() || originalFile.split('\\\\').pop() || originalFile\n if (fileName === originalFile) {\n // Source is just a filename (common with Vite inline source maps)\n // If filePath is already a relative path like '/src/App.jsx', use it directly\n if (filePath.startsWith('/')) {\n originalFile = filePath.substring(1) // Remove leading slash\n console.log('[Claude Dev Server] Source is just a filename, using filePath:', originalFile)\n } else {\n // Fall back to relative path from fullPath\n originalFile = relative(projectRoot, fullPath)\n }\n } else {\n // Has directory but file doesn't exist, use relative\n originalFile = relative(projectRoot, possiblePath)\n }\n }\n }\n\n // console.log('[Claude Dev Server] Source map resolved:', {\n // original: { file: originalFile, line: original.line, column: original.column },\n // generated: { file: filePath, line, column }\n // })\n\n return {\n file: originalFile,\n line: original.line,\n column: original.column || 1,\n original: {\n source: original.source,\n line: original.line,\n column: original.column,\n name: original.name\n }\n }\n }\n\n // No original position found, return generated\n return { file: relative(projectRoot, fullPath), line, column }\n } catch (err) {\n console.error('[Claude Dev Server] Source map resolution error:', err)\n return { error: String(err) }\n }\n}\n\n/**\n * Handle Next.js Turbopack source file lookup.\n * Given a page path, find the corresponding source file by parsing Turbopack chunks.\n */\nasync function handleTurbopackLookup(\n projectRoot: string,\n pagePath: string,\n targetPort: number\n): Promise<{ file?: string; line?: number; error?: string }> {\n try {\n console.log('[Claude Dev Server] Turbopack lookup for page:', pagePath)\n\n // Get the HTML page to find loaded chunk URLs\n const pageRes = await fetch(`http://localhost:${targetPort}${pagePath}`)\n if (!pageRes.ok) {\n return { error: 'Failed to fetch page' }\n }\n\n const html = await pageRes.text()\n const chunkUrls: string[] = []\n\n // Extract chunk URLs from HTML\n const scriptMatches = html.matchAll(/<script[^>]*src=\"([^\"]*\\/_next\\/static\\/chunks\\/[^\"]*)\"/g)\n for (const match of scriptMatches) {\n if (match[1]) {\n chunkUrls.push(match[1])\n }\n }\n\n console.log('[Claude Dev Server] Found', chunkUrls.length, 'chunk URLs')\n\n // Parse each chunk to find module paths\n for (const chunkUrl of chunkUrls) {\n try {\n const fullUrl = chunkUrl.startsWith('http') ? chunkUrl : `http://localhost:${targetPort}${chunkUrl}`\n const chunkRes = await fetch(fullUrl)\n if (!chunkRes.ok) continue\n\n const chunkContent = await chunkRes.text()\n\n // Extract module paths from Turbopack format\n // Format: \"[project]/path/to/file.tsx\" or \"[project]/path/to/file.tsx (ecmascript)\"\n const modulePathRegex = /\\[project\\]([^\\s\"]+\\.(tsx?|jsx?))/g\n const matches = [...chunkContent.matchAll(modulePathRegex)]\n\n for (const match of matches) {\n if (match[1]) {\n const sourcePath = match[1]\n // Remove [project] prefix and convert to relative path\n let relativePath = sourcePath.replace(/^\\[project\\]/, '')\n\n // Check if this path matches the current page\n // Normalize page path: /zh/login -> /login or /app/[lng]/(auth)/login/page.tsx\n const normalizedPagePath = pagePath.replace(/^\\/[^/]+/, '') // Remove language prefix\n\n if (relativePath.toLowerCase().includes(normalizedPagePath.toLowerCase()) ||\n relativePath.toLowerCase().includes('login')) {\n // Found matching source file\n console.log('[Claude Dev Server] Found source file:', relativePath)\n\n return {\n file: relativePath,\n line: undefined // Turbopack doesn't provide line numbers\n }\n }\n }\n }\n } catch (e) {\n console.log('[Claude Dev Server] Error fetching chunk:', chunkUrl, e)\n }\n }\n\n return { error: 'Source file not found for page: ' + pagePath }\n } catch (err) {\n console.error('[Claude Dev Server] Turbopack lookup error:', err)\n return { error: String(err) }\n }\n}\n\n/**\n * Check if request is for an HTML page (not assets, API, WebSocket, etc.)\n */\nfunction isHtmlPageRequest(req: IncomingMessage): boolean {\n const accept = req.headers.accept || ''\n const url = req.url || ''\n\n // Check if request accepts HTML\n if (!accept.includes('text/html')) {\n return false\n }\n\n // Check if it's a page request (not assets, API, etc.)\n if (url.startsWith('/@') || url.startsWith('/_next/') ||\n url.startsWith('/ttyd') || url.startsWith('/dev.html')) {\n return false\n }\n\n return true\n}\n\nfunction createProxyServer(targetPort: number, wsPort: number, projectRoot: string) {\n // 读取 ttyd 资源文件\n // 从当前模块路径计算 assets 目录\n // moduleDir 是 /Users/lloyd/moox/claude-dev-server/dist\n // 所以需要 assets 是 /Users/lloyd/moox/claude-dev-server/dist/assets\n const moduleDir = dirname(fileURLToPath(import.meta.url))\n const assetsPath = join(moduleDir, 'assets')\n\n let ttydHtml: string\n let ttydBridgeJs: string\n let devHtml: string\n\n try {\n ttydHtml = readFileSync(join(assetsPath, 'ttyd-terminal.html'), 'utf-8')\n ttydBridgeJs = readFileSync(join(assetsPath, 'ttyd-bridge.js'), 'utf-8')\n devHtml = readFileSync(join(assetsPath, 'dev.html'), 'utf-8')\n } catch (e: any) {\n console.error('[Claude Dev Server] Failed to read assets from', assetsPath)\n console.error('[Claude Dev Server] moduleDir:', moduleDir)\n console.error('[Claude Dev Server] Error:', e.message)\n throw new Error('Assets not found. Please run `npm run build` first.')\n }\n\n const server = http.createServer((req, res) => {\n // Check if request is from dev.html iframe\n const referer = req.headers.referer || ''\n const isFromDevPage = referer.includes('dev.html')\n\n // Handle /dev.html route\n if (req.url?.startsWith('/dev.html')) {\n const urlParams = new URL(req.url || '', `http://${req.headers.host}`)\n const originalPath = urlParams.searchParams.get('path') || '/'\n\n // Replace placeholders in dev HTML\n const host = req.headers.host || 'localhost:3000'\n const origin = `http://${host}`\n const modifiedDevHtml = devHtml.replace(\n /__CLAUDE_IFRAME_SRC__/g,\n `${origin}${originalPath}`\n ).replace(\n /__CLAUDE_ORIGINAL_PATH__/g,\n originalPath\n )\n res.setHeader('Content-Type', 'text/html')\n res.end(modifiedDevHtml)\n return\n }\n\n // If not from dev.html and requesting HTML page, redirect to dev.html\n if (!isFromDevPage && isHtmlPageRequest(req)) {\n const currentPath = req.url || '/'\n const devPageUrl = `/dev.html?path=${encodeURIComponent(currentPath)}`\n res.writeHead(302, { 'Location': devPageUrl })\n res.end()\n return\n }\n\n // 处理 @claude-port 端点\n if (req.url === '/@claude-port') {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ port: wsPort }))\n return\n }\n\n // 处理 sourcemap 解析端点\n if (req.url?.startsWith('/@sourcemap?')) {\n const url = new URL(req.url, `http://localhost:${wsPort}`)\n const file = url.searchParams.get('file')\n const line = url.searchParams.get('line')\n const column = url.searchParams.get('col')\n\n if (file && line && column) {\n handleSourceMapRequest(projectRoot, file, parseInt(line), parseInt(column || '1'), targetPort)\n .then(result => {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(result))\n })\n .catch(err => {\n console.error('[Claude Dev Server] Source map error:', err)\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ error: err.message }))\n })\n return\n }\n }\n\n // 处理 Next.js/Turbopack 源文件查找端点\n if (req.url?.startsWith('/@sourcemap-lookup?')) {\n const url = new URL(req.url, `http://localhost:${wsPort}`)\n const page = url.searchParams.get('page')\n const framework = url.searchParams.get('framework')\n\n if (page && framework === 'nextjs') {\n handleTurbopackLookup(projectRoot, page, targetPort)\n .then(result => {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(result))\n })\n .catch(err => {\n console.error('[Claude Dev Server] Turbopack lookup error:', err)\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ error: err.message }))\n })\n return\n }\n }\n\n // 处理 /ttyd/* 路由\n if (req.url?.startsWith('/ttyd/')) {\n const urlPath = req.url.split('?')[0] // 移除查询参数\n\n if (urlPath === '/ttyd/index.html' || urlPath === '/ttyd/') {\n res.setHeader('Content-Type', 'text/html')\n res.end(ttydHtml)\n return\n }\n\n if (urlPath === '/ttyd/ttyd-bridge.js') {\n res.setHeader('Content-Type', 'application/javascript')\n res.end(ttydBridgeJs)\n return\n }\n\n // Handle ttyd token endpoint\n if (urlPath === '/ttyd/token' || urlPath === '/ttyd/index.html/token') {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ token: '' }))\n return\n }\n\n // 其他 /ttyd/* 路由返回 404\n res.statusCode = 404\n res.end('Not found')\n return\n }\n\n // 代理到目标服务器\n // If request is from dev.html, don't inject - serve original HTML\n // Remove accept-encoding to get uncompressed content\n const proxyHeaders = { ...req.headers }\n delete proxyHeaders['accept-encoding']\n\n const shouldInject = !isFromDevPage\n\n const options = {\n hostname: 'localhost',\n port: targetPort,\n path: req.url,\n method: req.method,\n headers: proxyHeaders,\n }\n\n const proxyReq = http.request(options, (proxyRes) => {\n // Inject scripts only if not from wrapper\n if (proxyRes.headers['content-type']?.includes('text/html') && shouldInject) {\n const body: Buffer[] = []\n proxyRes.on('data', (chunk) => body.push(chunk))\n proxyRes.on('end', () => {\n const html = Buffer.concat(body).toString('utf8')\n const injected = injectScripts(html, wsPort, projectRoot)\n const statusCode = proxyRes.statusCode || 200\n res.writeHead(statusCode, {\n ...proxyRes.headers,\n 'content-length': Buffer.byteLength(injected),\n })\n res.end(injected)\n })\n } else {\n const statusCode = proxyRes.statusCode || 200\n res.writeHead(statusCode, proxyRes.headers)\n proxyRes.pipe(res)\n }\n })\n\n proxyReq.on('error', (err) => {\n console.error('[Claude Dev Server] Proxy error:', err)\n res.statusCode = 502\n res.end('Bad Gateway')\n })\n\n req.pipe(proxyReq)\n })\n\n // Handle WebSocket upgrade requests (e.g., Next.js webpack-hmr, Vite HMR)\n server.on('upgrade', (req: any, socket: any, head: Buffer) => {\n // Check if this is a WebSocket upgrade request\n if (req.headers['upgrade']?.toLowerCase() !== 'websocket') {\n return\n }\n\n console.log('[Claude Dev Server] WebSocket upgrade request:', req.url)\n\n // Create raw TCP connection to target server\n const targetSocket = createConnection(targetPort, 'localhost', () => {\n console.log('[Claude Dev Server] Connected to target WebSocket server')\n\n // Forward the upgrade request to target\n const upgradeRequest = [\n `${req.method} ${req.url} HTTP/1.1`,\n `Host: localhost:${targetPort}`,\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Key: ${req.headers['sec-websocket-key']}`,\n `Sec-WebSocket-Version: ${req.headers['sec-websocket-version'] || '13'}`,\n ]\n\n if (req.headers['sec-websocket-protocol']) {\n upgradeRequest.push(`Sec-WebSocket-Protocol: ${req.headers['sec-websocket-protocol']}`)\n }\n if (req.headers['sec-websocket-extensions']) {\n upgradeRequest.push(`Sec-WebSocket-Extensions: ${req.headers['sec-websocket-extensions']}`)\n }\n\n targetSocket.write(upgradeRequest.join('\\r\\n') + '\\r\\n\\r\\n')\n\n // Forward the head (remaining data from the upgrade request)\n if (head && head.length > 0) {\n targetSocket.write(head)\n }\n })\n\n // Handle response from target server\n targetSocket.on('data', (data: Buffer) => {\n if (socket.writable) {\n socket.write(data)\n }\n })\n\n // Handle data from client\n socket.on('data', (data: Buffer) => {\n if (targetSocket.writable) {\n targetSocket.write(data)\n }\n })\n\n // Handle connection close\n socket.on('close', () => {\n console.log('[Claude Dev Server] Client WebSocket closed')\n targetSocket.destroy()\n })\n\n targetSocket.on('close', () => {\n console.log('[Claude Dev Server] Target WebSocket closed')\n socket.end()\n })\n\n // Handle errors\n socket.on('error', (err: Error) => {\n console.error('[Claude Dev Server] Client socket error:', err.message)\n targetSocket.destroy()\n })\n\n targetSocket.on('error', (err: Error) => {\n console.error('[Claude Dev Server] Target socket error:', err.message)\n socket.end()\n })\n })\n\n return server\n}\n\nfunction injectScripts(html: string, wsPort: number, projectRoot: string): string {\n // Check if already injected to prevent \"nested\" pages\n if (html.includes('claude-dev-server-container') || html.includes('__CLAUDE_ORIGINAL_HTML__')) {\n console.log('[Claude Dev Server] HTML already injected, returning as-is')\n return html\n }\n\n // Verify that the original HTML is clean (no our scripts)\n const hasOurScripts = html.includes('CLIENT_SCRIPT') || html.includes('claude-dev-server-container')\n if (hasOurScripts) {\n console.log('[Claude Dev Server] Warning: Original HTML already has our scripts')\n }\n\n // Don't inject anything into the original HTML\n // The inspect functionality will be implemented entirely in the outer layer\n const modifiedHtml = html\n console.log('[Claude Dev Server] Creating split layout, original HTML length:', html.length)\n\n // Use Base64 encoding to pass HTML to avoid any escaping issues with special characters\n const base64Html = Buffer.from(modifiedHtml, 'utf-8').toString('base64')\n\n // Create new split-layout HTML page\n const projectRootScript = `<script>window.__CLAUDE_PROJECT_ROOT__ = ${JSON.stringify(projectRoot)};window.__CLAUDE_ORIGINAL_HTML_BASE64__ = \"${base64Html}\";</script>`\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Claude Dev Server</title>\n ${CLIENT_STYLES}\n ${projectRootScript}\n</head>\n<body>\n <script type=\"module\">${CLIENT_SCRIPT.replace(/wsPort:\\s*\\d+/, `wsPort: ${wsPort}`)}</script>\n</body>\n</html>`\n}\n\n/**\n * Generate Sec-WebSocket-Accept header value for WebSocket handshake.\n * RFC 6455: base64(sha1(clientKey + GUID))\n */\nfunction generateWebSocketAccept(clientKey: string): string {\n const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'\n const hash = createHash('sha1')\n .update(clientKey + GUID)\n .digest('base64')\n return hash\n}\n"]}
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { startUniversalServer } from './chunk-PAE5WTS2.js';
2
+ import { startUniversalServer } from './chunk-PZVR2URG.js';
3
3
  import { execSync } from 'child_process';
4
4
 
5
5
  async function checkTtyd() {
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { startUniversalServer } from './chunk-PAE5WTS2.js';
1
+ export { startUniversalServer } from './chunk-PZVR2URG.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-server",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Universal dev server wrapper with Claude Code AI assistant - works with Vite, Next.js, Webpack and more",
5
5
  "author": "lloydzhou",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server/pty.ts","../src/server/source-map.ts","../src/server/websocket.ts","../src/client/injection.js","../src/universal/index.ts"],"names":["resolve","__filename","spawn","SourceMapConsumer"],"mappings":"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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAgLtB,IAAM,aAAA,GAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;A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","file":"chunk-PAE5WTS2.js","sourcesContent":["import { spawn } from 'child_process'\nimport { randomBytes } from 'crypto'\n\nexport interface PtyOptions {\n cwd: string\n claudePath: string\n args: string[]\n env?: Record<string, string>\n}\n\nexport function spawnClaudeCode(options: PtyOptions) {\n // Generate a random port for ttyd\n const port = 50000 + Math.floor(Math.random() * 10000)\n\n // Start ttyd with claude command\n const ttydProc = spawn('ttyd', [\n '--port', String(port),\n '--interface', '127.0.0.1',\n '--writable',\n options.claudePath,\n ...options.args,\n ], {\n cwd: options.cwd,\n env: {\n ...process.env,\n ...options.env,\n TERM: 'xterm-256color',\n FORCE_COLOR: '1',\n },\n })\n\n ttydProc.on('exit', (code) => {\n console.log(`[claude-dev-server] ttyd exited - code: ${code}`)\n })\n\n ttydProc.on('error', (err) => {\n console.error(`[claude-dev-server] ttyd error: ${err.message}`)\n })\n\n // Wait a bit for ttyd to start, then return the WebSocket URL\n return new Promise<{ wsUrl: string; process: typeof ttydProc; port: number }>((resolve, reject) => {\n ttydProc.stdout?.on('data', (data: Buffer) => {\n const msg = data.toString()\n console.log(`[ttyd] ${msg}`)\n })\n\n ttydProc.stderr?.on('data', (data: Buffer) => {\n const msg = data.toString()\n console.error(`[ttyd stderr] ${msg}`)\n })\n\n // Give ttyd a moment to start\n setTimeout(() => {\n resolve({\n wsUrl: `ws://127.0.0.1:${port}`,\n process: ttydProc,\n port,\n })\n }, 500)\n\n ttydProc.on('error', reject)\n })\n}\n","import { SourceMapConsumer } from 'source-map'\n\nexport interface SourcePosition {\n source: string\n line: number\n column: number\n name?: string\n}\n\nexport interface CodeLocation {\n file: string\n line: number\n column: number\n content?: string\n}\n\n// Store source maps by generated file path\nconst sourceMapCache = new Map<string, SourceMapConsumer>()\n\nexport async function parseSourceMap(sourceMapUrl: string, content: string): Promise<void> {\n try {\n const consumer = await new SourceMapConsumer(content)\n sourceMapCache.set(sourceMapUrl, consumer)\n } catch (err) {\n console.error('Failed to parse source map:', err)\n }\n}\n\nexport async function findOriginalPosition(\n generatedFile: string,\n line: number,\n column: number\n): Promise<SourcePosition | null> {\n const consumer = sourceMapCache.get(generatedFile)\n if (!consumer) {\n return null\n }\n\n try {\n const position = consumer.originalPositionFor({ line, column })\n if (position.source) {\n return {\n source: position.source,\n line: position.line || 1,\n column: position.column || 0,\n name: position.name,\n }\n }\n } catch (err) {\n console.error('Failed to find original position:', err)\n }\n\n return null\n}\n\nexport function generateVSCodeURI(location: CodeLocation): string {\n // Generate VS Code URI scheme for opening files\n // vscode://file/{path}:{line}:{col}\n const filePath = location.file.replace(/\\\\/g, '/')\n return `vscode://file/${filePath}:${location.line}:${location.column}`\n}\n\nexport function formatCodeContext(location: CodeLocation): string {\n return `\n📍 Code Location:\n File: ${location.file}\n Line: ${location.line}\n Column: ${location.column}\n`\n}\n\nexport function clearCache() {\n sourceMapCache.clear()\n}\n","import { WebSocketServer, WebSocket } from 'ws'\nimport { spawnClaudeCode } from './pty.js'\nimport { findOriginalPosition, parseSourceMap, CodeLocation, formatCodeContext } from './source-map.js'\nimport { readFile } from 'fs/promises'\nimport { resolve } from 'path'\n\nexport interface WebSocketServerOptions {\n port?: number\n projectRoot: string\n claudePath: string\n claudeArgs: string[]\n}\n\nexport function createWebSocketServer(options: WebSocketServerOptions) {\n let wss: WebSocketServer | null = null\n let port = options.port || 0\n let ttydInfo: { wsUrl: string; process: any; port: number } | null = null\n\n const start = async (): Promise<{ wsPort: number; ttydPort: number }> => {\n // Start ttyd first\n console.log('[claude-dev-server] Starting ttyd...')\n ttydInfo = await spawnClaudeCode({\n cwd: options.projectRoot,\n claudePath: options.claudePath,\n args: options.claudeArgs,\n })\n console.log(`[claude-dev-server] ttyd running at ${ttydInfo.wsUrl}`)\n\n // Also start a simple WebSocket server for inspect functionality\n return new Promise((resolve, reject) => {\n wss = new WebSocketServer({ port, host: '127.0.0.1' })\n\n wss.on('listening', () => {\n const address = wss!.address()\n if (address && typeof address === 'object') {\n port = address.port\n resolve({ wsPort: port, ttydPort: ttydInfo!.port })\n }\n })\n\n wss.on('error', (err) => {\n reject(err)\n })\n\n wss.on('connection', (ws: WebSocket) => {\n ws.on('message', async (message: Buffer) => {\n try {\n const msg = JSON.parse(message.toString())\n\n if (msg.type === 'inspect') {\n await handleInspect(msg, ws, options.projectRoot)\n } else if (msg.type === 'loadSourceMap') {\n await handleLoadSourceMap(msg, ws, options.projectRoot)\n }\n } catch (err) {\n // Ignore\n }\n })\n\n // Send ready message with ttyd URL\n ws.send(JSON.stringify({\n type: 'ready',\n ttydUrl: ttydInfo!.wsUrl\n }))\n })\n })\n }\n\n const stop = () => {\n ttydInfo?.process.kill()\n wss?.close()\n }\n\n return { start, stop }\n}\n\nasync function handleLoadSourceMap(\n msg: any,\n ws: WebSocket,\n projectRoot: string\n) {\n const { sourceMapUrl } = msg\n try {\n const mapPath = resolve(projectRoot, sourceMapUrl.replace(/^\\//, ''))\n const content = await readFile(mapPath, 'utf-8')\n await parseSourceMap(sourceMapUrl, content)\n ws.send(JSON.stringify({\n type: 'sourceMapLoaded',\n sourceMapUrl,\n success: true\n }))\n } catch (err) {\n ws.send(JSON.stringify({\n type: 'sourceMapLoaded',\n sourceMapUrl,\n success: false,\n error: (err as Error).message\n }))\n }\n}\n\nasync function handleInspect(\n msg: any,\n ws: WebSocket,\n projectRoot: string\n) {\n const { url, line, column, sourceMapUrl } = msg\n\n let location: CodeLocation | null = null\n\n if (sourceMapUrl) {\n const original = await findOriginalPosition(sourceMapUrl, line, column)\n if (original) {\n location = {\n file: resolve(projectRoot, original.source),\n line: original.line,\n column: original.column,\n }\n }\n }\n\n if (!location) {\n const match = url.match(/\\/@fs\\/(.+?)(?:\\?|$)|\\/@vite\\/(.+?)(?:\\?|$)/)\n if (match) {\n location = {\n file: decodeURIComponent(match[1] || match[2]),\n line,\n column,\n }\n }\n }\n\n ws.send(JSON.stringify({\n type: 'inspectResult',\n location: location ? {\n file: location.file,\n line: location.line,\n column: location.column,\n context: formatCodeContext(location)\n } : null\n }))\n}\n","// Client-side script - pure JavaScript (no TypeScript)\n// This file will be injected into the browser\n\n// STYLES FOR SPLIT LAYOUT\nexport const CLIENT_STYLES = `\n<style id=\"claude-dev-server-styles\">\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\nhtml, body {\n width: 100%;\n height: 100%;\n overflow: hidden;\n background: transparent;\n}\n.claude-dev-server-container {\n display: flex;\n width: 100vw;\n height: 100vh;\n overflow: hidden;\n background: transparent;\n}\n.claude-dev-server-left {\n width: 40%;\n min-width: 300px;\n max-width: 60%;\n overflow: hidden;\n position: relative;\n background: #fff;\n display: flex;\n flex-direction: column;\n}\n.claude-dev-server-left iframe {\n width: 100%;\n height: 100%;\n border: none;\n}\n.claude-dev-server-divider {\n width: 6px;\n background: #3e3e3e;\n position: relative;\n cursor: col-resize;\n transition: background 0.2s;\n flex-shrink: 0;\n}\n.claude-dev-server-divider:hover,\n.claude-dev-server-divider.dragging {\n background: #d97757;\n}\n.claude-dev-server-right {\n flex: 1;\n min-width: 300px;\n overflow: hidden;\n position: relative;\n display: flex;\n flex-direction: column;\n}\n.claude-dev-server-terminal {\n flex: 1;\n overflow: hidden;\n position: relative;\n background: #000;\n}\n.claude-dev-server-terminal iframe,\n.claude-dev-server-terminal-iframe {\n width: 100%;\n height: 100%;\n border: none;\n}\n.claude-dev-server-dev-iframe {\n width: 100%;\n height: 100%;\n border: none;\n}\n.claude-dev-server-terminal-header {\n padding: 8px 12px;\n background: #2d2d2d;\n border-bottom: 1px solid #3e3e3e;\n display: flex;\n justify-content: space-between;\n align-items: center;\n user-select: none;\n min-height: 40px;\n}\n.claude-dev-server-title {\n font-weight: 600;\n color: #fff;\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-family: 'SF Mono', 'Monaco', 'Cascadia Code', 'Consolas', monospace;\n}\n.claude-dev-server-title svg {\n width: 14px;\n height: 14px;\n flex-shrink: 0;\n}\n.claude-dev-server-actions {\n display: flex;\n gap: 6px;\n}\n.claude-dev-server-btn {\n background: #d97757;\n border: none;\n color: #fff;\n cursor: pointer;\n font-family: inherit;\n font-size: 11px;\n padding: 4px 10px;\n border-radius: 3px;\n transition: background 0.15s;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n.claude-dev-server-btn:hover {\n background: #c96a4a;\n}\n.claude-dev-server-btn.active {\n background: #b85d3f;\n color: #fff;\n}\n.claude-dev-server-inspect-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n z-index: 2147483646;\n display: none;\n}\n.claude-dev-server-inspect-overlay.active {\n display: block;\n}\n.claude-dev-server-highlight {\n position: absolute;\n border: 2px solid #007acc;\n background: rgba(0, 122, 204, 0.1);\n pointer-events: none;\n transition: all 0.1s ease;\n}\n.claude-dev-server-highlight::after {\n content: attr(data-element);\n position: absolute;\n top: -20px;\n left: 0;\n background: #007acc;\n color: #fff;\n font-size: 10px;\n padding: 2px 4px;\n border-radius: 2px 2px 0 0;\n font-family: monospace;\n white-space: nowrap;\n}\n/* Portrait mode */\n@media (orientation: portrait) {\n .claude-dev-server-container {\n flex-direction: column;\n }\n .claude-dev-server-divider {\n width: 100%;\n height: 6px;\n cursor: row-resize;\n }\n .claude-dev-server-right {\n width: 100%;\n min-width: unset;\n max-width: unset;\n height: 50%;\n min-height: 200px;\n }\n}\n</style>\n`\n\n// NEW CLIENT SCRIPT FOR SPLIT LAYOUT\nexport const CLIENT_SCRIPT = `\n(() => {\n let ws = null\n let ttydIframe = null\n let devIframe = null\n let overlay = null\n let isInspectMode = false\n let ttydWsUrl = null\n let leftPanel = null\n let divider = null\n let rightPanel = null\n let isDragging = false\n let inspectListenersRegistered = false\n\n // Fetch the WebSocket port from the server\n async function getWsPort() {\n const res = await fetch('/@claude-port')\n const data = await res.json()\n return data.port\n }\n\n async function initWhenReady() {\n try {\n const port = await getWsPort()\n connect(port)\n } catch (err) {\n console.error('[Claude Dev Server] Failed to get port:', err)\n setTimeout(initWhenReady, 1000)\n return\n }\n // Create overlay first before split layout\n createOverlay()\n createSplitLayout()\n }\n\n function createSplitLayout() {\n // IMPORTANT: Only create layout in the top-level window, not in iframes\n // This prevents infinite nesting when the dev iframe loads\n if (window.top !== window.self) {\n console.log('[Claude Dev Server] Not in top window, skipping layout creation')\n return\n }\n\n // Check if already created\n if (document.querySelector('.claude-dev-server-container')) return\n // Also check if we're already in an injected page\n if (window.__CLAUDE_SPLIT_LAYOUT_CREATED__) return\n window.__CLAUDE_SPLIT_LAYOUT_CREATED__ = true\n\n // Get original HTML from window variable (set by server)\n // The HTML is Base64 encoded to avoid any escaping issues\n let originalHtml\n if (window.__CLAUDE_ORIGINAL_HTML_BASE64__) {\n // Decode Base64\n try {\n const decoded = atob(window.__CLAUDE_ORIGINAL_HTML_BASE64__)\n // Handle UTF-8 encoding\n const bytes = new Uint8Array(decoded.length)\n for (let i = 0; i < decoded.length; i++) {\n bytes[i] = decoded.charCodeAt(i)\n }\n originalHtml = new TextDecoder().decode(bytes)\n } catch (e) {\n console.error('[Claude Dev Server] Failed to decode Base64 HTML:', e)\n originalHtml = document.documentElement.outerHTML\n }\n } else {\n originalHtml = document.documentElement.outerHTML\n }\n\n // Create container\n const container = document.createElement('div')\n container.className = 'claude-dev-server-container'\n\n // Left panel - terminal (Claude)\n leftPanel = document.createElement('div')\n leftPanel.className = 'claude-dev-server-left'\n\n // Terminal header\n const header = document.createElement('div')\n header.className = 'claude-dev-server-terminal-header'\n header.innerHTML = \\`\n <span class=\"claude-dev-server-title\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\">\n <path d=\"M11.376 24L10.776 23.544L10.44 22.8L10.776 21.312L11.16 19.392L11.472 17.856L11.76 15.96L11.928 15.336L11.904 15.288L11.784 15.312L10.344 17.28L8.16 20.232L6.432 22.056L6.024 22.224L5.304 21.864L5.376 21.192L5.784 20.616L8.16 17.568L9.6 15.672L10.536 14.592L10.512 14.448H10.464L4.128 18.576L3 18.72L2.496 18.264L2.568 17.52L2.808 17.28L4.704 15.96L9.432 13.32L9.504 13.08L9.432 12.96H9.192L8.4 12.912L5.712 12.84L3.384 12.744L1.104 12.624L0.528 12.504L0 11.784L0.048 11.424L0.528 11.112L1.224 11.16L2.736 11.28L5.016 11.424L6.672 11.52L9.12 11.784H9.504L9.552 11.616L9.432 11.52L9.336 11.424L6.96 9.84L4.416 8.16L3.072 7.176L2.352 6.672L1.992 6.216L1.848 5.208L2.496 4.488L3.384 4.56L3.6 4.608L4.488 5.304L6.384 6.768L8.88 8.616L9.24 8.904L9.408 8.808V8.736L9.24 8.472L7.896 6.024L6.456 3.528L5.808 2.496L5.64 1.872C5.576 1.656 5.544 1.416 5.544 1.152L6.288 0.144001L6.696 0L7.704 0.144001L8.112 0.504001L8.736 1.92L9.72 4.152L11.28 7.176L11.736 8.088L11.976 8.904L12.072 9.168H12.24V9.024L12.36 7.296L12.6 5.208L12.84 2.52L12.912 1.752L13.296 0.840001L14.04 0.360001L14.616 0.624001L15.096 1.32L15.024 1.752L14.76 3.6L14.184 6.504L13.824 8.472H14.04L14.28 8.208L15.264 6.912L16.92 4.848L17.64 4.032L18.504 3.12L19.056 2.688H20.088L20.832 3.816L20.496 4.992L19.44 6.336L18.552 7.464L17.28 9.168L16.512 10.536L16.584 10.632H16.752L19.608 10.008L21.168 9.744L22.992 9.432L23.832 9.816L23.928 10.2L23.592 11.016L21.624 11.496L19.32 11.952L15.888 12.768L15.84 12.792L15.888 12.864L17.424 13.008L18.096 13.056H19.728L22.752 13.272L23.544 13.8L24 14.424L23.928 14.928L22.704 15.528L21.072 15.144L17.232 14.232L15.936 13.92H15.744V14.016L16.848 15.096L18.84 16.896L21.36 19.224L21.48 19.8L21.168 20.28L20.832 20.232L18.624 18.552L17.76 17.808L15.84 16.2H15.72V16.368L16.152 17.016L18.504 20.544L18.624 21.624L18.456 21.96L17.832 22.176L17.184 22.056L15.792 20.136L14.376 17.952L13.224 16.008L13.104 16.104L12.408 23.352L12.096 23.712L11.376 24Z\" fill=\"#d97757\"/>\n </svg>\n Claude Code\n </span>\n <div class=\"claude-dev-server-actions\">\n <button class=\"claude-dev-server-btn claude-dev-server-btn-inspect\" title=\"Inspect Element\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M19 11V4a2 2 0 00-2-2H4a2 2 0 00-2 2v13a2 2 0 002 2h7\"/>\n <path d=\"M12 12l4.166 10 1.48-4.355L22 16.166 12 12z\"/>\n <path d=\"M18 18l3 3\"/>\n </svg>\n Inspect\n </button>\n </div>\n \\`\n\n const inspectBtn = header.querySelector('.claude-dev-server-btn-inspect')\n inspectBtn.addEventListener('click', () => {\n if (isInspectMode) {\n disableInspectMode()\n } else {\n enableInspectMode()\n }\n })\n\n // Terminal container\n const terminal = document.createElement('div')\n terminal.className = 'claude-dev-server-terminal'\n\n // Ttyd iframe\n ttydIframe = document.createElement('iframe')\n ttydIframe.className = 'claude-dev-server-terminal-iframe'\n ttydIframe.allow = 'clipboard-read; clipboard-write'\n\n terminal.appendChild(ttydIframe)\n leftPanel.appendChild(header)\n leftPanel.appendChild(terminal)\n\n // Divider - draggable\n divider = document.createElement('div')\n divider.className = 'claude-dev-server-divider'\n setupDraggable(divider)\n\n // Right panel - dev server\n rightPanel = document.createElement('div')\n rightPanel.className = 'claude-dev-server-right'\n\n // Create dev server iframe with srcdoc\n devIframe = document.createElement('iframe')\n devIframe.className = 'claude-dev-server-dev-iframe'\n // The HTML already has inspect script injected by server\n devIframe.srcdoc = originalHtml\n\n rightPanel.appendChild(devIframe)\n\n // Assemble layout: Claude (left) | divider | dev server (right)\n container.appendChild(leftPanel)\n container.appendChild(divider)\n container.appendChild(rightPanel)\n\n // Replace body content\n document.body.innerHTML = ''\n document.body.appendChild(container)\n document.body.appendChild(overlay)\n\n // Wait for iframe to load before setting up communication\n devIframe.onload = () => {\n console.log('[Claude Dev Server] Dev iframe loaded')\n // Setup inspect mode communication\n setupInspectCommunication()\n }\n }\n\n function setupInspectCommunication() {\n // Inspect mode is now handled entirely in the outer layer\n // We'll access the iframe's document directly\n }\n\n function setupIframeInspectListeners() {\n if (!devIframe || !devIframe.contentDocument) return\n\n // Prevent duplicate listener registration\n if (inspectListenersRegistered) {\n return\n }\n\n const iframeDoc = devIframe.contentDocument\n const iframeWindow = devIframe.contentWindow\n\n const inspectHandler = (e) => {\n if (!isInspectMode) return\n\n e.preventDefault()\n e.stopPropagation()\n\n if (e.type === 'click') {\n const el = e.target\n const rect = el.getBoundingClientRect()\n const className = el.className ? String(el.className) : ''\n // Limit classnames to first 2-3 to avoid overly long selectors\n const classNames = className.split(' ').filter(c => c).slice(0, 3)\n const selector = el.tagName.toLowerCase() +\n (el.id ? '#' + el.id : '') +\n (classNames.length ? '.' + classNames.join('.') : '')\n\n // Highlight element\n if (overlay) {\n overlay.innerHTML = ''\n\n // Get iframe position on page\n const iframeRect = devIframe.getBoundingClientRect()\n\n // Calculate highlight position relative to main document\n // Element rect is relative to iframe viewport, need to add iframe position\n const highlightTop = iframeRect.top + rect.top\n const highlightLeft = iframeRect.left + rect.left\n\n const highlight = document.createElement('div')\n highlight.className = 'claude-dev-server-highlight'\n highlight.style.top = highlightTop + 'px'\n highlight.style.left = highlightLeft + 'px'\n highlight.style.width = rect.width + 'px'\n highlight.style.height = rect.height + 'px'\n highlight.dataset.element = selector\n overlay.appendChild(highlight)\n }\n\n // Get source location and send to terminal\n getSourceLocationFromElement(el).then(location => {\n if (location) {\n sendToTerminal(location)\n }\n disableInspectMode()\n })\n } else if (e.type === 'mousemove') {\n const el = e.target\n const rect = el.getBoundingClientRect()\n const className = el.className ? String(el.className) : ''\n // Limit classnames to first 2-3 to avoid overly long selectors\n const classNames = className.split(' ').filter(c => c).slice(0, 3)\n const selector = el.tagName.toLowerCase() +\n (el.id ? '#' + el.id : '') +\n (classNames.length ? '.' + classNames.join('.') : '')\n\n if (overlay) {\n overlay.innerHTML = ''\n\n // Get iframe position on page\n const iframeRect = devIframe.getBoundingClientRect()\n\n // Calculate highlight position relative to main document\n const highlightTop = iframeRect.top + rect.top\n const highlightLeft = iframeRect.left + rect.left\n\n const highlight = document.createElement('div')\n highlight.className = 'claude-dev-server-highlight'\n highlight.style.top = highlightTop + 'px'\n highlight.style.left = highlightLeft + 'px'\n highlight.style.width = rect.width + 'px'\n highlight.style.height = rect.height + 'px'\n highlight.dataset.element = selector\n overlay.appendChild(highlight)\n }\n }\n }\n\n // Store handler reference for later removal\n iframeDoc._claudeInspectHandler = inspectHandler\n\n // Add event listeners in capture phase\n iframeDoc.addEventListener('click', inspectHandler, true)\n iframeDoc.addEventListener('mousemove', inspectHandler, true)\n\n // Mark listeners as registered\n inspectListenersRegistered = true\n }\n\n async function handleInspectElement(elementInfo) {\n // This is now handled directly in setupIframeInspectListeners\n }\n\n async function getSourceLocationFromElement(element) {\n // Access the iframe's document to detect Next.js chunks\n const iframeDoc = devIframe?.contentDocument || document\n\n // Early check: detect Next.js by checking for _next/static chunks\n const hasNextJsChunks = Array.from(iframeDoc.querySelectorAll('script[src]'))\n .some(script => script.getAttribute('src')?.includes('/_next/static/chunks/'))\n\n if (hasNextJsChunks) {\n console.log('[Claude Dev Server] Next.js Turbopack detected, using specialized lookup')\n\n const pagePath = window.location.pathname\n console.log('[Claude Dev Server] Looking up source for page:', pagePath)\n\n try {\n const params = new URLSearchParams({\n page: pagePath,\n framework: 'nextjs'\n })\n const lookupUrl = '/@sourcemap-lookup?' + params.toString()\n console.log('[Claude Dev Server] Fetching:', lookupUrl)\n\n const response = await fetch(lookupUrl)\n console.log('[Claude Dev Server] Response status:', response.status)\n\n if (response.ok) {\n const result = await response.json()\n console.log('[Claude Dev Server] Lookup result:', result)\n if (result.file) {\n const elClassName = element.className ? String(element.className) : ''\n // Limit classnames to first 2-3 to avoid overly long selectors\n const classNames = elClassName.split(' ').filter(c => c).slice(0, 3)\n const selector = element.tagName.toLowerCase() +\n (element.id ? '#' + element.id : '') +\n (classNames.length ? '.' + classNames.join('.') : '')\n\n // Extract text content from element\n let textContent = ''\n if (element.nodeType === Node.TEXT_NODE) {\n textContent = element.textContent ? element.textContent.trim().substring(0, 50) : ''\n } else if (element.childNodes.length === 1 && element.childNodes[0].nodeType === Node.TEXT_NODE) {\n textContent = element.childNodes[0].textContent ? element.childNodes[0].textContent.trim().substring(0, 50) : ''\n } else {\n for (const child of element.childNodes) {\n if (child.nodeType === Node.TEXT_NODE && child.textContent && child.textContent.trim()) {\n textContent = child.textContent.trim().substring(0, 50)\n break\n }\n }\n }\n if (textContent && textContent.length >= 50) {\n textContent += '...'\n }\n\n return {\n url: result.file,\n line: result.line || undefined,\n column: result.column || undefined,\n selector: selector,\n text: textContent,\n hint: 'File: ' + result.file\n }\n }\n }\n } catch (e) {\n console.log('[Claude Dev Server] Next.js lookup failed:', e)\n }\n // If Next.js lookup failed, continue with normal flow\n }\n\n let sourceFile = null\n let sourceLine = 1\n let sourceColumn = 1\n\n // Try to get original line number using source map\n // Use server-side source map resolution with source-map library\n async function resolveSourceMap(filePath, line, column) {\n try {\n console.log('[Claude Dev Server] Calling server source map resolution for:', filePath, line, column)\n\n // Convert absolute file path to URL path for Vite\n let urlPath = filePath\n if (filePath.startsWith('/Users/')) {\n // Convert /Users/.../src/App.jsx to /src/App.jsx\n const parts = filePath.split('/')\n const srcIndex = parts.indexOf('src')\n if (srcIndex >= 0) {\n urlPath = '/' + parts.slice(srcIndex).join('/')\n }\n }\n\n console.log('[Claude Dev Server] Converted path to URL path:', urlPath)\n\n // Use the server-side source map resolution with URL path\n const params = new URLSearchParams({\n file: urlPath,\n line: String(line),\n col: String(column)\n })\n\n const response = await fetch('/@sourcemap?' + params.toString())\n if (!response.ok) {\n console.log('[Claude Dev Server] Source map request failed:', response.status)\n return null\n }\n\n const result = await response.json()\n console.log('[Claude Dev Server] Source map result:', result)\n\n if (result.error) {\n console.log('[Claude Dev Server] Source map error:', result.error)\n return null\n }\n\n if (result.file) {\n return {\n file: result.file,\n line: result.line,\n column: result.column\n }\n }\n\n return null\n } catch (e) {\n console.log('[Claude Dev Server] Source map lookup failed:', e.message)\n return null\n }\n }\n\n // Try to extract jsxDEV source location from React Fiber\n function extractJsxDevLocation(fiber) {\n try {\n // The jsxDEV location is stored in the element type's _debugInfo or _source\n // React 18 stores it differently - let's check multiple locations\n const elementType = fiber.elementType || fiber.type\n\n // Check if this is a jsxDEV call by looking at the string representation\n if (elementType && typeof elementType === 'function') {\n const fnStr = elementType.toString()\n // jsxDEV functions have a specific pattern\n if (fnStr.includes('jsxDEV') || fnStr.includes('jsx')) {\n console.log('[Claude Dev Server] Found jsxDEV element type')\n }\n }\n\n // Try to get _debugSource which might have jsxDEV metadata\n const debugSource = fiber._debugSource || fiber._debugInfo\n if (debugSource) {\n // For jsxDEV, check if there's a _source object with fileName/lineNumber\n const source = debugSource._source || debugSource.source || debugSource\n if (source && source.fileName && source.lineNumber !== undefined) {\n console.log('[Claude Dev Server] Found _debugSource with source location:', source)\n // NOTE: Don't use this directly! The lineNumber might be from transpiled code\n // We'll let the source map resolver handle it\n return null\n }\n }\n\n // Check the memoizedState or other properties for source location\n if (fiber.memoizedState) {\n // React might store jsxDEV location in memoizedState\n console.log('[Claude Dev Server] Checking memoizedState:', fiber.memoizedState)\n }\n\n // Check the memoizedProps or other properties for source location\n if (fiber.memoizedProps && fiber.memoizedProps.__source) {\n const source = fiber.memoizedProps.__source\n console.log('[Claude Dev Server] Found __source in memoizedProps:', source)\n return {\n file: source.fileName,\n line: source.lineNumber,\n column: source.columnNumber || 1\n }\n }\n\n // Check pendingProps for __source\n if (fiber.pendingProps && fiber.pendingProps.__source) {\n const source = fiber.pendingProps.__source\n console.log('[Claude Dev Server] Found __source in pendingProps:', source)\n return {\n file: source.fileName,\n line: source.lineNumber,\n column: source.columnNumber || 1\n }\n }\n } catch (e) {\n console.log('[Claude Dev Server] Error extracting jsxDEV location:', e)\n }\n return null\n }\n\n // Try React DevTools - handle React 18's randomized suffix\n const elKeys = Object.keys(element)\n let fiberKey = elKeys.find(k => k === '__reactFiber__' || k === '__reactInternalInstance' || k.indexOf('__reactFiber') === 0)\n let propsKey = elKeys.find(k => k === '__reactProps__' || k.indexOf('__reactProps') === 0)\n\n if (fiberKey) {\n const fiber = element[fiberKey]\n console.log('[Claude Dev Server] Found fiber at key:', fiberKey)\n\n // Log fiber structure for debugging\n console.log('[Claude Dev Server] Fiber structure:', {\n _debugSource: fiber._debugSource,\n elementType: fiber.elementType,\n type: fiber.type,\n memoizedProps: fiber.memoizedProps,\n pendingProps: fiber.pendingProps\n })\n\n // Log _debugSource details\n if (fiber._debugSource) {\n console.log('[Claude Dev Server] _debugSource details:', JSON.stringify(fiber._debugSource, null, 2))\n }\n\n // For Next.js, try to get component name from elementType\n if (!fiber._debugSource && fiber.elementType) {\n const elementType = fiber.elementType\n console.log('[Claude Dev Server] elementType:', elementType)\n console.log('[Claude Dev Server] elementType.name:', elementType.name)\n console.log('[Claude Dev Server] elementType.displayName:', elementType.displayName)\n\n // Try to get the function string to find component name\n if (typeof elementType === 'function') {\n const fnStr = elementType.toString()\n console.log('[Claude Dev Server] elementType function:', fnStr.substring(0, 200))\n }\n }\n\n // First, try to extract jsxDEV source location\n const jsxDevLocation = extractJsxDevLocation(fiber)\n if (jsxDevLocation) {\n sourceFile = jsxDevLocation.file\n sourceLine = jsxDevLocation.line\n sourceColumn = jsxDevLocation.column\n\n // Convert absolute path to relative path\n if (sourceFile.startsWith('/')) {\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n if (projectRoot && sourceFile.startsWith(projectRoot)) {\n sourceFile = sourceFile.substring(projectRoot.length + 1)\n if (sourceFile.startsWith('/')) {\n sourceFile = sourceFile.substring(1)\n }\n }\n }\n console.log('[Claude Dev Server] Using jsxDEV location:', sourceFile, sourceLine)\n } else {\n // Fall back to _debugSource\n const debugSource = fiber._debugSource || fiber.elementType?._debugSource || fiber.type?._debugSource || fiber.alternate?._debugSource\n if (debugSource && debugSource.fileName) {\n sourceFile = debugSource.fileName\n sourceLine = debugSource.lineNumber || 1\n sourceColumn = debugSource.columnNumber || 1\n\n // Convert relative path to absolute path for source map resolution\n let absolutePath = sourceFile\n if (!sourceFile.startsWith('/')) {\n // Relative path - resolve relative to project root\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n absolutePath = projectRoot + '/' + sourceFile\n }\n\n console.log('[Claude Dev Server] Resolving source map for:', absolutePath, 'at line:', sourceLine)\n\n // Use server-side source map resolution\n const original = await resolveSourceMap(absolutePath, sourceLine, sourceColumn)\n if (original) {\n sourceFile = original.file\n sourceLine = original.line\n sourceColumn = original.column\n console.log('[Claude Dev Server] Original location from source map:', sourceFile, sourceLine)\n } else {\n // Source map resolution failed, use the original file\n // Convert absolute path back to relative\n if (absolutePath.startsWith('/')) {\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n if (projectRoot && absolutePath.startsWith(projectRoot)) {\n sourceFile = absolutePath.substring(projectRoot.length + 1)\n if (sourceFile.startsWith('/')) {\n sourceFile = sourceFile.substring(1)\n }\n }\n }\n }\n console.log('[Claude Dev Server] Final React source:', sourceFile, sourceLine)\n } else {\n // Try going up the fiber tree\n let currentFiber = fiber\n let depth = 0\n while (currentFiber && depth < 20) {\n const jsxDevLoc = extractJsxDevLocation(currentFiber)\n if (jsxDevLoc) {\n sourceFile = jsxDevLoc.file\n sourceLine = jsxDevLoc.line\n sourceColumn = jsxDevLoc.column\n\n if (sourceFile.startsWith('/')) {\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n if (projectRoot && sourceFile.startsWith(projectRoot)) {\n sourceFile = sourceFile.substring(projectRoot.length + 1)\n if (sourceFile.startsWith('/')) {\n sourceFile = sourceFile.substring(1)\n }\n }\n }\n console.log('[Claude Dev Server] Found jsxDEV location at depth', depth, ':', sourceFile, sourceLine)\n break\n }\n\n const ds = currentFiber._debugSource || currentFiber.elementType?._debugSource || currentFiber.type?._debugSource\n if (ds && ds.fileName) {\n sourceFile = ds.fileName\n sourceLine = ds.lineNumber || 1\n sourceColumn = ds.columnNumber || 1\n\n // Use server-side source map resolution\n const original = await resolveSourceMap(sourceFile, sourceLine, sourceColumn)\n if (original) {\n sourceFile = original.file\n sourceLine = original.line\n sourceColumn = original.column\n } else {\n // Convert absolute path to relative path using project root\n if (sourceFile.startsWith('/')) {\n const projectRoot = window.__CLAUDE_PROJECT_ROOT__\n if (projectRoot && sourceFile.startsWith(projectRoot)) {\n sourceFile = sourceFile.substring(projectRoot.length + 1)\n if (sourceFile.startsWith('/')) {\n sourceFile = sourceFile.substring(1)\n }\n }\n }\n }\n console.log('[Claude Dev Server] Found React source at depth', depth, ':', sourceFile, sourceLine)\n break\n }\n currentFiber = currentFiber.return || currentFiber.alternate\n depth++\n }\n }\n }\n }\n\n // Try Vue component\n if (!sourceFile) {\n const vueComponent = element.__vueParentComponent || element.__vnode\n if (vueComponent) {\n const type = vueComponent.type || vueComponent.component\n if (type && type.__file) {\n sourceFile = type.__file\n console.log('[Claude Dev Server] Found Vue source:', sourceFile)\n }\n }\n }\n\n // Try Vite's HMR source map\n if (!sourceFile) {\n // Look for data-vite-dev-id or similar attributes\n const viteId = element.getAttribute('data-vite-dev-id')\n if (viteId) {\n // Extract file path from viteId (remove query params if any)\n const queryIndex = viteId.indexOf('?')\n sourceFile = '/' + (queryIndex >= 0 ? viteId.substring(0, queryIndex) : viteId)\n console.log('[Claude Dev Server] Found Vite ID:', viteId)\n }\n }\n\n // Check for inline script\n if (!sourceFile) {\n const inlineScripts = iframeDoc.querySelectorAll('script:not([src])')\n if (inlineScripts.length > 0) {\n const pathParts = window.location.pathname.split('/')\n const fileName = pathParts[pathParts.length - 1] || 'index.html'\n sourceFile = '/' + fileName\n\n const html = iframeDoc.documentElement.outerHTML\n const elId = element.id ? element.id : ''\n const elClass = element.className ? element.className : ''\n let elPattern\n if (elId) {\n elPattern = 'id=\"' + elId + '\"'\n } else if (elClass) {\n elPattern = 'class=\"' + elClass.split(' ')[0] + '\"'\n } else {\n elPattern = element.tagName.toLowerCase()\n }\n\n const matchIndex = html.indexOf(elPattern)\n if (matchIndex !== -1) {\n const beforeElement = html.substring(0, matchIndex)\n sourceLine = beforeElement.split('\\\\n').length\n }\n }\n }\n\n // Find main script\n if (!sourceFile) {\n const scripts = iframeDoc.querySelectorAll('script[src]')\n for (const script of scripts) {\n const src = script.getAttribute('src')\n if (src && !src.includes('cdn') && !src.includes('node_modules') &&\n (src.includes('/src/') || src.includes('/app.') || src.includes('/main.'))) {\n sourceFile = src\n break\n }\n }\n }\n\n // Fallback\n if (!sourceFile) {\n const pathParts = window.location.pathname.split('/')\n const fileName = pathParts[pathParts.length - 1] || 'index.html'\n sourceFile = '/' + fileName\n }\n\n const elClassName = element.className ? String(element.className) : ''\n // Limit classnames to first 2-3 to avoid overly long selectors\n const classNames = elClassName.split(' ').filter(c => c).slice(0, 3)\n const selector = element.tagName.toLowerCase() +\n (element.id ? '#' + element.id : '') +\n (classNames.length ? '.' + classNames.join('.') : '')\n\n // Get text content for better context\n let textContent = ''\n if (element.nodeType === Node.TEXT_NODE) {\n textContent = element.textContent ? element.textContent.trim().substring(0, 50) : ''\n } else if (element.childNodes.length === 1 && element.childNodes[0].nodeType === Node.TEXT_NODE) {\n textContent = element.childNodes[0].textContent ? element.childNodes[0].textContent.trim().substring(0, 50) : ''\n } else {\n // Try to get first text node from children\n for (const child of element.childNodes) {\n if (child.nodeType === Node.TEXT_NODE && child.textContent && child.textContent.trim()) {\n textContent = child.textContent.trim().substring(0, 50)\n break\n }\n }\n }\n if (textContent && textContent.length >= 50) {\n textContent += '...'\n }\n\n return {\n url: sourceFile,\n line: sourceLine,\n column: sourceColumn,\n selector: selector,\n text: textContent,\n hint: sourceFile ? 'File: ' + sourceFile : 'Element: ' + selector\n }\n }\n\n function setupDraggable(divider) {\n let startX = 0\n let startWidth = 0\n let containerWidth = 0\n\n // Remove existing listeners to avoid duplicates\n divider.removeEventListener('mousedown', startDrag)\n divider.removeEventListener('touchstart', startDrag)\n\n divider.addEventListener('mousedown', startDrag)\n divider.addEventListener('touchstart', startDrag)\n\n function startDrag(e) {\n isDragging = true\n divider.classList.add('dragging')\n\n // Disable pointer events on iframes to prevent interference\n const iframes = document.querySelectorAll('iframe')\n iframes.forEach(iframe => iframe.style.pointerEvents = 'none')\n\n const clientX = e.touches ? e.touches[0].clientX : e.clientX\n startX = clientX\n\n const container = document.querySelector('.claude-dev-server-container')\n const leftPanelEl = document.querySelector('.claude-dev-server-left')\n\n if (container && leftPanelEl) {\n containerWidth = container.offsetWidth\n startWidth = leftPanelEl.offsetWidth\n }\n\n e.preventDefault()\n }\n\n function drag(e) {\n if (!isDragging) return\n\n // Safety check: if mouse button is not pressed, end drag\n if (e.buttons === 0 && !e.touches) {\n endDrag()\n return\n }\n\n const clientX = e.touches ? e.touches[0].clientX : e.clientX\n const deltaX = clientX - startX\n\n // Calculate new width in pixels, then convert to percentage\n let newWidth = startWidth + deltaX\n let percentage = (newWidth / containerWidth) * 100\n\n // Clamp between 20% and 80%\n const clamped = Math.max(20, Math.min(80, percentage))\n\n const leftPanelEl = document.querySelector('.claude-dev-server-left')\n if (leftPanelEl) {\n leftPanelEl.style.flex = 'none'\n leftPanelEl.style.width = clamped + '%'\n }\n }\n\n function endDrag() {\n if (isDragging) {\n isDragging = false\n divider.classList.remove('dragging')\n\n // Re-enable pointer events on iframes\n const iframes = document.querySelectorAll('iframe')\n iframes.forEach(iframe => iframe.style.pointerEvents = '')\n }\n }\n\n // Use capture phase to ensure events are caught\n // Remove old listeners first to prevent duplicates\n document.removeEventListener('mousemove', drag, true)\n document.removeEventListener('touchmove', drag, true)\n document.removeEventListener('mouseup', endDrag, true)\n document.removeEventListener('touchend', endDrag, true)\n\n document.addEventListener('mousemove', drag, true)\n document.addEventListener('touchmove', drag, { passive: false, capture: true })\n document.addEventListener('mouseup', endDrag, true)\n document.addEventListener('touchend', endDrag, true)\n }\n\n function createOverlay() {\n if (overlay) return\n overlay = document.createElement('div')\n overlay.className = 'claude-dev-server-inspect-overlay'\n document.body.appendChild(overlay)\n }\n\n function enableInspectMode() {\n isInspectMode = true\n if (overlay) overlay.classList.add('active')\n // Setup inspect listeners on the iframe\n setupIframeInspectListeners()\n // Change cursor in iframe\n if (devIframe && devIframe.contentDocument && devIframe.contentDocument.body) {\n devIframe.contentDocument.body.style.cursor = 'crosshair'\n }\n const btn = document.querySelector('.claude-dev-server-btn-inspect')\n if (btn) btn.classList.add('active')\n }\n\n function disableInspectMode() {\n isInspectMode = false\n if (overlay) {\n overlay.classList.remove('active')\n overlay.innerHTML = ''\n }\n // Restore cursor in iframe\n if (devIframe && devIframe.contentDocument && devIframe.contentDocument.body) {\n devIframe.contentDocument.body.style.cursor = ''\n }\n const btn = document.querySelector('.claude-dev-server-btn-inspect')\n if (btn) btn.classList.remove('active')\n\n // Remove inspect listeners to free up resources\n removeIframeInspectListeners()\n }\n\n function removeIframeInspectListeners() {\n if (!devIframe || !devIframe.contentDocument) return\n\n const iframeDoc = devIframe.contentDocument\n const existingHandler = iframeDoc._claudeInspectHandler\n\n if (existingHandler) {\n iframeDoc.removeEventListener('click', existingHandler, true)\n iframeDoc.removeEventListener('mousemove', existingHandler, true)\n delete iframeDoc._claudeInspectHandler\n inspectListenersRegistered = false\n }\n }\n\n async function sendToTerminal(location) {\n // Use format: @filename <selector> \"text content\" (without line number)\n const filePath = location.url || location.file || 'unknown'\n\n // Build selector - handle Tailwind CSS classes by limiting\n const tagName = location.selector ? location.selector.split(/[.#]/)[0] : 'div'\n let selector = location.selector || tagName\n\n // Get text content for better context\n let textContent = ''\n if (location.text) {\n textContent = location.text\n } else if (location.hint && location.hint.includes('File:')) {\n // No text content available\n }\n\n // Format: @filename <selector> \"text content\" (no line number)\n let prompt = \\`@\\${filePath} <\\${selector}>\\`\n if (textContent) {\n prompt += \\` \"\\${textContent}\"\\`\n }\n\n console.log('[Claude Dev Server] Sending to terminal:', prompt)\n\n // Store the interval ID so we can clear it if needed\n if (!window._claudeSendRetryInterval) {\n window._claudeSendRetryInterval = null\n }\n\n // Clear any existing retry interval\n if (window._claudeSendRetryInterval) {\n clearInterval(window._claudeSendRetryInterval)\n window._claudeSendRetryInterval = null\n }\n\n // Send to terminal with retry logic\n const sendToTerminalInternal = () => {\n if (!ttydIframe || !ttydIframe.contentWindow) {\n return false\n }\n\n const win = ttydIframe.contentWindow\n if (win.sendToTerminal) {\n win.sendToTerminal(prompt)\n console.log('[Claude Dev Server] Sent via sendToTerminal:', prompt)\n // Clear interval on success\n if (window._claudeSendRetryInterval) {\n clearInterval(window._claudeSendRetryInterval)\n window._claudeSendRetryInterval = null\n }\n return true\n }\n\n return false\n }\n\n // Try immediately\n if (sendToTerminalInternal()) {\n return\n }\n\n // If not ready, wait and retry\n let attempts = 0\n const maxAttempts = 50\n window._claudeSendRetryInterval = setInterval(() => {\n attempts++\n if (sendToTerminalInternal() || attempts >= maxAttempts) {\n clearInterval(window._claudeSendRetryInterval)\n window._claudeSendRetryInterval = null\n if (attempts >= maxAttempts) {\n console.warn('[Claude Dev Server] Could not send to terminal after retries')\n }\n }\n }, 100)\n }\n\n function loadTerminalIframe(ttydUrl) {\n if (!ttydIframe) return\n ttydWsUrl = ttydUrl\n ttydIframe.src = '/ttyd/index.html?ws=' + encodeURIComponent(ttydUrl)\n ttydIframe.onload = () => {\n console.log('[Claude Dev Server] Terminal iframe loaded')\n }\n }\n\n function connect(port) {\n const WS_URL = 'ws://localhost:' + port\n ws = new WebSocket(WS_URL)\n\n ws.onopen = () => {\n console.log('[Claude Dev Server] Connected to control server')\n }\n\n ws.onmessage = (e) => {\n try {\n const msg = JSON.parse(e.data)\n console.log('[Claude Dev Server] Received message:', msg.type, msg)\n if (msg.type === 'ready' && msg.ttydUrl) {\n loadTerminalIframe(msg.ttydUrl)\n }\n } catch (err) {\n console.error('[Claude Dev Server] Message parse error:', err)\n }\n }\n\n ws.onclose = () => {\n console.log('[Claude Dev Server] Control WebSocket disconnected, reconnecting...')\n setTimeout(() => connect(port), 2000)\n }\n\n ws.onerror = (err) => {\n console.error('[Claude Dev Server] Control WebSocket error:', err)\n }\n }\n\n initWhenReady()\n\n document.addEventListener('keydown', (e) => {\n if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key === 'I') {\n e.preventDefault()\n if (isInspectMode) {\n disableInspectMode()\n } else {\n enableInspectMode()\n }\n }\n if (e.key === 'Escape' && isInspectMode) {\n disableInspectMode()\n }\n })\n})()\n`\n","import { spawn } from 'child_process'\nimport { existsSync, readFileSync } from 'fs'\nimport { createHash } from 'crypto'\nimport { join, dirname, relative, sep } from 'path'\nimport http, { IncomingMessage } from 'http'\nimport { fileURLToPath } from 'url'\nimport { createProxyMiddleware } from 'http-proxy-middleware'\nimport { WebSocketServer } from 'ws'\nimport { createConnection } from 'net'\nimport { SourceMapConsumer } from 'source-map'\nimport { createWebSocketServer } from '../server/websocket.js'\nimport { CLIENT_SCRIPT, CLIENT_STYLES } from '../client/injection.js'\n\nconst __filename = fileURLToPath(import.meta.url)\nconst __dirname = dirname(__filename)\n\nexport interface UniversalServerOptions {\n port?: number\n claudePath?: string\n claudeArgs?: string[]\n cwd?: string\n server?: {\n type?: 'vite' | 'next' | 'webpack' | 'custom'\n command?: string\n port?: number\n }\n}\n\nexport async function startUniversalServer(options: UniversalServerOptions = {}) {\n const cwd = options.cwd || process.cwd()\n const port = options.port || 3000\n\n // 1. 检测项目类型\n const projectType = options.server?.type || detectProjectType(cwd)\n const targetCommand = options.server?.command || getDefaultCommand(projectType)\n\n console.log(`[Claude Dev Server] Detected project type: ${projectType}`)\n console.log(`[Claude Dev Server] Starting target server...`)\n\n // 2. 启动目标 dev server(不预设端口)\n const targetServer = spawnTargetServer(targetCommand, cwd)\n\n // 3. 等待并检测目标服务器实际监听的端口\n console.log(`[Claude Dev Server] Waiting for target server to start (PID: ${targetServer.pid})...`)\n const targetPort = await detectServerPort(targetServer, 30000)\n\n if (!targetPort) {\n throw new Error('Failed to detect target server port. Please check if the dev server started successfully.')\n }\n\n console.log(`[Claude Dev Server] Target server is running on port ${targetPort}`)\n\n // 4. 启动控制 WebSocket 服务器(ttyd + Claude)\n const wsServer = createWebSocketServer({\n port: 0, // 自动分配端口\n projectRoot: cwd,\n claudePath: options.claudePath || 'claude',\n claudeArgs: options.claudeArgs || [],\n })\n\n const { wsPort, ttydPort } = await wsServer.start()\n console.log(`[Claude Dev Server] Control server running on ws://localhost:${wsPort}`)\n console.log(`[Claude Dev Server] ttyd running on ws://localhost:${ttydPort}`)\n\n // 5. 启动 HTTP 代理服务器\n const proxyServer = createProxyServer(targetPort, wsPort, cwd)\n proxyServer.listen(port)\n console.log(`[Claude Dev Server] Proxy server running on http://localhost:${port}`)\n console.log(`\\n🚀 Ready! Open http://localhost:${port} in your browser`)\n\n // 清理处理\n const cleanup = () => {\n console.log('[Claude Dev Server] Shutting down...')\n targetServer.kill()\n wsServer.stop()\n proxyServer.close()\n process.exit(0)\n }\n\n process.on('SIGINT', cleanup)\n process.on('SIGTERM', cleanup)\n\n return { proxyServer, targetServer, wsServer }\n}\n\nfunction detectProjectType(cwd: string): 'vite' | 'next' | 'webpack' | 'custom' {\n if (existsSync(join(cwd, 'vite.config.ts')) || existsSync(join(cwd, 'vite.config.js'))) {\n return 'vite'\n }\n if (existsSync(join(cwd, 'next.config.js')) || existsSync(join(cwd, 'next.config.mjs'))) {\n return 'next'\n }\n if (existsSync(join(cwd, 'webpack.config.js')) || existsSync(join(cwd, 'webpack.config.ts'))) {\n return 'webpack'\n }\n return 'custom'\n}\n\nfunction getDefaultCommand(projectType: string): string {\n switch (projectType) {\n case 'vite': return 'npm run dev'\n case 'next': return 'npm run dev'\n case 'webpack': return 'npm run dev'\n default: return 'npm run dev'\n }\n}\n\nfunction spawnTargetServer(command: string, cwd: string) {\n const [cmd, ...args] = command.split(' ')\n const child = spawn(cmd, args, {\n cwd,\n stdio: 'pipe',\n env: process.env,\n })\n\n // Forward child's stdout/stderr to parent so user can see dev server output\n child.stdout?.pipe(process.stdout)\n child.stderr?.pipe(process.stderr)\n\n return child\n}\n\n/**\n * Detect the port that the dev server is listening on by parsing stdout.\n * Most dev servers announce their port on startup like: \"Local: http://localhost:5173\"\n */\nasync function detectServerPort(childProcess: any, timeout: number): Promise<number | null> {\n return new Promise((resolve) => {\n const timeoutId = setTimeout(() => {\n cleanup()\n resolve(null)\n }, timeout)\n\n let stdout = ''\n\n const onData = (chunk: Buffer) => {\n stdout += chunk.toString()\n\n // Match common port announcement patterns:\n // Vite: \"Local: http://localhost:5173/\"\n // Next.js: \"Local: http://localhost:3000\"\n // Webpack: \"http://localhost:8080/\"\n const patterns = [\n /localhost:(\\d{4,5})/,\n /127\\.0\\.0\\.1:(\\d{4,5})/,\n /0\\.0\\.0\\.0:(\\d{4,5})/,\n ]\n\n for (const pattern of patterns) {\n const match = stdout.match(pattern)\n if (match) {\n const port = parseInt(match[1], 10)\n console.log(`[Claude Dev Server] Detected port from stdout: ${port}`)\n cleanup()\n resolve(port)\n return\n }\n }\n }\n\n const cleanup = () => {\n clearTimeout(timeoutId)\n childProcess.stdout?.off('data', onData)\n }\n\n childProcess.stdout?.on('data', onData)\n })\n}\n\n/**\n * Handle source map resolution request.\n * Given a compiled file path and line/column, find the original source position.\n */\nasync function handleSourceMapRequest(\n projectRoot: string,\n filePath: string,\n line: number,\n column: number,\n targetPort?: number\n): Promise<{ file?: string; line?: number; column?: number; original?: any; error?: string }> {\n try {\n let content: string\n let fullPath = filePath\n\n // If filePath starts with / and looks like a URL path, fetch from Vite\n if (filePath.startsWith('/') && targetPort) {\n // console.log('[Claude Dev Server] Fetching from Vite:', filePath)\n try {\n const response = await fetch(`http://localhost:${targetPort}${filePath}`)\n if (!response.ok) {\n console.log('[Claude Dev Server] Failed to fetch from Dev Server:', response.status)\n return { error: 'Failed to fetch from Dev Server' }\n }\n content = await response.text()\n console.log('[Claude Dev Server] Fetched', content.length, 'chars from Dev Server')\n } catch (e) {\n console.log('[Claude Dev Server] Fetch error:', e)\n return { error: 'Fetch error: ' + (e as Error).message }\n }\n } else {\n // If filePath is absolute, check if it's within projectRoot\n if (!filePath.startsWith('/')) {\n fullPath = join(projectRoot, filePath)\n }\n\n // Check if the file exists\n if (!existsSync(fullPath)) {\n console.log('[Claude Dev Server] File not found:', fullPath)\n return { error: 'File not found' }\n }\n\n // Read the file content\n content = readFileSync(fullPath, 'utf-8')\n\n console.log('[Claude Dev Server] Resolving source map for:', fullPath, 'at line:', line)\n }\n\n // Look for sourceMappingURL comment\n // Format: //# sourceMappingURL=filename.js.map or /*# sourceMappingURL=filename.js.map */\n // Or inline: //# sourceMappingURL=data:application/json;base64,...\n let sourceMapUrl: string | null = null\n const patterns = [\n /\\/\\/[@#]\\s*sourceMappingURL=([^\\s]+)/,\n /\\/\\*[@#]\\s*sourceMappingURL=([^\\s]+)\\s*\\*\\//\n ]\n\n for (const pattern of patterns) {\n const match = content.match(pattern)\n if (match) {\n sourceMapUrl = match[1]\n console.log('[Claude Dev Server] Found sourceMappingURL:', sourceMapUrl.substring(0, 100) + '...')\n break\n }\n }\n\n if (!sourceMapUrl) {\n console.log('[Claude Dev Server] No source map found in:', fullPath)\n return { file: relative(projectRoot, fullPath), line, column }\n }\n\n let sourceMapContent: string\n let sourceMap: any\n\n // Check if it's an inline source map (data URL)\n if (sourceMapUrl.startsWith('data:application/json;base64,') ||\n sourceMapUrl.startsWith('data:application/json;charset=utf-8;base64,')) {\n console.log('[Claude Dev Server] Found inline source map')\n // Extract base64 content\n const base64Data = sourceMapUrl.split(',', 2)[1]\n sourceMapContent = Buffer.from(base64Data, 'base64').toString('utf-8')\n try {\n sourceMap = JSON.parse(sourceMapContent)\n } catch (e) {\n console.log('[Claude Dev Server] Failed to parse inline source map:', e)\n return { file: relative(projectRoot, fullPath), line, column }\n }\n } else if (sourceMapUrl.startsWith('http://') || sourceMapUrl.startsWith('https://')) {\n // Remote source map - try to fetch via proxy\n console.log('[Claude Dev Server] Remote source map not supported:', sourceMapUrl)\n return { file: relative(projectRoot, fullPath), line, column }\n } else {\n // External source map file\n let sourceMapPath: string\n if (sourceMapUrl.startsWith('/')) {\n // Absolute path\n sourceMapPath = sourceMapUrl\n } else {\n // Relative path - resolve relative to the file\n sourceMapPath = join(dirname(fullPath), sourceMapUrl)\n }\n\n console.log('[Claude Dev Server] Reading external source map:', sourceMapPath)\n\n // Read the source map\n if (!existsSync(sourceMapPath)) {\n console.log('[Claude Dev Server] Source map file not found:', sourceMapPath)\n return { file: relative(projectRoot, fullPath), line, column }\n }\n\n sourceMapContent = readFileSync(sourceMapPath, 'utf-8')\n sourceMap = JSON.parse(sourceMapContent)\n }\n\n // console.log('[Claude Dev Server] Source map loaded, sources:', sourceMap.sources?.length, 'mappings:', sourceMap.mappings?.substring(0, 50) + '...')\n // console.log('[Claude Dev Server] Source map sources:', sourceMap.sources)\n\n // Use source-map library to find original position\n const consumer = await new SourceMapConsumer(sourceMap)\n const original = consumer.originalPositionFor({\n line: line,\n column: column\n })\n consumer.destroy()\n\n // console.log('[Claude Dev Server] Source map result:', {\n // generated: { line, column },\n // original: original\n // })\n\n if (original.source && original.line !== null) {\n // Convert source path to be relative to project root\n let originalFile = original.source\n if (originalFile.startsWith('webpack://')) {\n // Remove webpack:// prefix\n originalFile = originalFile.replace(/^webpack:\\/\\/[\\/\\\\]?/, '')\n }\n // For Vite and other bundlers, source might be just a filename\n if (!originalFile.startsWith('/')) {\n // Try to resolve relative to project root to verify the file exists\n const possiblePath = join(projectRoot, originalFile)\n if (existsSync(possiblePath)) {\n // Keep the original source path as-is (preserves directory structure)\n // originalFile is already correct (e.g., 'src/App.jsx')\n } else {\n // File doesn't exist at the given path\n // Check if it's just a filename (no directory separators)\n const fileName = originalFile.split('/').pop() || originalFile.split('\\\\').pop() || originalFile\n if (fileName === originalFile) {\n // Source is just a filename (common with Vite inline source maps)\n // If filePath is already a relative path like '/src/App.jsx', use it directly\n if (filePath.startsWith('/')) {\n originalFile = filePath.substring(1) // Remove leading slash\n console.log('[Claude Dev Server] Source is just a filename, using filePath:', originalFile)\n } else {\n // Fall back to relative path from fullPath\n originalFile = relative(projectRoot, fullPath)\n }\n } else {\n // Has directory but file doesn't exist, use relative\n originalFile = relative(projectRoot, possiblePath)\n }\n }\n }\n\n // console.log('[Claude Dev Server] Source map resolved:', {\n // original: { file: originalFile, line: original.line, column: original.column },\n // generated: { file: filePath, line, column }\n // })\n\n return {\n file: originalFile,\n line: original.line,\n column: original.column || 1,\n original: {\n source: original.source,\n line: original.line,\n column: original.column,\n name: original.name\n }\n }\n }\n\n // No original position found, return generated\n return { file: relative(projectRoot, fullPath), line, column }\n } catch (err) {\n console.error('[Claude Dev Server] Source map resolution error:', err)\n return { error: String(err) }\n }\n}\n\n/**\n * Handle Next.js Turbopack source file lookup.\n * Given a page path, find the corresponding source file by parsing Turbopack chunks.\n */\nasync function handleTurbopackLookup(\n projectRoot: string,\n pagePath: string,\n targetPort: number\n): Promise<{ file?: string; line?: number; error?: string }> {\n try {\n console.log('[Claude Dev Server] Turbopack lookup for page:', pagePath)\n\n // Get the HTML page to find loaded chunk URLs\n const pageRes = await fetch(`http://localhost:${targetPort}${pagePath}`)\n if (!pageRes.ok) {\n return { error: 'Failed to fetch page' }\n }\n\n const html = await pageRes.text()\n const chunkUrls: string[] = []\n\n // Extract chunk URLs from HTML\n const scriptMatches = html.matchAll(/<script[^>]*src=\"([^\"]*\\/_next\\/static\\/chunks\\/[^\"]*)\"/g)\n for (const match of scriptMatches) {\n if (match[1]) {\n chunkUrls.push(match[1])\n }\n }\n\n console.log('[Claude Dev Server] Found', chunkUrls.length, 'chunk URLs')\n\n // Parse each chunk to find module paths\n for (const chunkUrl of chunkUrls) {\n try {\n const fullUrl = chunkUrl.startsWith('http') ? chunkUrl : `http://localhost:${targetPort}${chunkUrl}`\n const chunkRes = await fetch(fullUrl)\n if (!chunkRes.ok) continue\n\n const chunkContent = await chunkRes.text()\n\n // Extract module paths from Turbopack format\n // Format: \"[project]/path/to/file.tsx\" or \"[project]/path/to/file.tsx (ecmascript)\"\n const modulePathRegex = /\\[project\\]([^\\s\"]+\\.(tsx?|jsx?))/g\n const matches = [...chunkContent.matchAll(modulePathRegex)]\n\n for (const match of matches) {\n if (match[1]) {\n const sourcePath = match[1]\n // Remove [project] prefix and convert to relative path\n let relativePath = sourcePath.replace(/^\\[project\\]/, '')\n\n // Check if this path matches the current page\n // Normalize page path: /zh/login -> /login or /app/[lng]/(auth)/login/page.tsx\n const normalizedPagePath = pagePath.replace(/^\\/[^/]+/, '') // Remove language prefix\n\n if (relativePath.toLowerCase().includes(normalizedPagePath.toLowerCase()) ||\n relativePath.toLowerCase().includes('login')) {\n // Found matching source file\n console.log('[Claude Dev Server] Found source file:', relativePath)\n\n return {\n file: relativePath,\n line: undefined // Turbopack doesn't provide line numbers\n }\n }\n }\n }\n } catch (e) {\n console.log('[Claude Dev Server] Error fetching chunk:', chunkUrl, e)\n }\n }\n\n return { error: 'Source file not found for page: ' + pagePath }\n } catch (err) {\n console.error('[Claude Dev Server] Turbopack lookup error:', err)\n return { error: String(err) }\n }\n}\n\n/**\n * Check if request is for an HTML page (not assets, API, WebSocket, etc.)\n */\nfunction isHtmlPageRequest(req: IncomingMessage): boolean {\n const accept = req.headers.accept || ''\n const url = req.url || ''\n\n // Check if request accepts HTML\n if (!accept.includes('text/html')) {\n return false\n }\n\n // Check if it's a page request (not assets, API, etc.)\n if (url.startsWith('/@') || url.startsWith('/_next/') ||\n url.startsWith('/ttyd') || url.startsWith('/dev.html')) {\n return false\n }\n\n return true\n}\n\nfunction createProxyServer(targetPort: number, wsPort: number, projectRoot: string) {\n // 读取 ttyd 资源文件\n // 从当前模块路径计算 assets 目录\n // moduleDir 是 /Users/lloyd/moox/claude-dev-server/dist\n // 所以需要 assets 是 /Users/lloyd/moox/claude-dev-server/dist/assets\n const moduleDir = dirname(fileURLToPath(import.meta.url))\n const assetsPath = join(moduleDir, 'assets')\n\n let ttydHtml: string\n let ttydBridgeJs: string\n let devHtml: string\n\n try {\n ttydHtml = readFileSync(join(assetsPath, 'ttyd-terminal.html'), 'utf-8')\n ttydBridgeJs = readFileSync(join(assetsPath, 'ttyd-bridge.js'), 'utf-8')\n devHtml = readFileSync(join(assetsPath, 'dev.html'), 'utf-8')\n } catch (e: any) {\n console.error('[Claude Dev Server] Failed to read assets from', assetsPath)\n console.error('[Claude Dev Server] moduleDir:', moduleDir)\n console.error('[Claude Dev Server] Error:', e.message)\n throw new Error('Assets not found. Please run `npm run build` first.')\n }\n\n const server = http.createServer((req, res) => {\n // Check if request is from dev.html iframe\n const referer = req.headers.referer || ''\n const isFromDevPage = referer.includes('dev.html')\n\n // Handle /dev.html route\n if (req.url?.startsWith('/dev.html')) {\n const urlParams = new URL(req.url || '', `http://${req.headers.host}`)\n const originalPath = urlParams.searchParams.get('path') || '/'\n\n // Replace placeholders in dev HTML\n const host = req.headers.host || 'localhost:3000'\n const origin = `http://${host}`\n const modifiedDevHtml = devHtml.replace(\n /__CLAUDE_IFRAME_SRC__/g,\n `${origin}${originalPath}`\n ).replace(\n /__CLAUDE_ORIGINAL_PATH__/g,\n originalPath\n )\n res.setHeader('Content-Type', 'text/html')\n res.end(modifiedDevHtml)\n return\n }\n\n // If not from dev.html and requesting HTML page, redirect to dev.html\n if (!isFromDevPage && isHtmlPageRequest(req)) {\n const currentPath = req.url || '/'\n const devPageUrl = `/dev.html?path=${encodeURIComponent(currentPath)}`\n res.writeHead(302, { 'Location': devPageUrl })\n res.end()\n return\n }\n\n // 处理 @claude-port 端点\n if (req.url === '/@claude-port') {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ port: wsPort }))\n return\n }\n\n // 处理 sourcemap 解析端点\n if (req.url?.startsWith('/@sourcemap?')) {\n const url = new URL(req.url, `http://localhost:${wsPort}`)\n const file = url.searchParams.get('file')\n const line = url.searchParams.get('line')\n const column = url.searchParams.get('col')\n\n if (file && line && column) {\n handleSourceMapRequest(projectRoot, file, parseInt(line), parseInt(column || '1'), targetPort)\n .then(result => {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(result))\n })\n .catch(err => {\n console.error('[Claude Dev Server] Source map error:', err)\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ error: err.message }))\n })\n return\n }\n }\n\n // 处理 Next.js/Turbopack 源文件查找端点\n if (req.url?.startsWith('/@sourcemap-lookup?')) {\n const url = new URL(req.url, `http://localhost:${wsPort}`)\n const page = url.searchParams.get('page')\n const framework = url.searchParams.get('framework')\n\n if (page && framework === 'nextjs') {\n handleTurbopackLookup(projectRoot, page, targetPort)\n .then(result => {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(result))\n })\n .catch(err => {\n console.error('[Claude Dev Server] Turbopack lookup error:', err)\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ error: err.message }))\n })\n return\n }\n }\n\n // 处理 /ttyd/* 路由\n if (req.url?.startsWith('/ttyd/')) {\n const urlPath = req.url.split('?')[0] // 移除查询参数\n\n if (urlPath === '/ttyd/index.html' || urlPath === '/ttyd/') {\n res.setHeader('Content-Type', 'text/html')\n res.end(ttydHtml)\n return\n }\n\n if (urlPath === '/ttyd/ttyd-bridge.js') {\n res.setHeader('Content-Type', 'application/javascript')\n res.end(ttydBridgeJs)\n return\n }\n\n // Handle ttyd token endpoint\n if (urlPath === '/ttyd/token' || urlPath === '/ttyd/index.html/token') {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ token: '' }))\n return\n }\n\n // 其他 /ttyd/* 路由返回 404\n res.statusCode = 404\n res.end('Not found')\n return\n }\n\n // 代理到目标服务器\n // If request is from dev.html, don't inject - serve original HTML\n // Remove accept-encoding to get uncompressed content\n const proxyHeaders = { ...req.headers }\n delete proxyHeaders['accept-encoding']\n\n const shouldInject = !isFromDevPage\n\n const options = {\n hostname: 'localhost',\n port: targetPort,\n path: req.url,\n method: req.method,\n headers: proxyHeaders,\n }\n\n const proxyReq = http.request(options, (proxyRes) => {\n // Inject scripts only if not from wrapper\n if (proxyRes.headers['content-type']?.includes('text/html') && shouldInject) {\n const body: Buffer[] = []\n proxyRes.on('data', (chunk) => body.push(chunk))\n proxyRes.on('end', () => {\n const html = Buffer.concat(body).toString('utf8')\n const injected = injectScripts(html, wsPort, projectRoot)\n const statusCode = proxyRes.statusCode || 200\n res.writeHead(statusCode, {\n ...proxyRes.headers,\n 'content-length': Buffer.byteLength(injected),\n })\n res.end(injected)\n })\n } else {\n const statusCode = proxyRes.statusCode || 200\n res.writeHead(statusCode, proxyRes.headers)\n proxyRes.pipe(res)\n }\n })\n\n proxyReq.on('error', (err) => {\n console.error('[Claude Dev Server] Proxy error:', err)\n res.statusCode = 502\n res.end('Bad Gateway')\n })\n\n req.pipe(proxyReq)\n })\n\n // Handle WebSocket upgrade requests (e.g., Next.js webpack-hmr, Vite HMR)\n server.on('upgrade', (req: any, socket: any, head: Buffer) => {\n // Check if this is a WebSocket upgrade request\n if (req.headers['upgrade']?.toLowerCase() !== 'websocket') {\n return\n }\n\n console.log('[Claude Dev Server] WebSocket upgrade request:', req.url)\n\n // Create raw TCP connection to target server\n const targetSocket = createConnection(targetPort, 'localhost', () => {\n console.log('[Claude Dev Server] Connected to target WebSocket server')\n\n // Forward the upgrade request to target\n const upgradeRequest = [\n `${req.method} ${req.url} HTTP/1.1`,\n `Host: localhost:${targetPort}`,\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Key: ${req.headers['sec-websocket-key']}`,\n `Sec-WebSocket-Version: ${req.headers['sec-websocket-version'] || '13'}`,\n ]\n\n if (req.headers['sec-websocket-protocol']) {\n upgradeRequest.push(`Sec-WebSocket-Protocol: ${req.headers['sec-websocket-protocol']}`)\n }\n if (req.headers['sec-websocket-extensions']) {\n upgradeRequest.push(`Sec-WebSocket-Extensions: ${req.headers['sec-websocket-extensions']}`)\n }\n\n targetSocket.write(upgradeRequest.join('\\r\\n') + '\\r\\n\\r\\n')\n\n // Forward the head (remaining data from the upgrade request)\n if (head && head.length > 0) {\n targetSocket.write(head)\n }\n })\n\n // Handle response from target server\n targetSocket.on('data', (data: Buffer) => {\n if (socket.writable) {\n socket.write(data)\n }\n })\n\n // Handle data from client\n socket.on('data', (data: Buffer) => {\n if (targetSocket.writable) {\n targetSocket.write(data)\n }\n })\n\n // Handle connection close\n socket.on('close', () => {\n console.log('[Claude Dev Server] Client WebSocket closed')\n targetSocket.destroy()\n })\n\n targetSocket.on('close', () => {\n console.log('[Claude Dev Server] Target WebSocket closed')\n socket.end()\n })\n\n // Handle errors\n socket.on('error', (err: Error) => {\n console.error('[Claude Dev Server] Client socket error:', err.message)\n targetSocket.destroy()\n })\n\n targetSocket.on('error', (err: Error) => {\n console.error('[Claude Dev Server] Target socket error:', err.message)\n socket.end()\n })\n })\n\n return server\n}\n\nfunction injectScripts(html: string, wsPort: number, projectRoot: string): string {\n // Check if already injected to prevent \"nested\" pages\n if (html.includes('claude-dev-server-container') || html.includes('__CLAUDE_ORIGINAL_HTML__')) {\n console.log('[Claude Dev Server] HTML already injected, returning as-is')\n return html\n }\n\n // Verify that the original HTML is clean (no our scripts)\n const hasOurScripts = html.includes('CLIENT_SCRIPT') || html.includes('claude-dev-server-container')\n if (hasOurScripts) {\n console.log('[Claude Dev Server] Warning: Original HTML already has our scripts')\n }\n\n // Don't inject anything into the original HTML\n // The inspect functionality will be implemented entirely in the outer layer\n const modifiedHtml = html\n console.log('[Claude Dev Server] Creating split layout, original HTML length:', html.length)\n\n // Use Base64 encoding to pass HTML to avoid any escaping issues with special characters\n const base64Html = Buffer.from(modifiedHtml, 'utf-8').toString('base64')\n\n // Create new split-layout HTML page\n const projectRootScript = `<script>window.__CLAUDE_PROJECT_ROOT__ = ${JSON.stringify(projectRoot)};window.__CLAUDE_ORIGINAL_HTML_BASE64__ = \"${base64Html}\";</script>`\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Claude Dev Server</title>\n ${CLIENT_STYLES}\n ${projectRootScript}\n</head>\n<body>\n <script type=\"module\">${CLIENT_SCRIPT.replace(/wsPort:\\s*\\d+/, `wsPort: ${wsPort}`)}</script>\n</body>\n</html>`\n}\n\n/**\n * Generate Sec-WebSocket-Accept header value for WebSocket handshake.\n * RFC 6455: base64(sha1(clientKey + GUID))\n */\nfunction generateWebSocketAccept(clientKey: string): string {\n const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'\n const hash = createHash('sha1')\n .update(clientKey + GUID)\n .digest('base64')\n return hash\n}\n"]}