claude-opencode-viewer 2.6.13 → 2.6.15

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.
Files changed (3) hide show
  1. package/index.html +28 -58
  2. package/package.json +1 -1
  3. package/server.js +18 -2
package/index.html CHANGED
@@ -174,13 +174,13 @@
174
174
  background: none;
175
175
  border: 1px solid #333;
176
176
  color: #aaa;
177
- padding: 4px 10px;
178
- font-size: 12px;
177
+ padding: 3px 6px;
178
+ font-size: 11px;
179
179
  cursor: pointer;
180
180
  border-radius: 4px;
181
181
  display: flex;
182
182
  align-items: center;
183
- gap: 4px;
183
+ gap: 3px;
184
184
  flex-shrink: 0;
185
185
  }
186
186
 
@@ -191,8 +191,8 @@
191
191
  }
192
192
 
193
193
  .history-toggle-btn svg {
194
- width: 14px;
195
- height: 14px;
194
+ width: 12px;
195
+ height: 12px;
196
196
  }
197
197
 
198
198
  .session-loading {
@@ -703,6 +703,12 @@
703
703
  </svg>
704
704
  <span>Diff</span>
705
705
  </button>
706
+ <button class="history-toggle-btn" id="msg-toggle" style="color:#c9a0dc; border-color:#5a3a6a;">
707
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
708
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
709
+ </svg>
710
+ <span>复制</span>
711
+ </button>
706
712
  </div>
707
713
  <div id="mode-switcher">
708
714
  <span id="mode-label"></span>
@@ -798,6 +804,7 @@
798
804
  <div class="virtual-key" data-key="tab">Tab</div>
799
805
  <div class="virtual-key" data-key="esc">Esc</div>
800
806
  <div class="virtual-key" data-key="ctrlc">Ctrl+C</div>
807
+ <div class="virtual-key" data-key="paste">Ctrl+V</div>
801
808
  </div>
802
809
  </div>
803
810
  </div>
@@ -1117,58 +1124,17 @@
1117
1124
  }
1118
1125
  }
1119
1126
 
1120
- // 长按检测
1121
- var longPressTimer = null;
1122
- var longPressTriggered = false;
1123
- var LONG_PRESS_DELAY = 800; // ms
1124
- var LONG_PRESS_MOVE_THRESHOLD = 10; // px,移动超过此距离取消长按
1125
- var touchStartX = 0;
1126
- var touchStartY = 0;
1127
-
1128
- function clearLongPress() {
1129
- if (longPressTimer) {
1130
- clearTimeout(longPressTimer);
1131
- longPressTimer = null;
1132
- }
1133
- // 始终恢复 xterm textarea,防止 disabled 残留
1134
- var xtermTa = terminalEl.querySelector('.xterm-helper-textarea');
1135
- if (xtermTa) xtermTa.removeAttribute('disabled');
1136
- }
1137
-
1138
1127
  function handleTouchStart(e) {
1139
1128
  stopMomentum();
1140
1129
  altScrollAccum = 0;
1141
- longPressTriggered = false;
1142
- clearLongPress();
1143
1130
  if (e.touches.length !== 1) return;
1144
1131
  lastY = e.touches[0].clientY;
1145
1132
  lastTime = performance.now();
1146
1133
  velocitySamples = [];
1147
- touchStartX = e.touches[0].clientX;
1148
- touchStartY = e.touches[0].clientY;
1149
-
1150
- // 启动长按计时器
1151
- // 在长按检测期间阻止 xterm textarea 获取焦点,防止弹出键盘
1152
- var xtermTa = terminalEl.querySelector('.xterm-helper-textarea');
1153
- if (xtermTa) {
1154
- xtermTa.setAttribute('disabled', 'true');
1155
- }
1156
-
1157
- longPressTimer = setTimeout(function() {
1158
- longPressTriggered = true;
1159
- longPressTimer = null;
1160
- openMessageViewer();
1161
- }, LONG_PRESS_DELAY);
1162
1134
  }
1163
1135
 
1164
1136
  function handleTouchMove(e) {
1165
1137
  if (e.touches.length !== 1) return;
1166
- // 移动超过阈值才取消长按(容忍手指微小抖动)
1167
- var dx = e.touches[0].clientX - touchStartX;
1168
- var dy2 = e.touches[0].clientY - touchStartY;
1169
- if (Math.abs(dx) > LONG_PRESS_MOVE_THRESHOLD || Math.abs(dy2) > LONG_PRESS_MOVE_THRESHOLD) {
1170
- clearLongPress();
1171
- }
1172
1138
  var y = e.touches[0].clientY;
1173
1139
  var now = performance.now();
1174
1140
  var dt = now - lastTime;
@@ -1191,17 +1157,6 @@
1191
1157
  }
1192
1158
 
1193
1159
  function handleTouchEnd() {
1194
- console.log('[scroll] touchend');
1195
- clearLongPress();
1196
-
1197
- // 长按已触发,不执行滚动惯性
1198
- if (longPressTriggered) {
1199
- longPressTriggered = false;
1200
- pendingDy = 0;
1201
- pixelAccum = 0;
1202
- velocitySamples = [];
1203
- return;
1204
- }
1205
1160
 
1206
1161
  if (scrollRaf) {
1207
1162
  cancelAnimationFrame(scrollRaf);
@@ -1476,6 +1431,16 @@
1476
1431
  };
1477
1432
 
1478
1433
  function sendKey(keyName) {
1434
+ if (keyName === 'paste') {
1435
+ if (navigator.clipboard && navigator.clipboard.readText) {
1436
+ navigator.clipboard.readText().then(function(text) {
1437
+ if (text && ws && ws.readyState === 1 && !isTransitioning) {
1438
+ ws.send(JSON.stringify({ type: 'input', data: text }));
1439
+ }
1440
+ }).catch(function() {});
1441
+ }
1442
+ return;
1443
+ }
1479
1444
  var seq = KEY_MAP[keyName];
1480
1445
  if (seq && ws && ws.readyState === 1 && !isTransitioning) {
1481
1446
  ws.send(JSON.stringify({ type: 'input', data: seq }));
@@ -1852,7 +1817,7 @@
1852
1817
  }
1853
1818
 
1854
1819
 
1855
- // 长按打开消息查看器
1820
+ // 消息查看器
1856
1821
  var messageViewer = document.getElementById('message-viewer');
1857
1822
  var msgViewerContent = document.getElementById('msg-viewer-content');
1858
1823
  var msgViewerClose = document.getElementById('msg-viewer-close');
@@ -1932,6 +1897,11 @@
1932
1897
  closeMessageViewer();
1933
1898
  });
1934
1899
 
1900
+ // 顶部消息按钮
1901
+ document.getElementById('msg-toggle').addEventListener('click', function() {
1902
+ openMessageViewer();
1903
+ });
1904
+
1935
1905
  // ======= Git Diff 功能 =======
1936
1906
  var diffBarVisible = false;
1937
1907
  var diffChanges = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-opencode-viewer",
3
- "version": "2.6.13",
3
+ "version": "2.6.15",
4
4
  "description": "A unified terminal viewer for Claude Code and OpenCode with seamless switching",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/server.js CHANGED
@@ -15,8 +15,8 @@ import Database from 'better-sqlite3';
15
15
  process.title = 'claude-opencode-viewer';
16
16
 
17
17
  const __dirname = dirname(fileURLToPath(import.meta.url));
18
- let PORT = parseInt(process.argv[2]) || 7008;
19
18
  const IS_PC = process.argv.includes('--pc');
19
+ let PORT = parseInt(process.argv[2]) || (IS_PC ? 19200 : 7008);
20
20
  const USE_HTTPS = process.argv.includes('--https');
21
21
  const JSON_OUTPUT = process.argv.includes('--json');
22
22
 
@@ -853,7 +853,23 @@ function startServer(retries = 0) {
853
853
  console.log('\n按 Ctrl+C 停止服务\n');
854
854
  }
855
855
 
856
- await spawnProcess('opencode');
856
+ // 尝试恢复最近的会话,如果没有则新建
857
+ let lastSessionId = null;
858
+ try {
859
+ const db = new Database(OPENCODE_DB_PATH, { readonly: true });
860
+ const row = db.prepare(
861
+ `SELECT id FROM session WHERE parent_id IS NULL AND time_archived IS NULL ORDER BY time_updated DESC LIMIT 1`
862
+ ).get();
863
+ db.close();
864
+ if (row) lastSessionId = row.id;
865
+ } catch (e) {}
866
+
867
+ if (lastSessionId) {
868
+ console.log(`[startup] 恢复最近会话: ${lastSessionId}`);
869
+ await spawnProcess('opencode', lastSessionId);
870
+ } else {
871
+ await spawnProcess('opencode');
872
+ }
857
873
  });
858
874
 
859
875
  server.on('error', (err) => {