evolcore 0.0.15 → 0.0.17
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/CHANGELOG.md +31 -0
- package/README.md +1 -0
- package/dist/agents/claude-runner.js +148 -29
- package/dist/agents/codex-runner.js +36 -10
- package/dist/agents/ecagent-runner.js +4 -1
- package/dist/aun/msg/group.js +3 -1
- package/dist/aun/msg/p2p.js +8 -6
- package/dist/channels/aun.js +73 -20
- package/dist/channels/daemon.js +15 -9
- package/dist/cli/init.js +7 -3
- package/dist/cli/task-context.js +48 -3
- package/dist/config/config-manager.js +1 -0
- package/dist/core/audit/log-integrity.js +149 -0
- package/dist/core/auth/authorization-audit.js +73 -3
- package/dist/core/event-catalog.js +1 -0
- package/dist/core/message/response-engine.js +36 -21
- package/dist/core/permission/tool-error-code.js +47 -0
- package/dist/core/permission/tool-policy.js +61 -2
- package/dist/index.js +8 -4
- package/dist/ipc.js +11 -6
- package/dist/paths.js +18 -1
- package/dist/trigger/scheduler.js +5 -4
- package/dist/utils/cross-platform.js +1 -24
- package/dist/utils/error-utils.js +38 -0
- package/dist/utils/instance-registry.js +35 -27
- package/dist/utils/logger.js +41 -10
- package/dist/utils/windows-autostart.js +50 -9
- package/dist/utils/windows-output.js +36 -0
- package/kits/docs/evolcore/config.md +1 -0
- package/kits/schemas/agent-config.schema.10.json +6 -0
- package/kits/schemas/daemon.schema.1.json +1 -1
- package/kits/schemas/daemon.schema.2.json +1 -1
- package/kits/schemas/daemon.schema.3.json +1 -1
- package/kits/schemas/daemon.schema.4.json +1 -1
- package/package.json +1 -1
package/dist/utils/logger.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import { resolvePaths } from '../paths.js';
|
|
3
3
|
import { LogWriter } from './log-writer.js';
|
|
4
|
+
import { classifyToolErrorCode } from '../core/permission/tool-error-code.js';
|
|
4
5
|
let currentLevel = process.env.LOG_LEVEL || 'INFO';
|
|
5
6
|
const LEVELS = { DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3 };
|
|
6
7
|
const config = {
|
|
@@ -46,30 +47,60 @@ export function normalizeStructuredLog(data) {
|
|
|
46
47
|
if (!data || typeof data !== 'object' || Array.isArray(data))
|
|
47
48
|
return data;
|
|
48
49
|
const nested = data.event && typeof data.event === 'object' ? data.event : undefined;
|
|
50
|
+
const eventType = data.type ?? nested?.type;
|
|
49
51
|
const correlationId = data.correlationId
|
|
52
|
+
?? data.correlation_id
|
|
50
53
|
?? data.callId
|
|
54
|
+
?? data.call_id
|
|
55
|
+
?? data.toolUseId
|
|
56
|
+
?? data.tool_use_id
|
|
51
57
|
?? data.requestId
|
|
58
|
+
?? data.request_id
|
|
52
59
|
?? data.operationId
|
|
53
60
|
?? data.msgId
|
|
54
61
|
?? nested?.correlationId
|
|
55
|
-
?? nested?.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
62
|
+
?? nested?.correlation_id
|
|
63
|
+
?? nested?.callId
|
|
64
|
+
?? nested?.call_id
|
|
65
|
+
?? nested?.toolUseId
|
|
66
|
+
?? nested?.tool_use_id;
|
|
67
|
+
const sessionId = data.sessionId ?? data.session_id ?? nested?.sessionId ?? nested?.session_id;
|
|
68
|
+
const agentAid = data.agentAid ?? data.agent_aid ?? data.selfAid ?? nested?.agentAid ?? nested?.agent_aid;
|
|
69
|
+
const permissionMode = data.permissionMode ?? data.permission_mode ?? nested?.permissionMode ?? nested?.permission_mode;
|
|
70
|
+
const toolName = data.toolName ?? data.tool ?? data.name ?? nested?.toolName ?? nested?.name;
|
|
71
|
+
const isToolResult = eventType === 'tool:result' || eventType === 'tool_result';
|
|
72
|
+
const isToolUse = eventType === 'tool:use' || eventType === 'tool_use';
|
|
73
|
+
const isError = data.isError ?? data.is_error ?? (data.ok === false ? true : undefined)
|
|
74
|
+
?? nested?.isError ?? nested?.is_error ?? (nested?.ok === false ? true : undefined);
|
|
75
|
+
const error = data.error ?? data.errorMessage ?? nested?.error ?? nested?.errorMessage;
|
|
76
|
+
const result = data.result ?? data.content ?? nested?.result ?? nested?.content;
|
|
60
77
|
const decision = data.decision
|
|
61
78
|
?? data.status
|
|
62
|
-
?? (isToolResult &&
|
|
63
|
-
?? (isToolResult &&
|
|
64
|
-
?? (
|
|
79
|
+
?? (isToolResult && isError === true ? 'error' : undefined)
|
|
80
|
+
?? (isToolResult && isError === false ? 'allow' : undefined)
|
|
81
|
+
?? (isToolUse ? 'started' : undefined)
|
|
65
82
|
?? nested?.decision;
|
|
83
|
+
const explicitErrorCode = data.errorCode
|
|
84
|
+
?? data.error_code
|
|
85
|
+
?? nested?.errorCode
|
|
86
|
+
?? nested?.error_code;
|
|
87
|
+
const errorCode = isToolResult && isError === true
|
|
88
|
+
? classifyToolErrorCode({ errorCode: explicitErrorCode, error, result })
|
|
89
|
+
: explicitErrorCode;
|
|
90
|
+
const lifecycleRecord = isToolUse || isToolResult;
|
|
91
|
+
const missingContextFields = lifecycleRecord
|
|
92
|
+
? ['sessionId', 'agentAid', 'permissionMode'].filter(field => ({ sessionId, agentAid, permissionMode }[field] == null))
|
|
93
|
+
: [];
|
|
66
94
|
return {
|
|
67
95
|
...data,
|
|
68
96
|
...(correlationId ? { correlationId } : {}),
|
|
69
|
-
...(sessionId ? { sessionId } : {}),
|
|
70
|
-
...(agentAid ? { agentAid } : {}),
|
|
97
|
+
...(sessionId ? { sessionId } : lifecycleRecord ? { sessionId: 'unknown' } : {}),
|
|
98
|
+
...(agentAid ? { agentAid } : lifecycleRecord ? { agentAid: 'unknown' } : {}),
|
|
99
|
+
...(permissionMode ? { permissionMode } : lifecycleRecord ? { permissionMode: 'unknown' } : {}),
|
|
71
100
|
...(toolName ? { toolName } : {}),
|
|
72
101
|
...(decision ? { decision } : {}),
|
|
102
|
+
...(errorCode ? { errorCode } : {}),
|
|
103
|
+
...(missingContextFields.length > 0 ? { contextMissing: missingContextFields } : {}),
|
|
73
104
|
};
|
|
74
105
|
}
|
|
75
106
|
export function localTimestamp() {
|
|
@@ -2,19 +2,35 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { spawnSync } from 'child_process';
|
|
4
4
|
import { getPackageRoot } from '../paths.js';
|
|
5
|
+
import { decodeWindowsOutput } from './windows-output.js';
|
|
5
6
|
export const WINDOWS_AUTOSTART_TASK_NAME = 'EvolCore';
|
|
6
7
|
function isWindows() {
|
|
7
8
|
return process.platform === 'win32';
|
|
8
9
|
}
|
|
9
10
|
function runSchtasks(args) {
|
|
10
11
|
return spawnSync('schtasks.exe', args, {
|
|
11
|
-
encoding: '
|
|
12
|
+
encoding: 'buffer',
|
|
12
13
|
windowsHide: true,
|
|
13
14
|
timeout: 15_000,
|
|
14
15
|
});
|
|
15
16
|
}
|
|
16
17
|
function commandError(result, fallback) {
|
|
17
|
-
|
|
18
|
+
const output = decodeWindowsOutput(result.stderr) || decodeWindowsOutput(result.stdout);
|
|
19
|
+
const status = result.status == null ? '' : `(退出码 ${result.status})`;
|
|
20
|
+
const signal = result.signal ? `(信号 ${result.signal})` : '';
|
|
21
|
+
return `${result.error?.message || output || fallback}${status}${signal}`.trim();
|
|
22
|
+
}
|
|
23
|
+
function isTaskNotFoundMessage(message) {
|
|
24
|
+
return /cannot find the file specified|系统找不到指定的文件|找不到指定的文件|指定的任务不存在|任务不存在/i.test(message);
|
|
25
|
+
}
|
|
26
|
+
function probeWindowsTask() {
|
|
27
|
+
const result = runSchtasks(['/Query', '/TN', WINDOWS_AUTOSTART_TASK_NAME]);
|
|
28
|
+
if (result.status === 0)
|
|
29
|
+
return { state: 'installed' };
|
|
30
|
+
const message = decodeWindowsOutput(result.stderr) || decodeWindowsOutput(result.stdout);
|
|
31
|
+
if (isTaskNotFoundMessage(message))
|
|
32
|
+
return { state: 'not-found' };
|
|
33
|
+
return { state: 'error', error: commandError(result, '查询 Windows 登录自启任务失败') };
|
|
18
34
|
}
|
|
19
35
|
function powershellLiteral(value) {
|
|
20
36
|
return `'${value.replace(/'/g, "''")}'`;
|
|
@@ -28,8 +44,7 @@ function wrapperPath(runtimeRoot) {
|
|
|
28
44
|
export function windowsAutostartInstalled() {
|
|
29
45
|
if (!isWindows())
|
|
30
46
|
return false;
|
|
31
|
-
|
|
32
|
-
return result.status === 0;
|
|
47
|
+
return probeWindowsTask().state === 'installed';
|
|
33
48
|
}
|
|
34
49
|
function createWrapper(runtimeRoot) {
|
|
35
50
|
const scriptPath = wrapperPath(runtimeRoot);
|
|
@@ -73,10 +88,18 @@ export function configureWindowsAutostart(enabled, runtimeRoot) {
|
|
|
73
88
|
const scriptPath = wrapperPath(absoluteRoot);
|
|
74
89
|
if (!enabled) {
|
|
75
90
|
const result = runSchtasks(['/Delete', '/TN', WINDOWS_AUTOSTART_TASK_NAME, '/F']);
|
|
76
|
-
if (result.status !== 0
|
|
91
|
+
if (result.status !== 0) {
|
|
92
|
+
const probe = probeWindowsTask();
|
|
93
|
+
if (probe.state === 'not-found') {
|
|
94
|
+
try {
|
|
95
|
+
fs.rmSync(scriptPath, { force: true });
|
|
96
|
+
}
|
|
97
|
+
catch { }
|
|
98
|
+
return { ok: true, enabled: false };
|
|
99
|
+
}
|
|
77
100
|
return {
|
|
78
101
|
ok: false,
|
|
79
|
-
enabled:
|
|
102
|
+
enabled: probe.state === 'installed',
|
|
80
103
|
error: commandError(result, '删除 Windows 开机自启任务失败'),
|
|
81
104
|
};
|
|
82
105
|
}
|
|
@@ -91,7 +114,11 @@ export function configureWindowsAutostart(enabled, runtimeRoot) {
|
|
|
91
114
|
try {
|
|
92
115
|
if (fs.existsSync(scriptPath))
|
|
93
116
|
previousWrapper = fs.readFileSync(scriptPath, 'utf8');
|
|
94
|
-
|
|
117
|
+
const previousTask = probeWindowsTask();
|
|
118
|
+
if (previousTask.state === 'error') {
|
|
119
|
+
return { ok: false, enabled: false, error: previousTask.error };
|
|
120
|
+
}
|
|
121
|
+
previouslyInstalled = previousTask.state === 'installed';
|
|
95
122
|
const taskScript = createWrapper(absoluteRoot);
|
|
96
123
|
const systemRoot = process.env.SystemRoot || 'C:\\Windows';
|
|
97
124
|
const powershell = path.join(systemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
@@ -108,14 +135,28 @@ export function configureWindowsAutostart(enabled, runtimeRoot) {
|
|
|
108
135
|
const result = runSchtasks(args);
|
|
109
136
|
if (result.status !== 0) {
|
|
110
137
|
const restoreError = restoreWrapper(scriptPath, previousWrapper);
|
|
111
|
-
const
|
|
138
|
+
const probe = probeWindowsTask();
|
|
112
139
|
const rollbackSuffix = restoreError ? `; 恢复原启动脚本失败: ${restoreError}` : '';
|
|
113
140
|
return {
|
|
114
141
|
ok: false,
|
|
115
|
-
enabled:
|
|
142
|
+
enabled: probe.state === 'installed',
|
|
116
143
|
error: `${commandError(result, '创建 Windows 开机自启任务失败')}${rollbackSuffix}`,
|
|
117
144
|
};
|
|
118
145
|
}
|
|
146
|
+
const probe = probeWindowsTask();
|
|
147
|
+
if (probe.state !== 'installed') {
|
|
148
|
+
const cleanup = runSchtasks(['/Delete', '/TN', WINDOWS_AUTOSTART_TASK_NAME, '/F']);
|
|
149
|
+
const afterCleanup = cleanup.status === 0 ? probeWindowsTask() : probe;
|
|
150
|
+
const restoreError = restoreWrapper(scriptPath, previousWrapper);
|
|
151
|
+
const details = probe.state === 'error' ? probe.error : '创建后无法查询到任务';
|
|
152
|
+
const cleanupError = cleanup.status === 0 ? '' : `; 清理任务失败: ${commandError(cleanup, '未知错误')}`;
|
|
153
|
+
const rollbackSuffix = restoreError ? `; 恢复原启动脚本失败: ${restoreError}` : '';
|
|
154
|
+
return {
|
|
155
|
+
ok: false,
|
|
156
|
+
enabled: afterCleanup.state === 'installed',
|
|
157
|
+
error: `${details}${cleanupError}${rollbackSuffix}`,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
119
160
|
return { ok: true, enabled: true };
|
|
120
161
|
}
|
|
121
162
|
catch (error) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { TextDecoder } from 'util';
|
|
2
|
+
/** Decode output from Windows native commands regardless of the active code page. */
|
|
3
|
+
export function decodeWindowsOutput(value) {
|
|
4
|
+
if (!value)
|
|
5
|
+
return '';
|
|
6
|
+
const bytes = Buffer.isBuffer(value) ? value : Buffer.from(value);
|
|
7
|
+
if (bytes.length === 0)
|
|
8
|
+
return '';
|
|
9
|
+
if (bytes.length >= 2 && bytes[0] === 0xff && bytes[1] === 0xfe) {
|
|
10
|
+
return bytes.subarray(2).toString('utf16le').replace(/^\uFEFF/, '');
|
|
11
|
+
}
|
|
12
|
+
if (bytes.length >= 2 && bytes[0] === 0xfe && bytes[1] === 0xff) {
|
|
13
|
+
const swapped = Buffer.allocUnsafe(bytes.length - 2);
|
|
14
|
+
for (let i = 2; i + 1 < bytes.length; i += 2) {
|
|
15
|
+
swapped[i - 2] = bytes[i + 1];
|
|
16
|
+
swapped[i - 1] = bytes[i];
|
|
17
|
+
}
|
|
18
|
+
return swapped.toString('utf16le').replace(/^\uFEFF/, '');
|
|
19
|
+
}
|
|
20
|
+
// Windows PowerShell 5.1 can emit UTF-16 without a BOM when stdout is
|
|
21
|
+
// redirected. NUL bytes are not expected in command text, so use them as
|
|
22
|
+
// the signal for this representation before trying code-page decoding.
|
|
23
|
+
const utf8Loose = bytes.toString('utf8');
|
|
24
|
+
if (utf8Loose.includes('\u0000')) {
|
|
25
|
+
const utf16 = bytes.toString('utf16le').replace(/^\uFEFF/, '');
|
|
26
|
+
if (!utf16.includes('\u0000'))
|
|
27
|
+
return utf16;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
return new TextDecoder('utf-8', { fatal: true }).decode(bytes).replace(/^\uFEFF/, '');
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// schtasks.exe uses the active Windows/OEM code page for redirected output.
|
|
34
|
+
return new TextDecoder('gb18030').decode(bytes).replace(/^\uFEFF/, '');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -176,6 +176,7 @@ ec config unset groupRules.mode \
|
|
|
176
176
|
`role` 由角色分配服务维护;`permissionMode` 仅在角色策略中维护
|
|
177
177
|
- **兼容字段**:`enable_rich_content` 仍可读取旧值,但已废弃且不再产生运行时效果
|
|
178
178
|
- **群规则策略**:`groupRules.mode` 仅 Agent owner 或 daemon owner 可 set/unset;其他角色可读取当前 relation 的有效值
|
|
179
|
+
- **源码诊断白名单**:`readonlySourceDiagnostics` 默认关闭;开启后只读会话仅可在项目源码目录执行受限、可证明只读查询,配置/证书/快照/session/锁文件仍禁止访问
|
|
179
180
|
- **仅人可写**:channels / owners / admins / 凭证 / aid / enabled / projects / aun / models.allowed
|
|
180
181
|
- Agent 托管环境写仅人字段被拒
|
|
181
182
|
|
|
@@ -195,6 +195,12 @@
|
|
|
195
195
|
"x-merge": "dict",
|
|
196
196
|
"description": "Agent 能力开关及能力参数"
|
|
197
197
|
},
|
|
198
|
+
"readonlySourceDiagnostics": {
|
|
199
|
+
"type": "boolean",
|
|
200
|
+
"x-merge": "scalar",
|
|
201
|
+
"default": false,
|
|
202
|
+
"description": "允许只读会话在显式源码目录内执行受限、可证明只读的诊断查询"
|
|
203
|
+
},
|
|
198
204
|
"observable": {
|
|
199
205
|
"type": "boolean",
|
|
200
206
|
"default": false,
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"enabled": { "type": "boolean", "default": true, "description": "是否启用空闲监控" },
|
|
68
68
|
"timeout": { "type": "number", "default": 120, "description": "空闲超时秒数" },
|
|
69
69
|
"retryAttemptTimeout": { "type": "number", "description": "API 重试尝试连续无事件时的超时秒数;未设置时继承 timeout" },
|
|
70
|
-
"maxExecutionTime": { "type": "number", "
|
|
70
|
+
"maxExecutionTime": { "type": "number", "description": "单个任务总执行时限(秒);未配置、非数字或小于等于 0 表示不限制" }
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"ecweb": {
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"enabled": { "type": "boolean", "default": true, "description": "是否启用空闲监控" },
|
|
78
78
|
"timeout": { "type": "number", "default": 120, "description": "空闲超时秒数" },
|
|
79
79
|
"retryAttemptTimeout": { "type": "number", "description": "API 重试尝试连续无事件时的超时秒数;未设置时继承 timeout" },
|
|
80
|
-
"maxExecutionTime": { "type": "number", "
|
|
80
|
+
"maxExecutionTime": { "type": "number", "description": "单个任务总执行时限(秒);未配置、非数字或小于等于 0 表示不限制" }
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"ecweb": {
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"enabled": { "type": "boolean", "default": true, "description": "是否启用空闲监控" },
|
|
100
100
|
"timeout": { "type": "number", "default": 120, "description": "空闲超时秒数" },
|
|
101
101
|
"retryAttemptTimeout": { "type": "number", "description": "API 重试尝试连续无事件时的超时秒数;未设置时继承 timeout" },
|
|
102
|
-
"maxExecutionTime": { "type": "number", "
|
|
102
|
+
"maxExecutionTime": { "type": "number", "description": "单个任务总执行时限(秒);未配置、非数字或小于等于 0 表示不限制" }
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
105
|
"ecweb": {
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"enabled": { "type": "boolean", "default": true, "description": "是否启用空闲监控" },
|
|
113
113
|
"timeout": { "type": "number", "default": 120, "description": "空闲超时秒数" },
|
|
114
114
|
"retryAttemptTimeout": { "type": "number", "description": "API 重试尝试连续无事件时的超时秒数;未设置时继承 timeout" },
|
|
115
|
-
"maxExecutionTime": { "type": "number", "
|
|
115
|
+
"maxExecutionTime": { "type": "number", "description": "单个任务总执行时限(秒);未配置、非数字或小于等于 0 表示不限制" }
|
|
116
116
|
}
|
|
117
117
|
},
|
|
118
118
|
"ecweb": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evolcore",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "AI Agent gateway connecting Claude, Codex, Gemini, and the bundled ecagent runner to messaging channels with multi-project session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|