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
@@ -3,7 +3,7 @@ import fs from 'fs';
3
3
  import { CronExpressionParser } from 'cron-parser';
4
4
  import { logger } from '../utils/logger.js';
5
5
  import { matchTriggerEvent, TriggerEventSource } from './event-source.js';
6
- import { definitionRevision, parseDurationMs, previewText, renderTemplate, resolveScriptPath, sha256, validateConcurrencyCombination, } from './validation.js';
6
+ import { definitionRevision, executionTimeoutMs, parseDurationMs, previewText, renderTemplate, resolveScriptPath, sha256, validateConcurrencyCombination, } from './validation.js';
7
7
  import { TargetSessionLockRegistry } from './session-lock.js';
8
8
  import { enterTrigger, formatTriggerPath } from '../core/causation/context.js';
9
9
  import { createRootCausation } from '../core/causation/context.js';
@@ -13,6 +13,13 @@ const MAX_TIMER_MS = 2_147_483_647;
13
13
  const RUN_ABORT_SETTLE_GRACE_MS = 1_000;
14
14
  const RUN_COMPLETION_BARRIER_MS = 1_500;
15
15
  const TRIGGER_RESTART_RESUME_PROMPT = 'EvolCore 服务已重启。请基于当前会话记录继续完成刚才被中断的 Trigger 任务;不要重新从头执行已经完成的步骤。';
16
+ function eventSessionKey(payload, fallbackAgentAid) {
17
+ const agentAid = typeof payload.agentAid === 'string' && payload.agentAid.trim()
18
+ ? payload.agentAid.trim()
19
+ : fallbackAgentAid;
20
+ const sessionId = typeof payload.sessionId === 'string' ? payload.sessionId : '';
21
+ return `${agentAid}:${sessionId}`;
22
+ }
16
23
  export class TriggerRuntimeScheduler {
17
24
  manager;
18
25
  state;
@@ -818,6 +825,7 @@ export class TriggerRuntimeScheduler {
818
825
  attemptId: `${runId}:attempt:${attempt}`,
819
826
  firedAt,
820
827
  prompt,
828
+ sourcePayload,
821
829
  dryRun,
822
830
  causation,
823
831
  signal,
@@ -869,7 +877,17 @@ export class TriggerRuntimeScheduler {
869
877
  + ` model=${definition.execution.model ?? '<agent-default>'}`
870
878
  + ` effort=${definition.execution.effort ?? '<agent-default>'}`);
871
879
  const attemptId = `${runId}:attempt:${attempt}`;
872
- const executionDeadlineAt = this.daemonExecutionDeadlineAt(Date.now());
880
+ const executionStartedAt = Date.now();
881
+ const configuredExecutionTimeout = executionTimeoutMs(definition.execution);
882
+ const daemonExecutionDeadlineAt = this.daemonExecutionDeadlineAt(executionStartedAt);
883
+ const configuredExecutionDeadlineAt = configuredExecutionTimeout === undefined
884
+ ? undefined
885
+ : executionStartedAt + configuredExecutionTimeout;
886
+ const executionDeadlineAt = daemonExecutionDeadlineAt === undefined
887
+ ? configuredExecutionDeadlineAt
888
+ : configuredExecutionDeadlineAt === undefined
889
+ ? daemonExecutionDeadlineAt
890
+ : Math.min(daemonExecutionDeadlineAt, configuredExecutionDeadlineAt);
873
891
  const executionSession = await this.daemonChannel.getOrCreateConversationSession(definition, this.runtime.projectPath, runtimeBaseagent, runId, attemptId);
874
892
  const activeRun = this.state.startExecutionAttempt?.(definition.id, runId, {
875
893
  attempt,
@@ -963,7 +981,13 @@ export class TriggerRuntimeScheduler {
963
981
  });
964
982
  }
965
983
  async checkConcurrency(definition, nextRunId, source) {
966
- const runs = this.running.get(definition.id);
984
+ const allRuns = this.running.get(definition.id);
985
+ // An event-session trigger owns many independent sessions. Forbid/replace
986
+ // applies within the source session, so one failure cannot suppress another.
987
+ const runs = definition.feedback.strategy === 'event_session' && allRuns
988
+ ? new Map([...allRuns].filter(([, runtime]) => eventSessionKey(runtime.source.payload, definition.agentAid)
989
+ === eventSessionKey(source.payload, definition.agentAid)))
990
+ : allRuns;
967
991
  if (!runs || runs.size === 0 || definition.reliability.concurrency === 'allow')
968
992
  return undefined;
969
993
  const first = runs.values().next().value;
@@ -1753,7 +1777,7 @@ export class TriggerRuntimeScheduler {
1753
1777
  publishTriggerRunOutcome(definition, audit) {
1754
1778
  if (!this.eventBus || audit.status === 'dry-run')
1755
1779
  return;
1756
- const target = primaryTarget(definition);
1780
+ const target = audit.feedback?.target ?? primaryTarget(definition);
1757
1781
  const targetChannel = target?.channelKey ?? 'daemon';
1758
1782
  const targetChannelId = target?.channelId ?? definition.agentAid;
1759
1783
  const base = {
@@ -2027,6 +2051,8 @@ function summarizeReply(reply, opts = {}) {
2027
2051
  function primaryTarget(definition) {
2028
2052
  if (definition.feedback.strategy === 'target')
2029
2053
  return definition.feedback.target;
2054
+ if (definition.feedback.strategy === 'event_session')
2055
+ return undefined;
2030
2056
  if (!definition.origin)
2031
2057
  return undefined;
2032
2058
  return {
@@ -3,6 +3,8 @@ import crypto from 'crypto';
3
3
  import { normalizePermissionMode as normalizePermissionModeContract } from '../core/permission/mode.js';
4
4
  import { formatChannelKey } from '../core/channel-loader.js';
5
5
  const MAX_SCRIPT_TIMEOUT_MS = 900_000;
6
+ const TRIGGER_SESSION_TIMEOUT_MS = 30 * 60_000;
7
+ const MAX_EXECUTION_TIMEOUT_MS = 2_147_483_647;
6
8
  export const TRIGGER_SCHEMA_VERSION = 3.1;
7
9
  const LEGACY_TRIGGER_SCHEMA_VERSION = 4;
8
10
  const DEFAULT_NOOP_SENTINEL = '[[NOOP]]';
@@ -35,7 +37,7 @@ export function normalizeTriggerDefinition(input, opts = {}) {
35
37
  * channelId shape inference at runtime.
36
38
  */
37
39
  export function assertExplicitAunDeliveryRoutes(definition) {
38
- if (definition.feedback.strategy === 'silent')
40
+ if (definition.feedback.strategy === 'silent' || definition.feedback.strategy === 'event_session')
39
41
  return;
40
42
  const target = definition.feedback.strategy === 'target'
41
43
  ? definition.feedback.target
@@ -58,6 +60,11 @@ export function assertExplicitAunDeliveryRoutes(definition) {
58
60
  export function validateTriggerDefinition(definition) {
59
61
  normalizeTriggerDefinition(definition);
60
62
  }
63
+ /** Resolve a model-backed attempt's deadline; target sessions are unlimited by default. */
64
+ export function executionTimeoutMs(execution) {
65
+ return execution.timeoutMs ?? (execution.type === 'target_session'
66
+ ? undefined : TRIGGER_SESSION_TIMEOUT_MS);
67
+ }
61
68
  /**
62
69
  * Keep legacy `per_run` definitions byte-stable while giving runtime code one
63
70
  * canonical representation for session selection and validation.
@@ -428,8 +435,14 @@ function normalizeExecution(value, _opts) {
428
435
  throw new Error('execution.type must be script, trigger_session, or target_session');
429
436
  }
430
437
  const thread = normalizeExecutionThread(raw.thread);
438
+ if (raw.timeoutMs !== undefined && (type === 'script'
439
+ || typeof raw.timeoutMs !== 'number' || !Number.isSafeInteger(raw.timeoutMs)
440
+ || raw.timeoutMs <= 0 || raw.timeoutMs > MAX_EXECUTION_TIMEOUT_MS)) {
441
+ throw new Error('execution.timeoutMs must be an integer between 1 and 2147483647 for a model-backed Trigger');
442
+ }
431
443
  const execution = {
432
444
  type,
445
+ ...(raw.timeoutMs !== undefined ? { timeoutMs: raw.timeoutMs } : {}),
433
446
  prompt: type === 'script' ? optionalString(raw.prompt) : requiredString(raw.prompt, 'execution.prompt'),
434
447
  script: type === 'script' ? normalizeScript(raw.script) : undefined,
435
448
  thread: type === 'trigger_session' ? (thread ?? 'by_trigger') : thread,
@@ -511,8 +524,8 @@ function normalizeFeedback(value, agentAid) {
511
524
  throw new Error('feedback must be an object');
512
525
  const raw = value;
513
526
  const strategy = requiredString(raw.strategy, 'feedback.strategy');
514
- if (strategy !== 'origin' && strategy !== 'target' && strategy !== 'silent') {
515
- throw new Error('feedback.strategy must be origin, target, or silent');
527
+ if (strategy !== 'origin' && strategy !== 'target' && strategy !== 'event_session' && strategy !== 'silent') {
528
+ throw new Error('feedback.strategy must be origin, target, event_session, or silent');
516
529
  }
517
530
  return {
518
531
  strategy,
@@ -630,6 +643,10 @@ function normalizeOnError(value) {
630
643
  }
631
644
  function validateTriggerSemantics(definition) {
632
645
  const execution = definition.execution;
646
+ if (definition.feedback.strategy === 'event_session'
647
+ && (definition.source.type !== 'event' || execution.type !== 'target_session')) {
648
+ throw new Error('feedback.strategy=event_session requires an event source and target_session execution');
649
+ }
633
650
  if (execution.type === 'script') {
634
651
  if (!execution.script)
635
652
  throw new Error('execution.script is required when execution.type=script');
@@ -449,7 +449,10 @@ export function resolveCliEntry(packageRoot) {
449
449
  try {
450
450
  const require = createRequire(path.join(packageRoot, 'package.json'));
451
451
  const tsxUrl = pathToFileURL(require.resolve('tsx')).href;
452
- return { args: ['--import', tsxUrl, sourceEntry], usingSource: true, entry: sourceEntry };
452
+ const imports = process.platform === 'win32'
453
+ ? ['--import', 'data:text/javascript,globalThis.process.geteuid=()=>-1', '--import', tsxUrl]
454
+ : ['--import', tsxUrl];
455
+ return { args: [...imports, sourceEntry], usingSource: true, entry: sourceEntry };
453
456
  }
454
457
  catch {
455
458
  // tsx missing (e.g. `npm prune --production`): fall through to dist.
@@ -488,11 +491,37 @@ export function encodePath(projectPath) {
488
491
  /**
489
492
  * Cross-platform process liveness check.
490
493
  */
494
+ function readLinuxProcessState(pid) {
495
+ if (process.platform !== 'linux')
496
+ return null;
497
+ try {
498
+ const stat = fs.readFileSync(`/proc/${pid}/stat`, 'utf8');
499
+ // The comm field may contain ')', so use the final closing parenthesis.
500
+ const closeParen = stat.lastIndexOf(')');
501
+ if (closeParen < 0)
502
+ return null;
503
+ return stat.slice(closeParen + 2, closeParen + 3) || null;
504
+ }
505
+ catch {
506
+ // Keep the kill(0) fallback below for permission and procfs races.
507
+ return null;
508
+ }
509
+ }
510
+ /** Return the Linux proc state (for example Z, D, S, or R), when available. */
511
+ export function getProcessState(pid) {
512
+ if (!Number.isInteger(pid) || pid <= 0)
513
+ return null;
514
+ return readLinuxProcessState(pid);
515
+ }
491
516
  export function isProcessRunning(pid) {
492
517
  if (!Number.isInteger(pid) || pid <= 0)
493
518
  return false;
494
519
  if (isWindows)
495
520
  return isWindowsProcessRunning(pid);
521
+ // A zombie has exited; only its unreaped process-table entry remains. A
522
+ // kill(pid, 0) probe alone reports such an entry as alive on Linux.
523
+ if (readLinuxProcessState(pid) === 'Z')
524
+ return false;
496
525
  try {
497
526
  process.kill(pid, 0);
498
527
  return true;
@@ -70,6 +70,7 @@ export async function fetchRemotePairingCode(authorizedBy) {
70
70
  try {
71
71
  const response = await ipcQuery(resolvePaths().socket, {
72
72
  type: 'remote-auth.pair-code',
73
+ source: 'host-cli',
73
74
  ...(authorizedBy?.trim() ? { authorizedBy: authorizedBy.trim() } : {}),
74
75
  }, 2_000);
75
76
  if (!response?.ok || typeof response.code !== 'string' || typeof response.expiresAt !== 'number')
@@ -1,160 +1,160 @@
1
- {
2
- "rules": [
3
- {
4
- "id": "context-too-long-cn",
5
- "match": "上下文过长",
6
- "action": "stop",
7
- "type": "context_too_long",
8
- "message": "⚠️ 上下文过长,请手动输入 /compact 压缩上下文"
9
- },
10
- {
11
- "id": "context-too-long-en",
12
- "match": "context too long",
13
- "action": "stop",
14
- "type": "context_too_long",
15
- "message": "⚠️ 上下文过长,请手动输入 /compact 压缩上下文"
16
- },
17
- {
18
- "id": "prompt-too-long",
19
- "match": "prompt is too long",
20
- "action": "stop",
21
- "type": "context_too_long",
22
- "message": "⚠️ 输入过长,请精简提问或使用 /compact 压缩上下文"
23
- },
24
- {
25
- "id": "invalid-api-key",
26
- "match": "invalid api key",
27
- "action": "stop",
28
- "type": "auth_error",
29
- "message": "❌ API Key 无效,请检查密钥配置。使用 /status 查看当前配置"
30
- },
31
- {
32
- "id": "key-not-found",
33
- "match": "key_not_found",
34
- "action": "stop",
35
- "type": "auth_error",
36
- "message": "❌ API Key 未找到,请检查密钥配置"
37
- },
38
- {
39
- "id": "api-key-verifier-too-many-connections",
40
- "match": "error 1040 (08004): too many connections",
41
- "action": "retry",
42
- "type": "api_error",
43
- "message": "⚠️ API 服务繁忙,请稍后重试"
44
- },
45
- {
46
- "id": "credit-query-timeout",
47
- "match": "积分查询超时",
48
- "action": "retry",
49
- "type": "api_error",
50
- "message": "⚠️ 积分查询超时,请稍后重试"
51
- },
52
- {
53
- "id": "capacity-pool-switching-cn",
54
- "match": "算力池切换",
55
- "action": "retry",
56
- "type": "api_error",
57
- "message": "⚠️ 当前算力池切换中,请稍后重试"
58
- },
59
- {
60
- "id": "retry-attempt-stalled",
61
- "match": "retry_attempt_stalled",
62
- "action": "retry",
63
- "type": "api_error",
64
- "message": "⚠️ API 重试调用长时间无响应"
65
- },
66
- {
67
- "id": "selected-model-at-capacity",
68
- "match": "selected model is at capacity",
69
- "action": "retry",
70
- "type": "api_error",
71
- "message": "⚠️ 当前模型繁忙,请稍后重试"
72
- },
73
- {
74
- "id": "api-error-400",
75
- "match": "api error: 400",
76
- "action": "stop",
77
- "type": "api_error",
78
- "message": "❌ 请求格式错误,请检查输入内容"
79
- },
80
- {
81
- "id": "model-not-supported-403",
82
- "match": "api error: 403 不支持该模型",
83
- "action": "stop",
84
- "type": "model_unavailable",
85
- "message": "❌ 当前模型不受支持,请正确配置模型后重试"
86
- },
87
- {
88
- "id": "api-error-403",
89
- "match": "api error: 403",
90
- "action": "retry",
91
- "type": "api_error",
92
- "message": "⚠️ API 访问受限,请稍后重试"
93
- },
94
- {
95
- "id": "api-error-429",
96
- "match": "api error: 429",
97
- "action": "retry",
98
- "type": "api_error",
99
- "message": "⚠️ 请求过于频繁,请稍后重试"
100
- },
101
- {
102
- "id": "api-error-500",
103
- "match": "api error: 500",
104
- "action": "retry",
105
- "type": "api_error",
106
- "message": "❌ API 服务暂时不可用,请稍后重试"
107
- },
108
- {
109
- "id": "api-error-502",
110
- "match": "api error: 502",
111
- "action": "retry",
112
- "type": "api_error"
113
- },
114
- {
115
- "id": "api-error-503",
116
- "match": "api error: 503",
117
- "action": "retry",
118
- "type": "api_error"
119
- },
120
- {
121
- "id": "api-error-504",
122
- "match": "api error: 504",
123
- "action": "retry",
124
- "type": "api_error"
125
- },
126
- {
127
- "id": "not-valid-json",
128
- "match": "is not valid json",
129
- "action": "retry",
130
- "type": "api_error",
131
- "message": "⚠️ API 返回异常响应,请稍后重试"
132
- },
133
- {
134
- "id": "json-parse-error",
135
- "match": "json parse error",
136
- "action": "retry",
137
- "type": "api_error",
138
- "message": "⚠️ API 返回 JSON 解析异常,请稍后重试"
139
- },
140
- {
141
- "id": "feishu-permission",
142
- "match": "im:resource",
143
- "action": "stop",
144
- "type": "unknown",
145
- "message": "❌ 权限不足,请联系管理员配置应用权限"
146
- },
147
- {
148
- "id": "stream-error",
149
- "match": "stream",
150
- "action": "retry",
151
- "type": "stream_error"
152
- },
153
- {
154
- "id": "request-aborted",
155
- "match": "request was aborted",
156
- "action": "ignore",
157
- "type": "stream_error"
158
- }
159
- ]
160
- }
1
+ {
2
+ "rules": [
3
+ {
4
+ "id": "context-too-long-cn",
5
+ "match": "上下文过长",
6
+ "action": "stop",
7
+ "type": "context_too_long",
8
+ "message": "⚠️ 上下文过长,请手动输入 /compact 压缩上下文"
9
+ },
10
+ {
11
+ "id": "context-too-long-en",
12
+ "match": "context too long",
13
+ "action": "stop",
14
+ "type": "context_too_long",
15
+ "message": "⚠️ 上下文过长,请手动输入 /compact 压缩上下文"
16
+ },
17
+ {
18
+ "id": "prompt-too-long",
19
+ "match": "prompt is too long",
20
+ "action": "stop",
21
+ "type": "context_too_long",
22
+ "message": "⚠️ 输入过长,请精简提问或使用 /compact 压缩上下文"
23
+ },
24
+ {
25
+ "id": "invalid-api-key",
26
+ "match": "invalid api key",
27
+ "action": "stop",
28
+ "type": "auth_error",
29
+ "message": "❌ API Key 无效,请检查密钥配置。使用 /status 查看当前配置"
30
+ },
31
+ {
32
+ "id": "key-not-found",
33
+ "match": "key_not_found",
34
+ "action": "stop",
35
+ "type": "auth_error",
36
+ "message": "❌ API Key 未找到,请检查密钥配置"
37
+ },
38
+ {
39
+ "id": "api-key-verifier-too-many-connections",
40
+ "match": "error 1040 (08004): too many connections",
41
+ "action": "retry",
42
+ "type": "api_error",
43
+ "message": "⚠️ API 服务繁忙,请稍后重试"
44
+ },
45
+ {
46
+ "id": "credit-query-timeout",
47
+ "match": "积分查询超时",
48
+ "action": "retry",
49
+ "type": "api_error",
50
+ "message": "⚠️ 积分查询超时,请稍后重试"
51
+ },
52
+ {
53
+ "id": "capacity-pool-switching-cn",
54
+ "match": "算力池切换",
55
+ "action": "retry",
56
+ "type": "api_error",
57
+ "message": "⚠️ 当前算力池切换中,请稍后重试"
58
+ },
59
+ {
60
+ "id": "retry-attempt-stalled",
61
+ "match": "retry_attempt_stalled",
62
+ "action": "retry",
63
+ "type": "api_error",
64
+ "message": "⚠️ API 重试调用长时间无响应"
65
+ },
66
+ {
67
+ "id": "selected-model-at-capacity",
68
+ "match": "selected model is at capacity",
69
+ "action": "retry",
70
+ "type": "api_error",
71
+ "message": "⚠️ 当前模型繁忙,请稍后重试"
72
+ },
73
+ {
74
+ "id": "api-error-400",
75
+ "match": "api error: 400",
76
+ "action": "stop",
77
+ "type": "api_error",
78
+ "message": "❌ 请求格式错误,请检查输入内容"
79
+ },
80
+ {
81
+ "id": "model-not-supported-403",
82
+ "match": "api error: 403 不支持该模型",
83
+ "action": "stop",
84
+ "type": "model_unavailable",
85
+ "message": "❌ 当前模型不受支持,请正确配置模型后重试"
86
+ },
87
+ {
88
+ "id": "api-error-403",
89
+ "match": "api error: 403",
90
+ "action": "retry",
91
+ "type": "api_error",
92
+ "message": "⚠️ API 访问受限,请稍后重试"
93
+ },
94
+ {
95
+ "id": "api-error-429",
96
+ "match": "api error: 429",
97
+ "action": "retry",
98
+ "type": "api_error",
99
+ "message": "⚠️ 请求过于频繁,请稍后重试"
100
+ },
101
+ {
102
+ "id": "api-error-500",
103
+ "match": "api error: 500",
104
+ "action": "retry",
105
+ "type": "api_error",
106
+ "message": "❌ API 服务暂时不可用,请稍后重试"
107
+ },
108
+ {
109
+ "id": "api-error-502",
110
+ "match": "api error: 502",
111
+ "action": "retry",
112
+ "type": "api_error"
113
+ },
114
+ {
115
+ "id": "api-error-503",
116
+ "match": "api error: 503",
117
+ "action": "retry",
118
+ "type": "api_error"
119
+ },
120
+ {
121
+ "id": "api-error-504",
122
+ "match": "api error: 504",
123
+ "action": "retry",
124
+ "type": "api_error"
125
+ },
126
+ {
127
+ "id": "not-valid-json",
128
+ "match": "is not valid json",
129
+ "action": "retry",
130
+ "type": "api_error",
131
+ "message": "⚠️ API 返回异常响应,请稍后重试"
132
+ },
133
+ {
134
+ "id": "json-parse-error",
135
+ "match": "json parse error",
136
+ "action": "retry",
137
+ "type": "api_error",
138
+ "message": "⚠️ API 返回 JSON 解析异常,请稍后重试"
139
+ },
140
+ {
141
+ "id": "feishu-permission",
142
+ "match": "im:resource",
143
+ "action": "stop",
144
+ "type": "unknown",
145
+ "message": "❌ 权限不足,请联系管理员配置应用权限"
146
+ },
147
+ {
148
+ "id": "stream-error",
149
+ "match": "stream",
150
+ "action": "retry",
151
+ "type": "stream_error"
152
+ },
153
+ {
154
+ "id": "request-aborted",
155
+ "match": "request was aborted",
156
+ "action": "ignore",
157
+ "type": "stream_error"
158
+ }
159
+ ]
160
+ }
@@ -3,7 +3,36 @@ import path from 'path';
3
3
  import { getPackageRoot, resolvePaths } from '../paths.js';
4
4
  import { logger } from './logger.js';
5
5
  import { isSandboxInitializationFailure } from '../core/permission/sandbox-runtime.js';
6
+ /** A deadline imposed by an outer executor, handled by the ordinary task timeout path. */
7
+ export class ExecutionTimeoutError extends Error {
8
+ reason;
9
+ timeoutMs;
10
+ constructor(reason, timeoutMs) {
11
+ super('TOTAL_EXECUTION_TIMEOUT');
12
+ this.reason = reason;
13
+ this.timeoutMs = timeoutMs;
14
+ this.name = 'ExecutionTimeoutError';
15
+ }
16
+ }
17
+ export class OrphanedTargetSessionError extends Error {
18
+ reason = 'orphaned_target_session';
19
+ constructor() {
20
+ super('ORPHANED_TARGET_SESSION');
21
+ this.name = 'OrphanedTargetSessionError';
22
+ }
23
+ }
24
+ export function isExecutionFailure(error) {
25
+ return error instanceof ExecutionTimeoutError || error instanceof OrphanedTargetSessionError;
26
+ }
6
27
  export const CLAUDE_STARTUP_ARGUMENTS_TOO_LONG = 'claude_startup_arguments_too_long';
28
+ /** A completed provider response exhausted its output budget, rather than a transport failure. */
29
+ export function isOutputTokenLimitError(error) {
30
+ const record = error && typeof error === 'object' ? error : undefined;
31
+ const message = String(record?.message ?? error ?? '');
32
+ return record?.code === 'max_output_tokens'
33
+ || /^\s*max_output_tokens\s*$/i.test(message)
34
+ || /\breason["']?\s*[:=]\s*["']?max_output_tokens\b/i.test(message);
35
+ }
7
36
  /** Identify a Claude process-start failure without treating ordinary tool errors as startup failures. */
8
37
  export function isClaudeStartupArgumentsTooLong(error) {
9
38
  const code = error && typeof error === 'object' && 'code' in error
@@ -36,6 +65,7 @@ export var ErrorType;
36
65
  ErrorType["AUTH_ERROR"] = "auth_error";
37
66
  ErrorType["FILE_CORRUPT"] = "file_corrupt";
38
67
  ErrorType["STREAM_ERROR"] = "stream_error";
68
+ ErrorType["MAX_OUTPUT_TOKENS"] = "max_output_tokens";
39
69
  ErrorType["CONTEXT_TOO_LONG"] = "context_too_long";
40
70
  ErrorType["MODEL_UNAVAILABLE"] = "model_unavailable";
41
71
  ErrorType["SESSION_UNAVAILABLE"] = "session_unavailable";
@@ -78,6 +108,7 @@ const NON_INFRA_SUBTYPES = new Set([
78
108
  'stop',
79
109
  ]);
80
110
  const NON_INFRA_TERMINAL_REASONS = new Set([
111
+ 'max_output_tokens',
81
112
  'rapid_refill_breaker',
82
113
  'tool_deferred',
83
114
  'stop_hook_prevented',
@@ -278,7 +309,18 @@ function hasRetryableHttpStatus(text) {
278
309
  return RETRYABLE_HTTP_STATUS_PATTERN.test(text);
279
310
  }
280
311
  export function classifyError(error) {
312
+ if (error?.code === 'RUNNER_INTERRUPT_UNCONFIRMED')
313
+ return ErrorType.SESSION_UNAVAILABLE;
281
314
  const msg = (error?.message || '').toLowerCase();
315
+ // A damaged ecagent JSONL transcript is deterministic local state. Retrying
316
+ // the provider request cannot repair it and can append more entries to the
317
+ // same unusable file.
318
+ if (msg.includes('invalid jsonl session file') || msg.includes('invalid session file')) {
319
+ return ErrorType.SESSION_UNAVAILABLE;
320
+ }
321
+ // The broad dictionary rule for "stream" must not hide a provider budget limit.
322
+ if (isOutputTokenLimitError(error))
323
+ return ErrorType.MAX_OUTPUT_TOKENS;
282
324
  if (error?.code === 'TOPIC_BACKEND_UNAVAILABLE') {
283
325
  return ErrorType.SESSION_UNAVAILABLE;
284
326
  }
@@ -333,8 +375,15 @@ export function classifyError(error) {
333
375
  * 注意:401 认证错误不可重试(API Key 无效不会因重试恢复)
334
376
  */
335
377
  export function isRetryableError(error) {
378
+ if (error?.code === 'RUNNER_INTERRUPT_UNCONFIRMED')
379
+ return false;
380
+ // Replaying the same request does not increase its output budget.
381
+ if (isOutputTokenLimitError(error))
382
+ return false;
336
383
  const msg = error?.message || String(error);
337
384
  const lower = msg.toLowerCase();
385
+ if (lower.includes('invalid jsonl session file') || lower.includes('invalid session file'))
386
+ return false;
338
387
  // 字典优先 — 命中则直接返回
339
388
  const rule = matchErrorRule(lower);
340
389
  if (rule)
@@ -350,6 +399,13 @@ export function isRetryableError(error) {
350
399
  return false;
351
400
  }
352
401
  export function getErrorMessage(error, terminalReason, includeEmoji = true) {
402
+ if (error?.code === 'RUNNER_INTERRUPT_UNCONFIRMED')
403
+ return `${includeEmoji ? '⚠️ ' : ''}${error.message}`;
404
+ if (terminalReason === 'max_output_tokens' || isOutputTokenLimitError(error)) {
405
+ const prefix = includeEmoji ? '⚠️ ' : '';
406
+ return `${prefix}模型响应达到输出上限(max_output_tokens),本轮未完成。`
407
+ + '请降低推理强度或提高模型服务的输出预算,然后在原会话发送“继续,先核对已完成操作,只完成剩余工作”;无需重发原任务。';
408
+ }
353
409
  if (isClaudeStartupArgumentsTooLong(error)) {
354
410
  const prefix = includeEmoji ? '⚠️ ' : '';
355
411
  return `${prefix}当前 Claude 启动参数过长,任务未执行`;
@@ -374,7 +430,7 @@ export function getErrorMessage(error, terminalReason, includeEmoji = true) {
374
430
  case 'permission_denied':
375
431
  return `${prefix}权限被拒绝,操作已取消`;
376
432
  case 'sandbox_initialization_failed':
377
- return `${warnPrefix}只读执行沙箱启动失败(sandbox_initialization_failed),当前任务未执行;请检查 user namespace/seccomp 配置后重试`;
433
+ return `${warnPrefix}执行沙箱启动失败(sandbox_initialization_failed),当前操作未执行;请检查文件系统挂载规则及 user namespace/seccomp 配置`;
378
434
  case 'claude_startup_arguments_too_long':
379
435
  return `${warnPrefix}当前 Claude 启动参数过长,任务未执行`;
380
436
  case 'aborted_streaming':
@@ -386,6 +442,9 @@ export function getErrorMessage(error, terminalReason, includeEmoji = true) {
386
442
  const msg = error?.message || String(error);
387
443
  const warnPrefix = includeEmoji ? '⚠️ ' : '';
388
444
  const errPrefix = includeEmoji ? '❌ ' : '';
445
+ if (/invalid (?:jsonl )?session file/i.test(msg)) {
446
+ return `${errPrefix}ecagent 会话文件损坏,已停止自动重试;请使用 /repair 或 /new 恢复会话`;
447
+ }
389
448
  // Codex app-server reports this when another app-server still owns the
390
449
  // thread writer. Surface the handoff condition instead of hiding it behind
391
450
  // the generic "processing failed" message.
@@ -408,7 +467,7 @@ export function getErrorMessage(error, terminalReason, includeEmoji = true) {
408
467
  : `${warnPrefix}上下文过长,自动压缩失败,请手动输入 /compact 重试`;
409
468
  }
410
469
  if (isSandboxInitializationFailure(error)) {
411
- return `${warnPrefix}只读执行沙箱启动失败(sandbox_initialization_failed),当前任务未执行;请检查 user namespace/seccomp 配置后重试`;
470
+ return `${warnPrefix}执行沙箱启动失败(sandbox_initialization_failed),当前操作未执行;请检查文件系统挂载规则及 user namespace/seccomp 配置`;
412
471
  }
413
472
  if (msg.includes('401') || msg.includes('authentication_error') || msg.toLowerCase().includes('unauthorized')) {
414
473
  return `${errPrefix}API Key 无效,请检查密钥配置。使用 /status 查看当前配置`;