@zhongqian97-code/ecode 0.5.21 → 0.5.22

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 (2) hide show
  1. package/dist/index.js +72 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5250,7 +5250,7 @@ function generateAdminHtml(version2) {
5250
5250
  <html lang="zh">
5251
5251
  <head>
5252
5252
  <meta charset="UTF-8">
5253
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
5253
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, interactive-widget=resizes-content">
5254
5254
  <title>ecode web admin</title>
5255
5255
  <style>
5256
5256
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
@@ -5567,6 +5567,13 @@ function generateAdminHtml(version2) {
5567
5567
  .modal-footer { display:flex; gap:8px; justify-content:flex-end; margin-top:16px; }
5568
5568
  #upgrade-output { display:none; background:#0d1117; border:1px solid #30363d; border-radius:4px; padding:8px; font-family:monospace; font-size:12px; color:#c9d1d9; white-space:pre-wrap; max-height:200px; overflow-y:auto; margin-top:8px; }
5569
5569
 
5570
+ /* \u2500\u2500 Syntax highlight \u2500\u2500 */
5571
+ .kw { color: #ff7b72; }
5572
+ .str { color: #a5d6ff; }
5573
+ .cmt { color: #8b949e; font-style: italic; }
5574
+ .num { color: #79c0ff; }
5575
+ .fn { color: #d2a8ff; }
5576
+
5570
5577
  /* \u2500\u2500 Mobile \u2500\u2500 */
5571
5578
  @media (max-width: 600px) {
5572
5579
  #hamburger { display: block; }
@@ -5694,6 +5701,21 @@ function generateAdminHtml(version2) {
5694
5701
  return proto + '//' + location.host + '/api/ws/sessions/' + sessionId + '?token=' + encodeURIComponent(state.token);
5695
5702
  }
5696
5703
 
5704
+ // \u2500\u2500 Code highlighting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
5705
+ function highlightCode(code) {
5706
+ let s = escHtml(code);
5707
+ // keywords
5708
+ s = s.replace(/\b(function|const|let|var|return|if|else|for|while|class|import|export|from|async|await|new|this|typeof|instanceof|null|undefined|true|false)\b/g, '<span class="kw">$1</span>');
5709
+ // strings (single, double \u2014 after HTML escaping, quotes appear as &#39; or &quot;)
5710
+ s = s.replace(/(&#39;[^&#]*&#39;|&quot;[^&]*&quot;)/g, '<span class="str">$1</span>');
5711
+ // comments
5712
+ s = s.replace(/(//[^
5713
+ ]*)/g, '<span class="cmt">$1</span>');
5714
+ // numbers
5715
+ s = s.replace(/\b(d+.?d*)\b/g, '<span class="num">$1</span>');
5716
+ return s;
5717
+ }
5718
+
5697
5719
  // Basic markdown \u2192 HTML (no libs)
5698
5720
  function renderMarkdown(text) {
5699
5721
  // Escape HTML first
@@ -5701,9 +5723,9 @@ function generateAdminHtml(version2) {
5701
5723
  .replace(/&/g, '&amp;')
5702
5724
  .replace(/</g, '&lt;')
5703
5725
  .replace(/>/g, '&gt;');
5704
- // Code blocks
5726
+ // Code blocks (use highlightCode for syntax coloring)
5705
5727
  s = s.replace(/\`\`\`([\\s\\S]*?)\`\`\`/g, (_, code) =>
5706
- '<pre><code>' + code.trim() + '</code></pre>');
5728
+ '<pre><code>' + highlightCode(code.trim()) + '</code></pre>');
5707
5729
  // Inline code
5708
5730
  s = s.replace(/\`([^\`]+)\`/g, '<code>$1</code>');
5709
5731
  // Bold
@@ -5781,6 +5803,31 @@ function generateAdminHtml(version2) {
5781
5803
  state.streamingMsgEl = null;
5782
5804
  }
5783
5805
 
5806
+ async function loadMessages(sessionId) {
5807
+ try {
5808
+ const sep = '/api/sessions/' + sessionId + '/messages?token=' + encodeURIComponent(state.token);
5809
+ const res = await fetch(sep);
5810
+ if (!res.ok) return;
5811
+ const text = await res.text();
5812
+ const lines = text.split('\\n').filter(l => l.trim());
5813
+ const msgsEl = document.getElementById('messages');
5814
+ msgsEl.innerHTML = '';
5815
+ for (const line of lines) {
5816
+ try {
5817
+ const m = JSON.parse(line);
5818
+ if (m.content) {
5819
+ appendMessage(m.role === 'user' ? 'user' : 'assistant', renderMarkdown(m.content));
5820
+ }
5821
+ } catch { /* skip malformed lines */ }
5822
+ }
5823
+ if (!lines.length) {
5824
+ msgsEl.innerHTML = '<div class="empty-chat">\u6682\u65E0\u5386\u53F2\u6D88\u606F\uFF0C\u5F00\u59CB\u5BF9\u8BDD\u5427</div>';
5825
+ }
5826
+ } catch (e) {
5827
+ // silently ignore \u2014 session might have no log file yet
5828
+ }
5829
+ }
5830
+
5784
5831
  function appendMessage(role, htmlContent, opts) {
5785
5832
  const msgsEl = document.getElementById('messages');
5786
5833
  // Remove empty-chat placeholder
@@ -5848,7 +5895,12 @@ function generateAdminHtml(version2) {
5848
5895
  finalizeStreamingMsg();
5849
5896
  if (state.activeSessionId === sessionId && state.wsRetries < 5) {
5850
5897
  state.wsRetries++;
5851
- setTimeout(() => openWs(sessionId), 3000);
5898
+ const wsRetryDelay = Math.min(1000 * Math.pow(2, state.wsRetries), 30000);
5899
+ document.getElementById('ws-status').textContent =
5900
+ '\u91CD\u8FDE\u4E2D\u2026 (' + state.wsRetries + '/5\uFF0C' + (wsRetryDelay/1000).toFixed(0) + 's\u540E)';
5901
+ setTimeout(() => openWs(sessionId), wsRetryDelay);
5902
+ } else if (state.wsRetries >= 5) {
5903
+ document.getElementById('ws-status').textContent = '\u8FDE\u63A5\u5931\u8D25\uFF0C\u8BF7\u5237\u65B0\u9875\u9762';
5852
5904
  }
5853
5905
  };
5854
5906
  }
@@ -5957,6 +6009,7 @@ function generateAdminHtml(version2) {
5957
6009
  document.getElementById('chat-title').textContent =
5958
6010
  session ? (session.title || id.slice(0, 12) + '\u2026') : id;
5959
6011
  clearMessages();
6012
+ loadMessages(id);
5960
6013
  renderSidebar();
5961
6014
  setStatus('idle');
5962
6015
  connectWs(id);
@@ -6113,6 +6166,20 @@ function generateAdminHtml(version2) {
6113
6166
  }
6114
6167
  });
6115
6168
 
6169
+ // \u2500\u2500 Mobile keyboard adaptation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
6170
+ document.getElementById('msg-input').addEventListener('focus', () => {
6171
+ setTimeout(() => {
6172
+ document.getElementById('msg-input').scrollIntoView({ behavior: 'smooth', block: 'nearest' });
6173
+ }, 300);
6174
+ });
6175
+
6176
+ // \u2500\u2500 Global error boundary \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
6177
+ window.onerror = function(msg, src, line) {
6178
+ const wsStatusEl = document.getElementById('ws-status');
6179
+ if (wsStatusEl) wsStatusEl.textContent = '\u9519\u8BEF: ' + msg;
6180
+ return false;
6181
+ };
6182
+
6116
6183
  // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
6117
6184
  loadSessions();
6118
6185
  </script>
@@ -6423,7 +6490,7 @@ async function systemRoutes(app, opts) {
6423
6490
  try {
6424
6491
  latest = execSync("npm view @zhongqian97-code/ecode version", {
6425
6492
  encoding: "utf-8",
6426
- timeout: 5e3
6493
+ timeout: 2e3
6427
6494
  }).trim();
6428
6495
  } catch {
6429
6496
  latest = "unknown";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhongqian97-code/ecode",
3
- "version": "0.5.21",
3
+ "version": "0.5.22",
4
4
  "description": "A minimal Claude Code clone with REPL interface and bash tool calling",
5
5
  "type": "module",
6
6
  "author": "zhongqian97-code",