@zhongqian97-code/ecode 0.5.62 → 0.5.64

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/dist/index.js CHANGED
@@ -802,7 +802,7 @@ if (rawArgs[0] === "web") {
802
802
  webAutoApprove = true;
803
803
  }
804
804
  }
805
- const { buildServer, generateAccessToken } = await import("./web-N7JFJIBC.js");
805
+ const { buildServer, generateAccessToken } = await import("./web-X3KX3RJL.js");
806
806
  const token = finalConfig.webToken ?? generateAccessToken();
807
807
  const manager = new SessionManager(finalConfig);
808
808
  const __webDirname = dirname(fileURLToPath(import.meta.url));
@@ -56,7 +56,10 @@ function generateAdminHtml(version) {
56
56
  font-family: "Courier New", Courier, monospace;
57
57
  background: #0d1117;
58
58
  color: #c9d1d9;
59
- height: 100vh;
59
+ /* zoom \u653E\u5927\u6574\u4F53 UI\uFF1Bcalc \u8865\u507F\u8BA9\u89C6\u53E3\u9501\u5B9A\uFF0C\u907F\u514D 100vh \u88AB\u653E\u5927\u540E\u6EA2\u51FA */
60
+ zoom: var(--zoom, 1);
61
+ width: calc(100vw / var(--zoom, 1));
62
+ height: calc(100vh / var(--zoom, 1));
60
63
  display: flex;
61
64
  flex-direction: column;
62
65
  overflow: hidden;
@@ -510,6 +513,8 @@ function generateAdminHtml(version) {
510
513
  <h1>\u26A1 ecode web admin</h1>
511
514
  <span class="version">v${version}</span>
512
515
  <span id="topbar-model" class="version" style="display:none"></span>
516
+ <button id="zoom-out-btn" class="btn" title="\u7F29\u5C0F (Ctrl/Cmd -)" aria-label="\u7F29\u5C0F\u5B57\u4F53">A\u2212</button>
517
+ <button id="zoom-in-btn" class="btn" title="\u653E\u5927 (Ctrl/Cmd +)" aria-label="\u653E\u5927\u5B57\u4F53">A+</button>
513
518
  <button id="config-btn" class="btn">\u914D\u7F6E</button>
514
519
  <button id="upgrade-btn" class="btn">\u5347\u7EA7</button>
515
520
  <button id="toggle-tools-btn" class="btn">\u5DE5\u5177 \u25BE</button>
@@ -607,6 +612,7 @@ function generateAdminHtml(version) {
607
612
  showTools: true,
608
613
  skills: [], // cached skills from /api/skills
609
614
  skillsLoaded: false,
615
+ zoom: 1, // \u5168\u5C40 UI \u7F29\u653E\u7CFB\u6570
610
616
  };
611
617
 
612
618
  // \u2500\u2500 Toast \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
@@ -670,20 +676,45 @@ function generateAdminHtml(version) {
670
676
 
671
677
  // Basic markdown \u2192 HTML (no libs)
672
678
  function renderMarkdown(text) {
673
- // Escape HTML first
674
- let s = text
675
- .replace(/&/g, '&amp;')
676
- .replace(/</g, '&lt;')
677
- .replace(/>/g, '&gt;');
678
- // Code blocks (use highlightCode for syntax coloring)
679
- s = s.replace(/\`\`\`([\\s\\S]*?)\`\`\`/g, (_, code) =>
680
- '<pre><code>' + highlightCode(code.trim()) + '</code></pre>');
681
- // Inline code
682
- s = s.replace(/\`([^\`]+)\`/g, '<code>$1</code>');
683
- // Bold
679
+ // Protect fenced/inline code BEFORE escaping (highlightCode/escHtml escape internally)
680
+ const codeBlocks = [];
681
+ let s = String(text).replace(/\`\`\`([\\s\\S]*?)\`\`\`/g, (_, code) => {
682
+ codeBlocks.push('<pre><code>' + highlightCode(code.replace(/^\\n+/, '').replace(/\\n+$/, '')) + '</code></pre>');
683
+ return '\\u0001CB' + (codeBlocks.length - 1) + '\\u0001';
684
+ });
685
+ const inlineCode = [];
686
+ s = s.replace(/\`([^\`]+)\`/g, (_, code) => {
687
+ inlineCode.push('<code>' + escHtml(code) + '</code>');
688
+ return '\\u0001IC' + (inlineCode.length - 1) + '\\u0001';
689
+ });
690
+ // Escape remaining text
691
+ s = escHtml(s);
692
+ // Inline: links, bold, italic, strikethrough
693
+ s = s.replace(/\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>');
684
694
  s = s.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');
695
+ s = s.replace(/(^|[^*])\\*([^*\\n]+)\\*/g, '$1<em>$2</em>');
696
+ s = s.replace(/~~([^~]+)~~/g, '<del>$1</del>');
697
+ // Block: headers + lists, line by line
698
+ const lines = s.split('\\n');
699
+ const out = [];
700
+ let listType = null;
701
+ const closeList = () => { if (listType) { out.push('</' + listType + '>'); listType = null; } };
702
+ for (const line of lines) {
703
+ const h = line.match(/^(#+)\\s+(.*)$/);
704
+ const ul = line.match(/^\\s*[-*]\\s+(.*)$/);
705
+ const ol = line.match(/^\\s*\\d+\\.\\s+(.*)$/);
706
+ if (h) { closeList(); const lvl = Math.min(h[1].length, 6); out.push('<h' + lvl + '>' + h[2] + '</h' + lvl + '>'); }
707
+ else if (ul) { if (listType !== 'ul') { closeList(); out.push('<ul>'); listType = 'ul'; } out.push('<li>' + ul[1] + '</li>'); }
708
+ else if (ol) { if (listType !== 'ol') { closeList(); out.push('<ol>'); listType = 'ol'; } out.push('<li>' + ol[1] + '</li>'); }
709
+ else { closeList(); out.push(line); }
710
+ }
711
+ closeList();
712
+ s = out.join('\\n');
685
713
  // Paragraph breaks
686
714
  s = s.replace(/\\n\\n+/g, '</p><p>');
715
+ // Restore code placeholders
716
+ s = s.replace(/\\u0001CB(\\d+)\\u0001/g, (_, i) => codeBlocks[+i]);
717
+ s = s.replace(/\\u0001IC(\\d+)\\u0001/g, (_, i) => inlineCode[+i]);
687
718
  return '<p>' + s + '</p>';
688
719
  }
689
720
 
@@ -834,7 +865,10 @@ function generateAdminHtml(version) {
834
865
  function finalizeStreamingMsg() {
835
866
  if (state.streamingMsgEl) {
836
867
  const body = state.streamingMsgEl.querySelector('.msg-body');
837
- if (body) body.classList.remove('cursor-blink');
868
+ if (body) {
869
+ body.classList.remove('cursor-blink');
870
+ body.innerHTML = renderMarkdown(body.textContent);
871
+ }
838
872
  state.streamingMsgEl = null;
839
873
  }
840
874
  state.streamingThinkEl = null;
@@ -1363,6 +1397,32 @@ function generateAdminHtml(version) {
1363
1397
  }
1364
1398
  }
1365
1399
 
1400
+ // \u2500\u2500 \u5168\u5C40 UI \u7F29\u653E \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
1401
+ function clampZoom(z) {
1402
+ z = Math.round(z * 10) / 10;
1403
+ if (!(z > 0)) z = 1;
1404
+ return Math.min(2, Math.max(0.6, z));
1405
+ }
1406
+ function applyZoom(z) {
1407
+ state.zoom = clampZoom(z);
1408
+ document.documentElement.style.setProperty('--zoom', state.zoom);
1409
+ try { localStorage.setItem('ecode-zoom', String(state.zoom)); } catch {}
1410
+ }
1411
+ function initZoom() {
1412
+ let z = 1;
1413
+ try { z = parseFloat(localStorage.getItem('ecode-zoom')) || 1; } catch {}
1414
+ applyZoom(z);
1415
+ }
1416
+ document.getElementById('zoom-in-btn').addEventListener('click', () => applyZoom(state.zoom + 0.1));
1417
+ document.getElementById('zoom-out-btn').addEventListener('click', () => applyZoom(state.zoom - 0.1));
1418
+ document.addEventListener('keydown', function(e) {
1419
+ if (!(e.ctrlKey || e.metaKey)) return;
1420
+ if (e.key === '=' || e.key === '+') { e.preventDefault(); applyZoom(state.zoom + 0.1); }
1421
+ else if (e.key === '-' || e.key === '_') { e.preventDefault(); applyZoom(state.zoom - 0.1); }
1422
+ else if (e.key === '0') { e.preventDefault(); applyZoom(1); }
1423
+ });
1424
+
1425
+ initZoom();
1366
1426
  loadSessions();
1367
1427
  initModel();
1368
1428
  </script>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhongqian97-code/ecode",
3
- "version": "0.5.62",
3
+ "version": "0.5.64",
4
4
  "description": "A minimal Claude Code clone with REPL interface and bash tool calling",
5
5
  "type": "module",
6
6
  "author": "zhongqian97-code",