@zhongqian97-code/ecode 0.5.22 → 0.5.23

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 +69 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5593,6 +5593,7 @@ function generateAdminHtml(version2) {
5593
5593
  <button id="hamburger" aria-label="Toggle sidebar">\u2630</button>
5594
5594
  <h1>\u26A1 ecode web admin</h1>
5595
5595
  <span class="version">v${version2}</span>
5596
+ <span id="topbar-model" class="version" style="display:none"></span>
5596
5597
  <button id="config-btn" class="btn">\u914D\u7F6E</button>
5597
5598
  <button id="upgrade-btn" class="btn">\u5347\u7EA7</button>
5598
5599
  </div>
@@ -6107,6 +6108,7 @@ function generateAdminHtml(version2) {
6107
6108
  if (apiKeyVal) body.apiKey = apiKeyVal;
6108
6109
  try {
6109
6110
  await apiFetch('/api/config', { method: 'PUT', headers: {'Content-Type':'application/json'}, body: JSON.stringify(body) });
6111
+ updateTopbarModel(body.model);
6110
6112
  } catch (e) {
6111
6113
  // ignore errors silently for now
6112
6114
  }
@@ -6181,7 +6183,28 @@ function generateAdminHtml(version2) {
6181
6183
  };
6182
6184
 
6183
6185
  // \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
6186
+ function updateTopbarModel(model) {
6187
+ const el = document.getElementById('topbar-model');
6188
+ if (!el) return;
6189
+ if (model) {
6190
+ el.textContent = model;
6191
+ el.style.display = '';
6192
+ } else {
6193
+ el.style.display = 'none';
6194
+ }
6195
+ }
6196
+
6197
+ async function initModel() {
6198
+ try {
6199
+ const data = await apiFetch('/api/config');
6200
+ updateTopbarModel(data.model);
6201
+ } catch {
6202
+ // non-critical, ignore
6203
+ }
6204
+ }
6205
+
6184
6206
  loadSessions();
6207
+ initModel();
6185
6208
  </script>
6186
6209
  </body>
6187
6210
  </html>`;
@@ -6209,33 +6232,48 @@ async function statusRoutes(app, opts) {
6209
6232
  import { readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
6210
6233
  import { join as join13 } from "path";
6211
6234
  async function sessionsRoutes(app, opts) {
6212
- app.get("/api/sessions", async (_request, reply) => {
6213
- if (!opts.config.logDir) {
6214
- return reply.send([]);
6215
- }
6216
- return listSessions(opts.config.logDir);
6235
+ app.get("/api/sessions", async (_request, _reply) => {
6236
+ const fileSessions = opts.config.logDir ? listSessions(opts.config.logDir) : [];
6237
+ if (!opts.manager) {
6238
+ return fileSessions;
6239
+ }
6240
+ const runningSnapshots = opts.manager.listRunning();
6241
+ const fileIds = new Set(fileSessions.map((s) => s.id));
6242
+ const runtimeSessions = runningSnapshots.filter((s) => !fileIds.has(s.id)).map((s) => ({
6243
+ id: s.id,
6244
+ title: s.title,
6245
+ model: s.model,
6246
+ status: s.status,
6247
+ turnCount: s.turnCount,
6248
+ totalTokens: s.totalTokens,
6249
+ startTime: s.startedAt,
6250
+ lastActivity: s.lastActivity,
6251
+ cwd: "",
6252
+ logFile: ""
6253
+ }));
6254
+ return [...fileSessions, ...runtimeSessions];
6217
6255
  });
6218
6256
  app.get(
6219
6257
  "/api/sessions/:id/messages",
6220
6258
  async (request, reply) => {
6221
6259
  const { id } = request.params;
6222
- if (!opts.config.logDir) {
6223
- return reply.code(404).send({ success: false, error: "Log directory not configured" });
6224
- }
6225
- const session = findSession(opts.config.logDir, id);
6226
- if (!session) {
6227
- return reply.code(404).send({ success: false, error: `Session not found: ${id}` });
6228
- }
6229
- const logFilePath2 = join13(opts.config.logDir, session.logFile);
6230
- if (!existsSync4(logFilePath2)) {
6231
- return reply.code(404).send({ success: false, error: `Log file not found: ${session.logFile}` });
6260
+ if (opts.config.logDir) {
6261
+ const session = findSession(opts.config.logDir, id);
6262
+ if (session) {
6263
+ const logFilePath2 = join13(opts.config.logDir, session.logFile);
6264
+ if (existsSync4(logFilePath2)) {
6265
+ try {
6266
+ const content = readFileSync5(logFilePath2, "utf-8");
6267
+ return reply.header("Content-Type", "text/plain; charset=utf-8").send(content);
6268
+ } catch {
6269
+ }
6270
+ }
6271
+ }
6232
6272
  }
6233
- try {
6234
- const content = readFileSync5(logFilePath2, "utf-8");
6235
- return reply.header("Content-Type", "text/plain; charset=utf-8").send(content);
6236
- } catch (_err) {
6237
- return reply.code(404).send({ success: false, error: `Log file not found: ${session.logFile}` });
6273
+ if (opts.manager && opts.manager.getSession(id)) {
6274
+ return reply.header("Content-Type", "text/plain; charset=utf-8").send("");
6238
6275
  }
6276
+ return reply.code(404).send({ success: false, error: `Session not found: ${id}` });
6239
6277
  }
6240
6278
  );
6241
6279
  app.get(
@@ -6490,7 +6528,7 @@ async function systemRoutes(app, opts) {
6490
6528
  try {
6491
6529
  latest = execSync("npm view @zhongqian97-code/ecode version", {
6492
6530
  encoding: "utf-8",
6493
- timeout: 2e3
6531
+ timeout: 5e3
6494
6532
  }).trim();
6495
6533
  } catch {
6496
6534
  latest = "unknown";
@@ -6539,7 +6577,7 @@ async function buildServer(opts) {
6539
6577
  manager: opts.manager,
6540
6578
  version: opts.version
6541
6579
  });
6542
- await app.register(sessionsRoutes, { config: opts.config });
6580
+ await app.register(sessionsRoutes, { config: opts.config, manager: opts.manager });
6543
6581
  await app.register(configRoutes, { config: opts.config });
6544
6582
  await app.register(automationRoutes, { config: opts.config });
6545
6583
  await app.register(chatRoutes, { config: opts.config, manager: opts.manager });
@@ -6640,6 +6678,7 @@ var SessionRuntime = class {
6640
6678
  config;
6641
6679
  model;
6642
6680
  abortController = null;
6681
+ _stopAfterToolRound = false;
6643
6682
  _turnCount = 0;
6644
6683
  _totalTokens = 0;
6645
6684
  startedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -6758,6 +6797,10 @@ var SessionRuntime = class {
6758
6797
  this.bus.emit({ type: "tool.completed", callId: tc.id, toolName: tc.name, output: toolResult });
6759
6798
  this.messages.push({ role: "tool", tool_call_id: tc.id, content: toolResult });
6760
6799
  }
6800
+ if (this._stopAfterToolRound) {
6801
+ this._stopAfterToolRound = false;
6802
+ break;
6803
+ }
6761
6804
  } else {
6762
6805
  if (assistantText) {
6763
6806
  this.messages.push({
@@ -6792,7 +6835,10 @@ Proceed?`;
6792
6835
  this.bus.emit({ type: "approval.requested", requestId: reqId, kind, prompt });
6793
6836
  const approved = await promise;
6794
6837
  this._status = "tool_calling";
6795
- if (!approved) return SKIP_MESSAGE;
6838
+ if (!approved) {
6839
+ this._stopAfterToolRound = true;
6840
+ return SKIP_MESSAGE;
6841
+ }
6796
6842
  }
6797
6843
  if (signal.aborted) return SKIP_MESSAGE;
6798
6844
  const result = await executeBash(parsed.command);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhongqian97-code/ecode",
3
- "version": "0.5.22",
3
+ "version": "0.5.23",
4
4
  "description": "A minimal Claude Code clone with REPL interface and bash tool calling",
5
5
  "type": "module",
6
6
  "author": "zhongqian97-code",