evolclaw-web 1.0.0 → 1.1.0

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.
@@ -1,11 +1,12 @@
1
1
  <!DOCTYPE html>
2
- <html lang="zh-CN">
2
+ <html lang="zh-CN" data-theme="light">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>EvolClaw Watch</title>
7
7
  <link rel="icon" href="data:,">
8
8
  <link rel="stylesheet" href="/style.css">
9
+ <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
9
10
  </head>
10
11
  <body>
11
12
  <!-- 配对页 -->
@@ -24,16 +25,25 @@
24
25
  <header class="topbar">
25
26
  <span class="brand">🔭 EvolClaw Watch</span>
26
27
  <nav class="tabs">
27
- <button class="tab active" data-view="aid">AID</button>
28
+ <button class="tab active" data-view="agents">Agents</button>
28
29
  <button class="tab" data-view="msg">Messages</button>
29
30
  <button class="tab" data-view="session">Sessions</button>
31
+ <button class="tab" data-view="triggers">Triggers</button>
32
+ <button class="tab" data-view="cache">Cache</button>
33
+ <button class="tab" data-view="system">System</button>
34
+ <button class="tab" data-view="usage">Usage</button>
35
+
30
36
  </nav>
37
+ <span id="today-cost" class="today-cost"></span>
38
+ <span style="flex:1"></span>
39
+ 2026-06-10 05:36
31
40
  <span id="conn-status" class="conn-status">连接中…</span>
41
+ <button id="theme-btn" class="theme-btn" title="切换主题">🌗</button>
32
42
  <button id="logout-btn" class="logout-btn" title="退出配对">退出</button>
33
43
  </header>
34
44
 
35
45
  <main class="content">
36
- <section id="view-aid" class="view active"></section>
46
+ <section id="view-agents" class="view active"></section>
37
47
  <section id="view-msg" class="view">
38
48
  <div class="msg-layout">
39
49
  <div id="msg-aids" class="msg-col msg-aids"></div>
@@ -47,6 +57,88 @@
47
57
  <div id="sess-detail" class="sess-col sess-detail"></div>
48
58
  </div>
49
59
  </section>
60
+ <section id="view-triggers" class="view">
61
+ <div class="trig-layout">
62
+ <div id="trig-agents" class="msg-col trig-agents-col"></div>
63
+ <div id="trig-table" class="trig-table-col"></div>
64
+ </div>
65
+ </section>
66
+ <section id="view-cache" class="view"></section>
67
+ <section id="view-system" class="view"></section>
68
+ <section id="view-usage" class="view">
69
+ <div class="usage-layout">
70
+ <!-- 子 Tab:Dashboard / Explorer -->
71
+ <div class="usage-subtabs">
72
+ <button class="usage-subtab active" data-subview="overview">Overview</button>
73
+ <button class="usage-subtab" data-subview="dashboard">Dashboard</button>
74
+ <button class="usage-subtab" data-subview="explorer">Explorer</button>
75
+ </div>
76
+
77
+ <!-- Dashboard 面板 -->
78
+ <div id="usage-dashboard" class="usage-subpanel">
79
+ <div class="usage-cards" id="usage-cards"></div>
80
+ <div class="usage-chart-row">
81
+ <div id="usage-hourly-chart" class="usage-chart"></div>
82
+ <div id="usage-model-chart" class="usage-chart-sm"></div>
83
+ </div>
84
+ <div class="usage-table-section">
85
+ <h3>Top Peers (Today)</h3>
86
+ <table id="usage-top-peers" class="usage-table"></table>
87
+ </div>
88
+ </div>
89
+
90
+ <!-- Overview 面板 -->
91
+ <div id="usage-overview" class="usage-subpanel active">
92
+ <div id="ov-cards" class="usage-cards"></div>
93
+ <div class="usage-table-section" style="margin-top:4px">
94
+ <h3>按 Agent 汇总(全时段)</h3>
95
+ <table id="ov-agent-table" class="usage-table"></table>
96
+ </div>
97
+ </div>
98
+
99
+ <!-- Explorer 面板 -->
100
+ <div id="usage-explorer" class="usage-subpanel">
101
+ <div class="exp-layout">
102
+ <!-- 左侧列表 -->
103
+ <div class="exp-sidebar">
104
+ <div class="exp-sidebar-group">
105
+ <div class="exp-sidebar-title">Agents</div>
106
+ <div id="exp-agent-list"></div>
107
+ </div>
108
+ <div class="exp-sidebar-group">
109
+ <div class="exp-sidebar-title">Peers</div>
110
+ <div id="exp-peer-list"></div>
111
+ </div>
112
+ </div>
113
+ <!-- 右侧详情 -->
114
+ <div class="exp-detail">
115
+ <div id="exp-detail-header" class="exp-detail-header">
116
+ <span id="exp-selected-name">请从左侧选择 Agent 或 Peer</span>
117
+ </div>
118
+ <div id="exp-detail-cards" class="usage-cards" style="display:none"></div>
119
+ <div class="explorer-filters">
120
+ <label>From <input type="date" id="exp-from"></label>
121
+ <label>To <input type="date" id="exp-to"></label>
122
+ <label>Model <input type="text" id="exp-model" placeholder="model-id"></label>
123
+ <select id="exp-granularity">
124
+ <option value="hour">Hour</option>
125
+ <option value="day" selected>Day</option>
126
+ <option value="week">Week</option>
127
+ <option value="month">Month</option>
128
+ </select>
129
+ <button id="exp-query-btn">Query</button>
130
+ </div>
131
+ <div id="usage-explorer-chart" class="usage-chart" style="height:260px"></div>
132
+ <div class="usage-table-section" style="margin-top:12px">
133
+ <h3>Results</h3>
134
+ <table id="usage-explorer-table" class="usage-table"></table>
135
+ </div>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ </div>
140
+ </section>
141
+
50
142
  </main>
51
143
  </div>
52
144
 
@@ -1,4 +1,21 @@
1
- :root {
1
+ /* 亮色主题(默认) */
2
+ :root, [data-theme="light"] {
3
+ --bg: #f5f7fa;
4
+ --bg2: #ffffff;
5
+ --bg3: #eef1f6;
6
+ --border: #e2e6ed;
7
+ --fg: #1a202c;
8
+ --dim: #718096;
9
+ --accent: #4f6ef7;
10
+ --green: #38a169;
11
+ --red: #e53e3e;
12
+ --orange: #dd6b20;
13
+ --blue: #4f6ef7;
14
+ --magenta: #805ad5;
15
+ }
16
+
17
+ /* 暗色主题 */
18
+ [data-theme="dark"] {
2
19
  --bg: #0d1117;
3
20
  --bg2: #161b22;
4
21
  --bg3: #21262d;
@@ -94,6 +111,7 @@ body {
94
111
  .content { flex: 1; overflow: hidden; position: relative; }
95
112
  .view { display: none; height: 100%; overflow: auto; }
96
113
  .view.active { display: block; }
114
+ #view-usage.active { display: flex; flex-direction: column; overflow: hidden; }
97
115
 
98
116
  /* ── AID 表格 ── */
99
117
  table { width: 100%; border-collapse: collapse; font-size: 12px; }
@@ -247,5 +265,239 @@ tr:hover td { background: var(--bg2); }
247
265
  }
248
266
  .blk-result.err .result-body { border-color: var(--red); }
249
267
 
268
+ /* ── Cache 视图 ── */
269
+ #view-cache { padding: 16px 18px; }
270
+ .cache-cards {
271
+ display: grid;
272
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
273
+ gap: 10px;
274
+ margin-bottom: 22px;
275
+ }
276
+ .cache-card {
277
+ background: var(--bg2);
278
+ border: 1px solid var(--border);
279
+ border-radius: 8px;
280
+ padding: 12px 14px;
281
+ }
282
+ .cc-label { color: var(--dim); font-size: 11px; letter-spacing: 0.3px; }
283
+ .cc-value { font-size: 22px; font-weight: 600; margin: 4px 0 2px; font-variant-numeric: tabular-nums; }
284
+ .cc-value.on { color: var(--green); }
285
+ .cc-value.idle { color: var(--orange); }
286
+ .cc-value.off { color: var(--red); }
287
+ .cc-sub { color: var(--dim); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
288
+ .cache-h {
289
+ font-size: 12px; font-weight: 600; color: var(--dim);
290
+ text-transform: uppercase; letter-spacing: 0.5px;
291
+ margin: 8px 0 6px; padding-top: 6px;
292
+ }
293
+ #view-cache table { margin-bottom: 8px; }
294
+ #view-cache td { font-variant-numeric: tabular-nums; }
295
+ .tag {
296
+ display: inline-block; padding: 1px 7px; border-radius: 10px;
297
+ font-size: 10.5px; border: 1px solid var(--border); color: var(--dim);
298
+ }
299
+ .tag-agent { color: var(--blue); border-color: var(--blue); }
300
+ .tag-relation { color: var(--magenta); border-color: var(--magenta); }
301
+
302
+ /* ── Theme toggle ── */
303
+ .theme-btn {
304
+ background: none; border: 1px solid var(--border); border-radius: 6px;
305
+ color: var(--fg); cursor: pointer; padding: 2px 8px; font-size: 14px;
306
+ margin-left: 8px;
307
+ }
308
+ .theme-btn:hover { background: var(--bg3); }
309
+
310
+ /* ── Today cost in topbar ── */
311
+ .today-cost {
312
+ font-size: 12px; color: var(--green); font-weight: 600;
313
+ margin-left: auto; margin-right: 12px;
314
+ font-variant-numeric: tabular-nums;
315
+ }
250
316
 
317
+ /* ── Usage view ── */
318
+ .usage-layout {
319
+ padding: 0; overflow: hidden; flex: 1; display: flex; flex-direction: column;
320
+ }
321
+ .usage-subtabs { flex-shrink: 0; padding: 12px 16px 0; }
322
+ .usage-subpanel { display: none; flex: 1; overflow: hidden; }
323
+ .usage-subpanel.active { display: flex; flex-direction: column; }
324
+ #usage-dashboard { overflow-y: auto; padding: 16px; }
325
+ #usage-overview { overflow-y: auto; padding: 16px; }
326
+ .usage-cards {
327
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
328
+ gap: 12px; margin-bottom: 20px;
329
+ }
330
+ .usage-card {
331
+ background: var(--bg2); border: 1px solid var(--border); border-radius: 10px;
332
+ padding: 16px; text-align: center;
333
+ box-shadow: 0 1px 3px rgba(0,0,0,0.06);
334
+ }
335
+ .usage-card .card-value {
336
+ font-size: 22px; font-weight: 700; color: var(--accent);
337
+ font-variant-numeric: tabular-nums;
338
+ }
339
+ .usage-card .card-label {
340
+ font-size: 11px; color: var(--dim); margin-top: 4px; text-transform: uppercase;
341
+ letter-spacing: 0.5px;
342
+ }
343
+ .usage-chart-row {
344
+ display: flex; gap: 16px; margin-bottom: 20px;
345
+ }
346
+ .usage-chart {
347
+ flex: 2; height: 260px; background: var(--bg2); border: 1px solid var(--border);
348
+ border-radius: 10px; padding: 12px;
349
+ }
350
+ .usage-chart-sm {
351
+ flex: 1; height: 260px; background: var(--bg2); border: 1px solid var(--border);
352
+ border-radius: 10px; padding: 12px;
353
+ }
354
+ .usage-table-section {
355
+ background: var(--bg2); border: 1px solid var(--border); border-radius: 10px;
356
+ padding: 16px;
357
+ }
358
+ .usage-table-section h3 {
359
+ font-size: 13px; color: var(--dim); margin-bottom: 10px; font-weight: 500;
360
+ }
361
+ .usage-table {
362
+ width: 100%; border-collapse: collapse; font-size: 12px;
363
+ }
364
+ .usage-table th {
365
+ text-align: left; padding: 6px 10px; color: var(--dim); font-weight: 500;
366
+ border-bottom: 1px solid var(--border);
367
+ }
368
+ .usage-table td {
369
+ padding: 6px 10px; border-bottom: 1px solid var(--border);
370
+ font-variant-numeric: tabular-nums;
371
+ }
372
+ .usage-table tr:last-child td { border-bottom: none; }
373
+
374
+ @media (max-width: 800px) {
375
+ .usage-chart-row { flex-direction: column; }
376
+ .usage-chart, .usage-chart-sm { flex: none; height: 200px; }
377
+ }
378
+ .tag-kits { color: var(--green); border-color: var(--green); }
379
+ .tag-global { color: var(--orange); border-color: var(--orange); }
380
+ .cache-note { color: var(--dim); font-size: 11px; margin: 14px 2px 24px; line-height: 1.6; }
381
+
382
+ /* ── Control 视图 ── */
383
+ .ctrl-wrap { padding: 12px; overflow-y: auto; height: 100%; }
384
+ .ctrl-section { margin-bottom: 20px; }
385
+ .ctrl-h { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 8px; }
386
+ .ctrl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 8px; }
387
+ .ctrl-card { background: var(--bg2); border: 1px solid var(--border); border-radius: 6px; padding: 10px 12px; }
388
+ .ctrl-card.ctrl-locked { opacity: .5; }
389
+ .ctrl-card h3 { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 8px; }
390
+ .ctrl-kv { display: grid; grid-template-columns: auto 1fr; gap: 2px 8px; }
391
+ .kv-row { display: contents; }
392
+ .kv-k { color: var(--dim); font-size: 11.5px; }
393
+ .kv-v { color: var(--fg); font-size: 11.5px; word-break: break-all; }
394
+ .ctrl-cur { color: var(--accent); font-size: 12px; margin-right: 6px; }
395
+ .ctrl-select { font-size: 12px; background: var(--bg3); border: 1px solid var(--border); border-radius: 4px; color: var(--fg); padding: 3px 6px; max-width: 160px; }
396
+ .ctrl-row { display: flex; align-items: center; margin: 4px 0; }
397
+ .ctrl-msg { font-size: 12px; color: var(--dim); margin: 4px 0; }
398
+ .ctrl-msg.muted { color: var(--border); }
399
+ .ctrl-list { list-style: none; padding: 0; margin: 6px 0 0; }
400
+ .ctrl-list li { display: flex; align-items: center; gap: 5px; padding: 3px 0; border-bottom: 1px solid var(--border); font-size: 12px; }
401
+ .ctrl-list li:last-child { border-bottom: none; }
402
+ .ctrl-list .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
403
+ .ctrl-tag { font-size: 11px; color: var(--dim); }
404
+ .ctrl-btns { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
405
+ .ctrl-btn { font-size: 11px; padding: 2px 8px; border-radius: 3px; border: 1px solid var(--border); background: var(--bg3); color: var(--fg); cursor: pointer; }
406
+ .ctrl-btn:hover { border-color: var(--accent); color: var(--accent); }
407
+ .ctrl-btn.danger { color: var(--red); border-color: var(--red); }
408
+ .ctrl-btn:disabled { opacity: .4; cursor: not-allowed; }
409
+ .ctrl-toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: var(--bg3); border: 1px solid var(--border); border-radius: 5px; padding: 6px 14px; font-size: 12px; opacity: 0; pointer-events: none; transition: opacity .2s; z-index: 99; }
410
+ .ctrl-toast.show { opacity: 1; }
411
+ .ctrl-toast.err { border-color: var(--red); color: var(--red); }
412
+
413
+
414
+ /* ── Agents 页 ── */
415
+ .agents-toolbar { padding: 8px 12px; border-bottom: 1px solid var(--border); }
416
+ .agent-ops-cell { white-space: nowrap; }
417
+ .agent-ops { display: flex; gap: 4px; flex-wrap: nowrap; }
418
+ .agent-ops .ctrl-btn { padding: 1px 6px; }
419
+
420
+ /* ── System 页 ── */
421
+ .sys-wrap { padding: 12px; overflow-y: auto; height: 100%; }
422
+ .sys-actions { display: flex; gap: 8px; flex-wrap: wrap; }
423
+ .sys-health { display: flex; flex-direction: column; gap: 8px; }
424
+ .card-label { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 4px; }
425
+ .card-val { font-size: 13px; color: var(--fg); }
426
+
427
+ /* ── Triggers 页 ── */
428
+ .trig-layout { display: flex; height: 100%; overflow: hidden; }
429
+ .trig-agents-col { width: 200px; border-right: 1px solid var(--border); flex-shrink: 0; overflow-y: auto; }
430
+ .trig-table-col { flex: 1; overflow: auto; padding: 0; }
431
+ .trig-table-col table { width: 100%; border-collapse: collapse; font-size: 12px; }
432
+ .trig-table-col th { position: sticky; top: 0; background: var(--bg); padding: 6px 10px; text-align: left; border-bottom: 1px solid var(--border); color: var(--dim); font-weight: 500; white-space: nowrap; }
433
+ .trig-table-col td { padding: 6px 10px; border-bottom: 1px solid var(--border); vertical-align: top; white-space: nowrap; }
434
+ .trig-table-col tr:hover td { background: var(--bg2); }
435
+ .trig-table-col .trig-prompt { max-width: 240px; overflow: hidden; text-overflow: ellipsis; }
436
+ .trig-table-col tr.trig-done td { opacity: .55; }
437
+ .trig-badge { display: inline-block; padding: 1px 7px; border-radius: 9px; font-size: 11px; border: 1px solid transparent; white-space: nowrap; }
438
+ .trig-badge-active { color: var(--green, #3fb950); border-color: var(--green, #3fb950); }
439
+ .trig-badge-fired { color: var(--dim); border-color: var(--border); }
440
+ .trig-badge-cancelled { color: var(--red); border-color: var(--red); }
441
+ .trig-badge-expired { color: var(--dim); border-color: var(--border); }
442
+ /* ── Usage subtabs ── */
443
+ .usage-subtabs {
444
+ display: flex; gap: 4px; margin-bottom: 16px;
445
+ }
446
+ .usage-subtab {
447
+ background: var(--bg3); border: 1px solid var(--border); border-radius: 6px;
448
+ padding: 5px 14px; font-size: 12px; color: var(--dim); cursor: pointer;
449
+ }
450
+ .usage-subtab.active {
451
+ background: var(--accent); color: #fff; border-color: var(--accent);
452
+ }
453
+
454
+ /* ── Explorer filters ── */
455
+ .explorer-filters {
456
+ display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
457
+ margin-bottom: 16px; padding: 12px; background: var(--bg3);
458
+ border-radius: 8px; border: 1px solid var(--border);
459
+ }
460
+ .explorer-filters label {
461
+ font-size: 11px; color: var(--dim); display: flex; flex-direction: column; gap: 2px;
462
+ }
463
+ .explorer-filters input, .explorer-filters select {
464
+ padding: 4px 8px; font-size: 12px; border: 1px solid var(--border);
465
+ border-radius: 4px; background: var(--bg2); color: var(--fg);
466
+ }
467
+ .explorer-filters button {
468
+ padding: 6px 16px; background: var(--accent); color: #fff; border: none;
469
+ border-radius: 6px; cursor: pointer; font-size: 12px; font-weight: 500;
470
+ align-self: flex-end;
471
+ }
472
+ .explorer-filters button:hover { opacity: 0.9; }
473
+
474
+ /* ── Explorer layout (左侧列表 + 右侧详情) ── */
475
+ .exp-layout { display: flex; flex: 1; overflow: hidden; }
476
+ .exp-sidebar {
477
+ width: 220px; border-right: 1px solid var(--border); flex-shrink: 0;
478
+ overflow-y: auto; background: var(--bg2);
479
+ }
480
+ .exp-sidebar-group { padding: 8px 0; }
481
+ .exp-sidebar-title {
482
+ font-size: 10px; font-weight: 600; text-transform: uppercase;
483
+ color: var(--dim); padding: 4px 12px; letter-spacing: 0.5px;
484
+ }
485
+ .exp-sidebar-item {
486
+ padding: 6px 12px; cursor: pointer; border-radius: 4px;
487
+ margin: 1px 6px; font-size: 12px; display: flex; justify-content: space-between;
488
+ align-items: center; transition: background 0.1s;
489
+ }
490
+ .exp-sidebar-item:hover { background: var(--bg3); }
491
+ .exp-sidebar-item.active { background: var(--accent); color: #fff; }
492
+ .exp-sidebar-item .item-name {
493
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1;
494
+ }
495
+ .exp-sidebar-item .item-meta {
496
+ font-size: 10px; color: var(--dim); margin-left: 6px; flex-shrink: 0;
497
+ }
498
+ .exp-sidebar-item.active .item-meta { color: rgba(255,255,255,0.7); }
499
+ .exp-detail { flex: 1; padding: 16px; overflow-y: auto; }
500
+ .exp-detail-header {
501
+ font-size: 14px; font-weight: 600; margin-bottom: 12px; color: var(--fg);
502
+ }
251
503
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evolclaw-web",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Web-based monitoring dashboard for EvolClaw",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,10 +10,15 @@
10
10
  "dist/"
11
11
  ],
12
12
  "scripts": {
13
- "build": "tsc && chmod +x dist/index.js && cp -r src/static dist/",
13
+ "build": "tsc && node -e \"try{require('child_process').execFileSync('chmod',['+x','dist/index.js'])}catch{}\" && node -e \"const fs=require('fs'),path=require('path');fs.cpSync('src/static','dist/static',{recursive:true});const f='dist/static/index.html',n=new Date(),ts=n.getFullYear()+'-'+String(n.getMonth()+1).padStart(2,'0')+'-'+String(n.getDate()).padStart(2,'0')+' '+String(n.getHours()).padStart(2,'0')+':'+String(n.getMinutes()).padStart(2,'0');fs.writeFileSync(f,fs.readFileSync(f,'utf8').replace(/(\\<span class=\\\"build-ts\\\"[^>]*\\>)[^<]+(\\<\\/span\\>)/,'$1'+ts+'$2'))\"",
14
+ "dev": "node dev.mjs",
14
15
  "prepublishOnly": "npm run build"
15
16
  },
16
- "keywords": ["evolclaw", "monitoring", "debug"],
17
+ "keywords": [
18
+ "evolclaw",
19
+ "monitoring",
20
+ "debug"
21
+ ],
17
22
  "author": "",
18
23
  "license": "MIT",
19
24
  "peerDependencies": {