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.
- package/index.html +28 -58
- package/package.json +1 -1
- 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:
|
|
178
|
-
font-size:
|
|
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:
|
|
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:
|
|
195
|
-
height:
|
|
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
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
|
-
|
|
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) => {
|