evolcore 0.0.25 → 0.0.27

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 (304) hide show
  1. package/CHANGELOG.md +632 -565
  2. package/LICENSE +21 -21
  3. package/README.md +455 -455
  4. package/bin/codex-managed-acl.ps1 +203 -160
  5. package/bin/codex-managed-hook.mjs +208 -208
  6. package/bin/ec-safe-output.js +327 -327
  7. package/bin/ec.js +40 -29
  8. package/bin/install-codex-managed-hooks.mjs +582 -555
  9. package/dist/agents/baseagent-availability.js +68 -0
  10. package/dist/agents/baseagent.js +96 -46
  11. package/dist/agents/claude-runner.js +172 -33
  12. package/dist/agents/codex/app-server-client.js +76 -31
  13. package/dist/agents/codex/catalog.js +1 -1
  14. package/dist/agents/codex/diagnostics.js +34 -1
  15. package/dist/agents/codex-runner.js +434 -446
  16. package/dist/agents/ecagent-runner.js +174 -34
  17. package/dist/agents/gemini-runner.js +8 -7
  18. package/dist/agents/runner-types.js +75 -19
  19. package/dist/aun/aid/agentmd.js +151 -36
  20. package/dist/aun/aid/client.js +1 -1
  21. package/dist/aun/aid/control-aid.js +180 -1
  22. package/dist/aun/aid/identity.js +4 -4
  23. package/dist/aun/aid/index.js +1 -1
  24. package/dist/aun/aid/store.js +17 -13
  25. package/dist/aun/group/history.js +303 -0
  26. package/dist/aun/group/identity.js +43 -0
  27. package/dist/aun/group/index.js +5 -0
  28. package/dist/aun/{msg/group.js → group/operations.js} +162 -39
  29. package/dist/aun/{menu-client.js → menu/client.js} +85 -6
  30. package/dist/aun/menu/index.js +2 -0
  31. package/dist/aun/menu/transport.js +49 -0
  32. package/dist/aun/msg/index.js +2 -1
  33. package/dist/aun/msg/managed-operation.js +85 -19
  34. package/dist/aun/msg/mention-schema.js +51 -0
  35. package/dist/aun/msg/p2p.js +19 -9
  36. package/dist/aun/msg/upload.js +43 -80
  37. package/dist/aun/outbox.js +29 -7
  38. package/dist/aun/rpc/client.js +1 -0
  39. package/dist/aun/storage/client.js +39 -50
  40. package/dist/channels/aun.js +842 -318
  41. package/dist/channels/daemon.js +10 -6
  42. package/dist/cli/agent-command.js +212 -89
  43. package/dist/cli/agent-create.js +626 -11
  44. package/dist/cli/agent.js +125 -13
  45. package/dist/cli/aun-commands.js +487 -337
  46. package/dist/cli/bench.js +20 -20
  47. package/dist/cli/config.js +55 -33
  48. package/dist/cli/contact.js +72 -15
  49. package/dist/cli/ctl-command.js +24 -24
  50. package/dist/cli/daemon-commands.js +140 -63
  51. package/dist/cli/diag.js +31 -0
  52. package/dist/cli/fs-command.js +70 -70
  53. package/dist/cli/handoff-command.js +46 -14
  54. package/dist/cli/index.js +91 -79
  55. package/dist/cli/init.js +34 -1
  56. package/dist/cli/link-rules.js +21 -21
  57. package/dist/cli/managed-command-guard.js +5 -1
  58. package/dist/cli/menu-client.js +51 -32
  59. package/dist/cli/model.js +3 -3
  60. package/dist/cli/net-check.js +22 -22
  61. package/dist/cli/queue-command.js +31 -31
  62. package/dist/cli/response.js +32 -32
  63. package/dist/cli/restart-monitor.js +103 -42
  64. package/dist/cli/stats.js +51 -51
  65. package/dist/cli/task-command.js +59 -0
  66. package/dist/cli/task-context.js +97 -49
  67. package/dist/cli/trigger-command.js +74 -64
  68. package/dist/config/builtin-roles.js +11 -0
  69. package/dist/config/config-field-policy.js +11 -0
  70. package/dist/config/config-manager.js +32 -4
  71. package/dist/config/config-operation-service.js +160 -0
  72. package/dist/config/contact-book-store.js +1 -1
  73. package/dist/config/contact-book.js +1 -1
  74. package/dist/config/contact-operation-service.js +97 -8
  75. package/dist/config/peer-role-resolver.js +1 -1
  76. package/dist/config/resolved-config-op.js +30 -7
  77. package/dist/config-store.js +1 -1
  78. package/dist/core/agent-application-service.js +7 -1
  79. package/dist/core/audit/event-key.js +17 -2
  80. package/dist/core/audit/log-integrity.js +34 -8
  81. package/dist/core/auth/agent-delegation.js +48 -14
  82. package/dist/core/auth/auth-gateway.js +2 -0
  83. package/dist/core/auth/authorization-audit.js +53 -49
  84. package/dist/core/auth/operation-authorizer.js +90 -7
  85. package/dist/core/auth/operation-catalog.js +145 -4
  86. package/dist/core/auth/remote-access-store.js +155 -10
  87. package/dist/core/bootstrap-messages.js +66 -7
  88. package/dist/core/bootstrap-service.js +111 -20
  89. package/dist/core/command/agent-control.js +88 -7
  90. package/dist/core/command/agent-storage-menu.js +443 -0
  91. package/dist/core/command/cli-intent-parser.js +19 -0
  92. package/dist/core/command/command-handler.js +159 -65
  93. package/dist/core/command/data-root-resolver.js +273 -0
  94. package/dist/core/command/diag-service.js +118 -0
  95. package/dist/core/command/group-menu.js +7 -2
  96. package/dist/core/command/menu-catalog.js +46 -7
  97. package/dist/core/command/menu-handler.js +392 -100
  98. package/dist/core/command/menu-protocol.js +45 -6
  99. package/dist/core/command/menu-token-store.js +41 -8
  100. package/dist/core/command/role-menu.js +2 -2
  101. package/dist/core/command/slash-gate.js +34 -4
  102. package/dist/core/command/slash-handler.js +123 -43
  103. package/dist/core/event-catalog.js +4 -0
  104. package/dist/core/evolagent-registry.js +28 -2
  105. package/dist/core/group/invite-service.js +924 -0
  106. package/dist/core/handoff/runtime.js +205 -27
  107. package/dist/core/handoff/store.js +193 -4
  108. package/dist/core/interaction-router.js +22 -8
  109. package/dist/core/message/im-renderer.js +146 -34
  110. package/dist/core/message/message-bridge.js +163 -20
  111. package/dist/core/message/message-log.js +5 -3
  112. package/dist/core/message/message-queue.js +99 -41
  113. package/dist/core/message/message-utils.js +1 -0
  114. package/dist/core/message/response-engine.js +755 -144
  115. package/dist/core/model/catalog-service.js +79 -49
  116. package/dist/core/model/context-window-suffix.js +33 -0
  117. package/dist/core/model/model-catalog.js +1 -1
  118. package/dist/core/model/model-permission.js +12 -3
  119. package/dist/core/permission/approval-gateway.js +36 -3
  120. package/dist/core/permission/ec-command-parser.js +112 -41
  121. package/dist/core/permission/protected-paths.js +134 -16
  122. package/dist/core/permission/sandbox-runtime.js +108 -17
  123. package/dist/core/permission/tool-error-code.js +15 -0
  124. package/dist/core/permission/tool-policy.js +9 -8
  125. package/dist/core/relation/peer-identity.js +57 -6
  126. package/dist/core/relation/shared-data.js +106 -0
  127. package/dist/core/role/runtime-policy.js +64 -0
  128. package/dist/core/runtime-lock.js +10 -26
  129. package/dist/core/session/runner-task-history.js +170 -0
  130. package/dist/core/session/session-manager.js +34 -6
  131. package/dist/core/session/session-mapper.js +41 -0
  132. package/dist/core/session/session-turn-coordinator.js +37 -7
  133. package/dist/core/session/session-turns.js +48 -7
  134. package/dist/core/task/task-recovery-service.js +176 -0
  135. package/dist/core/task/task-resume-operation.js +32 -0
  136. package/dist/eck/group-rules-sync.js +5 -3
  137. package/dist/eck/kit-renderer.js +1 -0
  138. package/dist/index.js +588 -217
  139. package/dist/ipc.js +193 -15
  140. package/dist/paths.js +17 -4
  141. package/dist/product.js +2 -0
  142. package/dist/response-system/engines/v1/proactive-flow.js +59 -2
  143. package/dist/stats/billing.js +41 -15
  144. package/dist/stats/db.js +159 -159
  145. package/dist/stats/eck-vars.js +9 -9
  146. package/dist/stats/price-resolver.js +28 -10
  147. package/dist/stats/query.js +139 -139
  148. package/dist/stats/role-budget.js +6 -6
  149. package/dist/stats/writer.js +51 -51
  150. package/dist/trigger/event-source.js +19 -0
  151. package/dist/trigger/feedback.js +233 -40
  152. package/dist/trigger/parser.js +55 -5
  153. package/dist/trigger/patch.js +9 -0
  154. package/dist/trigger/scheduler.js +30 -4
  155. package/dist/trigger/validation.js +20 -3
  156. package/dist/utils/cross-platform.js +30 -1
  157. package/dist/utils/ecweb-utils.js +1 -0
  158. package/dist/utils/error-dict.json +160 -160
  159. package/dist/utils/error-utils.js +61 -2
  160. package/dist/utils/evolcore-version.js +129 -0
  161. package/dist/utils/logger.js +26 -14
  162. package/dist/utils/macos-autostart.js +22 -22
  163. package/dist/utils/model-prices.jsonl +23 -23
  164. package/dist/utils/npm-ops.js +176 -35
  165. package/dist/utils/tool-summary.js +59 -3
  166. package/dist/utils/welcome.js +196 -23
  167. package/ecagent/LICENSE +21 -21
  168. package/ecagent/NOTICE +11 -11
  169. package/ecagent/README.md +61 -61
  170. package/ecagent/dist/harness/agent-harness.js +3 -0
  171. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  172. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  173. package/ecagent/dist/harness/messages.js +7 -7
  174. package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
  175. package/kits/docs/GUIDE.md +20 -20
  176. package/kits/docs/INDEX.md +60 -66
  177. package/kits/docs/aun/CHEATSHEET.md +19 -19
  178. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  179. package/kits/docs/channels/aun.md +69 -56
  180. package/kits/docs/channels/feishu.md +56 -56
  181. package/kits/docs/context-assembly.md +379 -367
  182. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  183. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  184. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  185. package/kits/docs/eck_templates/runtime.template.md +19 -19
  186. package/kits/docs/evolcore/INDEX.md +76 -71
  187. package/kits/docs/evolcore/agent-create.md +202 -165
  188. package/kits/docs/evolcore/agent.md +99 -67
  189. package/kits/docs/evolcore/aid.md +68 -60
  190. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
  191. package/kits/docs/evolcore/config.md +241 -195
  192. package/kits/docs/evolcore/contact.md +75 -68
  193. package/kits/docs/evolcore/ctl.md +46 -46
  194. package/kits/docs/evolcore/event.md +216 -216
  195. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  196. package/kits/docs/evolcore/fs.md +110 -110
  197. package/kits/docs/evolcore/group-collaboration.md +244 -244
  198. package/kits/docs/evolcore/group-fs.md +17 -17
  199. package/kits/docs/evolcore/group-rules.md +251 -251
  200. package/kits/docs/evolcore/group.md +267 -152
  201. package/kits/docs/evolcore/menu-client.md +58 -34
  202. package/kits/docs/evolcore/model.md +50 -50
  203. package/kits/docs/evolcore/msg.md +169 -165
  204. package/kits/docs/evolcore/response.md +75 -75
  205. package/kits/docs/evolcore/rpc.md +37 -37
  206. package/kits/docs/evolcore/self-summary.md +29 -29
  207. package/kits/docs/evolcore/stats.md +83 -83
  208. package/kits/docs/evolcore/storage.md +53 -50
  209. package/kits/docs/evolcore/task.md +14 -0
  210. package/kits/docs/evolcore/trigger.md +623 -575
  211. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  212. package/kits/docs/identity/PATH_OPS.md +16 -16
  213. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  214. package/kits/docs/identity/identity-tools.md +26 -26
  215. package/kits/docs/path-registry.md +62 -62
  216. package/kits/docs/prompt-loading-architecture.md +269 -269
  217. package/kits/docs/venues/aun-group.md +45 -45
  218. package/kits/docs/venues/aun-private.md +10 -10
  219. package/kits/docs/venues/client-desktop.md +10 -10
  220. package/kits/docs/venues/client-mobile.md +10 -10
  221. package/kits/docs/venues/feishu-group.md +13 -13
  222. package/kits/docs/venues/feishu-private.md +9 -9
  223. package/kits/docs/venues/group.md +42 -25
  224. package/kits/docs/venues/private.md +10 -10
  225. package/kits/eck_manifest.auxiliary.json +43 -43
  226. package/kits/eck_manifest.json +217 -190
  227. package/kits/eck_message_manifest.json +74 -74
  228. package/kits/migrations/README-role-config-v4.md +32 -32
  229. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  230. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  231. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  232. package/kits/migrations/rename-config-file.mjs +99 -99
  233. package/kits/rules/01-overview.md +166 -162
  234. package/kits/rules/02-navigation.md +96 -96
  235. package/kits/rules/03-identity.md +36 -36
  236. package/kits/rules/04-relation.md +76 -75
  237. package/kits/rules/05-venue.md +60 -60
  238. package/kits/rules/06-channel.md +65 -63
  239. package/kits/schemas/_meta.json +53 -53
  240. package/kits/schemas/agent-config.schema.1.json +177 -177
  241. package/kits/schemas/agent-config.schema.10.json +395 -395
  242. package/kits/schemas/agent-config.schema.11.json +421 -421
  243. package/kits/schemas/agent-config.schema.12.json +451 -427
  244. package/kits/schemas/agent-config.schema.2.json +239 -239
  245. package/kits/schemas/agent-config.schema.3.json +119 -119
  246. package/kits/schemas/agent-config.schema.4.json +208 -208
  247. package/kits/schemas/agent-config.schema.5.json +326 -326
  248. package/kits/schemas/agent-config.schema.6.json +322 -322
  249. package/kits/schemas/agent-config.schema.7.json +303 -303
  250. package/kits/schemas/agent-config.schema.8.json +304 -304
  251. package/kits/schemas/agent-config.schema.9.json +364 -364
  252. package/kits/schemas/contact-book.schema.1.json +36 -36
  253. package/kits/schemas/contact-book.schema.2.json +43 -43
  254. package/kits/schemas/contact-book.schema.3.json +67 -67
  255. package/kits/schemas/daemon.schema.1.json +91 -91
  256. package/kits/schemas/daemon.schema.2.json +101 -101
  257. package/kits/schemas/daemon.schema.3.json +123 -123
  258. package/kits/schemas/daemon.schema.4.json +136 -136
  259. package/kits/schemas/daemon.schema.5.json +135 -135
  260. package/kits/schemas/daemon.schema.6.json +131 -131
  261. package/kits/schemas/defaults.schema.1.json +81 -81
  262. package/kits/schemas/defaults.schema.2.json +85 -85
  263. package/kits/schemas/defaults.schema.3.json +73 -73
  264. package/kits/schemas/defaults.schema.4.json +107 -107
  265. package/kits/schemas/defaults.schema.5.json +119 -119
  266. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  267. package/kits/schemas/migrations/README.md +30 -30
  268. package/kits/schemas/relation-config.schema.1.json +158 -158
  269. package/kits/schemas/relation-config.schema.2.json +73 -73
  270. package/kits/schemas/relation-config.schema.3.json +50 -50
  271. package/kits/schemas/relation-config.schema.4.json +47 -47
  272. package/kits/schemas/relation-config.schema.5.json +47 -47
  273. package/kits/schemas/relation-config.schema.6.json +46 -46
  274. package/kits/schemas/relation-config.schema.7.json +59 -59
  275. package/kits/schemas/relation-config.schema.8.json +103 -103
  276. package/kits/schemas/role-config.schema.1.json +215 -201
  277. package/kits/schemas/role-registry.schema.1.json +35 -35
  278. package/kits/schemas/single-session.schema.1.json +31 -31
  279. package/kits/schemas/single-session.schema.2.json +57 -57
  280. package/kits/schemas/single-session.schema.3.json +32 -32
  281. package/kits/templates/bootstrap-welcome.md +17 -17
  282. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  283. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  284. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  285. package/kits/templates/message-fragments/inject-default.md +2 -2
  286. package/kits/templates/message-fragments/item.md +2 -2
  287. package/kits/templates/roles/admin.json +92 -92
  288. package/kits/templates/roles/member.json +101 -96
  289. package/kits/templates/roles/owner.json +9 -9
  290. package/kits/templates/roles/visitor.json +90 -85
  291. package/kits/templates/system-fragments/baseagent.md +14 -14
  292. package/kits/templates/system-fragments/bootstrap.md +53 -34
  293. package/kits/templates/system-fragments/channel.md +28 -64
  294. package/kits/templates/system-fragments/commands.md +36 -28
  295. package/kits/templates/system-fragments/group-unread-history.md +7 -0
  296. package/kits/templates/system-fragments/identity.md +13 -13
  297. package/kits/templates/system-fragments/relation.md +19 -19
  298. package/kits/templates/system-fragments/reply.md +56 -0
  299. package/kits/templates/system-fragments/session.md +59 -59
  300. package/kits/templates/system-fragments/venue.md +31 -31
  301. package/package.json +104 -98
  302. package/dist/aun/group-identity.js +0 -9
  303. /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
  304. /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
@@ -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) {
@@ -81,62 +81,65 @@ export async function cmdTrigger(args) {
81
81
  }
82
82
  }
83
83
  function printHelp() {
84
- console.log(`用法: ec trigger <subcommand>
85
-
86
- 命令:
87
- list [--agent <aid>] [--all] [--json]
88
- show [--agent <aid>] <triggerId> [--json]
89
- history [--agent <aid>] [triggerId] [--limit <n>] [--json]
90
- create --exec <script|trigger-session|target-session> --file <trigger.json|trigger-dir> [--enable] [--json]
91
- OR
92
- create [--agent <aid>] --exec <script|trigger-session|target-session> --cron <expr>|--event <pattern> (--prompt <text>|--prompt-file <path>) [--enable] [其他flag]
93
- set ... (create 的兼容别名)
94
- update [--agent <aid>] <triggerId> <参数...> [--if-revision <sha256:...>] [--json]
95
- enable [--agent <aid>] <triggerId>
96
- disable [--agent <aid>] <triggerId>
97
- cancel [--agent <aid>] <triggerId> (disable 的兼容别名)
98
- delete|remove|rm [--agent <aid>] <triggerId>
99
- run [--agent <aid>] <triggerId> [--dry-run] [--json]
100
- template list|show <name> [--json]
101
-
102
- Create 参数模式支持:
103
- --once | --delay <时长> | --at <ISO时间> | --cron <表达式> | --every <时长> | --event <事件模式>
104
- --exec <script|trigger-session|target-session> (必填)
105
- --prompt <文本> | --prompt-file <路径>
106
- Shell 双引号内的双引号、反引号和变量形式的美元符号都需在前面加反斜杠;trigger 保存的是还原后的原文
107
- --script-path <路径> --script-runtime <node|python|bash>
108
- --script-args <JSON> --script-timeout <时长>
109
- --feedback <target> (origin/silent 仅可通过 --file 导入)
110
- --baseagent <name> (仅 --exec trigger-session)
111
- --model <模型> --effort <low|medium|high|xhigh|max>
112
- --max-runs <次数> --max-duration <时长: 30s|15m|2h|1d>
113
- --permission <readonly|auto|request|bypass|fullaccess>(省略则继承当前身份配置;fullaccess 仅 daemon-owner 且 feature flag 开启时可用)
114
- --tz <时区> (仅 cron)
115
- --target-channel <channelKey> --target-channel-id <ID> (AUN 可简写为 aun)
116
- --target-chat-type <private|group> (AUN 目标必填;channelId 同时作为群聊 ID)
117
- --target-session <main|thread> [--target-thread-id <threadId>]
118
- --trigger-thread <by-run|by-trigger> (兼容旧值 per-run)
119
- --name <名称>
120
-
121
- 通用输出参数:
122
- --json | --format json
123
-
124
- Update 参数:
125
- --once | --delay | --at | --cron | --every | --event [--tz]
126
- --prompt <文本> | --prompt-file <路径> --script-file <路径> --name <名称>
127
- --description <文本> (空字符串删除)
128
- --model <模型> --effort <强度> --permission <权限模式|inherit>(inherit 清除覆盖)
129
- --max-runs <次数> --max-duration <时长>
130
- --concurrency <forbid|replace|allow> --missed-policy <skip|run-once|run-all>
131
- --feedback <origin|target|silent>
132
- --target-channel <channelKey> --target-channel-id <ID> (必须同时指定)
133
- --target-chat-type <private|group> --target-session <main|thread> [--target-thread-id <threadId>]
134
- --trigger-thread <by-run|by-trigger> --baseagent <name> (仅 trigger_session 之间)
135
- --on-error <fail|retry> --noop-sentinel <文本>
136
- --retry-attempts <次数> --retry-backoff <毫秒>
137
- --script-runtime <node|python|bash> --script-args <JSON> --script-timeout <时长>
138
-
139
- 省略 --agent 时使用当前 agent AID;无会话上下文或跨身份操作时需要显式指定。
84
+ console.log(`用法: ec trigger <subcommand>
85
+
86
+ 命令:
87
+ list [--agent <aid>] [--all] [--json]
88
+ show [--agent <aid>] <triggerId> [--json]
89
+ history [--agent <aid>] [triggerId] [--limit <n>] [--json]
90
+ create --exec <script|trigger-session|target-session> --file <trigger.json|trigger-dir> [--enable] [--json]
91
+ OR
92
+ create [--agent <aid>] --exec <script|trigger-session|target-session> --cron <expr>|--event <pattern> (--prompt <text>|--prompt-file <path>) [--enable] [其他flag]
93
+ set ... (create 的兼容别名)
94
+ update [--agent <aid>] <triggerId> <参数...> [--if-revision <sha256:...>] [--json]
95
+ enable [--agent <aid>] <triggerId>
96
+ disable [--agent <aid>] <triggerId>
97
+ cancel [--agent <aid>] <triggerId> (disable 的兼容别名)
98
+ delete|remove|rm [--agent <aid>] <triggerId>
99
+ run [--agent <aid>] <triggerId> [--dry-run] [--json]
100
+ template list|show <name> [--json]
101
+
102
+ Create 参数模式支持:
103
+ --once | --delay <时长> | --at <ISO时间> | --cron <表达式> | --every <时长> | --event <事件模式>
104
+ --event-filter <JSON> (仅 --event;按事件 payload 字段匹配)
105
+ --exec <script|trigger-session|target-session> (必填)
106
+ --prompt <文本> | --prompt-file <路径>
107
+ Shell 双引号内的双引号、反引号和变量形式的美元符号都需在前面加反斜杠;trigger 保存的是还原后的原文
108
+ --script-path <路径> --script-runtime <node|python|bash>
109
+ --script-args <JSON> --script-timeout <时长>
110
+ --feedback <target|event-session> (event-session 使用事件来源会话)
111
+ --baseagent <name> (仅 --exec trigger-session)
112
+ --execution-timeout <时长>(模型类 Trigger 单次执行总时限)
113
+ --model <模型> --effort <low|medium|high|xhigh|max>
114
+ --max-runs <次数> --max-duration <时长: 30s|15m|2h|1d>
115
+ --permission <readonly|auto|request|bypass|fullaccess>(省略则继承当前身份配置;fullaccess 仅 daemon-owner 且 feature flag 开启时可用)
116
+ --tz <时区> (仅 cron)
117
+ --target-channel <channelKey> --target-channel-id <ID> (AUN 可简写为 aun)
118
+ --target-chat-type <private|group> (AUN 目标必填;channelId 同时作为群聊 ID)
119
+ --target-session <main|thread> [--target-thread-id <threadId>]
120
+ --trigger-thread <by-run|by-trigger> (兼容旧值 per-run)
121
+ --name <名称>
122
+
123
+ 通用输出参数:
124
+ --json | --format json
125
+
126
+ Update 参数:
127
+ --once | --delay | --at | --cron | --every | --event [--tz]
128
+ --prompt <文本> | --prompt-file <路径> --script-file <路径> --name <名称>
129
+ --description <文本> (空字符串删除)
130
+ --execution-timeout <时长>(模型类 Trigger 单次执行总时限)
131
+ --model <模型> --effort <强度> --permission <权限模式|inherit>(inherit 清除覆盖)
132
+ --max-runs <次数> --max-duration <时长>
133
+ --concurrency <forbid|replace|allow> --missed-policy <skip|run-once|run-all>
134
+ --feedback <origin|target|event-session|silent>
135
+ --target-channel <channelKey> --target-channel-id <ID> (必须同时指定)
136
+ --target-chat-type <private|group> --target-session <main|thread> [--target-thread-id <threadId>]
137
+ --trigger-thread <by-run|by-trigger> --baseagent <name> (仅 trigger_session 之间)
138
+ --on-error <fail|retry> --noop-sentinel <文本>
139
+ --retry-attempts <次数> --retry-backoff <毫秒>
140
+ --script-runtime <node|python|bash> --script-args <JSON> --script-timeout <时长>
141
+
142
+ 省略 --agent 时使用当前 agent AID;无会话上下文或跨身份操作时需要显式指定。
140
143
  任务会话中的跨身份操作仅允许目标 Agent 上具备 owner/admin 权限的调用者执行 list/show/history;创建、修改、启停、删除和运行仍只允许当前 Agent。`);
141
144
  }
142
145
  async function listTriggers(args, json) {
@@ -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 {
@@ -34,6 +34,7 @@ export function getManagementCommandPermissions(role) {
34
34
  'contact.read': { allow: true, scopes: ['agent'] },
35
35
  'contact.add': { allow: true, scopes: ['relation'], constraints: { ownPeerOnly: true, privateOnly: true } },
36
36
  'contact.block': { allow: true, scopes: ['agent'], constraints: { requireAgentAdmin: true } },
37
+ 'contact.review': { allow: true, scopes: ['agent'], constraints: { requireAgentAdmin: true } },
37
38
  'connect.write': { allow: true, scopes: ['agent'], constraints: { requireAgentAdmin: true } },
38
39
  'connect.access.write': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true } },
39
40
  'role.assign': { allow: true, scopes: ['agent'] },
@@ -43,6 +44,16 @@ export function getManagementCommandPermissions(role) {
43
44
  'agent.baseagent.update': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
44
45
  'observable.current': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true } },
45
46
  'observable.update': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
47
+ 'file.root.agent': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
48
+ 'file.root.storage': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
49
+ 'file.storage.list': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
50
+ 'file.storage.query': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
51
+ 'file.storage.fetch': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
52
+ 'file.storage.quota': { allow: true, scopes: ['agent'], constraints: { requireAgentOwner: true, targetCurrentAgentOnly: true } },
53
+ 'file.root.relation': { allow: true, scopes: ['relation', 'agent'], constraints: { targetCurrentAgentOnly: true } },
54
+ 'file.data.list': { allow: true, scopes: ['relation', 'agent'], constraints: { targetCurrentAgentOnly: true } },
55
+ 'file.data.query': { allow: true, scopes: ['relation', 'agent'], constraints: { targetCurrentAgentOnly: true } },
56
+ 'file.data.fetch': { allow: true, scopes: ['relation', 'agent'], constraints: { targetCurrentAgentOnly: true } },
46
57
  'config.get': { allow: true, scopes: ['agent', 'relation'] },
47
58
  'config.set': { allow: true, scopes: ['agent', 'relation'] },
48
59
  'config.unset': { allow: true, scopes: ['agent', 'relation'] },
@@ -29,14 +29,25 @@ const BASEAGENT_BEHAVIOR_FIELDS = new Set([
29
29
  'useVertex',
30
30
  ]);
31
31
  const SUPPORTED_BASEAGENTS = new Set(['claude', 'codex', 'gemini', 'ecagent']);
32
+ /** Public behavior fields for a runner this version does not implement. */
33
+ export function isUnsupportedBaseagentConfigField(fieldPath) {
34
+ const parts = fieldPath.split('.');
35
+ return parts.length === 3
36
+ && parts[0] === 'baseagents'
37
+ && /^[a-z][a-z0-9_-]*$/.test(parts[1])
38
+ && !SUPPORTED_BASEAGENTS.has(parts[1])
39
+ && BASEAGENT_BEHAVIOR_FIELDS.has(parts[2]);
40
+ }
32
41
  const SENSITIVE_TOP_FIELDS = new Set([
33
42
  '$schema_version',
34
43
  'aid',
35
44
  'enabled',
36
45
  'lifecycle',
37
46
  'initialized',
47
+ 'initialization',
38
48
  'owners',
39
49
  'access',
50
+ 'fullaccess',
40
51
  'admins',
41
52
  'channels',
42
53
  'aun',
@@ -19,7 +19,8 @@ import { atomicReadJson, atomicWriteJson } from '../utils/atomic-write.js';
19
19
  import { fileCache } from '../core/daemon-file-cache.js';
20
20
  import { isValidAid } from '../aun/aid/validation.js';
21
21
  import { normalizeAidDomain } from '../aun/aid/domain.js';
22
- import { isExplicitGroupId } from '../aun/group-identity.js';
22
+ import { isExplicitGroupId } from '../aun/group/index.js';
23
+ import { ensureRelationSharedDirectory } from '../core/relation/shared-data.js';
23
24
  import { parseContactAlias } from './contact-alias.js';
24
25
  import { loadSchema, listSchemaVersions, currentVersion, isSchemaName, } from './schema-registry.js';
25
26
  import { mergeLayers, expandVars, buildEnvResolver } from './merge.js';
@@ -881,6 +882,9 @@ export function write(target, value, sel, opts = {}) {
881
882
  }
882
883
  // 2. 写入文件
883
884
  fs.mkdirSync(path.dirname(file), { recursive: true });
885
+ if (target === ConfigTarget.Relation && sel?.self && sel.peerKey) {
886
+ ensureRelationSharedDirectory(sel.self, sel.peerKey);
887
+ }
884
888
  atomicWriteJson(file, normalized);
885
889
  finishConfigWrite(target, sel, file);
886
890
  }
@@ -1291,6 +1295,27 @@ export function resolveAgentConfig(sel, opts = {}) {
1291
1295
  stripRelationRoleData(stripStaticOwnerField(relationConfig)),
1292
1296
  ];
1293
1297
  const merged = mergeLayers(layers, fields);
1298
+ // A baseagent block is a configuration record rather than an atomic value:
1299
+ // selecting a model at Agent or relation scope must retain the defaults
1300
+ // gateway credentials and endpoint. Keep the generic dictionary merge
1301
+ // contract unchanged for every other field.
1302
+ merged.baseagents = mergeBaseagentBlocks(layers);
1303
+ return merged;
1304
+ }
1305
+ function mergeBaseagentBlocks(layers) {
1306
+ const merged = {};
1307
+ for (const layer of layers) {
1308
+ const baseagents = layer?.baseagents;
1309
+ if (!baseagents || typeof baseagents !== 'object' || Array.isArray(baseagents))
1310
+ continue;
1311
+ for (const [name, rawBlock] of Object.entries(baseagents)) {
1312
+ if (!rawBlock || typeof rawBlock !== 'object' || Array.isArray(rawBlock)) {
1313
+ merged[name] = rawBlock;
1314
+ continue;
1315
+ }
1316
+ merged[name] = { ...(merged[name] ?? {}), ...rawBlock };
1317
+ }
1318
+ }
1294
1319
  return merged;
1295
1320
  }
1296
1321
  /**
@@ -1326,12 +1351,13 @@ function stripStaticOwnerField(config) {
1326
1351
  if (!Object.prototype.hasOwnProperty.call(config, 'owners')
1327
1352
  && !Object.prototype.hasOwnProperty.call(config, 'admins')
1328
1353
  && !Object.prototype.hasOwnProperty.call(config, 'access')
1329
- && !Object.prototype.hasOwnProperty.call(config, 'groupSlashRequireMentions'))
1354
+ && !Object.prototype.hasOwnProperty.call(config, 'groupSlashRequireMentions')
1355
+ && !Object.prototype.hasOwnProperty.call(config, 'fullaccess'))
1330
1356
  return config;
1331
- // groupSlashRequireMentions is intentionally Agent-only. Relation/defaults
1357
+ // fullaccess and groupSlashRequireMentions are Agent-only. Relation/defaults
1332
1358
  // files allow forward-compatible unknown properties, so strip it before the
1333
1359
  // generic merge chain can treat a manually written value as an override.
1334
- const { owners: _owners, admins: _admins, access: _access, groupSlashRequireMentions: _groupSlashRequireMentions, ...rest } = config;
1360
+ const { owners: _owners, admins: _admins, access: _access, groupSlashRequireMentions: _groupSlashRequireMentions, fullaccess: _fullaccess, ...rest } = config;
1335
1361
  return rest;
1336
1362
  }
1337
1363
  function stripRelationRoleData(config) {
@@ -1354,7 +1380,9 @@ export function resolveEffective(sel, opts = {}) {
1354
1380
  enabled: config.enabled,
1355
1381
  lifecycle: config.lifecycle,
1356
1382
  initialized: config.initialized,
1383
+ initialization: config.initialization,
1357
1384
  owners: config.owners,
1385
+ fullaccess: config.fullaccess,
1358
1386
  aun: config.aun,
1359
1387
  channels: config.channels ?? [],
1360
1388
  models: config.models,