ec-web 0.0.17 → 0.0.19
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.
- package/dist/ipc-client.js +4 -1
- package/dist/paths.js +1 -6
- package/dist/sources/logs.js +56 -12
- package/dist/static/app.js +8 -2
- package/dist/static/index.html +2 -2
- package/package.json +1 -1
package/dist/ipc-client.js
CHANGED
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
import net from 'net';
|
|
10
10
|
import fs from 'fs';
|
|
11
11
|
import path from 'path';
|
|
12
|
-
|
|
12
|
+
// Keep this list aligned with evolcore's local-control IPC gate. `evolagent.list`
|
|
13
|
+
// is used by the Agents view and is read-only from EC Web's perspective, but the
|
|
14
|
+
// daemon still requires the local control token before returning its registry.
|
|
15
|
+
const LOCAL_CONTROL_COMMANDS = new Set(['evolagent.list', 'menu.exec', 'monitor-snapshot']);
|
|
13
16
|
export function ipcQuery(socketPath, cmd, timeoutMs = 3000) {
|
|
14
17
|
let request = cmd;
|
|
15
18
|
if (LOCAL_CONTROL_COMMANDS.has(cmd.type) && typeof cmd.controlToken !== 'string') {
|
package/dist/paths.js
CHANGED
|
@@ -7,12 +7,10 @@
|
|
|
7
7
|
* 根目录解析优先级:
|
|
8
8
|
* 1. --home 命令行参数(由 index.ts 写入 process.env.EVOLCORE_HOME)
|
|
9
9
|
* 2. EVOLCORE_HOME 环境变量
|
|
10
|
-
* 3.
|
|
11
|
-
* 4. ~/.evolcore
|
|
10
|
+
* 3. ~/.evolcore
|
|
12
11
|
*/
|
|
13
12
|
import path from 'path';
|
|
14
13
|
import os from 'os';
|
|
15
|
-
import fs from 'fs';
|
|
16
14
|
import crypto from 'crypto';
|
|
17
15
|
const isWindows = process.platform === 'win32';
|
|
18
16
|
let _root = null;
|
|
@@ -22,9 +20,6 @@ export function resolveRoot() {
|
|
|
22
20
|
if (process.env.EVOLCORE_HOME) {
|
|
23
21
|
_root = process.env.EVOLCORE_HOME;
|
|
24
22
|
}
|
|
25
|
-
else if (fs.existsSync(path.join(process.cwd(), 'agents', 'defaults.json'))) {
|
|
26
|
-
_root = process.cwd();
|
|
27
|
-
}
|
|
28
23
|
else {
|
|
29
24
|
_root = path.join(os.homedir(), '.evolcore');
|
|
30
25
|
}
|
package/dist/sources/logs.js
CHANGED
|
@@ -14,12 +14,17 @@ const LOG_SOURCES = [
|
|
|
14
14
|
{ id: 'triggers', label: 'Trigger runs', pattern: /^trigger-runs(?:-.+)?\.(?:log|jsonl)$/ },
|
|
15
15
|
{ id: 'restart', label: 'Restart', pattern: /^restart\.log$/ },
|
|
16
16
|
{ id: 'menu-cli', label: 'Menu CLI', pattern: /^menu-cli-exec\.log$/ },
|
|
17
|
+
{ id: 'menu-protocol', label: 'Menu Protocol', pattern: /^menu-protocol(?:-.+)?\.log$/ },
|
|
17
18
|
{ id: 'causation', label: 'Causation spans', pattern: /^causation-spans(?:-.+)?\.log$/ },
|
|
19
|
+
{ id: 'command-audit', label: 'Command audit', pattern: /^command-audit(?:-.+)?\.log$/ },
|
|
20
|
+
{ id: 'role-mutations', label: 'Role mutations', pattern: /^role-mutations(?:-.+)?\.log$/ },
|
|
18
21
|
];
|
|
19
22
|
const DEFAULT_LIMIT = 500;
|
|
20
|
-
const MAX_LIMIT =
|
|
21
|
-
const
|
|
23
|
+
const MAX_LIMIT = 2000;
|
|
24
|
+
const TAIL_READ_CHUNK_BYTES = 256 * 1024;
|
|
25
|
+
const MAX_FILE_TAIL_BYTES = 32 * 1024 * 1024;
|
|
22
26
|
const MAX_LINE_CHARS = 12_000;
|
|
27
|
+
const MAX_JSON_PARSE_CHARS = 4 * 1024 * 1024;
|
|
23
28
|
function listLogFiles() {
|
|
24
29
|
const logsDir = resolvePaths().logs;
|
|
25
30
|
try {
|
|
@@ -55,12 +60,30 @@ function availableSources(files) {
|
|
|
55
60
|
function readTail(file, maxLines) {
|
|
56
61
|
if (file.size <= 0 || maxLines <= 0)
|
|
57
62
|
return [];
|
|
58
|
-
const bytes = Math.min(file.size, MAX_FILE_TAIL_BYTES);
|
|
59
|
-
const buffer = Buffer.allocUnsafe(bytes);
|
|
60
63
|
let handle = null;
|
|
61
64
|
try {
|
|
62
65
|
handle = fs.openSync(file.path, 'r');
|
|
63
|
-
|
|
66
|
+
const chunks = [];
|
|
67
|
+
let position = file.size;
|
|
68
|
+
let bytesRead = 0;
|
|
69
|
+
let newlineCount = 0;
|
|
70
|
+
while (position > 0 && bytesRead < MAX_FILE_TAIL_BYTES && newlineCount <= maxLines) {
|
|
71
|
+
const chunkSize = Math.min(TAIL_READ_CHUNK_BYTES, position, MAX_FILE_TAIL_BYTES - bytesRead);
|
|
72
|
+
const chunk = Buffer.allocUnsafe(chunkSize);
|
|
73
|
+
position -= chunkSize;
|
|
74
|
+
fs.readSync(handle, chunk, 0, chunkSize, position);
|
|
75
|
+
chunks.unshift(chunk);
|
|
76
|
+
bytesRead += chunkSize;
|
|
77
|
+
for (const byte of chunk)
|
|
78
|
+
if (byte === 0x0a)
|
|
79
|
+
newlineCount += 1;
|
|
80
|
+
}
|
|
81
|
+
let text = Buffer.concat(chunks).toString('utf8');
|
|
82
|
+
if (position > 0) {
|
|
83
|
+
const firstBreak = text.indexOf('\n');
|
|
84
|
+
text = firstBreak >= 0 ? text.slice(firstBreak + 1) : '';
|
|
85
|
+
}
|
|
86
|
+
return text.split(/\r?\n/).filter(Boolean).slice(-maxLines);
|
|
64
87
|
}
|
|
65
88
|
catch {
|
|
66
89
|
return [];
|
|
@@ -72,12 +95,6 @@ function readTail(file, maxLines) {
|
|
|
72
95
|
}
|
|
73
96
|
catch { }
|
|
74
97
|
}
|
|
75
|
-
let text = buffer.toString('utf8');
|
|
76
|
-
if (bytes < file.size) {
|
|
77
|
-
const firstBreak = text.indexOf('\n');
|
|
78
|
-
text = firstBreak >= 0 ? text.slice(firstBreak + 1) : '';
|
|
79
|
-
}
|
|
80
|
-
return text.split(/\r?\n/).filter(Boolean).slice(-maxLines);
|
|
81
98
|
}
|
|
82
99
|
function shortLogName(file) {
|
|
83
100
|
return path.basename(file)
|
|
@@ -175,6 +192,28 @@ function parseJsonLine(raw, file) {
|
|
|
175
192
|
raw,
|
|
176
193
|
};
|
|
177
194
|
}
|
|
195
|
+
if (typeof value.event === 'string' && value.event.trim()) {
|
|
196
|
+
const event = value.event.trim();
|
|
197
|
+
if (!level) {
|
|
198
|
+
level = event.endsWith('.failed') || event.endsWith('.error')
|
|
199
|
+
? 'error'
|
|
200
|
+
: (event.endsWith('.completed') ? 'info' : 'debug');
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
timestamp,
|
|
204
|
+
level,
|
|
205
|
+
file,
|
|
206
|
+
module: event.split(/[.:]/)[0] || shortLogName(file),
|
|
207
|
+
actor: value.selfAid ? String(value.selfAid) : (value.self_aid ? String(value.self_aid) : null),
|
|
208
|
+
direction: null,
|
|
209
|
+
event,
|
|
210
|
+
fields: collectFields(value, new Set(['ts', 'timestamp', 'event', 'selfAid', 'self_aid']), 10),
|
|
211
|
+
format: 'json',
|
|
212
|
+
userMessage: false,
|
|
213
|
+
message: '',
|
|
214
|
+
raw,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
178
217
|
if (value.runId && value.triggerId) {
|
|
179
218
|
const startedAt = Number(value.startedAt);
|
|
180
219
|
const finishedAt = Number(value.finishedAt);
|
|
@@ -328,7 +367,12 @@ function parseLine(rawLine, file) {
|
|
|
328
367
|
const raw = rawLine.length > MAX_LINE_CHARS
|
|
329
368
|
? `${rawLine.slice(0, MAX_LINE_CHARS)} …`
|
|
330
369
|
: rawLine;
|
|
331
|
-
|
|
370
|
+
if (rawLine.startsWith('{') && rawLine.length <= MAX_JSON_PARSE_CHARS) {
|
|
371
|
+
const parsed = parseJsonLine(rawLine, file);
|
|
372
|
+
if (parsed)
|
|
373
|
+
return { ...parsed, raw };
|
|
374
|
+
}
|
|
375
|
+
return parseTextLine(raw, file);
|
|
332
376
|
}
|
|
333
377
|
function linesFor(files, source, limit) {
|
|
334
378
|
const matching = files
|
package/dist/static/app.js
CHANGED
|
@@ -108,9 +108,9 @@ const translations = {
|
|
|
108
108
|
'logs.search': '搜索',
|
|
109
109
|
'logs.searchPlaceholder': '筛选当前日志',
|
|
110
110
|
'logs.lines': '行数',
|
|
111
|
-
'logs.lines.200': '200 行',
|
|
112
111
|
'logs.lines.500': '500 行',
|
|
113
112
|
'logs.lines.1000': '1000 行',
|
|
113
|
+
'logs.lines.2000': '2000 行',
|
|
114
114
|
'logs.follow': '跟随尾部',
|
|
115
115
|
'logs.live': '自动刷新',
|
|
116
116
|
'logs.meta': '{files} 个文件 · {size} · 更新于 {time}',
|
|
@@ -131,7 +131,10 @@ const translations = {
|
|
|
131
131
|
'logs.source.triggers': '触发器运行',
|
|
132
132
|
'logs.source.restart': '重启',
|
|
133
133
|
'logs.source.menu-cli': '菜单 CLI',
|
|
134
|
+
'logs.source.menu-protocol': 'Menu 协议',
|
|
134
135
|
'logs.source.causation': '因果链路',
|
|
136
|
+
'logs.source.command-audit': '命令审计',
|
|
137
|
+
'logs.source.role-mutations': '角色变更',
|
|
135
138
|
|
|
136
139
|
// Agents view
|
|
137
140
|
'agents.subtitle.enabled': '启用',
|
|
@@ -1011,9 +1014,9 @@ const translations = {
|
|
|
1011
1014
|
'logs.search': 'Search',
|
|
1012
1015
|
'logs.searchPlaceholder': 'Filter current logs',
|
|
1013
1016
|
'logs.lines': 'Lines',
|
|
1014
|
-
'logs.lines.200': '200 Lines',
|
|
1015
1017
|
'logs.lines.500': '500 Lines',
|
|
1016
1018
|
'logs.lines.1000': '1000 Lines',
|
|
1019
|
+
'logs.lines.2000': '2000 Lines',
|
|
1017
1020
|
'logs.follow': 'Follow tail',
|
|
1018
1021
|
'logs.live': 'Auto refresh',
|
|
1019
1022
|
'logs.meta': '{files} files · {size} · updated {time}',
|
|
@@ -1034,7 +1037,10 @@ const translations = {
|
|
|
1034
1037
|
'logs.source.triggers': 'Trigger runs',
|
|
1035
1038
|
'logs.source.restart': 'Restart',
|
|
1036
1039
|
'logs.source.menu-cli': 'Menu CLI',
|
|
1040
|
+
'logs.source.menu-protocol': 'Menu Protocol',
|
|
1037
1041
|
'logs.source.causation': 'Causation spans',
|
|
1042
|
+
'logs.source.command-audit': 'Command audit',
|
|
1043
|
+
'logs.source.role-mutations': 'Role mutations',
|
|
1038
1044
|
|
|
1039
1045
|
// Agents view
|
|
1040
1046
|
'agents.subtitle.enabled': 'Enabled',
|
package/dist/static/index.html
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
|
|
49
49
|
</nav>
|
|
50
50
|
<span style="flex:1"></span>
|
|
51
|
-
2026-08-
|
|
51
|
+
2026-08-27 15:27
|
|
52
52
|
<span id="conn-status" class="conn-status" data-i18n="status.connecting">连接中…</span>
|
|
53
53
|
<button id="lang-btn" class="theme-btn" data-i18n-title="language.buttonTitle" title="切换语言">🌐</button>
|
|
54
54
|
<button id="theme-btn" class="theme-btn" data-i18n-title="theme.buttonTitle" title="主题">🌗</button>
|
|
@@ -109,9 +109,9 @@
|
|
|
109
109
|
<label class="log-control log-limit-control">
|
|
110
110
|
<span class="visually-hidden" data-i18n="logs.lines">行数</span>
|
|
111
111
|
<select id="log-limit">
|
|
112
|
-
<option value="200" data-i18n="logs.lines.200">200 行</option>
|
|
113
112
|
<option value="500" data-i18n="logs.lines.500" selected>500 行</option>
|
|
114
113
|
<option value="1000" data-i18n="logs.lines.1000">1000 行</option>
|
|
114
|
+
<option value="2000" data-i18n="logs.lines.2000">2000 行</option>
|
|
115
115
|
</select>
|
|
116
116
|
</label>
|
|
117
117
|
<label class="log-follow">
|