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
@@ -51,6 +51,8 @@ export function parseMenuClientProtectedHeaders(value) {
51
51
  result.client_version = normalized.client_version;
52
52
  if (normalized.evol_version !== undefined)
53
53
  result.evol_version = normalized.evol_version;
54
+ if (normalized.sdk_version !== undefined)
55
+ result.sdk_version = normalized.sdk_version;
54
56
  if (normalized.auth_method === 'daemon-owner' || normalized.auth_method === 'remote-access-token' || normalized.auth_method === 'ecweb-token')
55
57
  result.auth_method = normalized.auth_method;
56
58
  else if (normalized.auth_method !== undefined)
@@ -118,11 +120,16 @@ export const MENU_NAME_COMMANDS = Object.freeze({
118
120
  dispatch: '/dispatch',
119
121
  observable: '/observable',
120
122
  system: '/system',
123
+ baseagents: '/baseagents',
121
124
  cli: '/cli',
122
125
  agent: '/agent',
123
126
  aid: '/aid',
124
127
  trigger: '/trigger',
125
128
  file: '/file',
129
+ 'agent-data-root': '/agent-data-root',
130
+ 'relation-data-root': '/relation-data-root',
131
+ 'agent-storage-root': '/agent-storage-root',
132
+ storage: '/storage',
126
133
  gateway: '/gateway',
127
134
  config: '/config',
128
135
  capability: '/capability',
@@ -208,11 +215,17 @@ export function isEvolMenuVersionGateEnabled() {
208
215
  export function isAunMenuTokenRequired() {
209
216
  return loadDaemonConfig().aun?.menuTokenRequired === true;
210
217
  }
211
- export function evolMenuResponseTransportMetadata() {
218
+ export function evolMenuResponseTransportMetadata(sdkVersion) {
212
219
  return {
213
220
  // Clear inherited request state so AUNChannel applies daemon aun.defaultEncrypt.
214
221
  encrypted: undefined,
215
- protectedHeaders: { ec_version: readInstalledEvolcoreVersion() },
222
+ protectedHeaders: {
223
+ ec_version: readInstalledEvolcoreVersion(),
224
+ ...(typeof sdkVersion === 'string' && sdkVersion.trim() ? { sdk_version: sdkVersion.trim() } : {}),
225
+ },
226
+ ...(typeof sdkVersion === 'string' && sdkVersion.trim()
227
+ ? { menuClientSdkVersion: sdkVersion.trim() }
228
+ : {}),
216
229
  };
217
230
  }
218
231
  const EXPLICIT_SCOPE_UPDATE_NAMES = new Set([
@@ -329,6 +342,12 @@ export function validateMenuRequest(request) {
329
342
  return { code: 'INVALID_ARGUMENT', message: 'File fetch requires args.path' };
330
343
  }
331
344
  }
345
+ if ((request.name === 'file' || request.cmd === '/file') && request.args !== undefined) {
346
+ const args = request.args;
347
+ if (args.rootId !== undefined && (typeof args.rootId !== 'string' || args.rootId.trim().length === 0)) {
348
+ return { code: 'INVALID_ARGUMENT', message: 'File rootId must be a non-empty string' };
349
+ }
350
+ }
332
351
  return null;
333
352
  }
334
353
  export function menuSuccess(header, data) {
@@ -371,10 +390,10 @@ export function enforceMenuResponseSize(response, maxBytes = 128 * 1024) {
371
390
  });
372
391
  }
373
392
  const INVALID_ARGUMENT_CODES = new Set([
374
- 'ARGUMENT_MISMATCH', 'FILE_TOO_LARGE', 'INVALID_ARGS', 'INVALID_DELEGATION',
393
+ 'ARGUMENT_MISMATCH', 'INVALID_ARGS', 'INVALID_DELEGATION',
375
394
  'INVALID_FIELD', 'INVALID_REVISION', 'INVALID_SCOPE', 'INVALID_TYPE', 'INVALID_VALUE', 'MISSING_AID',
376
395
  'MISSING_ARGV', 'MISSING_BASEAGENT', 'MISSING_CMD', 'MISSING_PEER', 'MISSING_VALUE',
377
- 'NOT_A_DIRECTORY', 'REVISION_REQUIRED', 'ROLE_VIOLATION',
396
+ 'REVISION_REQUIRED', 'ROLE_VIOLATION',
378
397
  ]);
379
398
  const STABLE_CODES = new Set([
380
399
  'ROLE_ACCESS_DENIED', 'PERMISSION_DENIED', 'UNAUTHORIZED', 'FORBIDDEN',
@@ -386,6 +405,9 @@ const STABLE_CODES = new Set([
386
405
  'RATE_LIMITED', 'CATALOG_STALE', 'DATA_MIGRATION_REQUIRED',
387
406
  'INVALID_CLIENT', 'REMOTE_ACCESS_TOKEN_INVALID', 'ECWEB_TOKEN_INVALID', 'CLIENT_BUSY', 'INVALID_RESPONSE', 'TIMEOUT',
388
407
  'RESPONSE_TOO_LARGE',
408
+ 'TOPIC_SESSION_NOT_FOUND', 'TOPIC_SESSION_LOOKUP_FAILED',
409
+ 'ROOT_NOT_FOUND', 'ROOT_FORBIDDEN', 'ROOT_EXPIRED', 'ROOT_SCOPE_MISMATCH', 'ROOT_PEER_MISMATCH',
410
+ 'INVALID_ROOT_ID', 'MISSING_ROOT_ID', 'INVALID_ROOT_PATH', 'NOT_A_DIRECTORY', 'FILE_TOO_LARGE',
389
411
  ]);
390
412
  export function normalizeMenuError(error) {
391
413
  const source = error && typeof error === 'object' ? error : {};
@@ -436,6 +458,16 @@ export class MenuRequestDeduper {
436
458
  this.ttlMs = ttlMs;
437
459
  this.maxEntries = maxEntries;
438
460
  }
461
+ /** Replace an acknowledged deferred operation's result after it fails. */
462
+ async replaceResult(key, fingerprint, previous, value) {
463
+ const entry = this.entries.get(key);
464
+ if (!entry || entry.fingerprint !== fingerprint || await entry.promise !== previous)
465
+ return;
466
+ if (this.entries.get(key) !== entry)
467
+ return;
468
+ entry.promise = Promise.resolve(value);
469
+ entry.expiresAt = Date.now() + this.ttlMs;
470
+ }
439
471
  async execute(key, fingerprint, operation) {
440
472
  this.prune();
441
473
  const existing = this.entries.get(key);
@@ -510,14 +542,16 @@ const MAX_LOG_DEPTH = 8;
510
542
  const MAX_LOG_KEYS = 100;
511
543
  const MAX_LOG_ARRAY_ITEMS = 100;
512
544
  const MAX_LOG_STRING_LENGTH = 4096;
513
- const SENSITIVE_LOG_KEY = /(?:^|[_-])(?:api[_-]?key|access[_-]?token|refresh[_-]?token|menu[_-]?token|token|secret(?:[_-]?key)?|password|passwd|credentials?|authorization|cookie|private[_-]?key|seed)(?:$|[_-])/i;
545
+ const SENSITIVE_LOG_KEY = /(?:^|[_-])(?:api[_-]?key|access[_-]?token|refresh[_-]?token|menu[_-]?token|root[_-]?id|token|secret(?:[_-]?key)?|password|passwd|credentials?|authorization|cookie|private[_-]?key|seed)(?:$|[_-])/i;
514
546
  const SENSITIVE_LOG_ARG = /(?:api[_-]?key|access[_-]?token|refresh[_-]?token|menu[_-]?token|token|secret|password|passwd|credential|authorization|cookie|private[_-]?key|seed)/i;
515
547
  function isSensitiveLogKey(key) {
516
548
  const normalized = key.replace(/([a-z0-9])([A-Z])/g, '$1_$2');
517
- return SENSITIVE_LOG_KEY.test(normalized);
549
+ return SENSITIVE_LOG_KEY.test(normalized) || /^(?:next[_-]?)?cursor$|^(?:download[_-]?)?url$|^ticket$/i.test(normalized);
518
550
  }
519
551
  function sanitizeInlineLogSecrets(value) {
520
552
  return value
553
+ .replace(/\b(?:sr1|sc1|dr1)\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '[REDACTED]')
554
+ .replace(/https?:\/\/[^\s"'<>]*[?&](?:t|token|signature|x-amz-signature)=[^\s"'<>]*/gi, '[REDACTED_URL]')
521
555
  .replace(/\b(authorization\s*:\s*Bearer\s+)[^\s"',;]+/gi, '$1[REDACTED]')
522
556
  .replace(/\bBearer\s+[^\s,;]+/gi, 'Bearer [REDACTED]')
523
557
  .replace(/\b(api[_-]?key|access[_-]?token|refresh[_-]?token|menu[_-]?token|token|password|passwd|secret|credential|authorization|cookie)\s*([=:])\s*(?:"[^"]*"|'[^']*'|\S+)/gi, '$1$2[REDACTED]')
@@ -567,6 +601,11 @@ function sanitizeLogArgv(value, depth, seen) {
567
601
  export function sanitizeMenuLogValue(value, key = '', depth = 0, seen = new WeakSet()) {
568
602
  if (isSensitiveLogKey(key))
569
603
  return '[REDACTED]';
604
+ // Pairing codes are intentionally returned as `code` on the wire for
605
+ // compatibility with /pair and the ECWeb API. Do not persist six-digit
606
+ // credentials in menu-protocol.log.
607
+ if (key === 'code' && typeof value === 'string' && /^\d{6}$/.test(value))
608
+ return '[REDACTED]';
570
609
  if (value === null || value === undefined || typeof value === 'number' || typeof value === 'boolean')
571
610
  return value;
572
611
  if (typeof value === 'bigint')
@@ -4,6 +4,20 @@ import { agentDataDir } from '../../paths.js';
4
4
  import { atomicReadJson, atomicWriteJson } from '../../utils/atomic-write.js';
5
5
  export const DEFAULT_MENU_TOKEN_IDLE_TIMEOUT_SECONDS = 30 * 24 * 60 * 60;
6
6
  export const MAX_MENU_TOKENS_PER_AGENT = 1_000;
7
+ function validInstallationId(value) {
8
+ return value === undefined || (typeof value === 'string' && value.length <= 256
9
+ && !/[\u0000-\u001f\u007f]/.test(value));
10
+ }
11
+ function normalizeInstallation(value) {
12
+ if (!value || typeof value !== 'object' || !validInstallationId(value.deviceId)
13
+ || !validInstallationId(value.slotId))
14
+ return null;
15
+ const deviceId = value.deviceId?.trim() || '';
16
+ const slotId = value.slotId?.trim() || '';
17
+ if (slotId && !deviceId)
18
+ return null;
19
+ return { deviceId, slotId };
20
+ }
7
21
  function hashToken(token) {
8
22
  return createHash('sha256').update(token).digest('hex');
9
23
  }
@@ -13,6 +27,9 @@ function isTokenRecord(value) {
13
27
  const record = value;
14
28
  return typeof record.peerAid === 'string'
15
29
  && record.peerAid.trim().length > 0
30
+ && validInstallationId(record.peerDeviceId)
31
+ && validInstallationId(record.peerSlotId)
32
+ && (!record.peerSlotId?.trim() || !!record.peerDeviceId?.trim())
16
33
  && typeof record.tokenHash === 'string'
17
34
  && /^[a-f0-9]{64}$/.test(record.tokenHash)
18
35
  && typeof record.requestedAt === 'number'
@@ -28,6 +45,10 @@ function isTokenRecord(value) {
28
45
  function isExpired(record, now) {
29
46
  return now - record.lastUsedAt >= record.idleTimeout * 1000;
30
47
  }
48
+ function installationMatches(record, installation) {
49
+ return (record.peerDeviceId?.trim() || '') === (installation.deviceId?.trim() || '')
50
+ && (record.peerSlotId?.trim() || '') === (installation.slotId?.trim() || '');
51
+ }
31
52
  function hashesEqual(left, right) {
32
53
  const leftBytes = Buffer.from(left, 'hex');
33
54
  const rightBytes = Buffer.from(right, 'hex');
@@ -41,10 +62,14 @@ export class MenuTokenStore {
41
62
  constructor(maxRecords = MAX_MENU_TOKENS_PER_AGENT) {
42
63
  this.maxRecords = maxRecords;
43
64
  }
44
- issue(selfAid, peerAid, metadata = {}, now = Date.now()) {
65
+ issue(selfAid, peerAid, metadata = {}, installationOrNow = {}, now = Date.now()) {
66
+ const installation = normalizeInstallation(typeof installationOrNow === 'number' ? {} : installationOrNow);
67
+ if (!installation)
68
+ return null;
69
+ const issuedAt = typeof installationOrNow === 'number' ? installationOrNow : now;
45
70
  const file = this.read(selfAid);
46
71
  const idleTimeout = DEFAULT_MENU_TOKEN_IDLE_TIMEOUT_SECONDS;
47
- const tokens = file.tokens.filter(record => record.peerAid !== peerAid && !isExpired(record, now));
72
+ const tokens = file.tokens.filter(record => (record.peerAid !== peerAid || !installationMatches(record, installation)) && !isExpired(record, issuedAt));
48
73
  if (tokens.length >= this.maxRecords) {
49
74
  if (tokens.length !== file.tokens.length)
50
75
  this.write(selfAid, tokens);
@@ -53,9 +78,11 @@ export class MenuTokenStore {
53
78
  const menuToken = `mt_${randomBytes(32).toString('base64url')}`;
54
79
  tokens.push({
55
80
  peerAid,
81
+ ...(installation.deviceId?.trim() ? { peerDeviceId: installation.deviceId.trim() } : {}),
82
+ ...(installation.slotId?.trim() ? { peerSlotId: installation.slotId.trim() } : {}),
56
83
  tokenHash: hashToken(menuToken),
57
- requestedAt: now,
58
- lastUsedAt: now,
84
+ requestedAt: issuedAt,
85
+ lastUsedAt: issuedAt,
59
86
  idleTimeout,
60
87
  ...(metadata.clientName ? { clientName: metadata.clientName } : {}),
61
88
  ...(metadata.clientVersion ? { clientVersion: metadata.clientVersion } : {}),
@@ -64,21 +91,27 @@ export class MenuTokenStore {
64
91
  this.write(selfAid, tokens);
65
92
  return { menuToken, idleTimeout };
66
93
  }
67
- use(selfAid, peerAid, menuToken, now = Date.now()) {
94
+ use(selfAid, peerAid, menuToken, installationOrNow = {}, now = Date.now()) {
95
+ const installation = normalizeInstallation(typeof installationOrNow === 'number' ? {} : installationOrNow);
96
+ if (!installation)
97
+ return false;
98
+ const usedAt = typeof installationOrNow === 'number' ? installationOrNow : now;
68
99
  const file = this.read(selfAid);
69
- const activeTokens = file.tokens.filter(record => !isExpired(record, now));
100
+ const activeTokens = file.tokens.filter(record => !isExpired(record, usedAt));
70
101
  const tokenHash = typeof menuToken === 'string' && menuToken.length > 0 && menuToken.length <= 256
71
102
  ? hashToken(menuToken)
72
103
  : undefined;
73
104
  const matchingIndex = tokenHash
74
- ? activeTokens.findIndex(record => record.peerAid === peerAid && hashesEqual(record.tokenHash, tokenHash))
105
+ ? activeTokens.findIndex(record => record.peerAid === peerAid
106
+ && installationMatches(record, installation)
107
+ && hashesEqual(record.tokenHash, tokenHash))
75
108
  : -1;
76
109
  if (matchingIndex < 0) {
77
110
  if (activeTokens.length !== file.tokens.length)
78
111
  this.write(selfAid, activeTokens);
79
112
  return false;
80
113
  }
81
- activeTokens[matchingIndex] = { ...activeTokens[matchingIndex], lastUsedAt: now };
114
+ activeTokens[matchingIndex] = { ...activeTokens[matchingIndex], lastUsedAt: usedAt };
82
115
  this.write(selfAid, activeTokens);
83
116
  return true;
84
117
  }
@@ -16,9 +16,9 @@ import { fileCache } from '../daemon-file-cache.js';
16
16
  import { currentVersion } from '../../config/schema-registry.js';
17
17
  import { loadSchema } from '../../config/schema-registry.js';
18
18
  import { rolePermissionFields, rolePermissionFieldOptions, rolePermissionFieldPatterns, validateRoleConfig, } from '../../config/role-schema.js';
19
- import { groupInfo, groupList, groupDirectoryErrorCode } from '../../aun/msg/group.js';
19
+ import { groupInfo, groupList, groupDirectoryErrorCode } from '../../aun/group/index.js';
20
20
  import { aidLookup, isValidAid } from '../../aun/aid/identity.js';
21
- import { isExplicitGroupId } from '../../aun/group-identity.js';
21
+ import { isExplicitGroupId } from '../../aun/group/index.js';
22
22
  import { readJsonFile, readLastJsonlLine, scanChatDirs, scanMetaFiles } from '../session/session-fs-store.js';
23
23
  import { constrainResolvedModelForRole } from '../model/model-permission.js';
24
24
  import { resolveRuntimePermissionMode, resolveRuntimeStringField } from '../role/runtime-policy.js';
@@ -45,7 +45,8 @@ export function probeSessionActivity(evidence, probes) {
45
45
  // 支持的命令列表
46
46
  const commands = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/stop', '/pause', '/compact', '/renew', '/repair', '/fork', '/del', '/perm', '/file', '/check', '/rewind', '/activity', '/observable', '/chatmode', '/mentionmode', '/ask', '/resume', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair'];
47
47
  const deprecatedCommands = ['/clear'];
48
- const exactBoundaryCommands = new Set(['/pause', '/resume', '/stop', '/pair']);
48
+ commands.push('/diag');
49
+ const exactBoundaryCommands = new Set(['/pause', '/resume', '/stop', '/pair', '/diag']);
49
50
  /** Parse the execution command without treating it as a quick/result command. */
50
51
  export function parseFullAccessCommand(content) {
51
52
  const match = content.match(/^\s*(\/fa|\/fullaccess)(?=\s|$)([\s\S]*)$/);
@@ -64,8 +65,37 @@ const aliases = {
64
65
  '/rw': '/rewind',
65
66
  '/base': '/baseagent',
66
67
  };
68
+ const GROUP_READ_ONLY_COMMANDS = new Set(['/mentionmode', '/model', '/effort', '/perm', '/baseagent']);
69
+ const GROUP_TASK_COMMANDS = new Set([
70
+ '/help', '/evolhelp', '/status', '/check', '/ask', '/pause', '/resume', '/stop', '/compact', '/renew',
71
+ ]);
72
+ /** Group slash policy applies to every role, including old command-card clicks. */
73
+ export function guardGroupSlashCommand(content, chatType) {
74
+ if (chatType !== 'group' || !content.trim().startsWith('/'))
75
+ return undefined;
76
+ const [inputCommand, ...args] = content.trim().split(/\s+/);
77
+ const command = aliases[inputCommand] ?? inputCommand;
78
+ if (GROUP_READ_ONLY_COMMANDS.has(command)) {
79
+ if (!args.length || (command === '/model' && args.length === 1 && ['current', 'list', 'check'].includes(args[0]))) {
80
+ return undefined;
81
+ }
82
+ return {
83
+ kind: 'command.error',
84
+ text: `❌ 群聊中 ${command} 仅支持查询,请在私聊或管理界面操作`,
85
+ reason: 'GROUP_COMMAND_READ_ONLY',
86
+ };
87
+ }
88
+ if (GROUP_TASK_COMMANDS.has(command))
89
+ return undefined;
90
+ return {
91
+ kind: 'command.error',
92
+ text: `❌ 群聊中不支持 ${inputCommand},输入 /help 查看可用命令`,
93
+ reason: 'GROUP_COMMAND_UNSUPPORTED',
94
+ };
95
+ }
67
96
  // 命令快速路径前缀(所有命令都不进入消息队列)
68
97
  const quickCommandPrefixes = ['/new', '/pwd', '/help', '/evolhelp', '/status', '/restart', '/reload', '/model', '/effort', '/baseagent', '/slist', '/session', '/rename', '/repair', '/fork', '/stop', '/pause', '/clear', '/compact', '/renew', '/del', '/perm', '/file', '/check', '/s ', '/name', '/rewind', '/rw', '/rw ', '/activity', '/observable', '/chatmode', '/mentionmode', '/ask', '/resume', '/base ', '/aid', '/rpc', '/storage', '/agent', '/trigger', '/upgrade', '/pair'];
98
+ quickCommandPrefixes.push('/diag');
69
99
  /**
70
100
  * 计算两个字符串的 Levenshtein 距离(编辑距离)
71
101
  */
@@ -95,7 +125,7 @@ function levenshteinDistance(str1, str2) {
95
125
  return matrix[len1][len2];
96
126
  }
97
127
  export function isQuickCommand(content) {
98
- return content === '/s' || quickCommandPrefixes.some(cmd => exactBoundaryCommands.has(cmd)
128
+ return content === '/s' || content === '/base' || quickCommandPrefixes.some(cmd => exactBoundaryCommands.has(cmd)
99
129
  ? content === cmd || content.startsWith(cmd + ' ')
100
130
  : content.startsWith(cmd));
101
131
  }
@@ -131,7 +161,7 @@ export function guardRoleCommand(content, activeChatType, isAdmin) {
131
161
  const userGroupCommands = [
132
162
  '/status', '/help', '/evolhelp', '/check', '/chatmode', '/mentionmode',
133
163
  '/model', '/effort', '/baseagent', '/perm', '/activity', '/stop', '/pause',
134
- '/resume', '/trigger', '/file',
164
+ '/resume', '/trigger', '/file', '/ask',
135
165
  ];
136
166
  const userCommands = activeChatType === 'group' && !isAdmin
137
167
  ? userGroupCommands
@@ -146,7 +176,7 @@ export function guardRoleCommand(content, activeChatType, isAdmin) {
146
176
  return {
147
177
  kind: 'command.error',
148
178
  text: activeChatType === 'group'
149
- ? '❌ 无权限:当前群聊仅支持 /status 和 /help'
179
+ ? '❌ 无权限:此命令仅限管理员使用,输入 /help 查看可用命令'
150
180
  : '❌ 无权限:此命令仅限管理员使用',
151
181
  };
152
182
  }