evolcore 0.0.26 → 0.0.28
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 +36 -0
- package/bin/codex-managed-acl.ps1 +43 -0
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +10 -5
- package/dist/agents/claude-runner.js +123 -22
- package/dist/agents/codex/app-server-client.js +70 -26
- package/dist/agents/codex/catalog.js +7 -1
- package/dist/agents/codex-runner.js +363 -421
- package/dist/agents/ecagent-runner.js +170 -25
- package/dist/agents/gemini-runner.js +6 -0
- package/dist/agents/runner-types.js +50 -2
- package/dist/aun/aid/agentmd.js +73 -31
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +3 -3
- package/dist/aun/group/history.js +303 -0
- package/dist/aun/group/identity.js +43 -0
- package/dist/aun/group/index.js +5 -0
- package/dist/aun/{msg/group.js → group/operations.js} +161 -38
- package/dist/aun/{menu-client.js → menu/client.js} +13 -7
- package/dist/aun/menu/index.js +2 -0
- package/dist/aun/menu/transport.js +49 -0
- package/dist/aun/msg/index.js +2 -1
- package/dist/aun/msg/managed-operation.js +84 -18
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +13 -8
- package/dist/aun/msg/upload.js +43 -88
- package/dist/aun/outbox.js +29 -7
- package/dist/aun/rpc/client.js +1 -0
- package/dist/aun/storage/client.js +39 -50
- package/dist/channels/aun.js +544 -239
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +108 -6
- package/dist/cli/agent-create.js +515 -2
- package/dist/cli/agent.js +109 -8
- package/dist/cli/aun-commands.js +191 -42
- package/dist/cli/config.js +8 -5
- package/dist/cli/contact.js +2 -2
- package/dist/cli/ctl-command.js +2 -2
- package/dist/cli/daemon-commands.js +111 -162
- package/dist/cli/diag.js +3 -3
- package/dist/cli/fs-command.js +3 -3
- package/dist/cli/handoff-command.js +6 -6
- package/dist/cli/index.js +8 -2
- package/dist/cli/init.js +34 -1
- package/dist/cli/managed-command-guard.js +2 -1
- package/dist/cli/menu-client.js +13 -5
- package/dist/cli/model.js +3 -3
- package/dist/cli/queue-command.js +2 -2
- package/dist/cli/response.js +2 -2
- package/dist/cli/restart-monitor.js +81 -19
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +20 -10
- package/dist/config/builtin-roles.js +10 -0
- package/dist/config/config-field-policy.js +11 -0
- package/dist/config/config-manager.js +32 -4
- package/dist/config/config-operation-service.js +20 -5
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +1 -1
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +5 -0
- package/dist/core/audit/event-key.js +17 -2
- package/dist/core/audit/log-integrity.js +34 -8
- package/dist/core/auth/agent-delegation.js +48 -14
- package/dist/core/auth/auth-gateway.js +2 -0
- package/dist/core/auth/authorization-audit.js +34 -38
- package/dist/core/auth/operation-authorizer.js +67 -5
- package/dist/core/auth/operation-catalog.js +110 -0
- package/dist/core/auth/remote-access-store.js +115 -9
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +110 -19
- package/dist/core/command/agent-control.js +88 -7
- package/dist/core/command/agent-storage-menu.js +443 -0
- package/dist/core/command/cli-intent-parser.js +19 -0
- package/dist/core/command/command-handler.js +105 -40
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +292 -27
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +34 -4
- package/dist/core/command/menu-handler.js +364 -96
- package/dist/core/command/menu-protocol.js +43 -6
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-handler.js +61 -37
- package/dist/core/event-catalog.js +4 -0
- package/dist/core/evolagent-registry.js +28 -2
- package/dist/core/group/invite-service.js +924 -0
- package/dist/core/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +94 -16
- package/dist/core/message/message-bridge.js +140 -13
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +73 -41
- package/dist/core/message/response-engine.js +729 -118
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +76 -36
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +72 -3
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +8 -8
- package/dist/core/relation/peer-identity.js +57 -6
- package/dist/core/relation/shared-data.js +106 -0
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/runtime-lock.js +10 -26
- package/dist/core/session/runner-task-history.js +170 -0
- package/dist/core/session/session-manager.js +38 -6
- package/dist/core/session/session-mapper.js +41 -0
- package/dist/core/session/session-turn-coordinator.js +37 -7
- package/dist/core/session/session-turns.js +48 -7
- package/dist/core/task/task-recovery-service.js +176 -0
- package/dist/core/task/task-resume-operation.js +32 -0
- package/dist/eck/group-rules-sync.js +5 -3
- package/dist/eck/kit-renderer.js +1 -0
- package/dist/index.js +322 -207
- package/dist/ipc.js +141 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +3 -0
- package/dist/trigger/event-source.js +19 -0
- package/dist/trigger/feedback.js +233 -40
- package/dist/trigger/parser.js +55 -5
- package/dist/trigger/patch.js +9 -0
- package/dist/trigger/scheduler.js +30 -4
- package/dist/trigger/validation.js +20 -3
- package/dist/utils/atomic-write.js +98 -0
- package/dist/utils/cross-platform.js +87 -16
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-utils.js +40 -2
- package/dist/utils/logger.js +23 -13
- package/dist/utils/npm-ops.js +119 -4
- package/dist/utils/package-version-info.js +244 -0
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +174 -1
- package/dist/utils/windows-shell-trust.js +37 -0
- package/ecagent/dist/harness/agent-harness.js +3 -0
- package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/INDEX.md +0 -6
- package/kits/docs/channels/aun.md +23 -2
- package/kits/docs/channels/feishu.md +1 -1
- package/kits/docs/context-assembly.md +29 -17
- package/kits/docs/evolcore/INDEX.md +8 -3
- package/kits/docs/evolcore/agent-create.md +39 -7
- package/kits/docs/evolcore/agent.md +33 -1
- package/kits/docs/evolcore/aid.md +9 -1
- package/kits/docs/evolcore/config.md +40 -1
- package/kits/docs/evolcore/group-collaboration.md +1 -1
- package/kits/docs/evolcore/group.md +117 -2
- package/kits/docs/evolcore/menu-client.md +16 -0
- package/kits/docs/evolcore/msg.md +3 -0
- package/kits/docs/evolcore/storage.md +3 -0
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +51 -3
- package/kits/docs/venues/group.md +5 -0
- package/kits/eck_manifest.json +27 -0
- package/kits/rules/01-overview.md +11 -7
- package/kits/rules/04-relation.md +2 -1
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +6 -4
- package/kits/schemas/agent-config.schema.12.json +25 -1
- package/kits/schemas/daemon.schema.6.json +2 -2
- package/kits/schemas/defaults.schema.5.json +1 -1
- package/kits/schemas/relation-config.schema.1.json +1 -1
- package/kits/schemas/relation-config.schema.5.json +1 -1
- package/kits/schemas/role-config.schema.1.json +14 -0
- package/kits/templates/roles/member.json +5 -0
- package/kits/templates/roles/visitor.json +5 -0
- package/kits/templates/system-fragments/baseagent.md +1 -1
- package/kits/templates/system-fragments/bootstrap.md +26 -9
- package/kits/templates/system-fragments/channel.md +8 -44
- package/kits/templates/system-fragments/commands.md +10 -2
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/reply.md +56 -0
- package/package.json +7 -3
- package/dist/aun/group-identity.js +0 -9
- /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
- /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
package/dist/cli/model.js
CHANGED
|
@@ -20,7 +20,7 @@ import { ipcQuery } from '../ipc.js';
|
|
|
20
20
|
import { parsePeerKey } from '../core/relation/peer-identity.js';
|
|
21
21
|
import { resolvePeerRoleDetail } from '../config/peer-role-resolver.js';
|
|
22
22
|
import { getFieldPermission } from '../config/roles.js';
|
|
23
|
-
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
23
|
+
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
24
24
|
import { formatModelCheck, runModelCheck } from '../core/model/model-diagnostics.js';
|
|
25
25
|
import { validateRuntimeStringFieldOverride } from '../core/role/runtime-policy.js';
|
|
26
26
|
const ALL_EFFORTS = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'auto'];
|
|
@@ -61,7 +61,7 @@ async function runCtlCommand(cmd, formatJson, timeoutMs = 10_000) {
|
|
|
61
61
|
type: 'ctl',
|
|
62
62
|
cmd,
|
|
63
63
|
sessionId,
|
|
64
|
-
delegationToken:
|
|
64
|
+
delegationToken: readDelegationCredential(),
|
|
65
65
|
}, timeoutMs);
|
|
66
66
|
if (!result)
|
|
67
67
|
fail(formatJson, 'DAEMON_UNAVAILABLE', '无法连接 evolcore 服务');
|
|
@@ -80,7 +80,7 @@ async function runManagedConfigOperation(args, formatJson) {
|
|
|
80
80
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
81
81
|
if (!sessionId)
|
|
82
82
|
fail(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID 未设置');
|
|
83
|
-
const delegationToken =
|
|
83
|
+
const delegationToken = readDelegationCredential();
|
|
84
84
|
if (!delegationToken) {
|
|
85
85
|
fail(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} 未设置`);
|
|
86
86
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolvePaths } from '../paths.js';
|
|
2
2
|
import { ipcQuery } from '../ipc.js';
|
|
3
|
-
import {
|
|
3
|
+
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
4
4
|
import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
|
|
5
5
|
export async function cmdQueue(args) {
|
|
6
6
|
if (args.length === 0 || isHelpFlag(args[0]) || wantsHelp(args)) {
|
|
@@ -98,7 +98,7 @@ JSON 时间字段:
|
|
|
98
98
|
after,
|
|
99
99
|
before,
|
|
100
100
|
sessionId: managed,
|
|
101
|
-
delegationToken:
|
|
101
|
+
delegationToken: readDelegationCredential(),
|
|
102
102
|
} : {
|
|
103
103
|
type: 'queue-snapshot',
|
|
104
104
|
agent,
|
package/dist/cli/response.js
CHANGED
|
@@ -17,7 +17,7 @@ import { ResponseModeRegistry } from '../response-system/registry.js';
|
|
|
17
17
|
import { registerBuiltinModes } from '../response-system/modes/index.js';
|
|
18
18
|
import { ipcQuery } from '../ipc.js';
|
|
19
19
|
import { resolvePaths } from '../paths.js';
|
|
20
|
-
import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
|
|
20
|
+
import { AGENT_DELEGATION_TOKEN_ENV, readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
21
21
|
const RESPONSE_MODE_FIELD = 'responseMode';
|
|
22
22
|
const RESPONSE_MODE_PARAMS_FIELD = 'responseModeParams';
|
|
23
23
|
/**
|
|
@@ -59,7 +59,7 @@ function fail(formatJson, code, message) {
|
|
|
59
59
|
}
|
|
60
60
|
async function managedConfig(fieldArgs, formatJson) {
|
|
61
61
|
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
62
|
-
const delegationToken =
|
|
62
|
+
const delegationToken = readDelegationCredential();
|
|
63
63
|
if (!sessionId)
|
|
64
64
|
fail(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID is not set');
|
|
65
65
|
if (!delegationToken)
|
|
@@ -6,17 +6,27 @@ import { resolvePaths, getPackageRoot, daemonControlDir } from '../paths.js';
|
|
|
6
6
|
import { loadDaemonConfig } from '../config-store.js';
|
|
7
7
|
import * as platform from '../utils/cross-platform.js';
|
|
8
8
|
import { EventBus } from '../core/event-bus.js';
|
|
9
|
-
import {
|
|
9
|
+
import { applyCachedPackageUpgrades, recordPackageUpgrade } from '../utils/package-version-info.js';
|
|
10
10
|
import { isValidAid } from '../aun/aid/index.js';
|
|
11
11
|
import { msgSend } from '../aun/msg/index.js';
|
|
12
12
|
import { scanInstances, cleanupInstances, writeRestartMonitor, removeRestartMonitor, isRestartMonitorWinner, findOrphanProcesses, killOrphans } from '../utils/instance-registry.js';
|
|
13
|
-
import { WEB_PACKAGE_NAME } from '../product.js';
|
|
13
|
+
import { MAIN_PACKAGE_NAME, WEB_PACKAGE_NAME } from '../product.js';
|
|
14
14
|
import { shouldSuppressRealRestart } from '../utils/restart-safety.js';
|
|
15
15
|
import { rotateStdoutLog } from '../utils/log-writer.js';
|
|
16
16
|
import { inspectDataMigrationRequirement } from '../core/data-migration.js';
|
|
17
|
-
import { DAEMON_SHUTDOWN_TIMEOUT_MS, requestDaemonShutdown } from './daemon-commands.js';
|
|
17
|
+
import { DAEMON_SHUTDOWN_TIMEOUT_MS, requestDaemonShutdown, stopCodexAppServerOrphans } from './daemon-commands.js';
|
|
18
18
|
import { getProcessStartTime, startTimeMatches } from '../utils/process-introspect.js';
|
|
19
19
|
const execFileAsync = promisify(execFile);
|
|
20
|
+
// Bound network notifications so they cannot hold up recovery after shutdown.
|
|
21
|
+
const OWNER_NOTIFICATION_TIMEOUT_MS = 5000;
|
|
22
|
+
let foregroundDaemonExit;
|
|
23
|
+
async function finishSuccessfulRestart() {
|
|
24
|
+
if (foregroundDaemonExit) {
|
|
25
|
+
removeRestartMonitor();
|
|
26
|
+
process.exit(await foregroundDaemonExit);
|
|
27
|
+
}
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
20
30
|
/**
|
|
21
31
|
* The package this monitor operates on, which is not always the one it runs
|
|
22
32
|
* from.
|
|
@@ -142,13 +152,14 @@ export async function cmdRestartMonitor() {
|
|
|
142
152
|
// still alive. Refuse to create a second daemon when an unregistered process
|
|
143
153
|
// from this package is found; a duplicate would connect AUN and kick the
|
|
144
154
|
// existing session before failing on IPC/port ownership.
|
|
145
|
-
const
|
|
155
|
+
const belongsToRuntime = (o) => {
|
|
146
156
|
if (o.confirmedTestDaemon)
|
|
147
157
|
return false;
|
|
148
158
|
const homeMatches = o.evolcoreHome && normalizePath(o.evolcoreHome) === normalizePath(p.root);
|
|
149
159
|
const packageMatches = !o.evolcoreHome && normalizePath(o.cmdline).includes(normalizePath(targetPackageRoot()));
|
|
150
160
|
return Boolean(homeMatches || packageMatches);
|
|
151
|
-
}
|
|
161
|
+
};
|
|
162
|
+
const runtimeOrphans = orphanSnapshot.filter(belongsToRuntime);
|
|
152
163
|
if (runtimeOrphans.length > 0) {
|
|
153
164
|
const pids = runtimeOrphans.map(o => o.pid).join(', ');
|
|
154
165
|
log(`Stopping unregistered EvolCore process(es): ${pids}`);
|
|
@@ -236,15 +247,32 @@ export async function cmdRestartMonitor() {
|
|
|
236
247
|
// for instance-file cleanup.
|
|
237
248
|
cleanupInstances();
|
|
238
249
|
}
|
|
239
|
-
//
|
|
240
|
-
|
|
250
|
+
// Preserve CLI restart's final ownership guards and optional orphan cleanup
|
|
251
|
+
// here, after election/shutdown, so no launcher stops a daemon before a
|
|
252
|
+
// watchdog has successfully loaded.
|
|
253
|
+
const remaining = findOrphanProcesses();
|
|
254
|
+
if (scanInstances().mains.some(item => item.alive) || remaining.some(belongsToRuntime)) {
|
|
255
|
+
log('Restart aborted: a runtime process appeared or survived shutdown');
|
|
256
|
+
cleanupPendingFile(pendingFile, log);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
const otherHome = remaining.filter(o => !o.confirmedTestDaemon && !belongsToRuntime(o));
|
|
260
|
+
if (process.argv.includes('--clear') && otherHome.length) {
|
|
261
|
+
log(`Cleaned cross-HOME orphans: ${killOrphans(otherHome).join(', ')}`);
|
|
262
|
+
}
|
|
263
|
+
else if (otherHome.length) {
|
|
264
|
+
log(`Other HOME orphan processes left running: ${otherHome.map(o => o.pid).join(', ')}`);
|
|
265
|
+
}
|
|
266
|
+
const stoppedCodex = stopCodexAppServerOrphans();
|
|
267
|
+
if (stoppedCodex)
|
|
268
|
+
log(`Cleaned ${stoppedCodex} EvolCore codex app-server orphan(s)`);
|
|
269
|
+
// Apply only the preflight cache. There is no registry VERSION query after
|
|
270
|
+
// shutdown (npm still downloads the exact cached package when needed).
|
|
271
|
+
log('Applying cached version information...');
|
|
241
272
|
// 升级会原地替换整包,先留一个可回退的产物副本。备份放 EVOLCORE_HOME 而非包目录:
|
|
242
273
|
// Linux/macOS 的全局目录常常不可写,而 HOME 一定可写。
|
|
243
274
|
const upgradeBackup = await backupDistForUpgrade(p, log);
|
|
244
|
-
const [upgrade, ecwebUpgrade] = await
|
|
245
|
-
tryUpgrade(),
|
|
246
|
-
tryUpgradeGlobalPkg(() => resolveGlobalPkg(WEB_PACKAGE_NAME), WEB_PACKAGE_NAME),
|
|
247
|
-
]);
|
|
275
|
+
const [upgrade, ecwebUpgrade] = await applyCachedPackageUpgrades(undefined, { log });
|
|
248
276
|
let upgradeRolledBack;
|
|
249
277
|
switch (upgrade.status) {
|
|
250
278
|
case 'upgraded':
|
|
@@ -285,8 +313,7 @@ export async function cmdRestartMonitor() {
|
|
|
285
313
|
await notifyDaemonOwners(p, `⚠️ evolcore 升级失败,使用当前版本继续\n${upgrade.error ?? ''}`.trim(), log);
|
|
286
314
|
break;
|
|
287
315
|
}
|
|
288
|
-
// EC Web
|
|
289
|
-
// 查询并行执行,npm 安装阶段由 npm-ops 的全局锁串行化。
|
|
316
|
+
// EC Web independently applies a valid cached result under the install lock.
|
|
290
317
|
switch (ecwebUpgrade.status) {
|
|
291
318
|
case 'upgraded':
|
|
292
319
|
log(`✅ ${WEB_PACKAGE_NAME} upgraded: ${ecwebUpgrade.from} → ${ecwebUpgrade.to}`);
|
|
@@ -320,6 +347,13 @@ export async function cmdRestartMonitor() {
|
|
|
320
347
|
// 启动并检测 ready signal
|
|
321
348
|
let started = await spawnAndWaitReady(p, log, READY_TIMEOUT);
|
|
322
349
|
if (started) {
|
|
350
|
+
if (upgrade.status === 'upgraded' || upgrade.status === 'failed') {
|
|
351
|
+
await recordPackageUpgrade(MAIN_PACKAGE_NAME, {
|
|
352
|
+
from: upgrade.from, to: upgrade.to, at: new Date().toISOString(),
|
|
353
|
+
status: upgradeRolledBack ? 'rolled-back' : upgrade.status === 'upgraded' ? 'succeeded' : 'failed',
|
|
354
|
+
error: upgradeRolledBack ?? upgrade.error,
|
|
355
|
+
}, log);
|
|
356
|
+
}
|
|
323
357
|
if (upgradeRolledBack) {
|
|
324
358
|
markRestartOutcome(pendingFile, 'rolled-back', upgradeRolledBack, log);
|
|
325
359
|
log(`✓ Service restarted after upgrade rollback`);
|
|
@@ -339,15 +373,21 @@ export async function cmdRestartMonitor() {
|
|
|
339
373
|
}
|
|
340
374
|
archiveSelfHealLog(p, log);
|
|
341
375
|
// 发起会话内的“重启成功”通知由新进程自行发送,此处只负责失败/自愈告警。
|
|
342
|
-
|
|
376
|
+
await finishSuccessfulRestart();
|
|
343
377
|
}
|
|
344
378
|
// 升级后的新版本起不来:回退到升级前的产物再试一次。
|
|
345
379
|
if (upgradeVersions?.to && !upgradeRolledBack) {
|
|
380
|
+
await recordPackageUpgrade(MAIN_PACKAGE_NAME, {
|
|
381
|
+
...upgradeVersions, at: new Date().toISOString(), status: 'failed', error: 'Upgraded daemon failed its ready check',
|
|
382
|
+
}, log);
|
|
346
383
|
if (await restoreDistBackup(upgradeBackup, log)) {
|
|
347
384
|
await notifyDaemonOwners(p, `⚠️ 升级到 ${upgradeVersions.to} 后启动失败,正在回滚到 ${upgradeVersions.from} 重试...`, log);
|
|
348
385
|
started = await spawnAndWaitReady(p, log, READY_TIMEOUT);
|
|
349
386
|
if (started) {
|
|
350
387
|
const reason = `升级到 ${upgradeVersions.to} 后启动失败,已回滚到 ${upgradeVersions.from}`;
|
|
388
|
+
await recordPackageUpgrade(MAIN_PACKAGE_NAME, {
|
|
389
|
+
...upgradeVersions, at: new Date().toISOString(), status: 'rolled-back', error: reason,
|
|
390
|
+
}, log);
|
|
351
391
|
log(`✓ ${reason}`);
|
|
352
392
|
markRestartOutcome(pendingFile, 'rolled-back', reason, log);
|
|
353
393
|
await notifyDaemonOwners(p, `⚠️ ${reason}。当前运行旧版本,请检查后重试。`, log);
|
|
@@ -480,6 +520,18 @@ async function sendHealSummary(p, attempts, log) {
|
|
|
480
520
|
function sleep(ms) {
|
|
481
521
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
482
522
|
}
|
|
523
|
+
function withTimeout(promise, timeoutMs) {
|
|
524
|
+
let timer;
|
|
525
|
+
const timeout = new Promise((_, reject) => {
|
|
526
|
+
timer = setTimeout(() => reject(new Error(`timeout after ${timeoutMs}ms`)), timeoutMs);
|
|
527
|
+
// Keep the monitor alive until recovery can resume, even if the SDK's
|
|
528
|
+
// pending operation has no referenced handles of its own.
|
|
529
|
+
});
|
|
530
|
+
return Promise.race([promise, timeout]).finally(() => {
|
|
531
|
+
if (timer)
|
|
532
|
+
clearTimeout(timer);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
483
535
|
function normalizePath(value) {
|
|
484
536
|
return value.replace(/[\\/]+/g, '/').toLowerCase();
|
|
485
537
|
}
|
|
@@ -844,9 +896,10 @@ async function spawnAndWaitReady(p, log, timeout) {
|
|
|
844
896
|
const out = fs.openSync(stdoutLog, 'a');
|
|
845
897
|
const err = fs.openSync(stdoutLog, 'a');
|
|
846
898
|
const appMain = path.join(targetPackageRoot(), 'dist', 'index.js');
|
|
899
|
+
const foreground = process.argv.includes('--foreground');
|
|
847
900
|
const child = spawn(process.execPath, ['--no-warnings=ExperimentalWarning', appMain], {
|
|
848
|
-
detached:
|
|
849
|
-
stdio: ['ignore', out, err],
|
|
901
|
+
detached: !foreground,
|
|
902
|
+
stdio: foreground ? 'inherit' : ['ignore', out, err],
|
|
850
903
|
windowsHide: true,
|
|
851
904
|
env: {
|
|
852
905
|
...process.env,
|
|
@@ -858,7 +911,16 @@ async function spawnAndWaitReady(p, log, timeout) {
|
|
|
858
911
|
}
|
|
859
912
|
});
|
|
860
913
|
const childPid = child.pid;
|
|
861
|
-
|
|
914
|
+
if (foreground) {
|
|
915
|
+
foregroundDaemonExit = new Promise(resolve => {
|
|
916
|
+
child.once('error', () => resolve(1));
|
|
917
|
+
child.once('exit', code => resolve(code ?? 1));
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
else
|
|
921
|
+
child.unref();
|
|
922
|
+
fs.closeSync(out);
|
|
923
|
+
fs.closeSync(err);
|
|
862
924
|
log(`Spawned new process PID: ${childPid}, waiting for ready signal...`);
|
|
863
925
|
// 轮询等待 ready.signal 出现
|
|
864
926
|
const start = Date.now();
|
|
@@ -1009,12 +1071,12 @@ async function notifyDaemonOwners(p, message, log) {
|
|
|
1009
1071
|
const text = formatDaemonOwnerNotice(p, message);
|
|
1010
1072
|
for (const owner of validOwners) {
|
|
1011
1073
|
try {
|
|
1012
|
-
const result = await msgSend({
|
|
1074
|
+
const result = await withTimeout(msgSend({
|
|
1013
1075
|
from: daemonAid,
|
|
1014
1076
|
to: owner,
|
|
1015
1077
|
body: { mode: 'text', text },
|
|
1016
1078
|
slotId: 'restart-monitor',
|
|
1017
|
-
});
|
|
1079
|
+
}), OWNER_NOTIFICATION_TIMEOUT_MS);
|
|
1018
1080
|
if (!result.ok) {
|
|
1019
1081
|
log(`Daemon owner notification failed for ${owner}: ${result.error}`);
|
|
1020
1082
|
continue;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { resolvePaths } from '../paths.js';
|
|
2
|
+
import { ipcQuery } from '../ipc.js';
|
|
3
|
+
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
4
|
+
import { wantsHelp } from './help.js';
|
|
5
|
+
const TASK_HELP = `用法: ec task resume <sessionId> [--format json]
|
|
6
|
+
|
|
7
|
+
恢复指定 EvolCore 会话的暂停任务或异常中断任务。
|
|
8
|
+
暂停时释放工具门控;异常中断时继续原 baseagent 会话。
|
|
9
|
+
已完成、正在执行或等待必要输入/审批的任务不会重复启动。
|
|
10
|
+
|
|
11
|
+
独立 CLI 使用本地 control token;托管任务使用当前会话的 delegation,
|
|
12
|
+
需有 Agent 管理权限,普通托管任务只能恢复本 Agent 的会话。`;
|
|
13
|
+
export async function cmdTask(args) {
|
|
14
|
+
if (!args.length || wantsHelp(args)) {
|
|
15
|
+
console.log(TASK_HELP);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const json = args.includes('--format') && args[args.indexOf('--format') + 1] === 'json';
|
|
19
|
+
const printError = (code, error) => {
|
|
20
|
+
if (json)
|
|
21
|
+
console.log(JSON.stringify({ ok: false, code, error }));
|
|
22
|
+
else
|
|
23
|
+
console.error(error);
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
};
|
|
26
|
+
const targetSessionId = args[1]?.trim();
|
|
27
|
+
if (args[0] !== 'resume' || !targetSessionId || targetSessionId.startsWith('-')
|
|
28
|
+
|| !(args.length === 2 || (args.length === 4 && args[2] === '--format' && args[3] === 'json'))) {
|
|
29
|
+
printError('INVALID_ARGUMENT', TASK_HELP);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const sessionId = process.env.EVOLCORE_SESSION_ID;
|
|
33
|
+
const delegationToken = readDelegationCredential();
|
|
34
|
+
if (sessionId !== undefined && !sessionId.trim()) {
|
|
35
|
+
printError('INVALID_DELEGATION', 'EVOLCORE_SESSION_ID 不能为空');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (sessionId && !delegationToken) {
|
|
39
|
+
printError('DELEGATION_REQUIRED', '托管任务缺少 delegation token');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const result = await ipcQuery(resolvePaths().socket, {
|
|
43
|
+
type: 'task.resume',
|
|
44
|
+
targetSessionId,
|
|
45
|
+
...(sessionId ? { sessionId, delegationToken } : {}),
|
|
46
|
+
}, 10_000);
|
|
47
|
+
if (!result) {
|
|
48
|
+
printError('IPC_UNAVAILABLE', '无法连接 EvolCore 服务;请查询任务状态后再决定是否重试');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (json)
|
|
52
|
+
console.log(JSON.stringify(result));
|
|
53
|
+
else if ('message' in result)
|
|
54
|
+
console.log(result.message);
|
|
55
|
+
else
|
|
56
|
+
console.error(result.error);
|
|
57
|
+
if (!result.ok)
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
}
|
package/dist/cli/task-context.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { normalizeCausation } from '../core/causation/context.js';
|
|
2
2
|
import { RUNTIME_LOCK_DIR_ENV } from '../core/runtime-lock.js';
|
|
3
3
|
import crypto from 'node:crypto';
|
|
4
|
+
import { execFileSync } from 'node:child_process';
|
|
4
5
|
import fs from 'node:fs';
|
|
5
6
|
import os from 'node:os';
|
|
6
7
|
import path from 'node:path';
|
|
8
|
+
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
9
|
+
import { resolveRoot } from '../paths.js';
|
|
7
10
|
export const TASK_RUNTIME_CONTEXT_ENV = 'EVOLCORE_TASK_RUNTIME_CONTEXT';
|
|
8
11
|
export const SESSION_RUNTIME_DIR_ENV = 'EVOLCORE_SESSION_RUNTIME_DIR';
|
|
9
12
|
export const DAEMON_RUNTIME_EPOCH_ENV = 'EVOLCORE_DAEMON_RUNTIME_EPOCH';
|
|
10
13
|
export { RUNTIME_LOCK_DIR_ENV };
|
|
11
14
|
const generatedProcessManagedTempDirs = new Set();
|
|
15
|
+
const preparedWindowsSessionRuntimeDirs = new Set();
|
|
12
16
|
let processTempCleanupRegistered = false;
|
|
13
17
|
function isPlainObject(value) {
|
|
14
18
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
@@ -37,7 +41,9 @@ function normalizeTaskRuntimeContext(value) {
|
|
|
37
41
|
processRole: optionalProcessRole(value.processRole),
|
|
38
42
|
dataScope: optionalDataScope(value.dataScope),
|
|
39
43
|
authorizedBy: optionalString(value.authorizedBy),
|
|
40
|
-
executionSource: value.executionSource === 'fullaccess-command'
|
|
44
|
+
executionSource: value.executionSource === 'fullaccess-command'
|
|
45
|
+
|| value.executionSource === 'trigger'
|
|
46
|
+
|| value.executionSource === 'agent-policy'
|
|
41
47
|
? value.executionSource : undefined,
|
|
42
48
|
daemonRuntimeEpoch: optionalString(value.daemonRuntimeEpoch),
|
|
43
49
|
threadId: optionalString(value.threadId),
|
|
@@ -189,29 +195,81 @@ export function ensureProcessManagedTempDir() {
|
|
|
189
195
|
throw error;
|
|
190
196
|
}
|
|
191
197
|
}
|
|
192
|
-
function
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return
|
|
198
|
+
function canonicalHome() {
|
|
199
|
+
const configured = path.resolve(resolveRoot());
|
|
200
|
+
let canonical;
|
|
201
|
+
try {
|
|
202
|
+
canonical = fs.realpathSync.native(configured);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
canonical = configured;
|
|
206
|
+
}
|
|
207
|
+
return process.platform === 'win32' ? canonical.toLowerCase() : canonical;
|
|
208
|
+
}
|
|
209
|
+
function systemTempRoot() {
|
|
210
|
+
const testRoot = process.env.EVOLCORE_TEST === '1' && process.env.TMPDIR?.trim();
|
|
211
|
+
const candidate = testRoot && path.isAbsolute(testRoot)
|
|
212
|
+
? testRoot
|
|
213
|
+
: process.platform === 'win32'
|
|
214
|
+
? path.join(process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows', 'Temp')
|
|
215
|
+
: process.platform === 'linux'
|
|
216
|
+
? '/tmp'
|
|
217
|
+
: os.tmpdir();
|
|
218
|
+
try {
|
|
219
|
+
return fs.realpathSync.native(candidate);
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return path.resolve(candidate);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function sessionRuntimeName(sessionId) {
|
|
226
|
+
const digest = crypto.createHash('sha256')
|
|
227
|
+
.update(canonicalHome())
|
|
228
|
+
.update('\0')
|
|
229
|
+
.update(sessionId)
|
|
230
|
+
.digest('hex')
|
|
231
|
+
.slice(0, 24);
|
|
232
|
+
return `ec-session-${digest}`;
|
|
202
233
|
}
|
|
203
|
-
/**
|
|
204
|
-
*
|
|
234
|
+
/**
|
|
235
|
+
* Windows Codex sandbox accounts and ordinary runner accounts are members of
|
|
236
|
+
* BUILTIN\Users. Session isolation is enforced by the distinct path plus the
|
|
237
|
+
* runner filesystem policy, so the runtime directory only needs a portable
|
|
238
|
+
* writable ACL rather than host-user secrecy.
|
|
239
|
+
*/
|
|
240
|
+
function ensureWindowsSessionRuntimeAccess(directory) {
|
|
241
|
+
if (process.platform !== 'win32' || preparedWindowsSessionRuntimeDirs.has(directory))
|
|
242
|
+
return;
|
|
243
|
+
const icacls = path.join(process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows', 'System32', 'icacls.exe');
|
|
244
|
+
execFileSync(icacls, [
|
|
245
|
+
directory,
|
|
246
|
+
'/grant',
|
|
247
|
+
'*S-1-5-32-545:(OI)(CI)M',
|
|
248
|
+
'/Q',
|
|
249
|
+
], { windowsHide: true, stdio: 'pipe' });
|
|
250
|
+
preparedWindowsSessionRuntimeDirs.add(directory);
|
|
251
|
+
}
|
|
252
|
+
/** Whether a task-provided runtime directory is a stable EvolCore session root. */
|
|
205
253
|
export function isManagedSessionRuntimeDir(directory, managedRoot) {
|
|
206
|
-
|
|
207
|
-
if (!directory || !path.isAbsolute(directory) || !tmpDir || !path.isAbsolute(tmpDir))
|
|
254
|
+
if (!directory || !path.isAbsolute(directory))
|
|
208
255
|
return false;
|
|
209
|
-
const root = path.resolve(tmpDir);
|
|
210
256
|
const resolved = path.resolve(directory);
|
|
211
|
-
const
|
|
212
|
-
|
|
257
|
+
const suppliedRoot = managedRoot?.trim();
|
|
258
|
+
const candidateRoot = suppliedRoot && path.isAbsolute(suppliedRoot)
|
|
259
|
+
? path.resolve(suppliedRoot)
|
|
260
|
+
: systemTempRoot();
|
|
261
|
+
const root = candidateRoot === resolved ? path.dirname(resolved) : candidateRoot;
|
|
262
|
+
if (path.dirname(resolved) !== root || !/^ec-session-[a-f0-9]{24}$/.test(path.basename(resolved)))
|
|
263
|
+
return false;
|
|
264
|
+
try {
|
|
265
|
+
const rootStat = fs.lstatSync(root);
|
|
266
|
+
if (!rootStat.isDirectory() || rootStat.isSymbolicLink())
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
213
270
|
return false;
|
|
214
|
-
|
|
271
|
+
}
|
|
272
|
+
return isPrivateDirectory(resolved);
|
|
215
273
|
}
|
|
216
274
|
/**
|
|
217
275
|
* Resolve the session-owned temporary root for a managed child process.
|
|
@@ -241,58 +299,43 @@ export function getManagedTaskTempDir(runtimeEnv) {
|
|
|
241
299
|
&& (!processRoot || !path.isAbsolute(processRoot) || path.resolve(configured) !== path.resolve(processRoot))
|
|
242
300
|
&& contextDir
|
|
243
301
|
&& path.resolve(contextDir) === path.resolve(configured)
|
|
244
|
-
&&
|
|
302
|
+
&& isManagedSessionRuntimeDir(configured);
|
|
245
303
|
if (!trusted) {
|
|
246
304
|
throw new Error('managed session TMPDIR is unavailable or untrusted');
|
|
247
305
|
}
|
|
248
306
|
return path.resolve(configured);
|
|
249
307
|
}
|
|
250
308
|
/**
|
|
251
|
-
* Create
|
|
252
|
-
*
|
|
253
|
-
*
|
|
309
|
+
* Create the stable private runtime directory for one EvolCore session.
|
|
310
|
+
* Its identity is independent of daemon/runner lifetimes and rotates only
|
|
311
|
+
* when EvolCore creates a new session id.
|
|
254
312
|
*/
|
|
255
313
|
export function ensureSessionRuntimeDir(sessionId) {
|
|
256
314
|
if (!sessionId)
|
|
257
315
|
return undefined;
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
if (!base || !path.isAbsolute(base) || !isPrivateDirectory(path.resolve(base))) {
|
|
261
|
-
base = ensureProcessManagedTempDir();
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
catch {
|
|
265
|
-
return undefined;
|
|
266
|
-
}
|
|
267
|
-
if (!base || !path.isAbsolute(base))
|
|
268
|
-
return undefined;
|
|
269
|
-
const root = path.resolve(base);
|
|
270
|
-
const digest = crypto.createHash('sha256').update(sessionId).digest('hex').slice(0, 24);
|
|
271
|
-
const directory = path.join(root, `evolcore-runtime-${digest}`);
|
|
316
|
+
const root = systemTempRoot();
|
|
317
|
+
const directory = path.join(root, sessionRuntimeName(sessionId));
|
|
272
318
|
try {
|
|
273
319
|
fs.mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
274
|
-
if (!isPrivateDirectory(root))
|
|
275
|
-
return undefined;
|
|
276
320
|
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
321
|
+
ensureWindowsSessionRuntimeAccess(directory);
|
|
277
322
|
fs.mkdirSync(path.join(directory, 'locks'), { recursive: true, mode: 0o700 });
|
|
278
|
-
return isManagedSessionRuntimeDir(directory) ? directory : undefined;
|
|
323
|
+
return isManagedSessionRuntimeDir(directory, root) ? directory : undefined;
|
|
279
324
|
}
|
|
280
325
|
catch {
|
|
281
326
|
return undefined;
|
|
282
327
|
}
|
|
283
328
|
}
|
|
284
|
-
/**
|
|
285
|
-
* session's history/files area. The caller must still pass this path through
|
|
286
|
-
* the task environment before a sandboxed child can use it. */
|
|
329
|
+
/** Return the lock namespace inside the session-owned runtime directory. */
|
|
287
330
|
export function ensureRuntimeLockDir(sessionRuntimeDir) {
|
|
288
331
|
if (!sessionRuntimeDir || !path.isAbsolute(sessionRuntimeDir))
|
|
289
332
|
return undefined;
|
|
290
|
-
if (!isManagedSessionRuntimeDir(sessionRuntimeDir)
|
|
333
|
+
if (!isManagedSessionRuntimeDir(sessionRuntimeDir))
|
|
291
334
|
return undefined;
|
|
292
|
-
const parent = path.
|
|
335
|
+
const parent = path.resolve(sessionRuntimeDir);
|
|
293
336
|
if (!isPrivateDirectory(parent))
|
|
294
337
|
return undefined;
|
|
295
|
-
const directory = path.join(parent, '
|
|
338
|
+
const directory = path.join(parent, 'locks');
|
|
296
339
|
try {
|
|
297
340
|
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
298
341
|
return isPrivateDirectory(directory) ? directory : undefined;
|
|
@@ -325,7 +368,7 @@ export function parseTaskRuntimeContext(raw) {
|
|
|
325
368
|
export function readTaskRuntimeContextFromEnv(env = process.env) {
|
|
326
369
|
return parseTaskRuntimeContext(env[TASK_RUNTIME_CONTEXT_ENV]);
|
|
327
370
|
}
|
|
328
|
-
export async function readTaskRuntimeContextFromDaemon(sessionId, timeoutMs = 500) {
|
|
371
|
+
export async function readTaskRuntimeContextFromDaemon(sessionId, timeoutMs = 500, env = process.env) {
|
|
329
372
|
if (!sessionId)
|
|
330
373
|
return undefined;
|
|
331
374
|
try {
|
|
@@ -333,7 +376,12 @@ export async function readTaskRuntimeContextFromDaemon(sessionId, timeoutMs = 50
|
|
|
333
376
|
import('../paths.js'),
|
|
334
377
|
import('../ipc.js'),
|
|
335
378
|
]);
|
|
336
|
-
const response = await ipcQuery(resolvePaths().socket, {
|
|
379
|
+
const response = await ipcQuery(resolvePaths().socket, {
|
|
380
|
+
type: 'task-runtime-context',
|
|
381
|
+
sessionId,
|
|
382
|
+
delegationToken: readDelegationCredential(env),
|
|
383
|
+
daemonRuntimeEpoch: env[DAEMON_RUNTIME_EPOCH_ENV],
|
|
384
|
+
}, timeoutMs);
|
|
337
385
|
return response?.ok && response.context ? response.context : undefined;
|
|
338
386
|
}
|
|
339
387
|
catch {
|
|
@@ -343,7 +391,7 @@ export async function readTaskRuntimeContextFromDaemon(sessionId, timeoutMs = 50
|
|
|
343
391
|
export async function readBestTaskRuntimeContext(env = process.env) {
|
|
344
392
|
const envContext = readTaskRuntimeContextFromEnv(env);
|
|
345
393
|
const sessionId = env.EVOLCORE_SESSION_ID || envContext?.sessionId;
|
|
346
|
-
return (await readTaskRuntimeContextFromDaemon(sessionId)) ?? envContext;
|
|
394
|
+
return (await readTaskRuntimeContextFromDaemon(sessionId, 500, env)) ?? envContext;
|
|
347
395
|
}
|
|
348
396
|
export function buildTaskRuntimeEnv(ctx) {
|
|
349
397
|
const clean = normalizeTaskRuntimeContext(ctx);
|
|
@@ -3,7 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import { resolvePaths } from '../paths.js';
|
|
4
4
|
import { ipcQuery } from '../ipc.js';
|
|
5
5
|
import { isHelpFlag, wantsHelp } from './help.js';
|
|
6
|
-
import {
|
|
6
|
+
import { readDelegationCredential } from '../core/auth/agent-delegation.js';
|
|
7
7
|
import { readTaskRuntimeContextFromEnv } from './task-context.js';
|
|
8
8
|
import { normalizeTriggerDefinition, resolveScriptPath, } from '../trigger/validation.js';
|
|
9
9
|
export async function cmdTrigger(args) {
|
|
@@ -101,13 +101,15 @@ function printHelp() {
|
|
|
101
101
|
|
|
102
102
|
Create 参数模式支持:
|
|
103
103
|
--once | --delay <时长> | --at <ISO时间> | --cron <表达式> | --every <时长> | --event <事件模式>
|
|
104
|
+
--event-filter <JSON> (仅 --event;按事件 payload 字段匹配)
|
|
104
105
|
--exec <script|trigger-session|target-session> (必填)
|
|
105
106
|
--prompt <文本> | --prompt-file <路径>
|
|
106
107
|
Shell 双引号内的双引号、反引号和变量形式的美元符号都需在前面加反斜杠;trigger 保存的是还原后的原文
|
|
107
108
|
--script-path <路径> --script-runtime <node|python|bash>
|
|
108
109
|
--script-args <JSON> --script-timeout <时长>
|
|
109
|
-
--feedback <target> (
|
|
110
|
+
--feedback <target|event-session> (event-session 使用事件来源会话)
|
|
110
111
|
--baseagent <name> (仅 --exec trigger-session)
|
|
112
|
+
--execution-timeout <时长>(模型类 Trigger 单次执行总时限)
|
|
111
113
|
--model <模型> --effort <low|medium|high|xhigh|max>
|
|
112
114
|
--max-runs <次数> --max-duration <时长: 30s|15m|2h|1d>
|
|
113
115
|
--permission <readonly|auto|request|bypass|fullaccess>(省略则继承当前身份配置;fullaccess 仅 daemon-owner 且 feature flag 开启时可用)
|
|
@@ -125,10 +127,11 @@ Update 参数:
|
|
|
125
127
|
--once | --delay | --at | --cron | --every | --event [--tz]
|
|
126
128
|
--prompt <文本> | --prompt-file <路径> --script-file <路径> --name <名称>
|
|
127
129
|
--description <文本> (空字符串删除)
|
|
130
|
+
--execution-timeout <时长>(模型类 Trigger 单次执行总时限)
|
|
128
131
|
--model <模型> --effort <强度> --permission <权限模式|inherit>(inherit 清除覆盖)
|
|
129
132
|
--max-runs <次数> --max-duration <时长>
|
|
130
133
|
--concurrency <forbid|replace|allow> --missed-policy <skip|run-once|run-all>
|
|
131
|
-
--feedback <origin|target|silent>
|
|
134
|
+
--feedback <origin|target|event-session|silent>
|
|
132
135
|
--target-channel <channelKey> --target-channel-id <ID> (必须同时指定)
|
|
133
136
|
--target-chat-type <private|group> --target-session <main|thread> [--target-thread-id <threadId>]
|
|
134
137
|
--trigger-thread <by-run|by-trigger> --baseagent <name> (仅 trigger_session 之间)
|
|
@@ -189,6 +192,7 @@ async function showTrigger(args, json) {
|
|
|
189
192
|
if (t.execution.type === 'script')
|
|
190
193
|
console.log(`script: ${scriptCommandLabel(t.execution.script)}`);
|
|
191
194
|
console.log(`model: ${t.execution.model ?? 'inherit'}`);
|
|
195
|
+
console.log(`executionTimeoutMs: ${t.execution.timeoutMs ?? 'default'}`);
|
|
192
196
|
console.log(`effort: ${t.execution.effort ?? 'inherit'}`);
|
|
193
197
|
console.log(`permission: ${t.execution.permissionMode ?? 'inherit'}`);
|
|
194
198
|
console.log(`feedback: ${t.feedback.strategy}${t.feedback.target ? ` -> ${t.feedback.target.channelKey}/${t.feedback.target.channelId}/${t.feedback.target.session}` : ''}`);
|
|
@@ -266,13 +270,14 @@ async function createTrigger(args, json) {
|
|
|
266
270
|
}
|
|
267
271
|
const parsed = parseResult.value;
|
|
268
272
|
const agentAid = parsed.agentId ?? resolveAgentAid(args);
|
|
269
|
-
|
|
273
|
+
const eventSession = parsed.feedbackStrategy === 'event_session';
|
|
274
|
+
if (parsed.feedbackStrategy !== 'target' && !eventSession) {
|
|
270
275
|
throw new Error('CLI flag 模式仅支持 --feedback target;origin/silent 请使用 /trigger 或 --file 导入 Trigger V3 第二阶段 JSON');
|
|
271
276
|
}
|
|
272
|
-
if (!parsed.targetChannel || !parsed.targetChannelId) {
|
|
277
|
+
if (!eventSession && (!parsed.targetChannel || !parsed.targetChannelId)) {
|
|
273
278
|
throw new Error('CLI flag 模式需要显式指定 --target-channel <channelKey> --target-channel-id <id>');
|
|
274
279
|
}
|
|
275
|
-
const targetIsAun = parsed.targetChannel === 'aun' || parsed.targetChannel
|
|
280
|
+
const targetIsAun = parsed.targetChannel === 'aun' || parsed.targetChannel?.startsWith('aun#');
|
|
276
281
|
if (targetIsAun && !parsed.targetChatType) {
|
|
277
282
|
throw new Error('AUN 目标必须显式指定 --target-chat-type private 或 group');
|
|
278
283
|
}
|
|
@@ -299,6 +304,7 @@ async function createTrigger(args, json) {
|
|
|
299
304
|
type: parsed.executionType,
|
|
300
305
|
...(script ? { script } : { prompt: parsed.prompt }),
|
|
301
306
|
...(parsed.model ? { model: parsed.model } : {}),
|
|
307
|
+
...(parsed.executionTimeoutMs !== undefined ? { timeoutMs: parsed.executionTimeoutMs } : {}),
|
|
302
308
|
...(parsed.effort ? { effort: parsed.effort } : {}),
|
|
303
309
|
...(parsed.permissionMode ? { permissionMode: parsed.permissionMode } : {}),
|
|
304
310
|
...(parsed.executionType === 'trigger_session' ? {
|
|
@@ -308,7 +314,7 @@ async function createTrigger(args, json) {
|
|
|
308
314
|
onError: 'retry',
|
|
309
315
|
noopSentinel: '[[NOOP]]',
|
|
310
316
|
},
|
|
311
|
-
feedback: {
|
|
317
|
+
feedback: eventSession ? { strategy: 'event_session' } : {
|
|
312
318
|
strategy: 'target',
|
|
313
319
|
target: {
|
|
314
320
|
channelKey: parsed.targetChannel,
|
|
@@ -362,8 +368,12 @@ function sourceFromParsed(parsed) {
|
|
|
362
368
|
}
|
|
363
369
|
if (parsed.scheduleType === 'interval')
|
|
364
370
|
return { type: 'interval', everyMs: Number(parsed.scheduleValue) };
|
|
365
|
-
if (parsed.scheduleType === 'event')
|
|
366
|
-
|
|
371
|
+
if (parsed.scheduleType === 'event') {
|
|
372
|
+
const source = { type: 'event', eventPattern: parsed.scheduleValue };
|
|
373
|
+
if (parsed.eventFilter !== undefined)
|
|
374
|
+
source.filter = parsed.eventFilter;
|
|
375
|
+
return source;
|
|
376
|
+
}
|
|
367
377
|
throw new Error(`unsupported scheduleType: ${parsed.scheduleType}`);
|
|
368
378
|
}
|
|
369
379
|
function executionTypeFromFlag(args) {
|
|
@@ -565,7 +575,7 @@ function handleTemplate(args) {
|
|
|
565
575
|
}
|
|
566
576
|
async function request(cmd, timeoutMs = 10_000) {
|
|
567
577
|
const actorSessionId = process.env.EVOLCORE_SESSION_ID;
|
|
568
|
-
const delegationToken =
|
|
578
|
+
const delegationToken = readDelegationCredential();
|
|
569
579
|
let controlToken;
|
|
570
580
|
if (!actorSessionId) {
|
|
571
581
|
try {
|