evolcore 0.0.25 → 0.0.26

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 (231) hide show
  1. package/CHANGELOG.md +607 -565
  2. package/LICENSE +21 -21
  3. package/README.md +455 -455
  4. package/bin/codex-managed-acl.ps1 +160 -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.js +96 -46
  10. package/dist/agents/claude-runner.js +50 -12
  11. package/dist/agents/codex/app-server-client.js +13 -5
  12. package/dist/agents/codex/catalog.js +1 -1
  13. package/dist/agents/codex/diagnostics.js +34 -1
  14. package/dist/agents/codex-runner.js +121 -38
  15. package/dist/agents/ecagent-runner.js +4 -9
  16. package/dist/agents/gemini-runner.js +2 -7
  17. package/dist/agents/runner-types.js +25 -17
  18. package/dist/aun/aid/agentmd.js +81 -8
  19. package/dist/aun/aid/client.js +1 -1
  20. package/dist/aun/aid/identity.js +1 -1
  21. package/dist/aun/aid/index.js +1 -1
  22. package/dist/aun/aid/store.js +17 -13
  23. package/dist/aun/menu-client.js +74 -0
  24. package/dist/aun/msg/group.js +1 -1
  25. package/dist/aun/msg/managed-operation.js +1 -1
  26. package/dist/aun/msg/p2p.js +6 -1
  27. package/dist/aun/msg/upload.js +30 -22
  28. package/dist/channels/aun.js +329 -94
  29. package/dist/cli/agent-command.js +105 -84
  30. package/dist/cli/agent-create.js +112 -10
  31. package/dist/cli/agent.js +16 -5
  32. package/dist/cli/aun-commands.js +297 -296
  33. package/dist/cli/bench.js +20 -20
  34. package/dist/cli/config.js +47 -28
  35. package/dist/cli/contact.js +70 -13
  36. package/dist/cli/ctl-command.js +22 -22
  37. package/dist/cli/daemon-commands.js +105 -40
  38. package/dist/cli/diag.js +31 -0
  39. package/dist/cli/fs-command.js +67 -67
  40. package/dist/cli/handoff-command.js +41 -9
  41. package/dist/cli/index.js +83 -77
  42. package/dist/cli/link-rules.js +21 -21
  43. package/dist/cli/managed-command-guard.js +3 -0
  44. package/dist/cli/menu-client.js +46 -31
  45. package/dist/cli/net-check.js +22 -22
  46. package/dist/cli/queue-command.js +29 -29
  47. package/dist/cli/response.js +30 -30
  48. package/dist/cli/restart-monitor.js +87 -40
  49. package/dist/cli/stats.js +51 -51
  50. package/dist/cli/trigger-command.js +56 -56
  51. package/dist/config/builtin-roles.js +1 -0
  52. package/dist/config/config-operation-service.js +145 -0
  53. package/dist/config/contact-operation-service.js +96 -7
  54. package/dist/config/resolved-config-op.js +27 -7
  55. package/dist/core/agent-application-service.js +2 -1
  56. package/dist/core/auth/authorization-audit.js +20 -12
  57. package/dist/core/auth/operation-authorizer.js +25 -4
  58. package/dist/core/auth/operation-catalog.js +35 -4
  59. package/dist/core/auth/remote-access-store.js +40 -1
  60. package/dist/core/bootstrap-service.js +1 -1
  61. package/dist/core/command/command-handler.js +83 -26
  62. package/dist/core/command/diag-service.js +118 -0
  63. package/dist/core/command/menu-catalog.js +12 -3
  64. package/dist/core/command/menu-handler.js +47 -26
  65. package/dist/core/command/menu-protocol.js +5 -0
  66. package/dist/core/command/menu-token-store.js +41 -8
  67. package/dist/core/command/slash-gate.js +34 -4
  68. package/dist/core/command/slash-handler.js +86 -21
  69. package/dist/core/handoff/runtime.js +205 -27
  70. package/dist/core/handoff/store.js +193 -4
  71. package/dist/core/message/im-renderer.js +72 -21
  72. package/dist/core/message/message-bridge.js +69 -9
  73. package/dist/core/message/message-queue.js +26 -0
  74. package/dist/core/message/message-utils.js +1 -0
  75. package/dist/core/message/response-engine.js +47 -28
  76. package/dist/core/model/catalog-service.js +79 -49
  77. package/dist/core/model/context-window-suffix.js +33 -0
  78. package/dist/core/model/model-catalog.js +1 -1
  79. package/dist/core/model/model-permission.js +12 -3
  80. package/dist/core/permission/ec-command-parser.js +51 -12
  81. package/dist/core/permission/sandbox-runtime.js +36 -14
  82. package/dist/core/permission/tool-policy.js +2 -1
  83. package/dist/index.js +280 -163
  84. package/dist/ipc.js +54 -2
  85. package/dist/response-system/engines/v1/proactive-flow.js +59 -2
  86. package/dist/stats/billing.js +41 -15
  87. package/dist/stats/db.js +159 -159
  88. package/dist/stats/eck-vars.js +9 -9
  89. package/dist/stats/price-resolver.js +28 -10
  90. package/dist/stats/query.js +139 -139
  91. package/dist/stats/role-budget.js +6 -6
  92. package/dist/stats/writer.js +51 -51
  93. package/dist/utils/cross-platform.js +30 -1
  94. package/dist/utils/error-dict.json +160 -160
  95. package/dist/utils/error-utils.js +21 -0
  96. package/dist/utils/evolcore-version.js +129 -0
  97. package/dist/utils/logger.js +3 -1
  98. package/dist/utils/macos-autostart.js +22 -22
  99. package/dist/utils/model-prices.jsonl +23 -23
  100. package/dist/utils/npm-ops.js +176 -35
  101. package/dist/utils/welcome.js +22 -22
  102. package/ecagent/LICENSE +21 -21
  103. package/ecagent/NOTICE +11 -11
  104. package/ecagent/README.md +61 -61
  105. package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
  106. package/ecagent/dist/harness/compaction/compaction.js +83 -83
  107. package/ecagent/dist/harness/messages.js +7 -7
  108. package/kits/docs/GUIDE.md +20 -20
  109. package/kits/docs/INDEX.md +66 -66
  110. package/kits/docs/aun/CHEATSHEET.md +19 -19
  111. package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
  112. package/kits/docs/channels/aun.md +56 -56
  113. package/kits/docs/channels/feishu.md +56 -56
  114. package/kits/docs/context-assembly.md +364 -364
  115. package/kits/docs/eck_templates/GUIDE.template.md +22 -22
  116. package/kits/docs/eck_templates/INDEX.template.md +28 -28
  117. package/kits/docs/eck_templates/path-registry.template.md +33 -33
  118. package/kits/docs/eck_templates/runtime.template.md +19 -19
  119. package/kits/docs/evolcore/INDEX.md +71 -71
  120. package/kits/docs/evolcore/agent-create.md +170 -165
  121. package/kits/docs/evolcore/agent.md +66 -66
  122. package/kits/docs/evolcore/aid.md +60 -60
  123. package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
  124. package/kits/docs/evolcore/config.md +202 -195
  125. package/kits/docs/evolcore/contact.md +75 -68
  126. package/kits/docs/evolcore/ctl.md +46 -46
  127. package/kits/docs/evolcore/event.md +216 -216
  128. package/kits/docs/evolcore/fs-architecture.md +1215 -1215
  129. package/kits/docs/evolcore/fs.md +110 -110
  130. package/kits/docs/evolcore/group-collaboration.md +243 -243
  131. package/kits/docs/evolcore/group-fs.md +17 -17
  132. package/kits/docs/evolcore/group-rules.md +251 -251
  133. package/kits/docs/evolcore/group.md +152 -152
  134. package/kits/docs/evolcore/menu-client.md +42 -34
  135. package/kits/docs/evolcore/model.md +50 -50
  136. package/kits/docs/evolcore/msg.md +166 -165
  137. package/kits/docs/evolcore/response.md +75 -75
  138. package/kits/docs/evolcore/rpc.md +37 -37
  139. package/kits/docs/evolcore/self-summary.md +29 -29
  140. package/kits/docs/evolcore/stats.md +83 -83
  141. package/kits/docs/evolcore/storage.md +50 -50
  142. package/kits/docs/evolcore/trigger.md +575 -575
  143. package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
  144. package/kits/docs/identity/PATH_OPS.md +16 -16
  145. package/kits/docs/identity/ROLE_DETAIL.md +25 -25
  146. package/kits/docs/identity/identity-tools.md +26 -26
  147. package/kits/docs/path-registry.md +62 -62
  148. package/kits/docs/prompt-loading-architecture.md +269 -269
  149. package/kits/docs/venues/aun-group.md +45 -45
  150. package/kits/docs/venues/aun-private.md +10 -10
  151. package/kits/docs/venues/client-desktop.md +10 -10
  152. package/kits/docs/venues/client-mobile.md +10 -10
  153. package/kits/docs/venues/feishu-group.md +13 -13
  154. package/kits/docs/venues/feishu-private.md +9 -9
  155. package/kits/docs/venues/group.md +37 -25
  156. package/kits/docs/venues/private.md +10 -10
  157. package/kits/eck_manifest.auxiliary.json +43 -43
  158. package/kits/eck_manifest.json +190 -190
  159. package/kits/eck_message_manifest.json +74 -74
  160. package/kits/migrations/README-role-config-v4.md +32 -32
  161. package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
  162. package/kits/migrations/migrate-role-config-v4.mjs +614 -614
  163. package/kits/migrations/migrate-role-config-v5.mjs +365 -365
  164. package/kits/migrations/rename-config-file.mjs +99 -99
  165. package/kits/rules/01-overview.md +162 -162
  166. package/kits/rules/02-navigation.md +96 -96
  167. package/kits/rules/03-identity.md +36 -36
  168. package/kits/rules/04-relation.md +75 -75
  169. package/kits/rules/05-venue.md +60 -60
  170. package/kits/rules/06-channel.md +63 -63
  171. package/kits/schemas/_meta.json +53 -53
  172. package/kits/schemas/agent-config.schema.1.json +177 -177
  173. package/kits/schemas/agent-config.schema.10.json +395 -395
  174. package/kits/schemas/agent-config.schema.11.json +421 -421
  175. package/kits/schemas/agent-config.schema.12.json +427 -427
  176. package/kits/schemas/agent-config.schema.2.json +239 -239
  177. package/kits/schemas/agent-config.schema.3.json +119 -119
  178. package/kits/schemas/agent-config.schema.4.json +208 -208
  179. package/kits/schemas/agent-config.schema.5.json +326 -326
  180. package/kits/schemas/agent-config.schema.6.json +322 -322
  181. package/kits/schemas/agent-config.schema.7.json +303 -303
  182. package/kits/schemas/agent-config.schema.8.json +304 -304
  183. package/kits/schemas/agent-config.schema.9.json +364 -364
  184. package/kits/schemas/contact-book.schema.1.json +36 -36
  185. package/kits/schemas/contact-book.schema.2.json +43 -43
  186. package/kits/schemas/contact-book.schema.3.json +67 -67
  187. package/kits/schemas/daemon.schema.1.json +91 -91
  188. package/kits/schemas/daemon.schema.2.json +101 -101
  189. package/kits/schemas/daemon.schema.3.json +123 -123
  190. package/kits/schemas/daemon.schema.4.json +136 -136
  191. package/kits/schemas/daemon.schema.5.json +135 -135
  192. package/kits/schemas/daemon.schema.6.json +131 -131
  193. package/kits/schemas/defaults.schema.1.json +81 -81
  194. package/kits/schemas/defaults.schema.2.json +85 -85
  195. package/kits/schemas/defaults.schema.3.json +73 -73
  196. package/kits/schemas/defaults.schema.4.json +107 -107
  197. package/kits/schemas/defaults.schema.5.json +119 -119
  198. package/kits/schemas/menu-exec-schema-commands.md +208 -208
  199. package/kits/schemas/migrations/README.md +30 -30
  200. package/kits/schemas/relation-config.schema.1.json +158 -158
  201. package/kits/schemas/relation-config.schema.2.json +73 -73
  202. package/kits/schemas/relation-config.schema.3.json +50 -50
  203. package/kits/schemas/relation-config.schema.4.json +47 -47
  204. package/kits/schemas/relation-config.schema.5.json +47 -47
  205. package/kits/schemas/relation-config.schema.6.json +46 -46
  206. package/kits/schemas/relation-config.schema.7.json +59 -59
  207. package/kits/schemas/relation-config.schema.8.json +103 -103
  208. package/kits/schemas/role-config.schema.1.json +201 -201
  209. package/kits/schemas/role-registry.schema.1.json +35 -35
  210. package/kits/schemas/single-session.schema.1.json +31 -31
  211. package/kits/schemas/single-session.schema.2.json +57 -57
  212. package/kits/schemas/single-session.schema.3.json +32 -32
  213. package/kits/templates/bootstrap-welcome.md +17 -17
  214. package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
  215. package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
  216. package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
  217. package/kits/templates/message-fragments/inject-default.md +2 -2
  218. package/kits/templates/message-fragments/item.md +2 -2
  219. package/kits/templates/roles/admin.json +92 -92
  220. package/kits/templates/roles/member.json +96 -96
  221. package/kits/templates/roles/owner.json +9 -9
  222. package/kits/templates/roles/visitor.json +85 -85
  223. package/kits/templates/system-fragments/baseagent.md +14 -14
  224. package/kits/templates/system-fragments/bootstrap.md +31 -29
  225. package/kits/templates/system-fragments/channel.md +64 -64
  226. package/kits/templates/system-fragments/commands.md +28 -28
  227. package/kits/templates/system-fragments/identity.md +13 -13
  228. package/kits/templates/system-fragments/relation.md +19 -19
  229. package/kits/templates/system-fragments/session.md +59 -59
  230. package/kits/templates/system-fragments/venue.md +31 -31
  231. package/package.json +100 -98
@@ -14,6 +14,7 @@ import path from 'path';
14
14
  import os from 'os';
15
15
  import { commandExists, isWindows, resolveProbePath } from '../utils/cross-platform.js';
16
16
  import { execFileSync } from 'child_process';
17
+ import { parse as parseToml } from 'smol-toml';
17
18
  /** Resolve the installed Codex CLI entrypoint, including npm shims on Windows. */
18
19
  export function resolveCodexCliPath() {
19
20
  return resolveProbePath('codex');
@@ -185,55 +186,74 @@ export function resolveAnthropicConfig(config, override) {
185
186
  || pickExec(config.agents?.claude?.pathToClaudeCodeExecutable);
186
187
  return { apiKey, baseUrl, headers, queryParams, model, effort, pathToClaudeCodeExecutable };
187
188
  }
189
+ function nonEmptyString(value) {
190
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
191
+ }
192
+ function recordValue(value) {
193
+ return value && typeof value === 'object' && !Array.isArray(value)
194
+ ? value
195
+ : undefined;
196
+ }
188
197
  export function loadCodexSettings() {
198
+ const configuredHome = process.env.CODEX_HOME?.trim();
199
+ const codexHome = configuredHome ? path.resolve(configuredHome) : path.join(os.homedir(), '.codex');
200
+ const authPath = path.join(codexHome, 'auth.json');
201
+ const configPath = path.join(codexHome, 'config.toml');
202
+ let authJsonApiKey;
189
203
  try {
190
- const configuredHome = process.env.CODEX_HOME?.trim();
191
- const codexHome = configuredHome ? path.resolve(configuredHome) : path.join(os.homedir(), '.codex');
192
- const authPath = path.join(codexHome, 'auth.json');
193
- let apiKey;
194
204
  if (fs.existsSync(authPath)) {
195
205
  const auth = JSON.parse(fs.readFileSync(authPath, 'utf-8'));
196
- apiKey = auth.OPENAI_API_KEY;
206
+ authJsonApiKey = nonEmptyString(auth?.OPENAI_API_KEY);
197
207
  }
198
- const configPath = path.join(codexHome, 'config.toml');
199
- let model;
200
- let baseUrl;
201
- let provider;
208
+ }
209
+ catch {
210
+ // A corrupt auth.json must not prevent the provider config from loading.
211
+ }
212
+ let model;
213
+ let baseUrl;
214
+ let provider;
215
+ let bearerToken;
216
+ let requiresOpenaiAuth;
217
+ try {
202
218
  if (fs.existsSync(configPath)) {
203
- const content = fs.readFileSync(configPath, 'utf-8');
204
- const modelMatch = content.match(/^model\s*=\s*"([^"]+)"/m);
205
- if (modelMatch)
206
- model = modelMatch[1];
207
- const providerMatch = content.match(/^model_provider\s*=\s*"([^"]+)"/m);
208
- if (providerMatch) {
209
- provider = providerMatch[1];
210
- baseUrl = readCodexProviderBaseUrl(content, provider);
211
- }
219
+ const parsed = recordValue(parseToml(fs.readFileSync(configPath, 'utf-8')));
220
+ model = nonEmptyString(parsed?.model);
221
+ provider = nonEmptyString(parsed?.model_provider);
222
+ const providers = recordValue(parsed?.model_providers);
223
+ const selectedProvider = provider ? recordValue(providers?.[provider]) : undefined;
224
+ baseUrl = nonEmptyString(selectedProvider?.base_url);
225
+ bearerToken = nonEmptyString(selectedProvider?.experimental_bearer_token);
226
+ requiresOpenaiAuth = typeof selectedProvider?.requires_openai_auth === 'boolean'
227
+ ? selectedProvider.requires_openai_auth
228
+ : undefined;
212
229
  }
213
- return { apiKey, baseUrl, model, provider };
214
230
  }
215
231
  catch { }
216
- return {};
217
- }
218
- function escapeRegExp(value) {
219
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
220
- }
221
- function readCodexProviderBaseUrl(content, provider) {
222
- const segments = /^[A-Za-z0-9_-]+$/.test(provider)
223
- ? [provider, JSON.stringify(provider)]
224
- : [JSON.stringify(provider)];
225
- for (const segment of segments) {
226
- const section = new RegExp(`^\\s*\\[\\s*model_providers\\s*\\.\\s*${escapeRegExp(segment)}\\s*\\]\\s*(?:#.*)?$`, 'm').exec(content);
227
- if (!section || section.index === undefined)
228
- continue;
229
- const tail = content.slice(section.index + section[0].length);
230
- const nextSection = tail.search(/^\s*\[/m);
231
- const block = nextSection >= 0 ? tail.slice(0, nextSection) : tail;
232
- const baseUrl = block.match(/^\s*base_url\s*=\s*"([^"]+)"/m)?.[1];
233
- if (baseUrl)
234
- return baseUrl;
232
+ // Codex applies a provider's explicit bearer token before auth.json. Keep
233
+ // that precedence so EvolCore and the app-server select the same identity.
234
+ if (bearerToken) {
235
+ return {
236
+ apiKey: bearerToken,
237
+ authType: 'bearerToken',
238
+ authSource: 'config.toml',
239
+ baseUrl,
240
+ model,
241
+ provider,
242
+ requiresOpenaiAuth,
243
+ };
235
244
  }
236
- return undefined;
245
+ if (authJsonApiKey) {
246
+ return {
247
+ apiKey: authJsonApiKey,
248
+ authType: 'apiKey',
249
+ authSource: 'auth.json',
250
+ baseUrl,
251
+ model,
252
+ provider,
253
+ requiresOpenaiAuth,
254
+ };
255
+ }
256
+ return { baseUrl, model, provider, requiresOpenaiAuth };
237
257
  }
238
258
  /**
239
259
  * Resolve a complete credential/endpoint pair for direct OpenAI HTTP calls.
@@ -248,14 +268,23 @@ export function resolveOpenaiDirectConfig(override) {
248
268
  ...normalizeRequestMetadata(override),
249
269
  };
250
270
  }
251
- const environment = directInferencePair(process.env.OPENAI_API_KEY, process.env.OPENAI_BASE_URL);
271
+ const settings = loadCodexSettings();
272
+ const configuredBearer = settings.authType === 'bearerToken'
273
+ ? directInferencePair(settings.apiKey, settings.baseUrl)
274
+ : undefined;
275
+ if (configuredBearer) {
276
+ return {
277
+ ...configuredBearer,
278
+ ...normalizeRequestMetadata(override),
279
+ };
280
+ }
281
+ const environment = directInferencePair(process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY, process.env.OPENAI_BASE_URL);
252
282
  if (environment) {
253
283
  return {
254
284
  ...environment,
255
285
  ...normalizeRequestMetadata(override),
256
286
  };
257
287
  }
258
- const settings = loadCodexSettings();
259
288
  const settingsResolved = directInferencePair(settings.apiKey, settings.baseUrl);
260
289
  return settingsResolved
261
290
  ? {
@@ -269,12 +298,31 @@ export function resolveOpenaiConfig(config, override, runtime) {
269
298
  const isPlaceholder = (v) => !v || v.includes('your-') || v.includes('placeholder');
270
299
  const overrideApiKey = isPlaceholder(override?.apiKey) ? undefined : override?.apiKey;
271
300
  const globalApiKey = isPlaceholder(config.agents?.codex?.apiKey) ? undefined : config.agents?.codex?.apiKey;
272
- const apiKey = overrideApiKey
273
- || globalApiKey
274
- || process.env.OPENAI_API_KEY
275
- || codexSettings.apiKey;
301
+ const environmentApiKey = [process.env.OPENAI_API_KEY, process.env.CODEX_API_KEY]
302
+ .map(value => isPlaceholder(value) ? undefined : value)
303
+ .find((value) => !!value);
304
+ const configuredBearer = codexSettings.authType === 'bearerToken' ? codexSettings.apiKey : undefined;
305
+ const storedApiKey = codexSettings.authType === 'apiKey' ? codexSettings.apiKey : undefined;
306
+ // A selected provider's explicit token is authoritative for that provider.
307
+ // OPENAI_API_KEY is not used by Codex when the provider declares its own
308
+ // bearer token, so choosing it here would make EvolCore and app-server use
309
+ // different credentials.
310
+ const credential = overrideApiKey
311
+ ? { apiKey: overrideApiKey, authType: 'apiKey', authSource: 'agent-config' }
312
+ : globalApiKey
313
+ ? { apiKey: globalApiKey, authType: 'apiKey', authSource: 'agent-config' }
314
+ : configuredBearer
315
+ ? { apiKey: configuredBearer, authType: 'bearerToken', authSource: 'config.toml' }
316
+ : environmentApiKey
317
+ ? { apiKey: environmentApiKey, authType: 'apiKey', authSource: 'environment' }
318
+ : storedApiKey
319
+ ? { apiKey: storedApiKey, authType: 'apiKey', authSource: 'auth.json' }
320
+ : undefined;
321
+ const apiKey = credential?.apiKey;
322
+ const authType = credential?.authType;
323
+ const authSource = credential?.authSource;
276
324
  if (!apiKey) {
277
- throw new Error('No OpenAI API key found. Set one of: baseagents.codex.apiKey (per-agent or defaults), env OPENAI_API_KEY, or ~/.codex/auth.json');
325
+ throw new Error('No Codex credential found. Set baseagents.codex.apiKey, env OPENAI_API_KEY/CODEX_API_KEY, ~/.codex/auth.json, or a provider experimental_bearer_token in ~/.codex/config.toml');
278
326
  }
279
327
  const isPlaceholderUrl = (v) => !v || v.includes('api.openai.com');
280
328
  const overrideBaseUrl = isPlaceholderUrl(override?.baseUrl) ? undefined : override?.baseUrl;
@@ -303,6 +351,8 @@ export function resolveOpenaiConfig(config, override, runtime) {
303
351
  ?? undefined;
304
352
  return {
305
353
  apiKey,
354
+ authType,
355
+ authSource,
306
356
  baseUrl,
307
357
  provider: codexSettings.provider,
308
358
  headers,
@@ -25,12 +25,13 @@ import { sanitizeSessionTitle } from '../core/session/session-title.js';
25
25
  import { resolveClaudeCapabilityRunOptionsForProject } from '../core/capability/capability-manager.js';
26
26
  import { normalizeExecutionPermissionMode, normalizePermissionMode, resolvePhaseOneExecutionSandbox } from '../core/permission/mode.js';
27
27
  import { buildClaudeProtectedFilesystem, containsHClassReference, containsLClassReference, isHClassPath, isLClassPath, isSameOrDescendant, resolveProtectedCandidate, } from '../core/permission/protected-paths.js';
28
- import { buildHClassGuardCommand, collectSandboxGuardDiagnostics, createSandboxInitializationError, getActiveSandboxInitializationFailure, isSandboxInitializationFailure, recordSandboxInitializationFailure, SANDBOX_INITIALIZATION_COOLDOWN_MS, SANDBOX_INITIALIZATION_FAILED, ensureClaudeGitWorktreeConfig, prependExecutableDirectory, resolveBubblewrapPath, summarizeBubblewrapArgsForLog, summarizeSandboxGuardDiagnostics, shouldFailIfClaudeSandboxUnavailable, shouldLogSandboxCircuitNotice, } from '../core/permission/sandbox-runtime.js';
28
+ import { buildHClassGuardCommand, collectSandboxGuardDiagnostics, createSandboxInitializationError, getActiveSandboxInitializationFailure, isSandboxInitializationFailure, isSandboxInitializationToolResult, recordSandboxInitializationFailure, SANDBOX_INITIALIZATION_COOLDOWN_MS, SANDBOX_INITIALIZATION_FAILED, ensureClaudeGitWorktreeConfig, prependExecutableDirectory, resolveBubblewrapPath, summarizeBubblewrapArgsForLog, summarizeSandboxGuardDiagnostics, shouldFailIfClaudeSandboxUnavailable, shouldLogSandboxCircuitNotice, } from '../core/permission/sandbox-runtime.js';
29
29
  import { buildClaudeUnixSocketAllowlist } from '../core/permission/unix-socket-policy.js';
30
30
  import { auditToolInfrastructureFailure, auditToolPreflightDenial } from '../core/auth/authorization-audit.js';
31
31
  import { getManagedTaskTempDir, isManagedSessionRuntimeDir } from '../cli/task-context.js';
32
32
  import { hasTrustedFullAccessContext } from './runner-types.js';
33
- import { contextTokensForUsage, usageForContext, isClaudeContextUsageModel, isOneMillionContextModel, realContextWindowForModel, autoCompactWindowForModel } from './runner-types.js';
33
+ import { contextTokensForUsage, usageForContext, isClaudeContextUsageModel, isOneMillionContextModel, realContextWindowForModel, autoCompactWindowForModel, sdkAutoCompactWindowForModel } from './runner-types.js';
34
+ import { hasContextWindowSuffix, stripContextWindowSuffix } from '../core/model/context-window-suffix.js';
34
35
  const resolveModule = createRequire(import.meta.url);
35
36
  /**
36
37
  * Resolve the platform package explicitly instead of relying on the SDK's
@@ -409,11 +410,18 @@ async function refreshGatewayPricing(baseUrl, apiKey, requestHeaders) {
409
410
  }
410
411
  /**
411
412
  * 为支持 1M 上下文的模型追加 `[1m]` 后缀——仅在交给 SDK query() 时调用。
412
- * 目录与校验层始终使用不带后缀的基础 ID,避免与网关 /models 返回值(无 `[1m]`)冲突。
413
+ *
414
+ * 若网关把窗口变体作为独立条目下发(目录里同时有 `claude-opus-5` 与
415
+ * `claude-opus-5[1m]`),裸 ID 就是用户明确选的非 1M 变体,不能擅自升级,
416
+ * 否则两条列表项的实际效果无法区分。只有目录未提供任何窗口变体时,才沿用
417
+ * 按本地名单补 `[1m]` 的旧行为。
413
418
  */
414
- function applyContextWindow(modelId) {
415
- if (/\[1m\]$/.test(modelId))
416
- return modelId; // 已带后缀
419
+ function applyContextWindow(modelId, catalog) {
420
+ if (hasContextWindowSuffix(modelId))
421
+ return modelId; // 窗口已显式指定
422
+ const variantListed = catalog?.models.some(m => hasContextWindowSuffix(m.id) && stripContextWindowSuffix(m.id) === modelId);
423
+ if (variantListed)
424
+ return modelId;
417
425
  if (isOneMillionContextModel(modelId))
418
426
  return `${modelId}[1m]`;
419
427
  return modelId;
@@ -500,9 +508,9 @@ export class AgentRunner {
500
508
  /** 每个 session 最近的子进程 stderr 行(环形缓冲),用于子进程崩溃时还原真正原因 */
501
509
  recentStderr = new Map();
502
510
  static STDERR_BUFFER_MAX = 80;
503
- async recordSandboxInfrastructureFailure(sessionId, inputId, permissionMode, error, stderr = []) {
511
+ async recordSandboxInfrastructureFailure(sessionId, inputId, permissionMode, error, stderr = [], scope = 'process') {
504
512
  const detail = createSandboxInitializationError(error, stderr);
505
- const circuit = recordSandboxInitializationFailure(detail, stderr);
513
+ const circuit = recordSandboxInitializationFailure(detail, stderr, Date.now(), scope === 'session' ? sessionId : undefined);
506
514
  const context = this.permissionContexts.get(sessionId);
507
515
  auditToolInfrastructureFailure({
508
516
  toolName: 'Bash',
@@ -1343,6 +1351,7 @@ export class AgentRunner {
1343
1351
  const taskMetadata = new Map();
1344
1352
  // tool_use_id → tool_name 映射,用于从 SDKUserMessage 的 tool_result 块中还原工具名
1345
1353
  const toolUseNames = new Map();
1354
+ const sandboxedBashCalls = new Set();
1346
1355
  const emittedToolResultIds = new Set();
1347
1356
  let turnCount = 0;
1348
1357
  const seenMessageIds = new Set();
@@ -1617,6 +1626,10 @@ export class AgentRunner {
1617
1626
  if (content.type === 'tool_use') {
1618
1627
  if (content.id)
1619
1628
  toolUseNames.set(content.id, content.name);
1629
+ if (content.id && content.name === 'Bash' && content.input?.dangerouslyDisableSandbox !== true
1630
+ && resolvePhaseOneExecutionSandbox(permissionMode, this.permissionContexts.get(sessionId)?.role).state !== 'off') {
1631
+ sandboxedBashCalls.add(content.id);
1632
+ }
1620
1633
  yield { type: 'tool_use', name: content.name, input: content.input, callId: content.id, turn: turnCount, outputTokens: turnOutputChars, assistantUuid: event.uuid };
1621
1634
  }
1622
1635
  else if (content.type === 'text' && content.text) {
@@ -1635,6 +1648,31 @@ export class AgentRunner {
1635
1648
  : block.content != null ? JSON.stringify(block.content) : '';
1636
1649
  if (block.tool_use_id)
1637
1650
  emittedToolResultIds.add(block.tool_use_id);
1651
+ if (sandboxedBashCalls.delete(block.tool_use_id) && block.is_error === true
1652
+ && isSandboxInitializationToolResult(block.content)) {
1653
+ const { detail } = await this.recordSandboxInfrastructureFailure(sessionId, block.tool_use_id, permissionMode, new Error(resultContent), [], 'session');
1654
+ // Stop this SDK query before another model/tool retry. Do not use
1655
+ // interrupt(), which waits for this very generator to finish.
1656
+ this.activeMessageStreams.get(sessionId)?.end();
1657
+ const query = sdkStream;
1658
+ try {
1659
+ await query.close?.();
1660
+ }
1661
+ catch (error) {
1662
+ logger.warn(`[ClaudeSandbox] failed to close sandbox-failed query: ${error}`);
1663
+ }
1664
+ yield {
1665
+ type: 'tool_result', name: toolName, result: resultContent, isError: true,
1666
+ error: detail.message, errorCode: 'CAPABILITY_UNAVAILABLE', callId: block.tool_use_id,
1667
+ correlationId: block.tool_use_id, decision: 'error', decisionSource: 'infrastructure',
1668
+ policyCode: SANDBOX_INITIALIZATION_FAILED, executed: false, executionState: 'blocked',
1669
+ };
1670
+ yield {
1671
+ type: 'complete', isError: true, subtype: 'infrastructure',
1672
+ terminalReason: SANDBOX_INITIALIZATION_FAILED, errors: [detail.message], queryFinal: true,
1673
+ };
1674
+ return;
1675
+ }
1638
1676
  yield {
1639
1677
  type: 'tool_result',
1640
1678
  name: toolName,
@@ -1992,7 +2030,7 @@ export class AgentRunner {
1992
2030
  const executionSandbox = resolvePhaseOneExecutionSandbox(callPermissionMode, runPermissionContext?.role);
1993
2031
  const inputId = modelOverride?.turn?.inputId ?? crypto.randomUUID();
1994
2032
  if (executionSandbox.state !== 'off') {
1995
- const activeSandboxFailure = getActiveSandboxInitializationFailure();
2033
+ const activeSandboxFailure = getActiveSandboxInitializationFailure(undefined, undefined, sessionId);
1996
2034
  if (activeSandboxFailure) {
1997
2035
  const detail = createSandboxInitializationError(new Error(`sandbox bootstrap circuit open; firstObservedAt=${activeSandboxFailure.openedAt} ` +
1998
2036
  `occurrences=${activeSandboxFailure.occurrences}; ${activeSandboxFailure.detail}`));
@@ -2469,7 +2507,7 @@ export class AgentRunner {
2469
2507
  else {
2470
2508
  logger.info(`[AgentRunner] systemPromptAppend: none`);
2471
2509
  }
2472
- const sdkModel = applyContextWindow(resolveCatalogModel(runCatalog, callModel));
2510
+ const sdkModel = applyContextWindow(resolveCatalogModel(runCatalog, callModel), runCatalog);
2473
2511
  const capabilityOptions = await this.resolveCapabilityRunOptions(projectPath);
2474
2512
  const managedSettings = callPermissionMode === 'fullaccess'
2475
2513
  ? undefined
@@ -2552,7 +2590,7 @@ export class AgentRunner {
2552
2590
  ...(executionSandbox.state === 'off' && callPermissionMode !== 'fullaccess' && process.platform === 'linux' ? {
2553
2591
  spawnClaudeCodeProcess: (options) => spawnClaudeWithHClassGuard(options, resolvePaths().root, handleClaudeStderr),
2554
2592
  } : {}),
2555
- autoCompactWindow: autoCompactWindowForModel(sdkModel),
2593
+ autoCompactWindow: sdkAutoCompactWindowForModel(sdkModel),
2556
2594
  advisorModel: 'haiku',
2557
2595
  canUseTool: canUseToolCallback,
2558
2596
  permissionMode: sdkPermissionMode,
@@ -2891,7 +2929,7 @@ export class AgentRunner {
2891
2929
  prompt,
2892
2930
  options: {
2893
2931
  cwd: projectPath,
2894
- ...(catalog && callModel ? { model: applyContextWindow(resolveCatalogModel(catalog, callModel)) } : {}),
2932
+ ...(catalog && callModel ? { model: applyContextWindow(resolveCatalogModel(catalog, callModel), catalog) } : {}),
2895
2933
  resume: agentSessionId,
2896
2934
  maxTurns: 1,
2897
2935
  tools: [],
@@ -232,7 +232,7 @@ export class CodexAppServerClient {
232
232
  : { sandbox: options?.sandbox ?? null }),
233
233
  config: this.buildThreadConfig(effort, options?.config),
234
234
  excludeTurns: false,
235
- persistExtendedHistory: false,
235
+ ...(options?.lastTurnId ? { lastTurnId: options.lastTurnId } : {}),
236
236
  });
237
237
  const forkedThreadId = response.thread?.id;
238
238
  if (title && forkedThreadId) {
@@ -252,16 +252,19 @@ export class CodexAppServerClient {
252
252
  await this.request('thread/compact/start', { threadId });
253
253
  return true;
254
254
  }
255
- async threadTurnsList(threadId, limit) {
255
+ async threadTurnsList(threadId, limit, cursor) {
256
256
  return this.request('thread/turns/list', {
257
257
  threadId,
258
258
  ...(limit ? { limit } : {}),
259
- sortDirection: 'asc',
259
+ ...(cursor ? { cursor } : {}),
260
+ // The app-server defaults to newest-first. `nextCursor` then walks
261
+ // toward older turns, which is the direction needed to hydrate history.
262
+ sortDirection: 'desc',
260
263
  itemsView: 'full',
261
264
  });
262
265
  }
263
266
  async threadTurnsItemsList(threadId, turnId, limit) {
264
- return this.request('thread/turns/items/list', {
267
+ return this.request('thread/items/list', {
265
268
  threadId,
266
269
  turnId,
267
270
  ...(limit ? { limit } : {}),
@@ -643,7 +646,12 @@ export class CodexAppServerClient {
643
646
  logger.warn(`[CodexAppServer] managed runtime lock directory unavailable: ${runtimeLockDir}`);
644
647
  }
645
648
  }
646
- env.CODEX_API_KEY = this.options.apiKey;
649
+ if (this.options.authType === 'bearerToken') {
650
+ delete env.CODEX_API_KEY;
651
+ }
652
+ else {
653
+ env.CODEX_API_KEY = this.options.apiKey;
654
+ }
647
655
  env.EVOLCORE_INSTANCE_SOCKET = resolvePaths().instanceSocket;
648
656
  for (const [name, value] of Object.entries(this.options.headers ?? {})) {
649
657
  env[codexHeaderEnvName(name)] = value;
@@ -28,7 +28,7 @@ export async function codexNativeCatalog(context) {
28
28
  if (context.baseagent !== 'codex')
29
29
  return null;
30
30
  const client = new CodexAppServerClient({
31
- apiKey: context.apiKey ?? '', baseUrl: context.baseUrl, provider: context.provider,
31
+ apiKey: context.apiKey ?? '', authType: context.authType, baseUrl: context.baseUrl, provider: context.provider,
32
32
  headers: context.headers, queryParams: context.queryParams,
33
33
  });
34
34
  let timer;
@@ -179,6 +179,39 @@ function realDirectoryState(directory) {
179
179
  return 'unavailable';
180
180
  }
181
181
  }
182
+ /** Read back the package root that managedHookLauncher() embedded. */
183
+ function launcherPackageRoot(launcher) {
184
+ const match = /^\s*const packageRoot = ("(?:[^"\\]|\\.)*")\s*;/m.exec(launcher);
185
+ if (!match)
186
+ return null;
187
+ try {
188
+ const value = JSON.parse(match[1]);
189
+ return typeof value === 'string' && value ? value : null;
190
+ }
191
+ catch {
192
+ return null;
193
+ }
194
+ }
195
+ /**
196
+ * A `npm link` install reaches the package through a symlinked global path, so
197
+ * the launcher and the running CLI legitimately spell the same package root
198
+ * differently. Compare the resolved targets instead of the literal strings;
199
+ * a launcher pointing at a genuinely different package still fails closed.
200
+ */
201
+ function samePackageRoot(embedded, expected) {
202
+ if (!embedded)
203
+ return false;
204
+ const normalize = (value) => path.normalize(value).replace(/[\\/]+$/, '').toLowerCase();
205
+ const resolved = (value) => {
206
+ try {
207
+ return normalize(fs.realpathSync(value));
208
+ }
209
+ catch {
210
+ return normalize(value);
211
+ }
212
+ };
213
+ return normalize(embedded) === normalize(expected) || resolved(embedded) === resolved(expected);
214
+ }
182
215
  /** Read-only inspection of the machine-wide Windows Codex managed hook. */
183
216
  export function inspectCodexManagedHook(options = {}) {
184
217
  const paths = codexManagedHookPaths(options);
@@ -252,7 +285,7 @@ export function inspectCodexManagedHook(options = {}) {
252
285
  const normalized = (value) => path.normalize(String(value || '')).toLowerCase();
253
286
  const expectedPackageRoot = path.resolve(options.packageRoot || process.cwd());
254
287
  const launcherValid = launcher.includes('EVOLCORE_MANAGED_HOOK_LAUNCHER')
255
- && launcher.toLowerCase().includes(JSON.stringify(expectedPackageRoot).toLowerCase());
288
+ && samePackageRoot(launcherPackageRoot(launcher), expectedPackageRoot);
256
289
  const configuredDir = config.hooks?.windows_managed_dir ?? config.hooks?.managed_dir;
257
290
  const groups = config.hooks?.PreToolUse;
258
291
  const canonicalCommand = (value) => {