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.
Files changed (177) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/bin/codex-managed-acl.ps1 +43 -0
  3. package/dist/agents/baseagent-availability.js +68 -0
  4. package/dist/agents/baseagent.js +10 -5
  5. package/dist/agents/claude-runner.js +123 -22
  6. package/dist/agents/codex/app-server-client.js +70 -26
  7. package/dist/agents/codex/catalog.js +7 -1
  8. package/dist/agents/codex-runner.js +363 -421
  9. package/dist/agents/ecagent-runner.js +170 -25
  10. package/dist/agents/gemini-runner.js +6 -0
  11. package/dist/agents/runner-types.js +50 -2
  12. package/dist/aun/aid/agentmd.js +73 -31
  13. package/dist/aun/aid/client.js +1 -1
  14. package/dist/aun/aid/control-aid.js +180 -1
  15. package/dist/aun/aid/identity.js +3 -3
  16. package/dist/aun/group/history.js +303 -0
  17. package/dist/aun/group/identity.js +43 -0
  18. package/dist/aun/group/index.js +5 -0
  19. package/dist/aun/{msg/group.js → group/operations.js} +161 -38
  20. package/dist/aun/{menu-client.js → menu/client.js} +13 -7
  21. package/dist/aun/menu/index.js +2 -0
  22. package/dist/aun/menu/transport.js +49 -0
  23. package/dist/aun/msg/index.js +2 -1
  24. package/dist/aun/msg/managed-operation.js +84 -18
  25. package/dist/aun/msg/mention-schema.js +51 -0
  26. package/dist/aun/msg/p2p.js +13 -8
  27. package/dist/aun/msg/upload.js +43 -88
  28. package/dist/aun/outbox.js +29 -7
  29. package/dist/aun/rpc/client.js +1 -0
  30. package/dist/aun/storage/client.js +39 -50
  31. package/dist/channels/aun.js +544 -239
  32. package/dist/channels/daemon.js +10 -6
  33. package/dist/cli/agent-command.js +108 -6
  34. package/dist/cli/agent-create.js +515 -2
  35. package/dist/cli/agent.js +109 -8
  36. package/dist/cli/aun-commands.js +191 -42
  37. package/dist/cli/config.js +8 -5
  38. package/dist/cli/contact.js +2 -2
  39. package/dist/cli/ctl-command.js +2 -2
  40. package/dist/cli/daemon-commands.js +111 -162
  41. package/dist/cli/diag.js +3 -3
  42. package/dist/cli/fs-command.js +3 -3
  43. package/dist/cli/handoff-command.js +6 -6
  44. package/dist/cli/index.js +8 -2
  45. package/dist/cli/init.js +34 -1
  46. package/dist/cli/managed-command-guard.js +2 -1
  47. package/dist/cli/menu-client.js +13 -5
  48. package/dist/cli/model.js +3 -3
  49. package/dist/cli/queue-command.js +2 -2
  50. package/dist/cli/response.js +2 -2
  51. package/dist/cli/restart-monitor.js +81 -19
  52. package/dist/cli/task-command.js +59 -0
  53. package/dist/cli/task-context.js +97 -49
  54. package/dist/cli/trigger-command.js +20 -10
  55. package/dist/config/builtin-roles.js +10 -0
  56. package/dist/config/config-field-policy.js +11 -0
  57. package/dist/config/config-manager.js +32 -4
  58. package/dist/config/config-operation-service.js +20 -5
  59. package/dist/config/contact-book-store.js +1 -1
  60. package/dist/config/contact-book.js +1 -1
  61. package/dist/config/contact-operation-service.js +1 -1
  62. package/dist/config/peer-role-resolver.js +1 -1
  63. package/dist/config/resolved-config-op.js +3 -0
  64. package/dist/config-store.js +1 -1
  65. package/dist/core/agent-application-service.js +5 -0
  66. package/dist/core/audit/event-key.js +17 -2
  67. package/dist/core/audit/log-integrity.js +34 -8
  68. package/dist/core/auth/agent-delegation.js +48 -14
  69. package/dist/core/auth/auth-gateway.js +2 -0
  70. package/dist/core/auth/authorization-audit.js +34 -38
  71. package/dist/core/auth/operation-authorizer.js +67 -5
  72. package/dist/core/auth/operation-catalog.js +110 -0
  73. package/dist/core/auth/remote-access-store.js +115 -9
  74. package/dist/core/bootstrap-messages.js +66 -7
  75. package/dist/core/bootstrap-service.js +110 -19
  76. package/dist/core/command/agent-control.js +88 -7
  77. package/dist/core/command/agent-storage-menu.js +443 -0
  78. package/dist/core/command/cli-intent-parser.js +19 -0
  79. package/dist/core/command/command-handler.js +105 -40
  80. package/dist/core/command/data-root-resolver.js +273 -0
  81. package/dist/core/command/diag-service.js +292 -27
  82. package/dist/core/command/group-menu.js +7 -2
  83. package/dist/core/command/menu-catalog.js +34 -4
  84. package/dist/core/command/menu-handler.js +364 -96
  85. package/dist/core/command/menu-protocol.js +43 -6
  86. package/dist/core/command/role-menu.js +2 -2
  87. package/dist/core/command/slash-handler.js +61 -37
  88. package/dist/core/event-catalog.js +4 -0
  89. package/dist/core/evolagent-registry.js +28 -2
  90. package/dist/core/group/invite-service.js +924 -0
  91. package/dist/core/interaction-router.js +22 -8
  92. package/dist/core/message/im-renderer.js +94 -16
  93. package/dist/core/message/message-bridge.js +140 -13
  94. package/dist/core/message/message-log.js +5 -3
  95. package/dist/core/message/message-queue.js +73 -41
  96. package/dist/core/message/response-engine.js +729 -118
  97. package/dist/core/permission/approval-gateway.js +36 -3
  98. package/dist/core/permission/ec-command-parser.js +76 -36
  99. package/dist/core/permission/protected-paths.js +134 -16
  100. package/dist/core/permission/sandbox-runtime.js +72 -3
  101. package/dist/core/permission/tool-error-code.js +15 -0
  102. package/dist/core/permission/tool-policy.js +8 -8
  103. package/dist/core/relation/peer-identity.js +57 -6
  104. package/dist/core/relation/shared-data.js +106 -0
  105. package/dist/core/role/runtime-policy.js +64 -0
  106. package/dist/core/runtime-lock.js +10 -26
  107. package/dist/core/session/runner-task-history.js +170 -0
  108. package/dist/core/session/session-manager.js +38 -6
  109. package/dist/core/session/session-mapper.js +41 -0
  110. package/dist/core/session/session-turn-coordinator.js +37 -7
  111. package/dist/core/session/session-turns.js +48 -7
  112. package/dist/core/task/task-recovery-service.js +176 -0
  113. package/dist/core/task/task-resume-operation.js +32 -0
  114. package/dist/eck/group-rules-sync.js +5 -3
  115. package/dist/eck/kit-renderer.js +1 -0
  116. package/dist/index.js +322 -207
  117. package/dist/ipc.js +141 -15
  118. package/dist/paths.js +17 -4
  119. package/dist/product.js +3 -0
  120. package/dist/trigger/event-source.js +19 -0
  121. package/dist/trigger/feedback.js +233 -40
  122. package/dist/trigger/parser.js +55 -5
  123. package/dist/trigger/patch.js +9 -0
  124. package/dist/trigger/scheduler.js +30 -4
  125. package/dist/trigger/validation.js +20 -3
  126. package/dist/utils/atomic-write.js +98 -0
  127. package/dist/utils/cross-platform.js +87 -16
  128. package/dist/utils/ecweb-utils.js +1 -0
  129. package/dist/utils/error-utils.js +40 -2
  130. package/dist/utils/logger.js +23 -13
  131. package/dist/utils/npm-ops.js +119 -4
  132. package/dist/utils/package-version-info.js +244 -0
  133. package/dist/utils/tool-summary.js +59 -3
  134. package/dist/utils/welcome.js +174 -1
  135. package/dist/utils/windows-shell-trust.js +37 -0
  136. package/ecagent/dist/harness/agent-harness.js +3 -0
  137. package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
  138. package/kits/docs/INDEX.md +0 -6
  139. package/kits/docs/channels/aun.md +23 -2
  140. package/kits/docs/channels/feishu.md +1 -1
  141. package/kits/docs/context-assembly.md +29 -17
  142. package/kits/docs/evolcore/INDEX.md +8 -3
  143. package/kits/docs/evolcore/agent-create.md +39 -7
  144. package/kits/docs/evolcore/agent.md +33 -1
  145. package/kits/docs/evolcore/aid.md +9 -1
  146. package/kits/docs/evolcore/config.md +40 -1
  147. package/kits/docs/evolcore/group-collaboration.md +1 -1
  148. package/kits/docs/evolcore/group.md +117 -2
  149. package/kits/docs/evolcore/menu-client.md +16 -0
  150. package/kits/docs/evolcore/msg.md +3 -0
  151. package/kits/docs/evolcore/storage.md +3 -0
  152. package/kits/docs/evolcore/task.md +14 -0
  153. package/kits/docs/evolcore/trigger.md +51 -3
  154. package/kits/docs/venues/group.md +5 -0
  155. package/kits/eck_manifest.json +27 -0
  156. package/kits/rules/01-overview.md +11 -7
  157. package/kits/rules/04-relation.md +2 -1
  158. package/kits/rules/05-venue.md +1 -1
  159. package/kits/rules/06-channel.md +6 -4
  160. package/kits/schemas/agent-config.schema.12.json +25 -1
  161. package/kits/schemas/daemon.schema.6.json +2 -2
  162. package/kits/schemas/defaults.schema.5.json +1 -1
  163. package/kits/schemas/relation-config.schema.1.json +1 -1
  164. package/kits/schemas/relation-config.schema.5.json +1 -1
  165. package/kits/schemas/role-config.schema.1.json +14 -0
  166. package/kits/templates/roles/member.json +5 -0
  167. package/kits/templates/roles/visitor.json +5 -0
  168. package/kits/templates/system-fragments/baseagent.md +1 -1
  169. package/kits/templates/system-fragments/bootstrap.md +26 -9
  170. package/kits/templates/system-fragments/channel.md +8 -44
  171. package/kits/templates/system-fragments/commands.md +10 -2
  172. package/kits/templates/system-fragments/group-unread-history.md +7 -0
  173. package/kits/templates/system-fragments/reply.md +56 -0
  174. package/package.json +7 -3
  175. package/dist/aun/group-identity.js +0 -9
  176. /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
  177. /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: process.env[AGENT_DELEGATION_TOKEN_ENV],
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 = process.env[AGENT_DELEGATION_TOKEN_ENV];
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 { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
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: process.env[AGENT_DELEGATION_TOKEN_ENV],
101
+ delegationToken: readDelegationCredential(),
102
102
  } : {
103
103
  type: 'queue-snapshot',
104
104
  agent,
@@ -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 = process.env[AGENT_DELEGATION_TOKEN_ENV];
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 { tryUpgrade, tryUpgradeGlobalPkg, resolveGlobalPkg } from '../utils/npm-ops.js';
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 runtimeOrphans = orphanSnapshot.filter(o => {
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
- log('Checking for updates...');
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 Promise.all([
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 是独立全局包,已安装时单独检查升级;与 EvolCore registry
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
- process.exit(0);
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: true,
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
- child.unref();
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
+ }
@@ -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' || value.executionSource === 'trigger'
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 isRunnerOwnedSessionRuntimeDir(directory) {
193
- const resolved = path.resolve(directory);
194
- const base = path.basename(resolved);
195
- const parent = path.dirname(resolved);
196
- // Codex allocates a private, direct child named with a 24-character digest
197
- // below its private evolcore-codex-* parent. The runner has already checked
198
- // canonical containment before returning this path to the response engine.
199
- const isCodexRuntime = /^[a-f0-9]{24}$/.test(base)
200
- && /^evolcore-codex-(?:\d+|user)$/.test(path.basename(parent));
201
- return isCodexRuntime && isPrivateDirectory(parent) && isPrivateDirectory(resolved);
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
- /** Whether a task-provided runtime directory stays inside the process-managed
204
- * TMPDIR and is safe to use for transient writes. */
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
- const tmpDir = (managedRoot ?? process.env.TMPDIR)?.trim();
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 relative = path.relative(root, resolved);
212
- if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))
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
- return isPrivateDirectory(root) && isPrivateDirectory(resolved);
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
- && (isManagedSessionRuntimeDir(configured) || isRunnerOwnedSessionRuntimeDir(configured));
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 a private runtime directory below the process-provided TMPDIR.
252
- * There is deliberately no os.tmpdir() fallback: managed sessions must not
253
- * silently escape the session-owned temporary workspace.
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
- let base = process.env.TMPDIR?.trim();
259
- try {
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
- /** Shared by tasks in one daemon runtime, while remaining outside each
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) && !isRunnerOwnedSessionRuntimeDir(sessionRuntimeDir))
333
+ if (!isManagedSessionRuntimeDir(sessionRuntimeDir))
291
334
  return undefined;
292
- const parent = path.dirname(path.resolve(sessionRuntimeDir));
335
+ const parent = path.resolve(sessionRuntimeDir);
293
336
  if (!isPrivateDirectory(parent))
294
337
  return undefined;
295
- const directory = path.join(parent, 'evolcore-locks');
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, { type: 'task-runtime-context', sessionId }, timeoutMs);
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 { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
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> (origin/silent 仅可通过 --file 导入)
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
- if (parsed.feedbackStrategy !== 'target') {
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.startsWith('aun#');
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
- return { type: 'event', eventPattern: parsed.scheduleValue };
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 = process.env[AGENT_DELEGATION_TOKEN_ENV];
578
+ const delegationToken = readDelegationCredential();
569
579
  let controlToken;
570
580
  if (!actorSessionId) {
571
581
  try {