evolcore 0.0.7 → 0.0.9

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 (230) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +38 -4
  3. package/dist/agents/baseagent.js +117 -24
  4. package/dist/agents/claude-runner.js +31 -2
  5. package/dist/agents/codex-app-server-client.js +37 -2
  6. package/dist/agents/codex-runner.js +11 -3
  7. package/dist/aun/aid/control-aid.js +40 -27
  8. package/dist/aun/aid/domain.js +23 -0
  9. package/dist/aun/msg/group.js +9 -9
  10. package/dist/aun/msg/p2p.js +11 -6
  11. package/dist/aun/msg/upload.js +43 -29
  12. package/dist/aun/outbox.js +48 -5
  13. package/dist/channels/aun.js +225 -71
  14. package/dist/cli/aun-commands.js +10 -7
  15. package/dist/cli/bench.js +4 -3
  16. package/dist/cli/daemon-commands.js +208 -68
  17. package/dist/cli/data-command.js +62 -35
  18. package/dist/cli/index.js +11 -1
  19. package/dist/cli/init-channel.js +1 -1
  20. package/dist/cli/init.js +112 -17
  21. package/dist/cli/model.js +5 -5
  22. package/dist/cli/restart-monitor.js +102 -22
  23. package/dist/config/builtin-role-templates.js +4 -3
  24. package/dist/config/config-field-policy.js +6 -2
  25. package/dist/config/config-manager.js +79 -11
  26. package/dist/config/gateway-config.js +80 -35
  27. package/dist/config/role-schema.js +18 -3
  28. package/dist/config/role-service.js +3 -3
  29. package/dist/config/role-store.js +4 -3
  30. package/dist/config-store.js +19 -3
  31. package/dist/core/auth/operation-authorizer.js +3 -1
  32. package/dist/core/baseagent-loader.js +5 -3
  33. package/dist/core/bootstrap-service.js +0 -12
  34. package/dist/core/capability/providers/codex-capability-provider.js +2 -2
  35. package/dist/core/channel-loader.js +15 -2
  36. package/dist/core/command/command-handler.js +1 -1
  37. package/dist/core/command/evol-menu-version-gate.js +3 -2
  38. package/dist/core/command/menu-handler.js +50 -28
  39. package/dist/core/command/menu-protocol.js +7 -4
  40. package/dist/core/command/slash-handler.js +4 -4
  41. package/dist/core/data-migration.js +517 -24
  42. package/dist/core/inference/text-inference.js +18 -5
  43. package/dist/core/message/message-bridge.js +17 -6
  44. package/dist/core/message/response-engine.js +22 -3
  45. package/dist/core/model/config-scope.js +3 -3
  46. package/dist/core/permission/tool-policy.js +18 -0
  47. package/dist/core/protected-paths.js +12 -1
  48. package/dist/index.js +794 -725
  49. package/dist/ipc.js +3 -1
  50. package/dist/product.js +1 -0
  51. package/dist/utils/autostart.js +27 -0
  52. package/dist/utils/codex-cli.js +39 -0
  53. package/dist/utils/cross-platform.js +147 -18
  54. package/dist/utils/ecweb-utils.js +15 -2
  55. package/dist/utils/instance-registry.js +43 -6
  56. package/dist/utils/macos-autostart.js +179 -0
  57. package/dist/utils/process-introspect.js +7 -3
  58. package/dist/utils/windows-autostart.js +130 -0
  59. package/ecagent/dist/agent-loop.d.ts +1 -1
  60. package/ecagent/dist/agent-loop.js +1 -1
  61. package/ecagent/dist/agent.d.ts +1 -1
  62. package/ecagent/dist/agent.js +1 -1
  63. package/ecagent/dist/harness/agent-harness.d.ts +1 -1
  64. package/ecagent/dist/harness/compaction/branch-summarization.d.ts +1 -1
  65. package/ecagent/dist/harness/compaction/compaction.d.ts +1 -1
  66. package/ecagent/dist/harness/compaction/utils.d.ts +1 -1
  67. package/ecagent/dist/harness/messages.d.ts +1 -1
  68. package/ecagent/dist/harness/session/session.d.ts +1 -1
  69. package/ecagent/dist/harness/types.d.ts +1 -1
  70. package/ecagent/dist/proxy.d.ts +1 -1
  71. package/ecagent/dist/proxy.js +1 -1
  72. package/ecagent/dist/types.d.ts +1 -1
  73. package/kits/migrations/migrate-role-config-v5.mjs +27 -2
  74. package/kits/rules/01-overview.md +3 -2
  75. package/kits/schemas/_meta.json +2 -1
  76. package/kits/schemas/agent-config.schema.10.json +19 -1
  77. package/kits/schemas/daemon.schema.4.json +136 -0
  78. package/kits/schemas/defaults.schema.4.json +15 -1
  79. package/kits/schemas/relation-config.schema.8.json +22 -1
  80. package/kits/schemas/role-config.schema.1.json +2 -2
  81. package/package.json +2 -4
  82. package/ecagent/dist/agent-loop.d.ts.map +0 -1
  83. package/ecagent/dist/agent-loop.js.map +0 -1
  84. package/ecagent/dist/agent.d.ts.map +0 -1
  85. package/ecagent/dist/agent.js.map +0 -1
  86. package/ecagent/dist/harness/agent-harness.d.ts.map +0 -1
  87. package/ecagent/dist/harness/agent-harness.js.map +0 -1
  88. package/ecagent/dist/harness/compaction/branch-summarization.d.ts.map +0 -1
  89. package/ecagent/dist/harness/compaction/branch-summarization.js.map +0 -1
  90. package/ecagent/dist/harness/compaction/compaction.d.ts.map +0 -1
  91. package/ecagent/dist/harness/compaction/compaction.js.map +0 -1
  92. package/ecagent/dist/harness/compaction/utils.d.ts.map +0 -1
  93. package/ecagent/dist/harness/compaction/utils.js.map +0 -1
  94. package/ecagent/dist/harness/env/nodejs.d.ts.map +0 -1
  95. package/ecagent/dist/harness/env/nodejs.js.map +0 -1
  96. package/ecagent/dist/harness/messages.d.ts.map +0 -1
  97. package/ecagent/dist/harness/messages.js.map +0 -1
  98. package/ecagent/dist/harness/prompt-templates.d.ts.map +0 -1
  99. package/ecagent/dist/harness/prompt-templates.js.map +0 -1
  100. package/ecagent/dist/harness/session/jsonl-repo.d.ts.map +0 -1
  101. package/ecagent/dist/harness/session/jsonl-repo.js.map +0 -1
  102. package/ecagent/dist/harness/session/jsonl-storage.d.ts.map +0 -1
  103. package/ecagent/dist/harness/session/jsonl-storage.js.map +0 -1
  104. package/ecagent/dist/harness/session/memory-repo.d.ts.map +0 -1
  105. package/ecagent/dist/harness/session/memory-repo.js.map +0 -1
  106. package/ecagent/dist/harness/session/memory-storage.d.ts.map +0 -1
  107. package/ecagent/dist/harness/session/memory-storage.js.map +0 -1
  108. package/ecagent/dist/harness/session/repo-utils.d.ts.map +0 -1
  109. package/ecagent/dist/harness/session/repo-utils.js.map +0 -1
  110. package/ecagent/dist/harness/session/session.d.ts.map +0 -1
  111. package/ecagent/dist/harness/session/session.js.map +0 -1
  112. package/ecagent/dist/harness/session/uuid.d.ts.map +0 -1
  113. package/ecagent/dist/harness/session/uuid.js.map +0 -1
  114. package/ecagent/dist/harness/skills.d.ts.map +0 -1
  115. package/ecagent/dist/harness/skills.js.map +0 -1
  116. package/ecagent/dist/harness/system-prompt.d.ts.map +0 -1
  117. package/ecagent/dist/harness/system-prompt.js.map +0 -1
  118. package/ecagent/dist/harness/types.d.ts.map +0 -1
  119. package/ecagent/dist/harness/types.js.map +0 -1
  120. package/ecagent/dist/harness/utils/shell-output.d.ts.map +0 -1
  121. package/ecagent/dist/harness/utils/shell-output.js.map +0 -1
  122. package/ecagent/dist/harness/utils/truncate.d.ts.map +0 -1
  123. package/ecagent/dist/harness/utils/truncate.js.map +0 -1
  124. package/ecagent/dist/index.d.ts.map +0 -1
  125. package/ecagent/dist/index.js.map +0 -1
  126. package/ecagent/dist/node.d.ts.map +0 -1
  127. package/ecagent/dist/node.js.map +0 -1
  128. package/ecagent/dist/proxy.d.ts.map +0 -1
  129. package/ecagent/dist/proxy.js.map +0 -1
  130. package/ecagent/dist/runtime/api/lazy.d.ts.map +0 -1
  131. package/ecagent/dist/runtime/api/lazy.js.map +0 -1
  132. package/ecagent/dist/runtime/api/pi-messages.d.ts.map +0 -1
  133. package/ecagent/dist/runtime/api/pi-messages.js.map +0 -1
  134. package/ecagent/dist/runtime/api/pi-messages.lazy.d.ts.map +0 -1
  135. package/ecagent/dist/runtime/api/pi-messages.lazy.js.map +0 -1
  136. package/ecagent/dist/runtime/auth/context.d.ts.map +0 -1
  137. package/ecagent/dist/runtime/auth/context.js.map +0 -1
  138. package/ecagent/dist/runtime/auth/credential-store.d.ts.map +0 -1
  139. package/ecagent/dist/runtime/auth/credential-store.js.map +0 -1
  140. package/ecagent/dist/runtime/auth/helpers.d.ts.map +0 -1
  141. package/ecagent/dist/runtime/auth/helpers.js.map +0 -1
  142. package/ecagent/dist/runtime/auth/resolve.d.ts.map +0 -1
  143. package/ecagent/dist/runtime/auth/resolve.js.map +0 -1
  144. package/ecagent/dist/runtime/auth/types.d.ts.map +0 -1
  145. package/ecagent/dist/runtime/auth/types.js.map +0 -1
  146. package/ecagent/dist/runtime/compat.d.ts.map +0 -1
  147. package/ecagent/dist/runtime/compat.js.map +0 -1
  148. package/ecagent/dist/runtime/index.d.ts.map +0 -1
  149. package/ecagent/dist/runtime/index.js.map +0 -1
  150. package/ecagent/dist/runtime/models.d.ts.map +0 -1
  151. package/ecagent/dist/runtime/models.js.map +0 -1
  152. package/ecagent/dist/runtime/oauth.d.ts.map +0 -1
  153. package/ecagent/dist/runtime/oauth.js.map +0 -1
  154. package/ecagent/dist/runtime/providers/faux.d.ts.map +0 -1
  155. package/ecagent/dist/runtime/providers/faux.js.map +0 -1
  156. package/ecagent/dist/runtime/types.d.ts.map +0 -1
  157. package/ecagent/dist/runtime/types.js.map +0 -1
  158. package/ecagent/dist/runtime/utils/diagnostics.d.ts.map +0 -1
  159. package/ecagent/dist/runtime/utils/diagnostics.js.map +0 -1
  160. package/ecagent/dist/runtime/utils/event-stream.d.ts.map +0 -1
  161. package/ecagent/dist/runtime/utils/event-stream.js.map +0 -1
  162. package/ecagent/dist/runtime/utils/headers.d.ts.map +0 -1
  163. package/ecagent/dist/runtime/utils/headers.js.map +0 -1
  164. package/ecagent/dist/runtime/utils/json-parse.d.ts.map +0 -1
  165. package/ecagent/dist/runtime/utils/json-parse.js.map +0 -1
  166. package/ecagent/dist/runtime/utils/oauth/types.d.ts.map +0 -1
  167. package/ecagent/dist/runtime/utils/oauth/types.js.map +0 -1
  168. package/ecagent/dist/runtime/utils/overflow.d.ts.map +0 -1
  169. package/ecagent/dist/runtime/utils/overflow.js.map +0 -1
  170. package/ecagent/dist/runtime/utils/provider-env.d.ts.map +0 -1
  171. package/ecagent/dist/runtime/utils/provider-env.js.map +0 -1
  172. package/ecagent/dist/runtime/utils/retry.d.ts.map +0 -1
  173. package/ecagent/dist/runtime/utils/retry.js.map +0 -1
  174. package/ecagent/dist/runtime/utils/typebox-helpers.d.ts.map +0 -1
  175. package/ecagent/dist/runtime/utils/typebox-helpers.js.map +0 -1
  176. package/ecagent/dist/runtime/utils/validation.d.ts.map +0 -1
  177. package/ecagent/dist/runtime/utils/validation.js.map +0 -1
  178. package/ecagent/dist/types.d.ts.map +0 -1
  179. package/ecagent/dist/types.js.map +0 -1
  180. package/ecagent/package.json +0 -93
  181. package/ecagent/src/agent-loop.ts +0 -792
  182. package/ecagent/src/agent.ts +0 -575
  183. package/ecagent/src/harness/agent-harness.ts +0 -1029
  184. package/ecagent/src/harness/compaction/branch-summarization.ts +0 -261
  185. package/ecagent/src/harness/compaction/compaction.ts +0 -753
  186. package/ecagent/src/harness/compaction/utils.ts +0 -144
  187. package/ecagent/src/harness/env/nodejs.ts +0 -569
  188. package/ecagent/src/harness/messages.ts +0 -164
  189. package/ecagent/src/harness/prompt-templates.ts +0 -267
  190. package/ecagent/src/harness/session/jsonl-repo.ts +0 -179
  191. package/ecagent/src/harness/session/jsonl-storage.ts +0 -314
  192. package/ecagent/src/harness/session/memory-repo.ts +0 -50
  193. package/ecagent/src/harness/session/memory-storage.ts +0 -133
  194. package/ecagent/src/harness/session/repo-utils.ts +0 -51
  195. package/ecagent/src/harness/session/session.ts +0 -338
  196. package/ecagent/src/harness/session/uuid.ts +0 -54
  197. package/ecagent/src/harness/skills.ts +0 -375
  198. package/ecagent/src/harness/system-prompt.ts +0 -34
  199. package/ecagent/src/harness/types.ts +0 -838
  200. package/ecagent/src/harness/utils/shell-output.ts +0 -135
  201. package/ecagent/src/harness/utils/truncate.ts +0 -344
  202. package/ecagent/src/index.ts +0 -46
  203. package/ecagent/src/node.ts +0 -2
  204. package/ecagent/src/proxy.ts +0 -367
  205. package/ecagent/src/runtime/api/lazy.ts +0 -70
  206. package/ecagent/src/runtime/api/pi-messages.lazy.ts +0 -4
  207. package/ecagent/src/runtime/api/pi-messages.ts +0 -436
  208. package/ecagent/src/runtime/auth/context.ts +0 -45
  209. package/ecagent/src/runtime/auth/credential-store.ts +0 -47
  210. package/ecagent/src/runtime/auth/helpers.ts +0 -46
  211. package/ecagent/src/runtime/auth/resolve.ts +0 -141
  212. package/ecagent/src/runtime/auth/types.ts +0 -182
  213. package/ecagent/src/runtime/compat.ts +0 -158
  214. package/ecagent/src/runtime/index.ts +0 -31
  215. package/ecagent/src/runtime/models.ts +0 -452
  216. package/ecagent/src/runtime/oauth.ts +0 -1
  217. package/ecagent/src/runtime/providers/faux.ts +0 -538
  218. package/ecagent/src/runtime/types.ts +0 -718
  219. package/ecagent/src/runtime/utils/diagnostics.ts +0 -45
  220. package/ecagent/src/runtime/utils/event-stream.ts +0 -88
  221. package/ecagent/src/runtime/utils/headers.ts +0 -18
  222. package/ecagent/src/runtime/utils/json-parse.ts +0 -124
  223. package/ecagent/src/runtime/utils/oauth/types.ts +0 -79
  224. package/ecagent/src/runtime/utils/overflow.ts +0 -165
  225. package/ecagent/src/runtime/utils/provider-env.ts +0 -52
  226. package/ecagent/src/runtime/utils/retry.ts +0 -101
  227. package/ecagent/src/runtime/utils/typebox-helpers.ts +0 -24
  228. package/ecagent/src/runtime/utils/validation.ts +0 -310
  229. package/ecagent/src/types.ts +0 -430
  230. package/ecagent/tsconfig.build.json +0 -32
@@ -3,8 +3,20 @@ function apiEndpoint(baseUrl, resource) {
3
3
  const configured = baseUrl?.trim();
4
4
  if (!configured)
5
5
  throw new Error('Direct text inference baseUrl is not configured');
6
- const base = configured.replace(/\/+$/, '');
7
- return base.endsWith('/v1') ? `${base}/${resource}` : `${base}/v1/${resource}`;
6
+ const parsed = new URL(configured);
7
+ const pathname = parsed.pathname.replace(/\/+$/, '');
8
+ parsed.pathname = pathname.endsWith('/v1')
9
+ ? `${pathname}/${resource}`
10
+ : `${pathname}/v1/${resource}`;
11
+ return parsed.toString();
12
+ }
13
+ function withQueryParams(url, queryParams) {
14
+ if (!queryParams || Object.keys(queryParams).length === 0)
15
+ return url;
16
+ const parsed = new URL(url);
17
+ for (const [name, value] of Object.entries(queryParams))
18
+ parsed.searchParams.set(name, value);
19
+ return parsed.toString();
8
20
  }
9
21
  async function parseError(response) {
10
22
  let raw = '';
@@ -28,10 +40,10 @@ export class AnthropicTextInferenceProvider {
28
40
  this.config = config;
29
41
  }
30
42
  async completeText(request) {
31
- const response = await fetch(apiEndpoint(this.config.baseUrl, 'messages'), {
43
+ const response = await fetch(withQueryParams(apiEndpoint(this.config.baseUrl, 'messages'), this.config.queryParams), {
32
44
  method: 'POST',
33
45
  signal: request.signal,
34
- headers: this.headers(),
46
+ headers: { ...this.headers(), ...this.config.headers },
35
47
  body: JSON.stringify({
36
48
  model: request.model,
37
49
  max_tokens: 256,
@@ -69,12 +81,13 @@ export class OpenAITextInferenceProvider {
69
81
  this.config = config;
70
82
  }
71
83
  async completeText(request) {
72
- const response = await fetch(apiEndpoint(this.config.baseUrl, 'responses'), {
84
+ const response = await fetch(withQueryParams(apiEndpoint(this.config.baseUrl, 'responses'), this.config.queryParams), {
73
85
  method: 'POST',
74
86
  signal: request.signal,
75
87
  headers: {
76
88
  'Content-Type': 'application/json',
77
89
  Authorization: `Bearer ${this.config.apiKey}`,
90
+ ...this.config.headers,
78
91
  },
79
92
  body: JSON.stringify({
80
93
  model: request.model,
@@ -627,6 +627,7 @@ export class MessageBridge {
627
627
  const menuControl = resolvedChannelType === 'aun'
628
628
  ? parseMenuControl(content)
629
629
  : { isMenu: false };
630
+ let menuResponseWarning;
630
631
  if (menuControl.isMenu) {
631
632
  this.logMenuInbound(channelName, msg, menuControl);
632
633
  if (!hasValidMenuId(menuControl)) {
@@ -649,7 +650,7 @@ export class MessageBridge {
649
650
  await this.sendMenuResponse(adapter, channelName, msg, menuFailure(header, {
650
651
  code: 'MENU_TOKEN_ENCRYPTION_REQUIRED',
651
652
  message: 'Menu 请求必须使用 E2EE',
652
- }), true);
653
+ }));
653
654
  return;
654
655
  }
655
656
  if (!isTokenRequest) {
@@ -666,6 +667,13 @@ export class MessageBridge {
666
667
  }));
667
668
  return;
668
669
  }
670
+ if (!menuTokenRequired && tokenSupplied && !tokenValid) {
671
+ this.logMenuDiagnostic('token-invalid-optional', channelName, msg, menuControl, 'MENU_TOKEN_INVALID');
672
+ menuResponseWarning = {
673
+ code: 'MENU_TOKEN_INVALID',
674
+ message: 'Menu token 无效,请重新申请',
675
+ };
676
+ }
669
677
  }
670
678
  const validationError = validateMenuRequest(menuControl.request);
671
679
  if (validationError) {
@@ -712,7 +720,7 @@ export class MessageBridge {
712
720
  });
713
721
  const identity = authSubject.identity;
714
722
  if (menuControl.isMenu) {
715
- await this.handleMenuControl(menuControl, channelName, resolvedChannelType, msg, adapter, authSubject);
723
+ await this.handleMenuControl(menuControl, channelName, resolvedChannelType, msg, adapter, authSubject, menuResponseWarning);
716
724
  return;
717
725
  }
718
726
  // 普通消息保留原始日志;控制 payload 使用脱敏元数据日志。
@@ -1074,7 +1082,7 @@ export class MessageBridge {
1074
1082
  throw { code: 'NOT_SUPPORTED', message: `Unsupported menu name: ${name}` };
1075
1083
  return mapped;
1076
1084
  }
1077
- async handleMenuControl(parsed, channel, channelType, msg, adapter, authSubject) {
1085
+ async handleMenuControl(parsed, channel, channelType, msg, adapter, authSubject, responseWarning) {
1078
1086
  if (!hasValidMenuId(parsed))
1079
1087
  return;
1080
1088
  const header = { id: parsed.id, ...(parsed.name?.trim() ? { name: parsed.name } : {}) };
@@ -1122,7 +1130,10 @@ export class MessageBridge {
1122
1130
  }
1123
1131
  if (deduped.replayed)
1124
1132
  this.logMenuDiagnostic('request-replay', channel, msg, parsed);
1125
- await this.sendMenuResponse(adapter, channel, msg, deduped.value, isTokenRequest);
1133
+ const response = responseWarning && 'data' in deduped.value
1134
+ ? { ...deduped.value, warning: responseWarning }
1135
+ : deduped.value;
1136
+ await this.sendMenuResponse(adapter, channel, msg, response);
1126
1137
  const deferredEffect = afterResponse;
1127
1138
  if (!deduped.replayed && deferredEffect) {
1128
1139
  try {
@@ -1191,7 +1202,7 @@ export class MessageBridge {
1191
1202
  return menuFailure(header, normalizeMenuError(error));
1192
1203
  }
1193
1204
  }
1194
- async sendMenuResponse(adapter, channel, msg, response, forceEncryption = false) {
1205
+ async sendMenuResponse(adapter, channel, msg, response) {
1195
1206
  if (!adapter?.send) {
1196
1207
  this.logMenuDiagnostic('transport-unavailable', channel, msg, {
1197
1208
  isMenu: true,
@@ -1208,7 +1219,7 @@ export class MessageBridge {
1208
1219
  ...(msg.replyContext ?? {}),
1209
1220
  metadata: {
1210
1221
  ...(msg.replyContext?.metadata ?? {}),
1211
- ...evolMenuResponseTransportMetadata(forceEncryption ? true : msg.encrypted),
1222
+ ...evolMenuResponseTransportMetadata(),
1212
1223
  },
1213
1224
  };
1214
1225
  const envelope = buildEnvelope({
@@ -890,6 +890,16 @@ export class ResponseEngine {
890
890
  return;
891
891
  renderer.addNotice(text, severity, subtype, true);
892
892
  }
893
+ async cancelStaleRunnerStart(agent, sessionId, streamKey, turnLease, taskId) {
894
+ if (this.turnCoordinator.isCurrent(turnLease))
895
+ return false;
896
+ logger.info(`[ResponseEngine] Stale turn detected after agent.runQuery start; cancelling unconsumed stream: session=${sessionId} task=${taskId}`);
897
+ await agent.interrupt(sessionId).catch(interruptError => {
898
+ logger.warn(`[ResponseEngine] Failed to cancel stale runner start: session=${sessionId} task=${taskId} error=${interruptError instanceof Error ? interruptError.message : String(interruptError)}`);
899
+ });
900
+ agent.cleanupStream(streamKey);
901
+ return true;
902
+ }
893
903
  async retryAfterContextRecovery(prompt, opts) {
894
904
  const { streamKey, renderer, agent, session, absoluteProjectPath, effectiveSystemPrompt, modelOverride, runtimeEnv, resetTimer, shouldSuppress, proactive, turnLease, } = opts;
895
905
  if (!session.agentSessionId || !canCompactAgent(agent)) {
@@ -911,6 +921,9 @@ export class ResponseEngine {
911
921
  await this.emitOperationalNotice(renderer, '✅ 压缩完成,继续处理...', 'info', 'compact-retry');
912
922
  await renderer.flush();
913
923
  const retryStream = await agent.runQuery(session.id, prompt, absoluteProjectPath, session.agentSessionId, undefined, effectiveSystemPrompt, this.sessionManager, modelOverride, runtimeEnv);
924
+ if (await this.cancelStaleRunnerStart(agent, session.id, streamKey, turnLease, turnLease.taskId)) {
925
+ throw new Error('RUNNER_START_SUPERSEDED');
926
+ }
914
927
  agent.registerStream(streamKey, retryStream);
915
928
  return await this.processEventStream(retryStream, session, agent, renderer, resetTimer, shouldSuppress, proactive, undefined, // 重试分支不调插件钩子
916
929
  undefined, turnLease);
@@ -2331,7 +2344,7 @@ export class ResponseEngine {
2331
2344
  try {
2332
2345
  const selector = { self: selfAid || undefined, peerKey };
2333
2346
  const modelResolution = resolveEffectiveFieldWithSource(`baseagents.${normalizedBaseagent.canonical}.model`, selector, { cache: true });
2334
- const effortResolution = resolveEffectiveFieldWithSource(`baseagents.${normalizedBaseagent.canonical}.${normalizedBaseagent.canonical === 'codex' ? 'reasoning' : 'effort'}`, selector, { cache: true });
2347
+ const effortResolution = resolveEffectiveFieldWithSource(`baseagents.${normalizedBaseagent.canonical}.effort`, selector, { cache: true });
2335
2348
  const modelDecision = constrainResolvedModelForRole({
2336
2349
  role: peerRole,
2337
2350
  baseagent: normalizedBaseagent.canonical,
@@ -2342,7 +2355,7 @@ export class ResponseEngine {
2342
2355
  selfAid: selfAid || undefined,
2343
2356
  });
2344
2357
  const model = modelDecision.model;
2345
- const effortField = `baseagents.${normalizedBaseagent.canonical}.${normalizedBaseagent.canonical === 'codex' ? 'reasoning' : 'effort'}`;
2358
+ const effortField = `baseagents.${normalizedBaseagent.canonical}.effort`;
2346
2359
  const effortDecision = resolveRuntimeStringField({
2347
2360
  selfAid: selfAid || undefined,
2348
2361
  role: peerRole,
@@ -2389,7 +2402,7 @@ export class ResponseEngine {
2389
2402
  effectiveModelSource = triggerModelDecision.constrained ? 'role' : 'trigger';
2390
2403
  }
2391
2404
  if (triggerEffortOverride) {
2392
- const effortField = `baseagents.${normalizedBaseagent.canonical}.${normalizedBaseagent.canonical === 'codex' ? 'reasoning' : 'effort'}`;
2405
+ const effortField = `baseagents.${normalizedBaseagent.canonical}.effort`;
2393
2406
  const triggerEffortDecision = resolveRuntimeStringField({
2394
2407
  selfAid: selfAid || undefined,
2395
2408
  role: peerRole,
@@ -2766,6 +2779,12 @@ export class ResponseEngine {
2766
2779
  try {
2767
2780
  logger.info(`[ResponseEngine] agent.runQuery start: agent=${agent.name} session=${session.id} task=${taskId} attempt=${runAttempt} apiRetries=${retryScheduler.apiRetryAttemptsMade} agentSessionId=${session.agentSessionId ?? 'none'}`);
2768
2781
  const stream = await agent.runQuery(session.id, effectivePrompt, absoluteProjectPath, session.agentSessionId, renderResult?.images.length ? renderResult.images : message.images, effectiveSystemPrompt, this.sessionManager, modelOverride, runtimeEnv);
2782
+ // The turn may be superseded while the runner is still creating its
2783
+ // backend query. Replay the interrupt after runQuery resolves, when
2784
+ // every runner is required to have an addressable cancellation handle.
2785
+ if (await this.cancelStaleRunnerStart(agent, session.id, streamKey, turnLease, taskId)) {
2786
+ throw new Error('RUNNER_START_SUPERSEDED');
2787
+ }
2769
2788
  agent.registerStream(streamKey, stream);
2770
2789
  streamRegistered = true;
2771
2790
  if (shouldTimeoutRetryAttempt) {
@@ -82,9 +82,9 @@ export function activeBaseagent(self) {
82
82
  catch { /* fall through */ }
83
83
  return 'claude';
84
84
  }
85
- /** codex 的推理强度字段名是 reasoning,其余是 effort */
86
- function effortField(ba) {
87
- return ba === 'codex' ? 'reasoning' : 'effort';
85
+ /** 所有 baseagent 统一使用 effort 表达推理强度。 */
86
+ function effortField(_ba) {
87
+ return 'effort';
88
88
  }
89
89
  // ── 写:单作用域 ──────────────────────────────────────────────────────
90
90
  /** 写入指定作用域。patch 中 undefined 不动;显式 null 删除字段。 */
@@ -169,6 +169,17 @@ function isOwnerOrAdminRole(role) {
169
169
  function hasNodeProcessTarget(command) {
170
170
  return /\bnode(?:js|\.exe)?\b/i.test(command);
171
171
  }
172
+ // 包发布命令:npm/pnpm/yarn/bun publish。
173
+ // 排除 --dry-run(不产生实际发布),保留 --provenance 等真实发布参数。
174
+ function isPackagePublishCommand(parsed) {
175
+ const runners = ['npm', 'pnpm', 'yarn', 'bun', 'npx'];
176
+ if (!runners.includes(parsed.executable))
177
+ return false;
178
+ const words = parsed.args.filter(arg => !arg.startsWith('-')).map(arg => arg.toLowerCase());
179
+ if (words[0] !== 'publish')
180
+ return false;
181
+ return !parsed.args.some(arg => arg === '--dry-run' || arg.startsWith('--dry-run='));
182
+ }
172
183
  function classifyHostProcessArgv(argv) {
173
184
  const executable = commandName(argv[0]);
174
185
  if (['ps', 'pgrep', 'pidof'].includes(executable)) {
@@ -279,6 +290,13 @@ function classifyStructuredCommand(command, depth = 0) {
279
290
  matches.push({ kind: 'git-push', reason: 'Git push 会修改远端仓库', approvalScope: 'request' });
280
291
  }
281
292
  }
293
+ if (isPackagePublishCommand(parsed)) {
294
+ matches.push({
295
+ kind: 'package-publish',
296
+ reason: '发布软件包到公共 registry,发布后无法替换同版本',
297
+ approvalScope: 'all',
298
+ });
299
+ }
282
300
  if (['kill', 'pkill', 'killall'].includes(parsed.executable) && hasNodeProcessTarget(parsed.raw)) {
283
301
  matches.push({ kind: 'process-kill', reason: '终止 Node.js 运行时进程', approvalScope: 'request' });
284
302
  }
@@ -322,9 +322,20 @@ export function buildCodexHClassFilesystemRules(root = resolveRoot()) {
322
322
  };
323
323
  }
324
324
  export function buildCodexProtectedFilesystemRules(root = resolveRoot()) {
325
+ const lClassRules = {};
326
+ for (const target of getExistingLClassReadOnlyTargets(root)) {
327
+ if (target.kind === 'directory') {
328
+ if (path.basename(target.path) === 'triggers')
329
+ lClassRules[target.path] = 'read';
330
+ lClassRules[path.join(target.path, '**')] = 'read';
331
+ }
332
+ else {
333
+ lClassRules[target.path] = 'read';
334
+ }
335
+ }
325
336
  return {
326
337
  ...buildCodexHClassFilesystemRules(root),
327
- ...Object.fromEntries(getLClassWritePatterns(root).map(pattern => [pattern, 'read'])),
338
+ ...lClassRules,
328
339
  };
329
340
  }
330
341
  export function hClassGrantIncludesProtectedPath(value, options = {}) {