evolcore 0.0.22 → 0.0.24
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 +74 -14
- package/README.md +4 -0
- package/bin/codex-managed-acl.ps1 +160 -0
- package/bin/codex-managed-hook.mjs +127 -10
- package/bin/ec-safe-output.js +85 -3
- package/bin/install-codex-managed-hooks.mjs +384 -95
- package/dist/agents/baseagent-availability.js +48 -0
- package/dist/agents/baseagent.js +30 -2
- package/dist/agents/claude-runner.js +179 -240
- package/dist/agents/{codex-app-server-client.js → codex/app-server-client.js} +90 -20
- package/dist/{utils/codex-app-server-registry.js → agents/codex/app-server-registry.js} +2 -2
- package/dist/agents/codex/catalog.js +70 -0
- package/dist/agents/codex/diagnostics.js +369 -0
- package/dist/agents/codex-runner.js +839 -192
- package/dist/agents/ecagent-runner.js +27 -34
- package/dist/agents/gemini-runner.js +62 -8
- package/dist/agents/runner-types.js +1 -1
- package/dist/aun/aid/managed-operation.js +28 -6
- package/dist/aun/aid/store.js +43 -0
- package/dist/aun/menu-client.js +272 -0
- package/dist/aun/msg/group.js +65 -4
- package/dist/aun/msg/index.js +1 -1
- package/dist/aun/msg/managed-operation.js +57 -5
- package/dist/aun/outbox.js +56 -18
- package/dist/aun/rpc/client.js +7 -1
- package/dist/channels/aun.js +178 -77
- package/dist/channels/daemon.js +7 -1
- package/dist/channels/dingtalk.js +1 -0
- package/dist/channels/feishu.js +10 -4
- package/dist/channels/wechat.js +81 -10
- package/dist/channels/wecom.js +2 -1
- package/dist/cli/agent-command.js +29 -3
- package/dist/cli/agent-create.js +538 -0
- package/dist/cli/agent.js +26 -675
- package/dist/cli/aun-commands.js +108 -24
- package/dist/cli/command-log.js +21 -2
- package/dist/cli/ctl-command.js +2 -0
- package/dist/cli/daemon-commands.js +289 -61
- package/dist/cli/index.js +22 -2
- package/dist/cli/init.js +2 -10
- package/dist/cli/managed-command-guard.js +3 -0
- package/dist/cli/menu-client.js +95 -0
- package/dist/cli/model.js +23 -8
- package/dist/cli/restart-monitor.js +432 -8
- package/dist/cli/stats.js +110 -0
- package/dist/cli/task-context.js +12 -2
- package/dist/cli/trigger-command.js +9 -1
- package/dist/config/builtin-roles.js +2 -0
- package/dist/config/schema-migration.js +14 -2
- package/dist/core/auth/agent-delegation.js +10 -7
- package/dist/core/auth/auth-gateway.js +3 -2
- package/dist/core/auth/authorization-audit.js +75 -18
- package/dist/core/auth/operation-authorizer.js +63 -3
- package/dist/core/auth/operation-catalog.js +14 -2
- package/dist/core/auth/remote-access-store.js +136 -0
- package/dist/core/baseagent-loader.js +4 -4
- package/dist/core/bootstrap-messages.js +39 -18
- package/dist/core/bootstrap-service.js +32 -26
- package/dist/core/capability/capability-manager.js +8 -4
- package/dist/core/capability/providers/codex-capability-provider.js +1 -1
- package/dist/core/command/agent-control.js +7 -2
- package/dist/core/command/command-handler.js +128 -30
- package/dist/core/command/daemon-diagnostics.js +448 -0
- package/dist/core/command/menu-catalog.js +6 -1
- package/dist/core/command/menu-handler.js +410 -98
- package/dist/core/command/menu-protocol.js +123 -0
- package/dist/core/command/slash-gate.js +4 -6
- package/dist/core/command/slash-handler.js +199 -70
- package/dist/core/data-migration.js +5 -15
- package/dist/core/event-catalog.js +3 -0
- package/dist/core/handoff/runtime.js +3 -1
- package/dist/core/handoff/store.js +7 -1
- package/dist/core/message/im-renderer.js +13 -6
- package/dist/core/message/message-bridge.js +5 -36
- package/dist/core/message/message-queue.js +20 -15
- package/dist/core/message/message-utils.js +6 -3
- package/dist/core/message/response-engine.js +147 -94
- package/dist/core/model/catalog-service.js +310 -0
- package/dist/core/model/model-catalog.js +134 -334
- package/dist/core/model/model-diagnostics.js +4 -5
- package/dist/core/model/model-fallback.js +9 -16
- package/dist/core/model/model-permission.js +5 -2
- package/dist/core/permission/approval-gateway.js +183 -32
- package/dist/core/permission/protected-paths.js +63 -4
- package/dist/core/permission/sandbox-runtime.js +4 -2
- package/dist/core/permission/tool-policy.js +257 -31
- package/dist/core/runtime-lock.js +13 -8
- package/dist/core/session/adapters/codex-session-file-adapter.js +71 -3
- package/dist/core/session/session-manager.js +49 -13
- package/dist/core/session/session-renew.js +1 -0
- package/dist/index.js +214 -57
- package/dist/ipc.js +191 -102
- package/dist/paths.js +23 -1
- package/dist/stats/billing.js +18 -4
- package/dist/trigger/manager.js +3 -1
- package/dist/trigger/parser.js +77 -13
- package/dist/trigger/patch.js +104 -1
- package/dist/utils/atomic-write.js +26 -2
- package/dist/utils/cross-platform.js +436 -1
- package/dist/utils/ecweb-supervisor.js +11 -2
- package/dist/utils/ecweb-utils.js +8 -26
- package/dist/utils/error-utils.js +16 -2
- package/dist/utils/model-prices.jsonl +23 -20
- package/dist/utils/npm-ops.js +70 -15
- package/dist/utils/windows-autostart.js +1 -1
- package/kits/docs/evolcore/INDEX.md +1 -0
- package/kits/docs/evolcore/agent-create.md +13 -0
- package/kits/docs/evolcore/group-collaboration.md +7 -2
- package/kits/docs/evolcore/menu-client.md +34 -0
- package/kits/migrations/migrate-contact-book-v2.mjs +9 -1
- package/kits/migrations/migrate-role-config-v4.mjs +11 -5
- package/kits/migrations/migrate-role-config-v5.mjs +8 -2
- package/kits/templates/roles/admin.json +2 -0
- package/kits/templates/roles/visitor.json +1 -0
- package/kits/templates/system-fragments/bootstrap.md +8 -1
- package/package.json +16 -4
- package/dist/utils/codex-cli.js +0 -43
package/dist/channels/wechat.js
CHANGED
|
@@ -40,6 +40,8 @@ const BACKOFF_DELAY_MS = 30_000;
|
|
|
40
40
|
const RETRY_DELAY_MS = 2_000;
|
|
41
41
|
const TYPING_TICKET_TTL_MS = 5 * 60 * 1000; // 5 min cache
|
|
42
42
|
const SESSION_EXPIRED_ERRCODE = -14;
|
|
43
|
+
const INVALID_SYNC_CURSOR_ERRCODE = -1;
|
|
44
|
+
const MAX_SYNC_CURSOR_BYTES = 64 * 1024;
|
|
43
45
|
export class WechatApiError extends Error {
|
|
44
46
|
endpoint;
|
|
45
47
|
ret;
|
|
@@ -71,6 +73,26 @@ export class WechatContextTokenRefreshRequiredError extends Error {
|
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* iLink cursors are opaque text, so validation deliberately stays conservative:
|
|
78
|
+
* reject values that cannot be safely round-tripped through the UTF-8 state file
|
|
79
|
+
* without imposing a specific encoding on future protocol versions.
|
|
80
|
+
*/
|
|
81
|
+
export function validateWechatSyncCursor(cursor) {
|
|
82
|
+
if (typeof cursor !== 'string') {
|
|
83
|
+
return { valid: false, reason: 'invalid_type' };
|
|
84
|
+
}
|
|
85
|
+
if (Buffer.byteLength(cursor, 'utf8') > MAX_SYNC_CURSOR_BYTES) {
|
|
86
|
+
return { valid: false, reason: 'too_large' };
|
|
87
|
+
}
|
|
88
|
+
if (cursor.includes('\uFFFD')) {
|
|
89
|
+
return { valid: false, reason: 'invalid_utf8' };
|
|
90
|
+
}
|
|
91
|
+
if (/[\s\u0000-\u001F\u007F-\u009F]/u.test(cursor)) {
|
|
92
|
+
return { valid: false, reason: 'invalid_character' };
|
|
93
|
+
}
|
|
94
|
+
return { valid: true };
|
|
95
|
+
}
|
|
74
96
|
/** Classify fetch/undici failures using the categories exposed by Tencent 2.4.6. */
|
|
75
97
|
export function classifyFetchError(err) {
|
|
76
98
|
if (err instanceof Error && err.name === 'AbortError') {
|
|
@@ -196,6 +218,7 @@ export class WechatChannel {
|
|
|
196
218
|
pendingContextMessages = new Map();
|
|
197
219
|
typingTicketCache = new Map();
|
|
198
220
|
getUpdatesBuf = '';
|
|
221
|
+
lastRejectedSyncCursor;
|
|
199
222
|
syncBufPath;
|
|
200
223
|
contextTokensPath;
|
|
201
224
|
onSessionExpired;
|
|
@@ -243,14 +266,24 @@ export class WechatChannel {
|
|
|
243
266
|
throw new Error('WeChat reauthentication required; run: ec init wechat');
|
|
244
267
|
}
|
|
245
268
|
// 恢复游标
|
|
269
|
+
this.getUpdatesBuf = '';
|
|
270
|
+
this.lastRejectedSyncCursor = undefined;
|
|
246
271
|
try {
|
|
247
272
|
if (fs.existsSync(this.syncBufPath)) {
|
|
248
|
-
|
|
249
|
-
|
|
273
|
+
const restoredCursor = fs.readFileSync(this.syncBufPath, 'utf-8');
|
|
274
|
+
const validation = validateWechatSyncCursor(restoredCursor);
|
|
275
|
+
if (validation.valid) {
|
|
276
|
+
this.getUpdatesBuf = restoredCursor;
|
|
277
|
+
logger.info(`[WeChat] Restored sync cursor (${Buffer.byteLength(restoredCursor, 'utf8')} bytes)`);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
this.clearSyncCursor(`persisted cursor is invalid (${validation.reason})`, restoredCursor);
|
|
281
|
+
}
|
|
250
282
|
}
|
|
251
283
|
}
|
|
252
|
-
catch {
|
|
253
|
-
|
|
284
|
+
catch (err) {
|
|
285
|
+
logger.warn(`[WeChat] Failed to restore sync cursor; starting from an empty cursor: ${err instanceof Error ? err.message : String(err)}`);
|
|
286
|
+
this.getUpdatesBuf = '';
|
|
254
287
|
}
|
|
255
288
|
// 通知 ilink 后端:bot 上线
|
|
256
289
|
try {
|
|
@@ -431,13 +464,22 @@ export class WechatChannel {
|
|
|
431
464
|
}
|
|
432
465
|
consecutiveFailures = 0;
|
|
433
466
|
// 保存游标
|
|
434
|
-
if (resp.get_updates_buf) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
467
|
+
if (resp.get_updates_buf !== undefined) {
|
|
468
|
+
const validation = validateWechatSyncCursor(resp.get_updates_buf);
|
|
469
|
+
if (!validation.valid) {
|
|
470
|
+
this.clearSyncCursor(`server returned an invalid cursor (${validation.reason})`, typeof resp.get_updates_buf === 'string' ? resp.get_updates_buf : undefined);
|
|
438
471
|
}
|
|
439
|
-
|
|
440
|
-
|
|
472
|
+
else if (resp.get_updates_buf) {
|
|
473
|
+
if (resp.get_updates_buf !== this.lastRejectedSyncCursor) {
|
|
474
|
+
this.lastRejectedSyncCursor = undefined;
|
|
475
|
+
}
|
|
476
|
+
this.getUpdatesBuf = resp.get_updates_buf;
|
|
477
|
+
try {
|
|
478
|
+
fs.writeFileSync(this.syncBufPath, this.getUpdatesBuf, 'utf-8');
|
|
479
|
+
}
|
|
480
|
+
catch {
|
|
481
|
+
// best-effort
|
|
482
|
+
}
|
|
441
483
|
}
|
|
442
484
|
}
|
|
443
485
|
// 处理消息
|
|
@@ -450,6 +492,17 @@ export class WechatChannel {
|
|
|
450
492
|
return;
|
|
451
493
|
if (this.isSessionPaused())
|
|
452
494
|
return;
|
|
495
|
+
if (err instanceof WechatApiError &&
|
|
496
|
+
err.endpoint === 'ilink/bot/getupdates' &&
|
|
497
|
+
err.hasCode(INVALID_SYNC_CURSOR_ERRCODE) &&
|
|
498
|
+
this.getUpdatesBuf &&
|
|
499
|
+
this.getUpdatesBuf !== this.lastRejectedSyncCursor) {
|
|
500
|
+
const rejectedCursor = this.getUpdatesBuf;
|
|
501
|
+
this.clearSyncCursor('getUpdates returned ret=-1', rejectedCursor);
|
|
502
|
+
consecutiveFailures = 0;
|
|
503
|
+
logger.warn('[WeChat] Retrying getUpdates immediately with an empty sync cursor');
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
453
506
|
consecutiveFailures++;
|
|
454
507
|
if (err instanceof WechatApiError) {
|
|
455
508
|
logger.error(`[WeChat] getUpdates API error (${consecutiveFailures}/${MAX_CONSECUTIVE_FAILURES}): ${err.message}`);
|
|
@@ -470,6 +523,24 @@ export class WechatChannel {
|
|
|
470
523
|
}
|
|
471
524
|
}
|
|
472
525
|
}
|
|
526
|
+
clearSyncCursor(reason, rejectedCursor) {
|
|
527
|
+
if (rejectedCursor)
|
|
528
|
+
this.lastRejectedSyncCursor = rejectedCursor;
|
|
529
|
+
this.getUpdatesBuf = '';
|
|
530
|
+
try {
|
|
531
|
+
let persistedAction = 'no persisted cursor';
|
|
532
|
+
if (fs.existsSync(this.syncBufPath)) {
|
|
533
|
+
const quarantinePath = `${this.syncBufPath}.corrupt-${Date.now()}`;
|
|
534
|
+
fs.renameSync(this.syncBufPath, quarantinePath);
|
|
535
|
+
persistedAction = `quarantined as ${path.basename(quarantinePath)}`;
|
|
536
|
+
}
|
|
537
|
+
logger.warn(`[WeChat] Cleared sync cursor: ${reason} (${persistedAction})`);
|
|
538
|
+
}
|
|
539
|
+
catch (err) {
|
|
540
|
+
logger.warn(`[WeChat] Cleared in-memory sync cursor but failed to quarantine persisted cursor: ` +
|
|
541
|
+
`${err instanceof Error ? err.message : String(err)}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
473
544
|
// ── Inbound Message Handler ──────────────────────────────────────────
|
|
474
545
|
async handleInboundMessage(msg) {
|
|
475
546
|
if (msg.message_type !== MSG_TYPE_USER)
|
package/dist/channels/wecom.js
CHANGED
|
@@ -1461,7 +1461,8 @@ export class WecomChannelPlugin {
|
|
|
1461
1461
|
return;
|
|
1462
1462
|
case 'status.started':
|
|
1463
1463
|
case 'status.queued':
|
|
1464
|
-
case 'status.progress':
|
|
1464
|
+
case 'status.progress':
|
|
1465
|
+
case 'status.notice': return;
|
|
1465
1466
|
case 'status.requires_action':
|
|
1466
1467
|
await channel.sendMessage(channelId, '等待 owner 审批', envelope.replyContext);
|
|
1467
1468
|
return;
|
|
@@ -69,6 +69,7 @@ Options:
|
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
const { agentList, agentShow, agentCreateInteractive, agentCreateNonInteractive, agentReload, agentEnable, agentDisable, agentGet, agentSet, agentRename, agentDelete, agentReady, runManagedAgentOperation, } = await import('./agent.js');
|
|
72
|
+
const { parseAgentOwnerArgs, resolveAgentCreatePlan, validateAgentCreatePlan } = await import('./agent-create.js');
|
|
72
73
|
if (process.env.EVOLCORE_SESSION_ID && !wantsHelp(args) && !new Set(['get', 'set', 'ready']).has(sub)) {
|
|
73
74
|
if (sub === 'new' && !args.includes('--non-interactive')) {
|
|
74
75
|
const error = {
|
|
@@ -210,6 +211,8 @@ Options:
|
|
|
210
211
|
--baseagent <claude|codex|gemini|ecagent>
|
|
211
212
|
默认: defaults 配置,否则检测本机可用基座
|
|
212
213
|
--owner <aid> 默认: daemon.json 第一个 owner
|
|
214
|
+
--owners <json-array> 多个 Owner;与 --owner 互斥
|
|
215
|
+
--handoff <context> 当前任务的 Bootstrap 上下文
|
|
213
216
|
--name <display-name> 默认: package.json name,否则目录名
|
|
214
217
|
--description <text> 默认: package.json description,否则使用 EvolCore 默认描述
|
|
215
218
|
--dry-run 只预览最终参数,不注册 AID、不写文件
|
|
@@ -223,6 +226,15 @@ Options:
|
|
|
223
226
|
ec agent new mybot.agentid.pub --non-interactive --project ../project --baseagent claude`);
|
|
224
227
|
return;
|
|
225
228
|
}
|
|
229
|
+
if (args.includes('--handoff')) {
|
|
230
|
+
const result = { ok: false, code: 'MANAGED_ONLY', error: '--handoff requires a managed Agent task' };
|
|
231
|
+
if (formatJson)
|
|
232
|
+
console.log(JSON.stringify(result));
|
|
233
|
+
else
|
|
234
|
+
console.error(result.error);
|
|
235
|
+
process.exitCode = 1;
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
226
238
|
const name = args[1];
|
|
227
239
|
const nonInteractive = args.includes('--non-interactive');
|
|
228
240
|
if (nonInteractive) {
|
|
@@ -234,12 +246,25 @@ Options:
|
|
|
234
246
|
const idx = args.indexOf(flag);
|
|
235
247
|
return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : undefined;
|
|
236
248
|
};
|
|
237
|
-
|
|
249
|
+
let ownerOptions;
|
|
250
|
+
try {
|
|
251
|
+
ownerOptions = parseAgentOwnerArgs(args);
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
const result = { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
255
|
+
if (formatJson)
|
|
256
|
+
console.log(JSON.stringify(result));
|
|
257
|
+
else
|
|
258
|
+
console.error(`❌ ${result.error}`);
|
|
259
|
+
process.exitCode = 1;
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
238
262
|
const plan = resolveAgentCreatePlan({
|
|
239
263
|
aid: name,
|
|
240
264
|
project: getArg('--project'),
|
|
241
265
|
baseagent: getArg('--baseagent'),
|
|
242
|
-
|
|
266
|
+
...ownerOptions,
|
|
267
|
+
handoff: getArg('--handoff'),
|
|
243
268
|
name: getArg('--name'),
|
|
244
269
|
description: getArg('--description'),
|
|
245
270
|
force: args.includes('--force'),
|
|
@@ -263,7 +288,7 @@ Options:
|
|
|
263
288
|
console.log(` AID: ${plan.aid}`);
|
|
264
289
|
console.log(` Project: ${plan.project}`);
|
|
265
290
|
console.log(` Baseagent: ${plan.baseagent} (${plan.baseagentSource})`);
|
|
266
|
-
console.log(` Owner: ${plan.owner || '未设置'} (${plan.ownerSource})`);
|
|
291
|
+
console.log(` Owner: ${plan.owners?.join(', ') || plan.owner || '未设置'} (${plan.ownerSource})`);
|
|
267
292
|
console.log(` Name: ${plan.name} (${plan.nameSource})`);
|
|
268
293
|
if (plan.description)
|
|
269
294
|
console.log(` Description: ${plan.description} (${plan.descriptionSource})`);
|
|
@@ -276,6 +301,7 @@ Options:
|
|
|
276
301
|
baseagent: plan.baseagent,
|
|
277
302
|
project: plan.project,
|
|
278
303
|
owner: plan.owner,
|
|
304
|
+
owners: plan.owners,
|
|
279
305
|
name: plan.name,
|
|
280
306
|
description: plan.description,
|
|
281
307
|
force: args.includes('--force'),
|