@zhongqian97-code/ecode 0.5.31 → 0.5.33

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 +85 -10
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1380,10 +1380,10 @@ function metadataPathFromLogFile(logFilePath2) {
1380
1380
  const dir = path6.dirname(logFilePath2);
1381
1381
  return path6.join(dir, `${base}-session.json`);
1382
1382
  }
1383
- function createSessionMetadata(logFilePath2, model) {
1383
+ function createSessionMetadata(logFilePath2, model, id) {
1384
1384
  const now = (/* @__PURE__ */ new Date()).toISOString();
1385
1385
  return {
1386
- id: crypto2.randomUUID(),
1386
+ id: id ?? crypto2.randomUUID(),
1387
1387
  startTime: now,
1388
1388
  lastActivity: now,
1389
1389
  cwd: process.cwd(),
@@ -5500,7 +5500,14 @@ function generateAdminHtml(version2) {
5500
5500
  padding: 4px 10px;
5501
5501
  color: #8b949e;
5502
5502
  font-size: 11px;
5503
+ cursor: pointer;
5504
+ user-select: none;
5505
+ display: flex;
5506
+ align-items: center;
5507
+ gap: 6px;
5503
5508
  }
5509
+ .tool-box-header:hover { background: #2d333b; }
5510
+ .tool-box.collapsed .tool-box-body { display: none; }
5504
5511
  .tool-box-body {
5505
5512
  padding: 8px 10px;
5506
5513
  color: #c9d1d9;
@@ -5678,12 +5685,15 @@ function generateAdminHtml(version2) {
5678
5685
  padding: 10px 16px;
5679
5686
  border-radius: 4px;
5680
5687
  font-size: 13px;
5681
- max-width: 320px;
5688
+ max-width: 360px;
5682
5689
  background: #21262d;
5683
5690
  color: #c9d1d9;
5684
5691
  border: 1px solid #30363d;
5685
5692
  pointer-events: auto;
5686
5693
  animation: toast-in .2s ease;
5694
+ display: flex;
5695
+ align-items: flex-start;
5696
+ gap: 10px;
5687
5697
  }
5688
5698
  .toast-error {
5689
5699
  background: #2d1b1b;
@@ -5695,6 +5705,19 @@ function generateAdminHtml(version2) {
5695
5705
  color: #3fb950;
5696
5706
  border-color: #2ea043;
5697
5707
  }
5708
+ .toast-close {
5709
+ background: none;
5710
+ border: none;
5711
+ color: inherit;
5712
+ font-size: 16px;
5713
+ line-height: 1;
5714
+ cursor: pointer;
5715
+ padding: 0;
5716
+ opacity: 0.6;
5717
+ flex-shrink: 0;
5718
+ margin-left: auto;
5719
+ }
5720
+ .toast-close:hover { opacity: 1; }
5698
5721
  @keyframes toast-in {
5699
5722
  from { opacity: 0; transform: translateX(20px); }
5700
5723
  to { opacity: 1; transform: translateX(0); }
@@ -5855,9 +5878,21 @@ function generateAdminHtml(version2) {
5855
5878
  if (!container) return;
5856
5879
  const el = document.createElement('div');
5857
5880
  el.className = 'toast toast-' + (type || 'info');
5858
- el.textContent = msg;
5881
+ const textSpan = document.createElement('span');
5882
+ textSpan.textContent = msg;
5883
+ el.appendChild(textSpan);
5884
+ if (type === 'error') {
5885
+ // \u9519\u8BEF Toast \u6301\u4E45\u5316\uFF1A\u4E0D\u81EA\u52A8\u6D88\u5931\uFF0C\u63D0\u4F9B\u5173\u95ED\u6309\u94AE
5886
+ const closeBtn = document.createElement('button');
5887
+ closeBtn.className = 'toast-close';
5888
+ closeBtn.textContent = '\xD7';
5889
+ closeBtn.setAttribute('aria-label', '\u5173\u95ED');
5890
+ closeBtn.onclick = () => el.remove();
5891
+ el.appendChild(closeBtn);
5892
+ } else {
5893
+ setTimeout(() => el.remove(), 4000);
5894
+ }
5859
5895
  container.appendChild(el);
5860
- setTimeout(() => el.remove(), 4000);
5861
5896
  }
5862
5897
 
5863
5898
  // \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
@@ -6144,7 +6179,10 @@ function generateAdminHtml(version2) {
6144
6179
  boxEl.className = 'tool-box';
6145
6180
  boxEl.setAttribute('data-tool-id', msg.callId || name);
6146
6181
  boxEl.innerHTML =
6147
- '<div class="tool-box-header">\u250C\u2500 ' + escHtml(name) + ' \u2500</div>' +
6182
+ '<div class="tool-box-header" onclick="toggleToolBox(this)">' +
6183
+ '<span class="tb-indicator">\u25BC</span>' +
6184
+ '<span class="tb-name">\u2699 ' + escHtml(name) + '</span>' +
6185
+ '</div>' +
6148
6186
  '<div class="tool-box-body">\u2026</div>';
6149
6187
  if (!state.showTools) boxEl.style.display = 'none';
6150
6188
  msgsEl.appendChild(boxEl);
@@ -6156,8 +6194,8 @@ function generateAdminHtml(version2) {
6156
6194
  if (boxEl) {
6157
6195
  const body = boxEl.querySelector('.tool-box-body');
6158
6196
  body.textContent = msg.output || '';
6159
- boxEl.querySelector('.tool-box-header').textContent =
6160
- '\u2514\u2500 ' + (msg.toolName || toolId) + ' \u2500';
6197
+ const nameEl = boxEl.querySelector('.tb-name');
6198
+ if (nameEl) nameEl.textContent = '\u2713 ' + (msg.toolName || toolId);
6161
6199
  }
6162
6200
  setStatus('idle');
6163
6201
  } else if (type === 'approval.requested') {
@@ -6195,6 +6233,15 @@ function generateAdminHtml(version2) {
6195
6233
  .replace(/>/g, '&gt;');
6196
6234
  }
6197
6235
 
6236
+ // \u2500\u2500 Tool box collapse \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
6237
+ function toggleToolBox(headerEl) {
6238
+ const box = headerEl.closest('.tool-box');
6239
+ if (!box) return;
6240
+ const isNowCollapsed = box.classList.toggle('collapsed');
6241
+ const indicator = headerEl.querySelector('.tb-indicator');
6242
+ if (indicator) indicator.textContent = isNowCollapsed ? '\u25B6' : '\u25BC';
6243
+ }
6244
+
6198
6245
  // \u2500\u2500 Skill dropdown \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
6199
6246
  var selectedSkillIndex = -1;
6200
6247
 
@@ -7190,13 +7237,21 @@ var SessionRuntime = class {
7190
7237
  _totalTokens = 0;
7191
7238
  startedAt = (/* @__PURE__ */ new Date()).toISOString();
7192
7239
  lastActivity = (/* @__PURE__ */ new Date()).toISOString();
7193
- title = "New Session";
7240
+ _title = "New Session";
7241
+ logger;
7194
7242
  constructor(config2, opts = {}) {
7195
7243
  this.id = opts.sessionId ?? crypto.randomUUID();
7196
7244
  this.config = config2;
7197
7245
  this.llm = opts.llm ?? createProvider(resolveActiveProfile(config2));
7198
7246
  this.model = config2.model;
7199
7247
  this.autoApproveNormal = opts.autoApproveNormal ?? false;
7248
+ if (config2.logDir) {
7249
+ this.logger = createLogger(config2.logDir, /* @__PURE__ */ new Date());
7250
+ const meta = createSessionMetadata(this.logger.filePath, this.model, this.id);
7251
+ writeSessionMetadata(this.logger.filePath, meta);
7252
+ } else {
7253
+ this.logger = null;
7254
+ }
7200
7255
  const systemContent = opts.systemPrompt ?? (config2.systemPrompt ?? DEFAULT_SYSTEM_PROMPT);
7201
7256
  this.messages = systemContent ? [{ role: "system", content: systemContent }] : [];
7202
7257
  if (opts.initialMessages) {
@@ -7221,6 +7276,7 @@ var SessionRuntime = class {
7221
7276
  */
7222
7277
  async submit(userInput) {
7223
7278
  this.messages.push({ role: "user", content: userInput });
7279
+ this.logger?.append({ ts: (/* @__PURE__ */ new Date()).toISOString(), role: "user", content: userInput });
7224
7280
  this.abortController = new AbortController();
7225
7281
  const signal = this.abortController.signal;
7226
7282
  try {
@@ -7236,6 +7292,17 @@ var SessionRuntime = class {
7236
7292
  }
7237
7293
  this._turnCount++;
7238
7294
  this.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
7295
+ if (this.logger) {
7296
+ if (this._turnCount === 1) {
7297
+ this._title = generateTitle(userInput);
7298
+ }
7299
+ updateSessionMetadata(this.logger.filePath, {
7300
+ title: this._title,
7301
+ turnCount: this._turnCount,
7302
+ totalTokens: this._totalTokens,
7303
+ lastActivity: this.lastActivity
7304
+ });
7305
+ }
7239
7306
  this._status = "idle";
7240
7307
  this.bus.emit({ type: "session.idle", sessionId: this.id });
7241
7308
  }
@@ -7298,12 +7365,19 @@ var SessionRuntime = class {
7298
7365
  ...assistantReasoning ? { reasoning_content: assistantReasoning } : {},
7299
7366
  ...lastReasoningDetails ? { reasoning_details: lastReasoningDetails } : {}
7300
7367
  });
7368
+ this.logger?.append({
7369
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
7370
+ role: "assistant",
7371
+ content: assistantText || null,
7372
+ tool_calls: toolCalls.map((tc) => ({ id: tc.id, type: "function", function: { name: tc.name, arguments: tc.arguments } }))
7373
+ });
7301
7374
  for (const tc of toolCalls) {
7302
7375
  if (signal.aborted) break;
7303
7376
  this.bus.emit({ type: "tool.started", callId: tc.id, toolName: tc.name, argsPreview: tc.arguments });
7304
7377
  const toolResult = await this.executeToolCall(tc, signal);
7305
7378
  this.bus.emit({ type: "tool.completed", callId: tc.id, toolName: tc.name, output: toolResult });
7306
7379
  this.messages.push({ role: "tool", tool_call_id: tc.id, content: toolResult });
7380
+ this.logger?.append({ ts: (/* @__PURE__ */ new Date()).toISOString(), role: "tool", tool_call_id: tc.id, content: toolResult });
7307
7381
  }
7308
7382
  if (this._stopAfterToolRound) {
7309
7383
  this._stopAfterToolRound = false;
@@ -7316,6 +7390,7 @@ var SessionRuntime = class {
7316
7390
  content: assistantText,
7317
7391
  ...assistantReasoning ? { reasoning_content: assistantReasoning } : {}
7318
7392
  });
7393
+ this.logger?.append({ ts: (/* @__PURE__ */ new Date()).toISOString(), role: "assistant", content: assistantText || null });
7319
7394
  }
7320
7395
  break;
7321
7396
  }
@@ -7428,7 +7503,7 @@ Proceed?`;
7428
7503
  snapshot() {
7429
7504
  return {
7430
7505
  id: this.id,
7431
- title: this.title,
7506
+ title: this._title,
7432
7507
  model: this.model,
7433
7508
  status: this._status,
7434
7509
  turnCount: this._turnCount,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhongqian97-code/ecode",
3
- "version": "0.5.31",
3
+ "version": "0.5.33",
4
4
  "description": "A minimal Claude Code clone with REPL interface and bash tool calling",
5
5
  "type": "module",
6
6
  "author": "zhongqian97-code",