evolcore 0.0.11 → 0.0.13

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 (164) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/bin/codex-managed-hook.mjs +80 -0
  3. package/bin/ec-safe-output.js +26 -7
  4. package/dist/agents/claude-runner.js +86 -7
  5. package/dist/agents/codex-app-server-client.js +174 -20
  6. package/dist/agents/codex-runner.js +375 -92
  7. package/dist/agents/ecagent-runner.js +39 -4
  8. package/dist/agents/gemini-runner.js +1 -0
  9. package/dist/aun/aid/client.js +11 -21
  10. package/dist/aun/aid/control-aid.js +36 -13
  11. package/dist/aun/aid/managed-operation.js +107 -0
  12. package/dist/aun/aid/store.js +13 -7
  13. package/dist/aun/group-fs-download.js +56 -0
  14. package/dist/aun/group-identity.js +1 -2
  15. package/dist/aun/msg/group.js +91 -44
  16. package/dist/aun/msg/index.js +1 -2
  17. package/dist/aun/msg/managed-operation.js +865 -0
  18. package/dist/aun/msg/mention-schema.js +20 -0
  19. package/dist/aun/msg/p2p.js +7 -0
  20. package/dist/aun/msg/upload.js +16 -1
  21. package/dist/aun/outbox.js +31 -2
  22. package/dist/aun/rpc/client.js +66 -0
  23. package/dist/aun/rpc/index.js +1 -2
  24. package/dist/aun/storage/{upload.js → client.js} +11 -2
  25. package/dist/aun/storage/index.js +1 -2
  26. package/dist/channels/aun.js +655 -240
  27. package/dist/channels/daemon.js +13 -0
  28. package/dist/cli/agent-command.js +56 -8
  29. package/dist/cli/agent.js +108 -31
  30. package/dist/cli/aun-commands.js +270 -69
  31. package/dist/cli/bench.js +12 -3
  32. package/dist/cli/cli-argv.js +10 -0
  33. package/dist/cli/config.js +9 -17
  34. package/dist/cli/ctl-command.js +1 -1
  35. package/dist/cli/daemon-commands.js +70 -55
  36. package/dist/cli/fs-command.js +79 -10
  37. package/dist/cli/handoff-command.js +3 -0
  38. package/dist/cli/index.js +30 -2
  39. package/dist/cli/init.js +77 -8
  40. package/dist/cli/managed-command-guard.js +41 -0
  41. package/dist/cli/model.js +11 -4
  42. package/dist/cli/queue-command.js +53 -1
  43. package/dist/cli/response.js +71 -0
  44. package/dist/cli/restart-monitor.js +7 -32
  45. package/dist/cli/trigger-command.js +11 -0
  46. package/dist/config/access-policy.js +1 -2
  47. package/dist/config/builtin-roles.js +9 -0
  48. package/dist/config/config-manager.js +21 -1
  49. package/dist/config/contact-book-store.js +11 -3
  50. package/dist/config/contact-request-service.js +161 -15
  51. package/dist/config/mention-mode.js +8 -24
  52. package/dist/config/peer-role-resolver.js +6 -2
  53. package/dist/config/role-migration-startup.js +53 -0
  54. package/dist/config/role-store.js +1 -1
  55. package/dist/core/auth/agent-delegation.js +1 -2
  56. package/dist/core/auth/auth-gateway.js +29 -1
  57. package/dist/core/auth/authorization-audit.js +15 -0
  58. package/dist/core/auth/operation-authorizer.js +31 -7
  59. package/dist/core/auth/operation-catalog.js +196 -25
  60. package/dist/core/bootstrap-messages.js +25 -0
  61. package/dist/core/bootstrap-service.js +64 -4
  62. package/dist/core/capability/providers/claude-capability-provider.js +9 -31
  63. package/dist/core/capability/providers/codex-capability-provider.js +4 -15
  64. package/dist/core/capability/skill-discovery.js +55 -0
  65. package/dist/core/channel-loader.js +1 -1
  66. package/dist/core/command/cli-intent-parser.js +9 -0
  67. package/dist/core/command/command-handler.js +650 -42
  68. package/dist/core/command/connect-menu.js +15 -0
  69. package/dist/core/command/group-menu.js +4 -4
  70. package/dist/core/command/menu-catalog.js +370 -0
  71. package/dist/core/command/menu-handler.js +230 -51
  72. package/dist/core/command/menu-protocol.js +94 -2
  73. package/dist/core/command/slash-gate.js +5 -2
  74. package/dist/core/command/slash-handler.js +99 -31
  75. package/dist/core/daemon-file-cache.js +2 -1
  76. package/dist/core/data-migration.js +9 -2
  77. package/dist/core/event-catalog.js +6 -0
  78. package/dist/core/evolagent.js +4 -2
  79. package/dist/core/handoff/dispatcher.js +5 -2
  80. package/dist/core/handoff/runtime.js +157 -22
  81. package/dist/core/handoff/store.js +29 -1
  82. package/dist/core/handoff/types.js +1 -0
  83. package/dist/core/interaction-router.js +10 -0
  84. package/dist/core/message/im-renderer.js +19 -0
  85. package/dist/core/message/logical-queue-bridge.js +1 -0
  86. package/dist/core/message/mention-schema.js +126 -0
  87. package/dist/core/message/message-bridge.js +298 -88
  88. package/dist/core/message/message-log.js +3 -0
  89. package/dist/core/message/message-queue.js +268 -39
  90. package/dist/core/message/message-utils.js +81 -4
  91. package/dist/core/message/response-engine.js +161 -77
  92. package/dist/core/message/stream-debouncer.js +10 -2
  93. package/dist/core/permission/approval-gateway.js +1 -0
  94. package/dist/core/permission/ec-command-parser.js +243 -18
  95. package/dist/core/permission/index.js +1 -1
  96. package/dist/core/permission/mode.js +15 -0
  97. package/dist/core/permission/readonly-shell-query.js +148 -8
  98. package/dist/core/permission/sandbox-runtime.js +43 -1
  99. package/dist/core/permission/tool-policy.js +322 -57
  100. package/dist/core/protected-paths.js +114 -4
  101. package/dist/core/session/session-manager.js +42 -4
  102. package/dist/core/session/session-mapper.js +20 -1
  103. package/dist/eck/detect.js +18 -1
  104. package/dist/eck/group-rules-sync.js +15 -44
  105. package/dist/eck/manifest-engine.js +39 -13
  106. package/dist/index.js +541 -180
  107. package/dist/ipc.js +232 -10
  108. package/dist/paths.js +3 -0
  109. package/dist/response-system/coordinator.js +6 -4
  110. package/dist/response-system/engines/v1/proactive-flow.js +26 -8
  111. package/dist/response-system/modes/single-session/index.js +14 -1
  112. package/dist/response-system/selector.js +6 -5
  113. package/dist/trigger/anomaly-store.js +4 -0
  114. package/dist/trigger/feedback.js +64 -11
  115. package/dist/trigger/manager.js +21 -1
  116. package/dist/trigger/parser.js +14 -2
  117. package/dist/trigger/scheduler.js +1 -0
  118. package/dist/trigger/script-executor.js +1 -0
  119. package/dist/trigger/validation.js +67 -6
  120. package/dist/utils/codex-app-server-registry.js +90 -0
  121. package/dist/utils/codex-cli.js +5 -1
  122. package/dist/utils/cross-platform.js +15 -0
  123. package/dist/utils/ecweb-supervisor.js +332 -0
  124. package/dist/utils/error-utils.js +10 -0
  125. package/dist/utils/npm-ops.js +5 -12
  126. package/dist/utils/tool-summary.js +11 -0
  127. package/kits/docs/channels/aun.md +1 -1
  128. package/kits/docs/context-assembly.md +2 -2
  129. package/kits/docs/evolcore/agent.md +11 -6
  130. package/kits/docs/evolcore/aid.md +14 -0
  131. package/kits/docs/evolcore/trigger.md +17 -1
  132. package/kits/docs/prompt-loading-architecture.md +1 -2
  133. package/kits/docs/venues/group.md +1 -1
  134. package/kits/eck_manifest.json +0 -12
  135. package/kits/migrations/migrate-contact-book-v2.mjs +1 -2
  136. package/kits/rules/04-relation.md +1 -1
  137. package/kits/rules/05-venue.md +2 -2
  138. package/kits/schemas/role-config.schema.1.json +1 -0
  139. package/kits/schemas/single-session.schema.1.json +3 -3
  140. package/kits/schemas/single-session.schema.2.json +3 -3
  141. package/kits/templates/roles/admin.json +27 -0
  142. package/kits/templates/roles/member.json +34 -1
  143. package/kits/templates/roles/visitor.json +35 -3
  144. package/kits/templates/system-fragments/bootstrap.md +1 -1
  145. package/kits/templates/system-fragments/channel.md +1 -1
  146. package/kits/templates/system-fragments/session.md +1 -1
  147. package/package.json +2 -2
  148. package/dist/aun/msg/payload-type.js +0 -27
  149. package/dist/aun/rpc/caller.js +0 -42
  150. package/dist/aun/rpc/connection.js +0 -25
  151. package/dist/aun/storage/manage.js +0 -10
  152. package/dist/config/access-policy-domain.js +0 -18
  153. package/dist/config/config-batch-get.js +0 -11
  154. package/dist/config/owner-policy.js +0 -4
  155. package/dist/config/role-config-v4-startup.js +0 -32
  156. package/dist/config/role-config-v5-startup.js +0 -27
  157. package/dist/core/auth/trigger-authorization.js +0 -15
  158. package/dist/core/command/evol-menu-version-gate.js +0 -39
  159. package/dist/core/interaction-registration.js +0 -10
  160. package/dist/core/permission/execution-sandbox.js +0 -16
  161. package/dist/core/relation/peer-key.js +0 -1
  162. package/dist/core/session/session-key.js +0 -24
  163. package/dist/eck/baseagent-caps.js +0 -18
  164. package/dist/eck/rules-loader.js +0 -28
@@ -1,5 +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
4
  import { getArgValue, isHelpFlag, wantsHelp } from './help.js';
4
5
  export async function cmdQueue(args) {
5
6
  if (args.length === 0 || isHelpFlag(args[0]) || wantsHelp(args)) {
@@ -9,10 +10,18 @@ export async function cmdQueue(args) {
9
10
 
10
11
  查询:
11
12
  --agent <aid> 必填,目标 agent(如 mybot.agentid.pub)
13
+ --after <time> 只显示 adapter 接收时间晚于该值的消息(epoch ms 或 ISO)
14
+ --before <time> 只显示 adapter 接收时间早于该值的消息(epoch ms 或 ISO)
12
15
  --showid 显示 messageId
13
16
  --full 显示完整消息内容(不截断)
14
17
  --format json 以 JSON 格式输出
15
18
 
19
+ JSON 时间字段:
20
+ receivedAt adapter 收到消息时间(epoch ms)
21
+ enqueuedAt 实际进入队列时间(epoch ms)
22
+ queueWaitMs 排队等待时长(ms)
23
+ processingStartedAt 开始处理时间(epoch ms,active)
24
+
16
25
  操作:
17
26
  --clear 清空该 agent 的所有待处理消息
18
27
  --cancel <messageId> 取消指定消息
@@ -20,6 +29,7 @@ export async function cmdQueue(args) {
20
29
 
21
30
  示例:
22
31
  ec queue --agent mybot.agentid.pub
32
+ ec queue --agent mybot.agentid.pub --after 2026-08-19T12:00:00+08:00
23
33
  ec queue --agent mybot.agentid.pub --showid
24
34
  ec queue --agent mybot.agentid.pub --clear
25
35
  ec queue --agent mybot.agentid.pub --cancel msg_d4e5f6
@@ -45,6 +55,12 @@ export async function cmdQueue(args) {
45
55
  process.exit(1);
46
56
  }
47
57
  const formatJson = formatValue === 'json';
58
+ const after = parseQueueTime(getArgValue(args, '--after'), '--after');
59
+ const before = parseQueueTime(getArgValue(args, '--before'), '--before');
60
+ if (after !== undefined && before !== undefined && after >= before) {
61
+ console.error('❌ --after 必须早于 --before');
62
+ process.exit(1);
63
+ }
48
64
  const clear = args.includes('--clear');
49
65
  const cancelIdx = args.indexOf('--cancel');
50
66
  const cancelCandidate = cancelIdx >= 0 && cancelIdx + 1 < args.length ? args[cancelIdx + 1] : undefined;
@@ -72,12 +88,25 @@ export async function cmdQueue(args) {
72
88
  : interrupt ? 'interrupt'
73
89
  : undefined;
74
90
  const socketPath = resolvePaths().socket;
75
- const result = await ipcQuery(socketPath, {
91
+ const managed = process.env.EVOLCORE_SESSION_ID;
92
+ const result = await ipcQuery(socketPath, managed ? {
93
+ type: 'queue.op',
94
+ agent,
95
+ action,
96
+ messageId: cancelMsgId,
97
+ sessionKey,
98
+ after,
99
+ before,
100
+ sessionId: managed,
101
+ delegationToken: process.env[AGENT_DELEGATION_TOKEN_ENV],
102
+ } : {
76
103
  type: 'queue-snapshot',
77
104
  agent,
78
105
  action,
79
106
  messageId: cancelMsgId,
80
107
  sessionKey,
108
+ after,
109
+ before,
81
110
  });
82
111
  if (!result) {
83
112
  console.error('错误: 无法连接 evolcore 服务');
@@ -108,6 +137,16 @@ export async function cmdQueue(args) {
108
137
  }
109
138
  console.log(renderQueueItemsCli(items, showId, full, agent));
110
139
  }
140
+ function parseQueueTime(value, flag) {
141
+ if (value === undefined)
142
+ return undefined;
143
+ const parsed = /^\d+$/.test(value) ? Number(value) : Date.parse(value);
144
+ if (!Number.isFinite(parsed)) {
145
+ console.error(`❌ ${flag} 必须是 epoch 毫秒或 ISO 时间: ${value}`);
146
+ process.exit(1);
147
+ }
148
+ return parsed;
149
+ }
111
150
  function renderQueueItemsCli(items, showId, full, aid) {
112
151
  const lines = [`${aid} — 队列 (${items.length} 条)`, ''];
113
152
  if (items.length === 0) {
@@ -141,6 +180,12 @@ function renderQueueItemsCli(items, showId, full, aid) {
141
180
  elapsed = sec >= 60 ? `${Math.floor(sec / 60)}m${sec % 60}s` : `${sec}s`;
142
181
  }
143
182
  parts.push(` ${elapsed.padEnd(elapsedColWidth)} `);
183
+ const wait = item.queueWaitMs == null ? '—' : formatDuration(item.queueWaitMs);
184
+ parts.push(` wait:${wait.padEnd(6)} `);
185
+ if (item.receivedAt != null)
186
+ parts.push(` recv:${formatQueueTime(item.receivedAt)} `);
187
+ if (item.enqueuedAt != null)
188
+ parts.push(` enq:${formatQueueTime(item.enqueuedAt)} `);
144
189
  // 内容列
145
190
  const content = full ? item.preview.replace(/\.\.\.$/, '') : item.preview;
146
191
  parts.push(`"${content}"`);
@@ -148,3 +193,10 @@ function renderQueueItemsCli(items, showId, full, aid) {
148
193
  }
149
194
  return lines.join('\n');
150
195
  }
196
+ function formatDuration(ms) {
197
+ const sec = Math.max(0, Math.round(ms / 1000));
198
+ return sec >= 60 ? `${Math.floor(sec / 60)}m${sec % 60}s` : `${sec}s`;
199
+ }
200
+ function formatQueueTime(timestamp) {
201
+ return new Date(timestamp).toISOString();
202
+ }
@@ -15,6 +15,9 @@ import { readField, writeField, determineFieldScope, normalizePeer, ModelScopeEr
15
15
  import { readFieldWithSource, resolveAgentConfig, ConfigTarget } from '../config/config-manager.js';
16
16
  import { ResponseModeRegistry } from '../response-system/registry.js';
17
17
  import { registerBuiltinModes } from '../response-system/modes/index.js';
18
+ import { ipcQuery } from '../ipc.js';
19
+ import { resolvePaths } from '../paths.js';
20
+ import { AGENT_DELEGATION_TOKEN_ENV } from '../core/auth/agent-delegation.js';
18
21
  const RESPONSE_MODE_FIELD = 'responseMode';
19
22
  const RESPONSE_MODE_PARAMS_FIELD = 'responseModeParams';
20
23
  /**
@@ -54,6 +57,71 @@ function fail(formatJson, code, message) {
54
57
  }
55
58
  process.exit(1);
56
59
  }
60
+ async function managedConfig(fieldArgs, formatJson) {
61
+ const sessionId = process.env.EVOLCORE_SESSION_ID;
62
+ const delegationToken = process.env[AGENT_DELEGATION_TOKEN_ENV];
63
+ if (!sessionId)
64
+ fail(formatJson, 'NO_SESSION', 'EVOLCORE_SESSION_ID is not set');
65
+ if (!delegationToken)
66
+ fail(formatJson, 'DELEGATION_REQUIRED', `${AGENT_DELEGATION_TOKEN_ENV} is not set`);
67
+ const response = await ipcQuery(resolvePaths().socket, {
68
+ type: 'config.op',
69
+ argv: ['config', ...fieldArgs],
70
+ sessionId,
71
+ delegationToken,
72
+ }, 10_000);
73
+ if (!response)
74
+ fail(formatJson, 'DAEMON_UNAVAILABLE', 'Unable to connect to the evolcore daemon');
75
+ if (!response.ok || !response.result?.ok) {
76
+ fail(formatJson, response.code || 'CONFIG_AUTH_FAILED', response.error || 'response config operation failed');
77
+ }
78
+ return response.result;
79
+ }
80
+ async function runManagedResponse(args, formatJson) {
81
+ if (getArgValue(args, '--self') || getArgValue(args, '--peer')) {
82
+ fail(formatJson, 'NOT_ALLOWED', 'Managed response commands always use the authenticated current relation');
83
+ }
84
+ const sub = args[0];
85
+ if (sub === 'set') {
86
+ const id = args[1];
87
+ if (!id)
88
+ fail(formatJson, 'MISSING_ID', 'set requires a mode id');
89
+ if (!buildRegistry().has(id))
90
+ fail(formatJson, 'UNKNOWN_MODE', `Unknown mode: ${id}`);
91
+ await managedConfig(['set', RESPONSE_MODE_FIELD, id], formatJson);
92
+ return emit(formatJson, { ok: true, scope: 'relation', mode: id }, () => `✓ 已设置响应模式为 ${id}(作用域: relation)`);
93
+ }
94
+ if (sub === 'reset') {
95
+ await managedConfig(['unset', RESPONSE_MODE_FIELD], formatJson);
96
+ return emit(formatJson, { ok: true, scope: 'relation' }, () => '✓ 已清除当前关系的响应模式设置');
97
+ }
98
+ if (sub === 'current') {
99
+ const modeResult = await managedConfig(['get', RESPONSE_MODE_FIELD], formatJson);
100
+ const paramsResult = await managedConfig(['get', RESPONSE_MODE_PARAMS_FIELD], formatJson);
101
+ const configuredMode = typeof modeResult.value === 'string' ? modeResult.value : undefined;
102
+ const mode = configuredMode ?? buildRegistry().getPreferredId();
103
+ return emit(formatJson, {
104
+ ok: true,
105
+ scope: 'relation',
106
+ responseMode: mode ?? null,
107
+ source: configuredMode ? 'config' : 'preferred',
108
+ sourceTarget: modeResult.source?.target ?? null,
109
+ responseModeParams: paramsResult.value ?? null,
110
+ }, () => `当前响应模式: ${mode ?? '(无)'}`);
111
+ }
112
+ if (sub === 'config') {
113
+ if (args[1] === 'set') {
114
+ fail(formatJson, 'NOT_ALLOWED', 'responseModeParams cannot be modified as an opaque object from a managed task');
115
+ }
116
+ const result = await managedConfig(['get', RESPONSE_MODE_PARAMS_FIELD], formatJson);
117
+ const params = result.value ?? {};
118
+ const modeId = args[1] && !args[1].startsWith('--') ? args[1] : undefined;
119
+ if (modeId)
120
+ return emit(formatJson, { ok: true, mode: modeId, config: params[modeId] ?? {} }, () => `${modeId} 配置: ${JSON.stringify(params[modeId] ?? {}, null, 2)}`);
121
+ return emit(formatJson, { ok: true, responseModeParams: params }, () => `所有模式配置: ${JSON.stringify(params, null, 2)}`);
122
+ }
123
+ fail(formatJson, 'NOT_ALLOWED', `response ${sub} is not available in a managed task`);
124
+ }
57
125
  /** 解析 --self / --peer 为作用域选择器 */
58
126
  function parseSelector(args, formatJson) {
59
127
  const self = getArgValue(args, '--self');
@@ -331,6 +399,9 @@ export async function cmdResponse(args) {
331
399
  console.log(HELP);
332
400
  return;
333
401
  }
402
+ if (process.env.EVOLCORE_SESSION_ID && sub !== 'list' && sub !== 'info') {
403
+ return runManagedResponse(args, formatJson);
404
+ }
334
405
  switch (sub) {
335
406
  case 'list': return cmdList(args, formatJson);
336
407
  case 'current': return cmdCurrent(args, formatJson);
@@ -6,8 +6,7 @@ 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, tryUpgradeAunSdk, tryUpgradeGlobalPkg, resolveGlobalPkg } from '../utils/npm-ops.js';
10
- import { resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG } from '../aun/aid/client.js';
9
+ import { tryUpgrade, tryUpgradeGlobalPkg, resolveGlobalPkg } from '../utils/npm-ops.js';
11
10
  import { isValidAid } from '../aun/aid/index.js';
12
11
  import { msgSend } from '../aun/msg/index.js';
13
12
  import { scanInstances, cleanupInstances, writeRestartMonitor, removeRestartMonitor, isRestartMonitorWinner, findOrphanProcesses, killOrphans } from '../utils/instance-registry.js';
@@ -15,7 +14,6 @@ import { WEB_PACKAGE_NAME } from '../product.js';
15
14
  import { shouldSuppressRealRestart } from '../utils/restart-safety.js';
16
15
  import { rotateStdoutLog } from '../utils/log-writer.js';
17
16
  import { inspectDataMigrationRequirement } from '../core/data-migration.js';
18
- import { serviceProxyNeedsEcweb, startEcwebIfEnabled } from './daemon-commands.js';
19
17
  const execFileAsync = promisify(execFile);
20
18
  // 清理 Claude Code 环境变量,防止 SDK 认为是嵌套会话
21
19
  function cleanEnv() {
@@ -181,21 +179,7 @@ export async function cmdRestartMonitor() {
181
179
  await notifyDaemonOwners(p, `⚠️ evolcore 升级失败,使用当前版本继续\n${upgrade.error ?? ''}`.trim(), log);
182
180
  break;
183
181
  }
184
- // AUN SDK 版本检查与升级
185
- const aunUpgrade = await tryUpgradeAunSdk(resolveAunCoreSdkPkg, AUN_CORE_SDK_PKG);
186
- switch (aunUpgrade.status) {
187
- case 'upgraded':
188
- log(`✅ AUN SDK upgraded: ${aunUpgrade.from} → ${aunUpgrade.to}`);
189
- await notifyDaemonOwners(p, `📦 AUN SDK 已升级 ${aunUpgrade.from} → ${aunUpgrade.to}`, log);
190
- break;
191
- case 'no-update':
192
- break;
193
- case 'failed':
194
- log(`⚠ AUN SDK upgrade failed (${aunUpgrade.from} → ${aunUpgrade.to}): ${aunUpgrade.error}`);
195
- await notifyDaemonOwners(p, `⚠️ AUN SDK 升级失败,使用当前版本继续\n${aunUpgrade.error ?? ''}`.trim(), log);
196
- break;
197
- }
198
- // EC Web 版本检查与升级(已安装才检查)
182
+ // EC Web 是独立全局包,已安装时单独检查升级。
199
183
  const ecwebUpgrade = await tryUpgradeGlobalPkg(() => resolveGlobalPkg(WEB_PACKAGE_NAME), WEB_PACKAGE_NAME);
200
184
  switch (ecwebUpgrade.status) {
201
185
  case 'upgraded':
@@ -209,22 +193,12 @@ export async function cmdRestartMonitor() {
209
193
  await notifyDaemonOwners(p, `⚠️ ${WEB_PACKAGE_NAME} 升级失败,使用当前版本继续\n${ecwebUpgrade.error ?? ''}`.trim(), log);
210
194
  break;
211
195
  }
212
- // source=ecweb Service Proxy 只在 daemon 启动后的短窗口内发现实例。
213
- // restart-monitor 直接 spawn daemon,必须在此先启动独立的 ec-web,不能绕过
214
- // cmdStart ECWeb 生命周期逻辑。
215
- const ecwebStartedBeforeDaemon = serviceProxyNeedsEcweb(loadDaemonConfig())
216
- ? await startEcwebIfEnabled(p)
217
- : false;
218
- if (ecwebStartedBeforeDaemon)
219
- log('ECWeb started before daemon');
196
+ // ECWeb is owned by the daemon. Starting it here used to race with the
197
+ // daemon's own launcher and ECWeb's stale-instance cleanup, which could
198
+ // leave ServiceProxy pointed at a dead PID.
220
199
  // 启动并检测 ready signal
221
200
  let started = await spawnAndWaitReady(p, log, READY_TIMEOUT);
222
201
  if (started) {
223
- // 没有 Service Proxy 时可以等 daemon ready 后再启动;有代理时已在上方启动,
224
- // 避免重新拉起造成实例记录和反向隧道短暂失配。
225
- if (!ecwebStartedBeforeDaemon && await startEcwebIfEnabled(p)) {
226
- log('ECWeb started after daemon');
227
- }
228
202
  log('✓ Service restarted successfully');
229
203
  archiveSelfHealLog(p, log);
230
204
  // 发起会话内的“重启成功”通知由新进程自行发送,此处只负责失败/自愈告警。
@@ -392,7 +366,7 @@ async function spawnAndWaitReady(p, log, timeout) {
392
366
  const out = fs.openSync(stdoutLog, 'a');
393
367
  const err = fs.openSync(stdoutLog, 'a');
394
368
  const appMain = path.join(getPackageRoot(), 'dist', 'index.js');
395
- const child = spawn('node', ['--no-warnings=ExperimentalWarning', appMain], {
369
+ const child = spawn(process.execPath, ['--no-warnings=ExperimentalWarning', appMain], {
396
370
  detached: true,
397
371
  stdio: ['ignore', out, err],
398
372
  windowsHide: true,
@@ -489,6 +463,7 @@ async function invokeClaude(claudePath, p, attempt, maxAttempts, timeout, log) {
489
463
  timeout,
490
464
  // Windows npm CLIs are .cmd shims; execFile needs a shell to run them.
491
465
  shell: platform.isWindows,
466
+ windowsHide: platform.isWindows,
492
467
  env: { ...process.env, CLAUDE_CODE_ENTRYPOINT: 'cli' },
493
468
  maxBuffer: 10 * 1024 * 1024,
494
469
  });
@@ -31,6 +31,10 @@ export async function cmdTrigger(args) {
31
31
  }
32
32
  return;
33
33
  }
34
+ if (process.env.EVOLCORE_SESSION_ID
35
+ && (hasOption(rest, '--file') || hasOption(rest, '--prompt-file') || hasOption(rest, '--script-path'))) {
36
+ throw new Error('Managed tasks cannot read trigger definitions, prompts, or scripts from local files; use inline prompt content');
37
+ }
34
38
  try {
35
39
  switch (sub) {
36
40
  case 'list':
@@ -109,6 +113,7 @@ Create 参数模式支持:
109
113
  --permission <readonly|auto|request|bypass>(省略则继承当前身份配置)
110
114
  --tz <时区> (仅 cron)
111
115
  --target-channel <channelKey> --target-channel-id <ID> (AUN 可简写为 aun)
116
+ --target-chat-type <private|group> (AUN 目标必填;channelId 同时作为群聊 ID)
112
117
  --target-session <main|thread> [--target-thread-id <threadId>]
113
118
  --trigger-thread <by-run|by-trigger> (兼容旧值 per-run)
114
119
  --name <名称>
@@ -259,6 +264,11 @@ async function createTrigger(args, json) {
259
264
  if (!parsed.targetChannel || !parsed.targetChannelId) {
260
265
  throw new Error('CLI flag 模式需要显式指定 --target-channel <channelKey> --target-channel-id <id>');
261
266
  }
267
+ const targetIsAun = parsed.targetChannel === 'aun' || parsed.targetChannel.startsWith('aun#');
268
+ if (targetIsAun && !parsed.targetChatType) {
269
+ throw new Error('AUN 目标必须显式指定 --target-chat-type private 或 group');
270
+ }
271
+ const targetChatType = parsed.targetChatType;
262
272
  const now = Date.now();
263
273
  if (parsed.targetSession === 'thread' && !parsed.targetThreadId) {
264
274
  throw new Error('--target-session thread 需要 --target-thread-id');
@@ -296,6 +306,7 @@ async function createTrigger(args, json) {
296
306
  channelKey: parsed.targetChannel,
297
307
  channelId: parsed.targetChannelId,
298
308
  session: parsed.targetSession,
309
+ ...(targetChatType ? { chatType: targetChatType } : {}),
299
310
  ...(parsed.targetSession === 'thread' ? { threadId: parsed.targetThreadId } : {}),
300
311
  },
301
312
  },
@@ -1,6 +1,5 @@
1
1
  import crypto from 'crypto';
2
- import { ConfigError, ConfigTarget, mutateConfig, read, validateConfig, } from './config-manager.js';
3
- import { validAgentOwnerIds, validateAccessPolicyDomain, } from './access-policy-domain.js';
2
+ import { ConfigError, ConfigTarget, mutateConfig, read, validateConfig, validAgentOwnerIds, validateAccessPolicyDomain, } from './config-manager.js';
4
3
  export class AccessPolicyError extends Error {
5
4
  code;
6
5
  data;
@@ -35,11 +35,20 @@ export function getManagementCommandPermissions(role) {
35
35
  'role.revoke': { allow: true, scopes: ['agent'] },
36
36
  'role.policy.read': { allow: true, scopes: ['agent'] },
37
37
  'role.relation.read': { allow: true, scopes: ['agent'] },
38
+ 'agent.baseagent.update': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
38
39
  'observable.current': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true } },
40
+ 'observable.update': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
39
41
  'config.get': { allow: true, scopes: ['agent', 'relation'] },
40
42
  'config.set': { allow: true, scopes: ['agent', 'relation'] },
41
43
  'config.unset': { allow: true, scopes: ['agent', 'relation'] },
42
44
  'role.policy.write': { allow: true, dangerous: true, scopes: ['agent'], constraints: { requireAgentAdmin: true } },
45
+ 'ec.aid.show': { allow: true, dangerous: true, scopes: ['agent'], constraints: { targetCurrentAgentOnly: true, requireAgentAdmin: true } },
46
+ 'ec.aid.agentmd.put': { allow: true, dangerous: true, scopes: ['agent'], constraints: { targetCurrentAgentOnly: true, requireAgentAdmin: true } },
47
+ 'ec.fs.mkdir': { allow: true, permissionMode: 'auto', scopes: ['relation'], constraints: { groupOnly: true, currentRelationOnly: true, targetCurrentAgentOnly: true } },
48
+ 'ec.fs.upload': { allow: true, permissionMode: 'auto', scopes: ['relation'], constraints: { groupOnly: true, currentRelationOnly: true, targetCurrentAgentOnly: true } },
49
+ 'ec.fs.copy': { allow: true, permissionMode: 'auto', scopes: ['relation'], constraints: { groupOnly: true, currentRelationOnly: true, targetCurrentAgentOnly: true } },
50
+ 'ec.fs.move': { allow: true, permissionMode: 'auto', scopes: ['relation'], constraints: { groupOnly: true, currentRelationOnly: true, targetCurrentAgentOnly: true } },
51
+ 'ec.fs.remove': { allow: true, permissionMode: 'auto', scopes: ['relation'], constraints: { groupOnly: true, currentRelationOnly: true, targetCurrentAgentOnly: true } },
43
52
  '*': { allow: true },
44
53
  // Reload is valid from an Agent's own channel and the daemon control plane.
45
54
  // The control-channel gate still requires a daemon owner for cross-Agent reloads.
@@ -28,7 +28,27 @@ import { clearRoleStoreCache, isRoleName } from './role-store.js';
28
28
  import { writeRoleDefinition, writeRoleRegistry } from './role-service.js';
29
29
  import { mutateContactBookTransactionSync } from './contact-book-store.js';
30
30
  import { DAEMON_SCHEMA_NAME } from '../product.js';
31
- import { validateAccessPolicyDomain } from './access-policy-domain.js';
31
+ export function shouldFailFastForMissingOwners(env = process.env) {
32
+ const value = (env.EVOLCORE_REQUIRE_OWNERS || '').trim().toLowerCase();
33
+ return value === '1' || value === 'true' || value === 'yes';
34
+ }
35
+ export function validAgentOwnerIds(agent) {
36
+ return [...new Set((agent?.owners ?? [])
37
+ .map(value => String(value || '').trim())
38
+ .filter(isValidAid))];
39
+ }
40
+ export function validateAccessPolicyDomain(selfAid, agent) {
41
+ const access = agent.access;
42
+ if (!access)
43
+ return undefined;
44
+ if (access.policyMode !== 'open' && validAgentOwnerIds(agent).length === 0) {
45
+ return {
46
+ code: 'restricted_mode_without_owner',
47
+ message: `Agent ${selfAid} cannot use ${access.policyMode} without an Owner`,
48
+ };
49
+ }
50
+ return undefined;
51
+ }
32
52
  export var ConfigTarget;
33
53
  (function (ConfigTarget) {
34
54
  ConfigTarget["Process"] = "process";
@@ -184,17 +184,25 @@ function mutateContactBookPreparedSyncInternal(selfAid, prepare) {
184
184
  value: prepared.value,
185
185
  };
186
186
  }
187
- prepared.beforeCommit?.({
187
+ const preparedChanges = prepared.beforeCommit?.({
188
188
  contact: next,
189
189
  previousContactRevision: previousRevision,
190
190
  contactRevision: nextRevision,
191
191
  });
192
192
  const before = readTextOrNull(file);
193
193
  const after = `${JSON.stringify(next, null, 2)}\n`;
194
- const changes = [{ file, before, after }];
194
+ const additionalChanges = preparedChanges === undefined
195
+ ? []
196
+ : Array.isArray(preparedChanges) ? preparedChanges : [preparedChanges];
197
+ const changes = [
198
+ { file, before, after },
199
+ ...additionalChanges,
200
+ ];
201
+ validateTransactionChanges(selfAid, changes);
195
202
  writeJournal(selfAid, { schemaVersion: 1, state: 'prepared', selfAid, changes });
196
203
  try {
197
- applyTransactionChange(changes[0]);
204
+ for (const change of changes)
205
+ applyTransactionChange(change);
198
206
  writeJournal(selfAid, { schemaVersion: 1, state: 'committed', selfAid, changes });
199
207
  removeJournal(selfAid);
200
208
  }