@zhongqian97-code/ecode 0.5.23 → 0.5.25

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 +76 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5574,6 +5574,43 @@ function generateAdminHtml(version2) {
5574
5574
  .num { color: #79c0ff; }
5575
5575
  .fn { color: #d2a8ff; }
5576
5576
 
5577
+ /* \u2500\u2500 Toast notifications \u2500\u2500 */
5578
+ #toast-container {
5579
+ position: fixed;
5580
+ top: 16px;
5581
+ right: 16px;
5582
+ z-index: 200;
5583
+ display: flex;
5584
+ flex-direction: column;
5585
+ gap: 8px;
5586
+ pointer-events: none;
5587
+ }
5588
+ .toast {
5589
+ padding: 10px 16px;
5590
+ border-radius: 4px;
5591
+ font-size: 13px;
5592
+ max-width: 320px;
5593
+ background: #21262d;
5594
+ color: #c9d1d9;
5595
+ border: 1px solid #30363d;
5596
+ pointer-events: auto;
5597
+ animation: toast-in .2s ease;
5598
+ }
5599
+ .toast-error {
5600
+ background: #2d1b1b;
5601
+ color: #ff7b72;
5602
+ border-color: #f85149;
5603
+ }
5604
+ .toast-success {
5605
+ background: #1a2d1a;
5606
+ color: #3fb950;
5607
+ border-color: #2ea043;
5608
+ }
5609
+ @keyframes toast-in {
5610
+ from { opacity: 0; transform: translateX(20px); }
5611
+ to { opacity: 1; transform: translateX(0); }
5612
+ }
5613
+
5577
5614
  /* \u2500\u2500 Mobile \u2500\u2500 */
5578
5615
  @media (max-width: 600px) {
5579
5616
  #hamburger { display: block; }
@@ -5658,6 +5695,9 @@ function generateAdminHtml(version2) {
5658
5695
  </div>
5659
5696
  </div>
5660
5697
 
5698
+ <!-- Toast notifications -->
5699
+ <div id="toast-container"></div>
5700
+
5661
5701
  <!-- Bash approval modal -->
5662
5702
  <div id="approval-modal" role="dialog" aria-modal="true">
5663
5703
  <div id="approval-box">
@@ -5684,6 +5724,17 @@ function generateAdminHtml(version2) {
5684
5724
  streamingMsgEl: null, // DOM element currently receiving delta tokens
5685
5725
  };
5686
5726
 
5727
+ // \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
5728
+ function showToast(msg, type) {
5729
+ const container = document.getElementById('toast-container');
5730
+ if (!container) return;
5731
+ const el = document.createElement('div');
5732
+ el.className = 'toast toast-' + (type || 'info');
5733
+ el.textContent = msg;
5734
+ container.appendChild(el);
5735
+ setTimeout(() => el.remove(), 4000);
5736
+ }
5737
+
5687
5738
  // \u2500\u2500 Helpers \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
5688
5739
  function apiUrl(path) {
5689
5740
  const sep = path.includes('?') ? '&' : '?';
@@ -5693,7 +5744,11 @@ function generateAdminHtml(version2) {
5693
5744
  async function apiFetch(path, opts = {}) {
5694
5745
  const url = apiUrl(path);
5695
5746
  const res = await fetch(url, opts);
5696
- if (!res.ok) throw new Error(res.status + ' ' + res.statusText);
5747
+ if (!res.ok) {
5748
+ let msg = res.status + ' ' + res.statusText;
5749
+ try { const err = await res.json(); if (err.error) msg = err.error; } catch {}
5750
+ throw new Error(msg);
5751
+ }
5697
5752
  return res.json();
5698
5753
  }
5699
5754
 
@@ -5959,8 +6014,7 @@ function generateAdminHtml(version2) {
5959
6014
  } else if (type === 'session.error') {
5960
6015
  finalizeStreamingMsg();
5961
6016
  setStatus('idle');
5962
- document.getElementById('ws-status').textContent =
5963
- '\u9519\u8BEF: ' + escHtml(msg.error || 'unknown error');
6017
+ showToast('\u9519\u8BEF: ' + (msg.error || 'unknown error'), 'error');
5964
6018
  }
5965
6019
  }
5966
6020
 
@@ -5996,7 +6050,7 @@ function generateAdminHtml(version2) {
5996
6050
  body: JSON.stringify({ requestId: pending.requestId || pending.id, approved }),
5997
6051
  });
5998
6052
  } catch (e) {
5999
- document.getElementById('ws-status').textContent = '\u5BA1\u6279\u8BF7\u6C42\u5931\u8D25: ' + e.message;
6053
+ showToast('\u5BA1\u6279\u8BF7\u6C42\u5931\u8D25: ' + e.message, 'error');
6000
6054
  }
6001
6055
  }
6002
6056
 
@@ -6033,7 +6087,7 @@ function generateAdminHtml(version2) {
6033
6087
  selectSession(session.id);
6034
6088
  }
6035
6089
  } catch (e) {
6036
- document.getElementById('ws-status').textContent = '\u521B\u5EFA\u4F1A\u8BDD\u5931\u8D25: ' + e.message;
6090
+ showToast('\u521B\u5EFA\u4F1A\u8BDD\u5931\u8D25: ' + e.message, 'error');
6037
6091
  }
6038
6092
  });
6039
6093
 
@@ -6054,7 +6108,7 @@ function generateAdminHtml(version2) {
6054
6108
  body: JSON.stringify({ message: text }),
6055
6109
  });
6056
6110
  } catch (e) {
6057
- document.getElementById('ws-status').textContent = '\u53D1\u9001\u5931\u8D25: ' + e.message;
6111
+ showToast('\u53D1\u9001\u5931\u8D25: ' + e.message, 'error');
6058
6112
  setStatus('idle');
6059
6113
  }
6060
6114
  }
@@ -6088,7 +6142,7 @@ function generateAdminHtml(version2) {
6088
6142
  document.getElementById('cfg-logdir').value = data.logDir || '';
6089
6143
  document.getElementById('cfg-systemprompt').value = data.systemPrompt || '';
6090
6144
  } catch (e) {
6091
- // open modal even if fetch fails; fields will be empty
6145
+ showToast('\u52A0\u8F7D\u914D\u7F6E\u5931\u8D25: ' + e.message, 'error');
6092
6146
  }
6093
6147
  document.getElementById('config-modal').classList.add('open');
6094
6148
  });
@@ -6109,8 +6163,9 @@ function generateAdminHtml(version2) {
6109
6163
  try {
6110
6164
  await apiFetch('/api/config', { method: 'PUT', headers: {'Content-Type':'application/json'}, body: JSON.stringify(body) });
6111
6165
  updateTopbarModel(body.model);
6166
+ showToast('\u914D\u7F6E\u5DF2\u4FDD\u5B58', 'success');
6112
6167
  } catch (e) {
6113
- // ignore errors silently for now
6168
+ showToast('\u4FDD\u5B58\u5931\u8D25: ' + e.message, 'error');
6114
6169
  }
6115
6170
  document.getElementById('config-modal').classList.remove('open');
6116
6171
  });
@@ -6432,8 +6487,19 @@ async function chatRoutes(app, opts) {
6432
6487
  if (typeof body.systemPrompt === "string") {
6433
6488
  sessionOpts.systemPrompt = body.systemPrompt;
6434
6489
  }
6435
- const runtime = await manager.createSession(sessionOpts);
6436
- return reply.code(201).send({ success: true, session: runtime.snapshot() });
6490
+ if (!opts.config.apiKey) {
6491
+ return reply.code(400).send({
6492
+ success: false,
6493
+ error: "\u672A\u914D\u7F6E API Key\uFF0C\u8BF7\u5148\u70B9\u51FB\u53F3\u4E0A\u89D2\u300C\u914D\u7F6E\u300D\u6309\u94AE\u586B\u5199"
6494
+ });
6495
+ }
6496
+ try {
6497
+ const runtime = await manager.createSession(sessionOpts);
6498
+ return reply.code(201).send({ success: true, session: runtime.snapshot() });
6499
+ } catch (err) {
6500
+ const msg = err instanceof Error ? err.message : String(err);
6501
+ return reply.code(500).send({ success: false, error: msg });
6502
+ }
6437
6503
  });
6438
6504
  app.post("/api/chat/sessions/:id/submit", async (request, reply) => {
6439
6505
  const { id } = request.params;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhongqian97-code/ecode",
3
- "version": "0.5.23",
3
+ "version": "0.5.25",
4
4
  "description": "A minimal Claude Code clone with REPL interface and bash tool calling",
5
5
  "type": "module",
6
6
  "author": "zhongqian97-code",