evolclaw-web 1.0.1 → 1.2.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
+ <button class="tab" data-view="monitor">Monitor</button>
36
+
30
37
  </nav>
38
+ <span style="flex:1"></span>
39
+ 2026-06-12 22:54
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,117 @@
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
+
142
+ <section id="view-monitor" class="view">
143
+ <div class="mon-layout">
144
+ <div class="mon-toolbar">
145
+ <span class="mon-toolbar-label">时间范围</span>
146
+ <div class="mon-range-tabs">
147
+ <button class="mon-range active" data-range="2m">2 分钟</button>
148
+ <button class="mon-range" data-range="10m">10 分钟</button>
149
+ <button class="mon-range" data-range="1h">1 小时</button>
150
+ </div>
151
+ <span style="flex:1"></span>
152
+ <span class="mon-legend">
153
+ <span class="mon-legend-item"><i class="lg-dot lg-proc"></i>evolclaw 进程</span>
154
+ <span class="mon-legend-item"><i class="lg-dot lg-sys"></i>整机系统</span>
155
+ </span>
156
+ </div>
157
+ <div id="mon-cards" class="usage-cards"></div>
158
+ <div class="mon-row2">
159
+ <div id="mon-cpu-chart" class="mon-chart"></div>
160
+ <div id="mon-mem-chart" class="mon-chart"></div>
161
+ </div>
162
+ <div class="mon-row2">
163
+ <div id="mon-msg-chart" class="mon-chart"></div>
164
+ <div id="mon-err-chart" class="mon-chart"></div>
165
+ </div>
166
+ <div class="mon-table-wrap" id="mon-agent-table-wrap"></div>
167
+ <div class="mon-err-wrap" id="mon-err-list"></div>
168
+ </div>
169
+ </section>
170
+
50
171
  </main>
51
172
  </div>
52
173
 
@@ -1,4 +1,23 @@
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
+ --msg-in: #1f9d55;
16
+ --msg-out: #2563eb;
17
+ }
18
+
19
+ /* 暗色主题 */
20
+ [data-theme="dark"] {
2
21
  --bg: #0d1117;
3
22
  --bg2: #161b22;
4
23
  --bg3: #21262d;
@@ -11,6 +30,8 @@
11
30
  --orange: #db8e3c;
12
31
  --blue: #58a6ff;
13
32
  --magenta: #bc8cff;
33
+ --msg-in: #56e39f;
34
+ --msg-out: #79b8ff;
14
35
  }
15
36
 
16
37
  * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -94,6 +115,7 @@ body {
94
115
  .content { flex: 1; overflow: hidden; position: relative; }
95
116
  .view { display: none; height: 100%; overflow: auto; }
96
117
  .view.active { display: block; }
118
+ #view-usage.active { display: flex; flex-direction: column; overflow: hidden; }
97
119
 
98
120
  /* ── AID 表格 ── */
99
121
  table { width: 100%; border-collapse: collapse; font-size: 12px; }
@@ -247,5 +269,401 @@ tr:hover td { background: var(--bg2); }
247
269
  }
248
270
  .blk-result.err .result-body { border-color: var(--red); }
249
271
 
272
+ /* ── Cache 视图 ── */
273
+ #view-cache { padding: 16px 18px; }
274
+ .cache-cards {
275
+ display: grid;
276
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
277
+ gap: 10px;
278
+ margin-bottom: 22px;
279
+ }
280
+ .cache-card {
281
+ background: var(--bg2);
282
+ border: 1px solid var(--border);
283
+ border-radius: 8px;
284
+ padding: 12px 14px;
285
+ }
286
+ .cc-label { color: var(--dim); font-size: 11px; letter-spacing: 0.3px; }
287
+ .cc-value { font-size: 22px; font-weight: 600; margin: 4px 0 2px; font-variant-numeric: tabular-nums; }
288
+ .cc-value.on { color: var(--green); }
289
+ .cc-value.idle { color: var(--orange); }
290
+ .cc-value.off { color: var(--red); }
291
+ .cc-sub { color: var(--dim); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
292
+ .cache-h {
293
+ font-size: 12px; font-weight: 600; color: var(--dim);
294
+ text-transform: uppercase; letter-spacing: 0.5px;
295
+ margin: 8px 0 6px; padding-top: 6px;
296
+ }
297
+ #view-cache table { margin-bottom: 8px; }
298
+ #view-cache td { font-variant-numeric: tabular-nums; }
299
+ .tag {
300
+ display: inline-block; padding: 1px 7px; border-radius: 10px;
301
+ font-size: 10.5px; border: 1px solid var(--border); color: var(--dim);
302
+ }
303
+ .tag-agent { color: var(--blue); border-color: var(--blue); }
304
+ .tag-relation { color: var(--magenta); border-color: var(--magenta); }
305
+
306
+ /* ── Theme toggle ── */
307
+ .theme-btn {
308
+ background: none; border: 1px solid var(--border); border-radius: 6px;
309
+ color: var(--fg); cursor: pointer; padding: 2px 8px; font-size: 14px;
310
+ margin-left: 8px;
311
+ }
312
+ .theme-btn:hover { background: var(--bg3); }
313
+
314
+ /* ── Usage view ── */
315
+ .usage-layout {
316
+ padding: 0; overflow: hidden; flex: 1; display: flex; flex-direction: column;
317
+ }
318
+ .usage-subtabs { flex-shrink: 0; padding: 12px 16px 0; }
319
+ .usage-subpanel { display: none; flex: 1; overflow: hidden; }
320
+ .usage-subpanel.active { display: flex; flex-direction: column; }
321
+ #usage-dashboard { overflow-y: auto; padding: 16px; }
322
+ #usage-overview { overflow-y: auto; padding: 16px; }
323
+ .usage-cards {
324
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
325
+ gap: 12px; margin-bottom: 20px;
326
+ }
327
+ .usage-card {
328
+ background: var(--bg2); border: 1px solid var(--border); border-radius: 10px;
329
+ padding: 16px; text-align: center;
330
+ box-shadow: 0 1px 3px rgba(0,0,0,0.06);
331
+ }
332
+ .usage-card .card-value {
333
+ font-size: 22px; font-weight: 700; color: var(--accent);
334
+ font-variant-numeric: tabular-nums;
335
+ }
336
+ .usage-card .card-label {
337
+ font-size: 11px; color: var(--dim); margin-top: 4px; text-transform: uppercase;
338
+ letter-spacing: 0.5px;
339
+ }
340
+ .usage-chart-row {
341
+ display: flex; gap: 16px; margin-bottom: 20px;
342
+ }
343
+ .usage-chart {
344
+ flex: 2; height: 260px; background: var(--bg2); border: 1px solid var(--border);
345
+ border-radius: 10px; padding: 12px;
346
+ }
347
+ .usage-chart-sm {
348
+ flex: 1; height: 260px; background: var(--bg2); border: 1px solid var(--border);
349
+ border-radius: 10px; padding: 12px;
350
+ }
351
+ .usage-table-section {
352
+ background: var(--bg2); border: 1px solid var(--border); border-radius: 10px;
353
+ padding: 16px;
354
+ }
355
+ .usage-table-section h3 {
356
+ font-size: 13px; color: var(--dim); margin-bottom: 10px; font-weight: 500;
357
+ }
358
+ .usage-table {
359
+ width: 100%; border-collapse: collapse; font-size: 12px;
360
+ }
361
+ .usage-table th {
362
+ text-align: left; padding: 6px 10px; color: var(--dim); font-weight: 500;
363
+ border-bottom: 1px solid var(--border);
364
+ }
365
+ .usage-table td {
366
+ padding: 6px 10px; border-bottom: 1px solid var(--border);
367
+ font-variant-numeric: tabular-nums;
368
+ }
369
+ .usage-table tr:last-child td { border-bottom: none; }
370
+
371
+ @media (max-width: 800px) {
372
+ .usage-chart-row { flex-direction: column; }
373
+ .usage-chart, .usage-chart-sm { flex: none; height: 200px; }
374
+ }
375
+ .tag-kits { color: var(--green); border-color: var(--green); }
376
+ .tag-global { color: var(--orange); border-color: var(--orange); }
377
+ .cache-note { color: var(--dim); font-size: 11px; margin: 14px 2px 24px; line-height: 1.6; }
378
+
379
+ /* ── Control 视图 ── */
380
+ .ctrl-wrap { padding: 12px; overflow-y: auto; height: 100%; }
381
+ .ctrl-section { margin-bottom: 20px; }
382
+ .ctrl-h { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 8px; }
383
+ .ctrl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 8px; }
384
+ .ctrl-card { background: var(--bg2); border: 1px solid var(--border); border-radius: 6px; padding: 10px 12px; }
385
+ .ctrl-card.ctrl-locked { opacity: .5; }
386
+ .ctrl-card h3 { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 8px; }
387
+ .ctrl-kv { display: grid; grid-template-columns: auto 1fr; gap: 2px 8px; }
388
+ .kv-row { display: contents; }
389
+ .kv-k { color: var(--dim); font-size: 11.5px; }
390
+ .kv-v { color: var(--fg); font-size: 11.5px; word-break: break-all; }
391
+ .ctrl-cur { color: var(--accent); font-size: 12px; margin-right: 6px; }
392
+ .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; }
393
+ .ctrl-row { display: flex; align-items: center; margin: 4px 0; }
394
+ .ctrl-msg { font-size: 12px; color: var(--dim); margin: 4px 0; }
395
+ .ctrl-msg.muted { color: var(--border); }
396
+ .ctrl-list { list-style: none; padding: 0; margin: 6px 0 0; }
397
+ .ctrl-list li { display: flex; align-items: center; gap: 5px; padding: 3px 0; border-bottom: 1px solid var(--border); font-size: 12px; }
398
+ .ctrl-list li:last-child { border-bottom: none; }
399
+ .ctrl-list .name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
400
+ .ctrl-tag { font-size: 11px; color: var(--dim); }
401
+ .ctrl-btns { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
402
+ .ctrl-btn { font-size: 11px; padding: 2px 8px; border-radius: 3px; border: 1px solid var(--border); background: var(--bg3); color: var(--fg); cursor: pointer; }
403
+ .ctrl-btn:hover { border-color: var(--accent); color: var(--accent); }
404
+ .ctrl-btn.danger { color: var(--red); border-color: var(--red); }
405
+ .ctrl-btn:disabled { opacity: .4; cursor: not-allowed; }
406
+ .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; }
407
+ .ctrl-toast.show { opacity: 1; }
408
+ .ctrl-toast.err { border-color: var(--red); color: var(--red); }
409
+
410
+
411
+ /* ── Agents 页 ── */
412
+ .agents-toolbar { padding: 8px 12px; border-bottom: 1px solid var(--border); }
413
+ .agent-ops-cell { white-space: nowrap; vertical-align: middle; }
414
+
415
+ /* disabled 行淡化 */
416
+ tr.ag-disabled td { opacity: .5; }
417
+ tr.ag-disabled .ag-name { color: var(--dim); }
418
+
419
+ /* 操作区:主按钮 + ··· 下拉 */
420
+ .agent-ops { display: flex; align-items: center; gap: 5px; }
421
+ .agent-ops .ctrl-btn { padding: 2px 9px; font-size: 11px; }
422
+ .ops-enable { color: var(--green) !important; border-color: var(--green) !important; }
423
+ .ops-clear-queue { color: var(--orange) !important; border-color: var(--orange) !important; }
424
+
425
+ /* 操作进行中状态 */
426
+ .agent-ops-busy { display: flex; align-items: center; gap: 6px; }
427
+ .ops-busy-label { font-size: 11px; color: var(--dim); font-style: italic; }
428
+
429
+ /* ··· 下拉菜单 */
430
+ .ops-more { position: relative; }
431
+ .ops-more-btn { letter-spacing: 2px; padding: 2px 6px !important; }
432
+ .ops-dropdown {
433
+ display: none; position: absolute; right: 0; top: calc(100% + 4px); z-index: 100;
434
+ background: var(--bg2); border: 1px solid var(--border); border-radius: 6px;
435
+ box-shadow: 0 4px 12px rgba(0,0,0,.15); min-width: 140px; overflow: hidden;
436
+ }
437
+ .ops-more.open .ops-dropdown { display: block; }
438
+ .ops-dd-item {
439
+ display: block; width: 100%; padding: 7px 14px; text-align: left;
440
+ font-size: 12px; background: none; border: none; color: var(--fg);
441
+ cursor: pointer; text-decoration: none; white-space: nowrap;
442
+ }
443
+ .ops-dd-item:hover { background: var(--bg3); }
444
+ .ops-dd-item.danger { color: var(--red); }
445
+ .ops-dd-item.danger:hover { background: var(--bg3); }
446
+
447
+ /* 顶部统计条(对齐终端 watch aid 状态栏)*/
448
+ .agents-stats {
449
+ display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px;
450
+ padding: 9px 14px; border-bottom: 1px solid var(--border);
451
+ background: var(--bg2); font-size: 12px; font-variant-numeric: tabular-nums;
452
+ }
453
+ .agents-stats .sg { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
454
+ .agents-stats .sg-k { color: var(--green); font-weight: 600; }
455
+ .agents-stats .sg-gw { font-family: ui-monospace, Consolas, monospace; color: var(--fg); }
456
+ .agents-stats .num-on { color: var(--green); font-weight: 600; }
457
+ .agents-stats .num-off { color: var(--red); font-weight: 600; }
458
+ .agents-stats .in { color: var(--green); }
459
+ .agents-stats .out { color: var(--blue); }
460
+
461
+ /* 两行一个 agent:主行 + 信息行 */
462
+ #view-agents tr.ag-main > td { border-bottom: none; padding-bottom: 3px; }
463
+ #view-agents tr.ag-sub > td { padding-top: 0; padding-bottom: 9px; color: var(--dim); }
464
+ #view-agents tr.ag-main:hover td, #view-agents tr.ag-sub:hover td { background: var(--bg2); }
465
+
466
+ /* AID 单元:状态点 + 显示名(主) + aid(次,dim) */
467
+ .ag-id { display: flex; align-items: center; gap: 7px; }
468
+ .ag-id .dot { margin: 0; flex-shrink: 0; }
469
+ .ag-id-text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
470
+ .ag-name { font-weight: 600; color: var(--fg); overflow: hidden; text-overflow: ellipsis; }
471
+ .ag-aid { font-size: 10.5px; color: var(--dim); font-family: ui-monospace, Consolas, monospace; overflow: hidden; text-overflow: ellipsis; }
472
+
473
+ /* 工作状态徽标(无边框,纯色文字) */
474
+ .state-badge { display: inline-block; padding: 1px 8px; border-radius: 10px; font-size: 11px; font-weight: 700; }
475
+ .state-badge.working { color: #fff; background: var(--orange); }
476
+ .state-badge.queued { color: #fff; background: var(--orange); }
477
+ .state-badge.idle { color: var(--dim); background: var(--bg3); }
478
+ .state-badge.connected { color: var(--green); background: var(--bg3); }
479
+ .state-badge.muted { color: var(--magenta); background: var(--bg3); }
480
+ .state-badge.stopped { color: var(--dim); background: var(--bg3); }
481
+
482
+ /* 队列数列 */
483
+ .ag-queue-num { color: var(--orange); font-weight: 600; font-variant-numeric: tabular-nums; }
484
+
485
+ /* 子标签栏 */
486
+ .ag-subtabs { display: inline-flex; gap: 2px; }
487
+ .ag-subtab { background: var(--bg3); border: 1px solid var(--border); border-radius: 6px; padding: 4px 14px; font-size: 12px; color: var(--dim); cursor: pointer; font-family: inherit; }
488
+ .ag-subtab.active { background: var(--accent); color: #fff; border-color: var(--accent); }
489
+ .agents-toolbar { display: flex; align-items: center; gap: 12px; padding: 8px 12px; border-bottom: 1px solid var(--border); }
490
+
491
+ /* 操作按钮:实心立体风 */
492
+ .ops-stop { background: var(--red) !important; color: #fff !important; border: none !important; box-shadow: 0 2px 4px rgba(229,62,62,.3); }
493
+ .ops-stop:hover { opacity: 0.85; }
494
+ .ops-start { background: var(--green) !important; color: #fff !important; border: none !important; box-shadow: 0 2px 4px rgba(56,161,105,.3); }
495
+ .ops-start:hover { opacity: 0.85; }
496
+ .ops-clear-queue { background: var(--orange) !important; color: #fff !important; border: none !important; box-shadow: 0 2px 4px rgba(221,107,32,.3); }
497
+ .ops-clear-queue:hover { opacity: 0.85; }
498
+ .ops-enable { background: var(--green) !important; color: #fff !important; border: none !important; box-shadow: 0 2px 4px rgba(56,161,105,.3); }
499
+ .ops-enable:hover { opacity: 0.85; }
500
+ .ops-mute { background: var(--magenta) !important; color: #fff !important; border: none !important; }
501
+ .ops-unmute { background: var(--green) !important; color: #fff !important; border: none !important; }
502
+
503
+ /* 信息行:最近消息(进绿/出蓝,对端橙)+ 项目路径 */
504
+ .ag-info { display: flex; flex-direction: column; gap: 2px; }
505
+ .ag-msg-wrap { position: relative; }
506
+ .ag-msg { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 70vw; }
507
+ .ag-msg .arrow-in { color: var(--msg-in); font-weight: 700; }
508
+ .ag-msg .arrow-out { color: var(--msg-out); font-weight: 700; }
509
+ .ag-msg .peer { color: var(--orange); font-weight: 600; }
510
+ .ag-msg .text-in { color: var(--msg-in); font-weight: 500; }
511
+ .ag-msg .text-out { color: var(--msg-out); font-weight: 500; }
512
+ .ag-msg .mtag { display: inline-block; padding: 0 4px; margin: 0 2px; border-radius: 3px; font-size: 10px; background: var(--bg3); color: var(--magenta); vertical-align: middle; }
513
+ .ag-msg .mtags { color: var(--magenta); font-size: 10.5px; }
514
+ .ag-path { font-family: ui-monospace, Consolas, monospace; font-size: 10.5px; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 70vw; }
515
+
516
+ /* 消息 tooltip(hover 浮层)*/
517
+ .msg-tip { display: none; position: absolute; bottom: calc(100% + 4px); left: 0; z-index: 200; background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 4px 16px rgba(0,0,0,.2); padding: 8px 12px; min-width: 300px; max-width: 600px; white-space: normal; }
518
+ .ag-msg-wrap:hover .msg-tip { display: block; }
519
+ .tip-row { font-size: 12px; line-height: 1.8; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 500; }
520
+ .tip-row-in { color: var(--msg-in); }
521
+ .tip-row-out { color: var(--msg-out); }
522
+ .tip-kind { margin: 0 2px; font-weight: 600; }
523
+ .tip-flag { margin: 0 2px; padding: 0 4px; border-radius: 3px; background: var(--bg3); color: var(--magenta); font-size: 10.5px; }
524
+ .tip-row b { color: var(--orange); font-weight: 600; }
525
+
526
+
527
+ /* ── System 页 ── */
528
+ .sys-wrap { padding: 12px; overflow-y: auto; height: 100%; }
529
+ .sys-actions { display: flex; gap: 8px; flex-wrap: wrap; }
530
+ .sys-health { display: flex; flex-direction: column; gap: 8px; }
531
+ .card-label { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 4px; }
532
+ .card-val { font-size: 13px; color: var(--fg); }
533
+
534
+ /* Agent 健康卡片网格 */
535
+ .agent-health-grid {
536
+ display: grid;
537
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
538
+ gap: 10px;
539
+ }
540
+ .agent-health-card {
541
+ background: var(--bg2);
542
+ border: 1px solid var(--border);
543
+ border-radius: 8px;
544
+ padding: 12px 14px;
545
+ }
546
+ .ahc-head { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
547
+ .ahc-aid { font-weight: 600; font-size: 13px; color: var(--fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
548
+ .ahc-status { margin-left: auto; font-size: 11px; color: var(--dim); }
549
+ .ahc-row { display: flex; gap: 8px; font-size: 12px; margin: 3px 0; }
550
+ .ahc-k { color: var(--dim); width: 32px; flex-shrink: 0; }
551
+ .ahc-v { color: var(--fg); flex: 1; min-width: 0; }
552
+ .ahc-path { font-family: var(--mono, ui-monospace, monospace); color: var(--dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
553
+ .ch-row { line-height: 1.6; }
554
+ .ahc-err { margin-top: 6px; font-size: 12px; color: var(--red); white-space: normal; word-break: break-word; }
555
+
556
+ /* ── Triggers 页 ── */
557
+ .trig-layout { display: flex; height: 100%; overflow: hidden; }
558
+ .trig-agents-col { width: 200px; border-right: 1px solid var(--border); flex-shrink: 0; overflow-y: auto; }
559
+ .trig-table-col { flex: 1; overflow: auto; padding: 0; }
560
+ .trig-table-col table { width: 100%; border-collapse: collapse; font-size: 12px; }
561
+ .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; }
562
+ .trig-table-col td { padding: 6px 10px; border-bottom: 1px solid var(--border); vertical-align: top; white-space: nowrap; }
563
+ .trig-table-col tr:hover td { background: var(--bg2); }
564
+ .trig-table-col .trig-prompt { max-width: 240px; overflow: hidden; text-overflow: ellipsis; }
565
+ .trig-table-col tr.trig-done td { opacity: .55; }
566
+ .trig-badge { display: inline-block; padding: 1px 7px; border-radius: 9px; font-size: 11px; border: 1px solid transparent; white-space: nowrap; }
567
+ .trig-badge-active { color: var(--green, #3fb950); border-color: var(--green, #3fb950); }
568
+ .trig-badge-fired { color: var(--dim); border-color: var(--border); }
569
+ .trig-badge-cancelled { color: var(--red); border-color: var(--red); }
570
+ .trig-badge-expired { color: var(--dim); border-color: var(--border); }
571
+ /* ── Usage subtabs ── */
572
+ .usage-subtabs {
573
+ display: flex; gap: 4px; margin-bottom: 16px;
574
+ }
575
+ .usage-subtab {
576
+ background: var(--bg3); border: 1px solid var(--border); border-radius: 6px;
577
+ padding: 5px 14px; font-size: 12px; color: var(--dim); cursor: pointer;
578
+ }
579
+ .usage-subtab.active {
580
+ background: var(--accent); color: #fff; border-color: var(--accent);
581
+ }
582
+
583
+ /* ── Explorer filters ── */
584
+ .explorer-filters {
585
+ display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
586
+ margin-bottom: 16px; padding: 12px; background: var(--bg3);
587
+ border-radius: 8px; border: 1px solid var(--border);
588
+ }
589
+ .explorer-filters label {
590
+ font-size: 11px; color: var(--dim); display: flex; flex-direction: column; gap: 2px;
591
+ }
592
+ .explorer-filters input, .explorer-filters select {
593
+ padding: 4px 8px; font-size: 12px; border: 1px solid var(--border);
594
+ border-radius: 4px; background: var(--bg2); color: var(--fg);
595
+ }
596
+ .explorer-filters button {
597
+ padding: 6px 16px; background: var(--accent); color: #fff; border: none;
598
+ border-radius: 6px; cursor: pointer; font-size: 12px; font-weight: 500;
599
+ align-self: flex-end;
600
+ }
601
+ .explorer-filters button:hover { opacity: 0.9; }
602
+
603
+ /* ── Explorer layout (左侧列表 + 右侧详情) ── */
604
+ .exp-layout { display: flex; flex: 1; overflow: hidden; }
605
+ .exp-sidebar {
606
+ width: 220px; border-right: 1px solid var(--border); flex-shrink: 0;
607
+ overflow-y: auto; background: var(--bg2);
608
+ }
609
+ .exp-sidebar-group { padding: 8px 0; }
610
+ .exp-sidebar-title {
611
+ font-size: 10px; font-weight: 600; text-transform: uppercase;
612
+ color: var(--dim); padding: 4px 12px; letter-spacing: 0.5px;
613
+ }
614
+ .exp-sidebar-item {
615
+ padding: 6px 12px; cursor: pointer; border-radius: 4px;
616
+ margin: 1px 6px; font-size: 12px; display: flex; justify-content: space-between;
617
+ align-items: center; transition: background 0.1s;
618
+ }
619
+ .exp-sidebar-item:hover { background: var(--bg3); }
620
+ .exp-sidebar-item.active { background: var(--accent); color: #fff; }
621
+ .exp-sidebar-item .item-name {
622
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1;
623
+ }
624
+ .exp-sidebar-item .item-meta {
625
+ font-size: 10px; color: var(--dim); margin-left: 6px; flex-shrink: 0;
626
+ }
627
+ .exp-sidebar-item.active .item-meta { color: rgba(255,255,255,0.7); }
628
+ .exp-detail { flex: 1; padding: 16px; overflow-y: auto; }
629
+ .exp-detail-header {
630
+ font-size: 14px; font-weight: 600; margin-bottom: 12px; color: var(--fg);
631
+ }
250
632
 
633
+ /* ── Monitor ─────────────────────────────────── */
634
+ .mon-layout { padding: 16px; display: flex; flex-direction: column; gap: 14px; min-height: 100%; box-sizing: border-box; }
635
+ .mon-toolbar { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
636
+ .mon-toolbar-label { font-size: 12px; color: var(--dim); font-weight: 500; }
637
+ .mon-range-tabs { display: flex; gap: 2px; background: var(--bg3); border-radius: 6px; padding: 2px; }
638
+ .mon-range { padding: 4px 12px; border: none; background: none; border-radius: 5px; font-size: 12px; font-family: inherit; color: var(--dim); cursor: pointer; }
639
+ .mon-range:hover { color: var(--fg); }
640
+ .mon-range.active { background: var(--accent); color: #fff; }
641
+ .mon-legend { display: flex; gap: 14px; font-size: 11px; color: var(--dim); }
642
+ .mon-legend-item { display: inline-flex; align-items: center; gap: 4px; }
643
+ .lg-dot { display: inline-block; width: 10px; height: 3px; border-radius: 2px; }
644
+ .lg-proc { background: var(--accent); }
645
+ .lg-sys { background: var(--orange); }
646
+ .mon-row2 { display: flex; gap: 14px; }
647
+ .mon-chart { flex: 1; height: 220px; min-width: 0; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
648
+ .mon-table-wrap { min-width: 0; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 14px; overflow-x: auto; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
649
+ .mon-section-title { font-size: 13px; font-weight: 500; color: var(--dim); margin-bottom: 10px; }
650
+ .mon-section-sub { font-weight: 400; color: var(--dim); font-size: 11px; }
651
+ .mon-err-wrap { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 14px; box-shadow: 0 1px 3px rgba(0,0,0,0.06); }
652
+ .mon-err-rows { max-height: 240px; overflow-y: auto; }
653
+ .mon-err-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid var(--border); font-size: 12px; }
654
+ .mon-err-row:last-child { border-bottom: none; }
655
+ .mon-err-time { flex-shrink: 0; width: 36px; color: var(--dim); font-variant-numeric: tabular-nums; }
656
+ .mon-err-tag { flex-shrink: 0; padding: 1px 6px; border-radius: 3px; font-size: 10px; font-weight: 500; }
657
+ .tag-task { background: #fef3cd; color: #856404; }
658
+ .tag-tool { background: #d1ecf1; color: #0c5460; }
659
+ [data-theme="dark"] .tag-task { background: #3d2a1a; color: #db8e3c; }
660
+ [data-theme="dark"] .tag-tool { background: #1a3d42; color: #76c7d4; }
661
+ .mon-err-aid { flex-shrink: 0; max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--accent); font-weight: 500; }
662
+ .mon-err-kind { flex-shrink: 0; max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--red); }
663
+ .mon-err-msg { flex: 1; color: var(--dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
664
+ @media (max-width: 900px) {
665
+ .mon-row2 { flex-direction: column; }
666
+ .mon-chart { height: 190px; }
667
+ .mon-toolbar { flex-wrap: wrap; }
668
+ }
251
669
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evolclaw-web",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "Web-based monitoring dashboard for EvolClaw",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,7 +10,8 @@
10
10
  "dist/"
11
11
  ],
12
12
  "scripts": {
13
- "build": "tsc && chmod +x dist/index.js && cp -r src/static dist/",
13
+ "build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && 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
17
  "keywords": [