evolcore 0.0.35 → 0.0.36

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 (224) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +6 -0
  3. package/bin/install-codex-managed-hooks.mjs +20 -3
  4. package/dist/agents/baseagent-availability.js +1 -1
  5. package/dist/agents/baseagent.js +88 -0
  6. package/dist/agents/claude-runner.js +59 -12
  7. package/dist/agents/codex/app-server-client.js +18 -1
  8. package/dist/agents/codex-runner.js +262 -21
  9. package/dist/agents/ecagent-runner.js +47 -11
  10. package/dist/agents/gemini-runner.js +36 -12
  11. package/dist/aun/aid/client.js +4 -3
  12. package/dist/aun/aid/control-aid.js +270 -8
  13. package/dist/aun/aid/identity.js +6 -3
  14. package/dist/aun/aid/ownership-operation.js +58 -0
  15. package/dist/aun/aid/store.js +1 -0
  16. package/dist/aun/group/fs-download.js +67 -2
  17. package/dist/aun/group/history.js +20 -5
  18. package/dist/aun/group/operations.js +8 -2
  19. package/dist/aun/menu/client.js +39 -2
  20. package/dist/aun/menu/transport.js +1 -1
  21. package/dist/aun/msg/history.js +43 -4
  22. package/dist/aun/msg/managed-operation.js +30 -53
  23. package/dist/aun/msg/p2p.js +51 -15
  24. package/dist/aun/outbox.js +4 -0
  25. package/dist/channels/aun.js +260 -73
  26. package/dist/channels/daemon.js +6 -4
  27. package/dist/channels/feishu.js +3 -0
  28. package/dist/cli/agent-command.js +161 -223
  29. package/dist/cli/agent-create.js +190 -223
  30. package/dist/cli/agent.js +3 -1
  31. package/dist/cli/aid-bind-command.js +53 -0
  32. package/dist/cli/aun-commands.js +384 -91
  33. package/dist/cli/bench.js +1 -1
  34. package/dist/cli/cli-argv.js +74 -0
  35. package/dist/cli/daemon-commands.js +105 -74
  36. package/dist/cli/diag.js +1 -1
  37. package/dist/cli/fs-command.js +18 -19
  38. package/dist/cli/getmeta-command.js +159 -6
  39. package/dist/cli/index.js +6 -12
  40. package/dist/cli/init-channel.js +8 -55
  41. package/dist/cli/init.js +125 -218
  42. package/dist/cli/queue-command.js +11 -8
  43. package/dist/cli/restart-monitor.js +134 -48
  44. package/dist/cli/session-command.js +1 -1
  45. package/dist/cli/stats.js +7 -5
  46. package/dist/cli/thread-command.js +103 -30
  47. package/dist/cli/trigger-command.js +1 -1
  48. package/dist/cli/watch-msg-diag.js +1 -0
  49. package/dist/config/access-policy.js +2 -2
  50. package/dist/config/boot-log.js +14 -11
  51. package/dist/config/config-field-policy.js +9 -1
  52. package/dist/config/config-manager.js +176 -90
  53. package/dist/config/config-operation-service.js +7 -14
  54. package/dist/config/contact-book-store.js +142 -26
  55. package/dist/config/contact-book.js +4 -2
  56. package/dist/config/lifecycle.js +1 -1
  57. package/dist/config/owner-config.js +96 -0
  58. package/dist/config/peer-role-resolver.js +12 -18
  59. package/dist/config/providers-config.js +382 -0
  60. package/dist/config/providers-import.js +74 -0
  61. package/dist/config/providers-management.js +328 -0
  62. package/dist/config/providers.js +22 -0
  63. package/dist/config/resolved-config-op.js +17 -14
  64. package/dist/config/snapshot.js +28 -16
  65. package/dist/config-store.js +18 -14
  66. package/dist/core/agent-ipc-registration.js +21 -63
  67. package/dist/core/agent-runtime.js +16 -5
  68. package/dist/core/auth/agent-delegation.js +199 -25
  69. package/dist/core/auth/auth-gateway.js +44 -2
  70. package/dist/core/auth/authorization-denial.js +1 -1
  71. package/dist/core/auth/debug-context.js +2 -1
  72. package/dist/core/auth/delegation-authorization.js +2 -2
  73. package/dist/core/auth/delegation-diagnostics.js +4 -1
  74. package/dist/core/auth/operation-authorizer.js +10 -1
  75. package/dist/core/auth/operation-catalog.js +19 -1
  76. package/dist/core/bootstrap-service.js +43 -20
  77. package/dist/core/channel-loader.js +0 -1
  78. package/dist/core/channel-runtime.js +30 -4
  79. package/dist/core/command/agent-control.js +196 -37
  80. package/dist/core/command/cli-intent-parser.js +60 -4
  81. package/dist/core/command/command-handler.js +212 -60
  82. package/dist/core/command/connect-menu.js +1 -0
  83. package/dist/core/command/diag-service.js +5 -4
  84. package/dist/core/command/file-search.js +368 -0
  85. package/dist/core/command/menu-catalog.js +2 -1
  86. package/dist/core/command/menu-handler.js +292 -107
  87. package/dist/core/command/menu-protocol.js +23 -0
  88. package/dist/core/command/role-menu.js +7 -19
  89. package/dist/core/command/skill-slash.js +130 -25
  90. package/dist/core/command/slash-handler.js +101 -53
  91. package/dist/core/command/topic-slash.js +16 -5
  92. package/dist/core/daemon-bootstrap.js +7 -1
  93. package/dist/core/daemon-control.js +19 -1
  94. package/dist/core/daemon-lifecycle.js +2 -1
  95. package/dist/core/event-catalog.js +2 -0
  96. package/dist/core/evolagent-registry.js +13 -2
  97. package/dist/core/evolagent.js +3 -6
  98. package/dist/core/handoff/ipc-registration.js +2 -2
  99. package/dist/core/handoff/runtime.js +40 -6
  100. package/dist/core/handoff/store.js +1 -0
  101. package/dist/core/inference/text-inference.js +95 -6
  102. package/dist/core/ipc-registration.js +43 -24
  103. package/dist/core/memory/consolidation-context.js +4 -1
  104. package/dist/core/memory/consolidation.js +25 -14
  105. package/dist/core/message/aun-ipc-sender.js +296 -88
  106. package/dist/core/message/aun-request-registry.js +226 -0
  107. package/dist/core/message/create-status.js +33 -4
  108. package/dist/core/message/message-bridge.js +62 -13
  109. package/dist/core/message/message-log.js +0 -1
  110. package/dist/core/message/message-queue.js +4 -1
  111. package/dist/core/message/message-utils.js +8 -1
  112. package/dist/core/message/peer-mode.js +17 -9
  113. package/dist/core/message/response-engine.js +266 -124
  114. package/dist/core/message/retry-scheduler.js +11 -8
  115. package/dist/core/model/catalog-service.js +60 -18
  116. package/dist/core/model/model-catalog.js +112 -9
  117. package/dist/core/model/model-fallback.js +94 -26
  118. package/dist/core/ownership/owner-resolver.js +687 -0
  119. package/dist/core/permission/approval-gateway.js +196 -62
  120. package/dist/core/permission/ec-command-parser.js +138 -25
  121. package/dist/core/permission/filesystem-approval-scope.js +141 -0
  122. package/dist/core/permission/protected-paths.js +14 -1
  123. package/dist/core/permission/sandbox-runtime.js +171 -18
  124. package/dist/core/permission/tool-policy.js +13 -2
  125. package/dist/core/role/runtime-policy.js +3 -4
  126. package/dist/core/session/session-idle-monitor.js +10 -8
  127. package/dist/core/session/session-manager.js +72 -45
  128. package/dist/core/session/session-mapper.js +18 -7
  129. package/dist/core/session/session-renew.js +5 -4
  130. package/dist/core/session/session-title.js +2 -1
  131. package/dist/core/session/session-turn-coordinator.js +4 -2
  132. package/dist/core/skill/index-generator.js +2 -16
  133. package/dist/core/task/task-recovery-service.js +15 -2
  134. package/dist/core/thread/command-parser.js +28 -13
  135. package/dist/core/thread/index.js +1 -0
  136. package/dist/core/thread/ipc-operation.js +11 -8
  137. package/dist/core/thread/thread-operation.js +79 -44
  138. package/dist/core/thread/thread-route.js +54 -6
  139. package/dist/core/thread/thread-service.js +236 -45
  140. package/dist/core/thread/topic-id.js +248 -0
  141. package/dist/eck/kit-renderer.js +1 -1
  142. package/dist/eck/message-renderer.js +12 -2
  143. package/dist/index.js +50 -27
  144. package/dist/ipc.js +59 -6
  145. package/dist/paths.js +1 -0
  146. package/dist/product.js +1 -0
  147. package/dist/response-system/engines/v1/proactive-flow.js +10 -3
  148. package/dist/stats/db.js +8 -0
  149. package/dist/stats/writer.js +26 -4
  150. package/dist/trigger/authorization.js +48 -3
  151. package/dist/trigger/feedback.js +28 -10
  152. package/dist/trigger/ipc-service.js +86 -10
  153. package/dist/trigger/local-files.js +55 -23
  154. package/dist/trigger/scheduler.js +57 -11
  155. package/dist/trigger/system-definitions.js +1 -0
  156. package/dist/trigger/validation.js +44 -15
  157. package/dist/utils/aid-bind.js +17 -297
  158. package/dist/utils/avatar-upload.js +16 -4
  159. package/dist/utils/cross-platform.js +109 -34
  160. package/dist/utils/ecweb-supervisor.js +1 -1
  161. package/dist/utils/ecweb-utils.js +8 -1
  162. package/dist/utils/error-utils.js +44 -6
  163. package/dist/utils/instance-registry.js +12 -2
  164. package/dist/utils/npm-ops.js +102 -27
  165. package/dist/utils/package-version-info.js +72 -27
  166. package/dist/utils/restart-safety.js +50 -0
  167. package/dist/utils/upgrade-jobs.js +304 -0
  168. package/dist/utils/windows-autostart.js +17 -10
  169. package/kits/docs/INDEX.md +5 -0
  170. package/kits/docs/aun/ABILITY_CALLING.md +239 -0
  171. package/kits/docs/evolcore/INDEX.md +14 -3
  172. package/kits/docs/evolcore/agent-create.md +55 -141
  173. package/kits/docs/evolcore/agent.md +38 -16
  174. package/kits/docs/evolcore/aid.md +34 -0
  175. package/kits/docs/evolcore/config.md +20 -1
  176. package/kits/docs/evolcore/event.md +2 -2
  177. package/kits/docs/evolcore/fs.md +18 -2
  178. package/kits/docs/evolcore/group-collaboration.md +13 -246
  179. package/kits/docs/evolcore/group.md +2 -1
  180. package/kits/docs/evolcore/memory-consolidation-batches.md +1 -1
  181. package/kits/docs/evolcore/menu-protocol.md +65 -1
  182. package/kits/docs/evolcore/msg.md +64 -2
  183. package/kits/docs/evolcore/skill.md +86 -0
  184. package/kits/docs/evolcore/stats.md +6 -0
  185. package/kits/docs/evolcore/task.md +2 -0
  186. package/kits/docs/evolcore/thread-chain.md +145 -51
  187. package/kits/docs/evolcore/trigger.md +48 -3
  188. package/kits/eck_manifest.json +21 -0
  189. package/kits/eck_message_manifest.json +4 -4
  190. package/kits/migrations/migrate-role-config-v5.mjs +20 -7
  191. package/kits/rules/01-overview.md +2 -1
  192. package/kits/rules/03-identity.md +3 -1
  193. package/kits/rules/04-relation.md +1 -1
  194. package/kits/rules/07-memory-and-thread.md +1 -1
  195. package/kits/schemas/_meta.json +16 -1
  196. package/kits/schemas/agent-config.schema.13.json +44 -2
  197. package/kits/schemas/contact-book.schema.3.json +5 -0
  198. package/kits/schemas/daemon.schema.6.json +3 -1
  199. package/kits/schemas/daemon.schema.8.json +329 -0
  200. package/kits/schemas/defaults.schema.5.json +39 -3
  201. package/kits/schemas/providers.schema.1.json +76 -0
  202. package/kits/schemas/relation-config.schema.9.json +5 -1
  203. package/kits/skills/.switches.json +28 -0
  204. package/kits/skills/aid-ability/SKILL.md +214 -0
  205. package/kits/skills/ec-agent-create/SKILL.md +162 -0
  206. package/kits/skills/ec-group/SKILL.md +2 -1
  207. package/kits/skills/ec-group-collaboration/SKILL.md +228 -0
  208. package/kits/skills/ec-identity/SKILL.md +143 -0
  209. package/kits/skills/ec-skill/scripts/cli.mjs +36 -3
  210. package/kits/skills/ec-skill/scripts/skill.mjs +202 -15
  211. package/kits/skills/ec-trigger/SKILL.md +167 -0
  212. package/kits/skills/ec-trigger/references/examples.md +153 -0
  213. package/kits/skills/thread-ops/SKILL.md +108 -420
  214. package/kits/templates/message-fragments/thread-context.md +1 -2
  215. package/kits/templates/message-fragments/trigger-thread-check.md +1 -1
  216. package/kits/templates/roles/member.json +1 -1
  217. package/kits/templates/roles/visitor.json +1 -0
  218. package/kits/templates/system-fragments/bootstrap.md +1 -0
  219. package/kits/templates/system-fragments/channel.md +2 -1
  220. package/kits/templates/system-fragments/commands.md +5 -4
  221. package/kits/templates/system-fragments/identity.md +2 -0
  222. package/kits/templates/system-fragments/session.md +1 -1
  223. package/kits/templates/system-fragments/venue.md +1 -1
  224. package/package.json +4 -3
@@ -10,6 +10,8 @@ import { assertWindowsCodexFilesystemRuleBudget, buildCodexProtectedFilesystemRu
10
10
  import { CODEX_THREAD_ACTIVE_WRITER, CodexAppServerClient, } from './codex/app-server-client.js';
11
11
  import { resolveOpenaiConfig, resolveCodexCliPath, resolveCodexPowerShellShimPath, } from './baseagent.js';
12
12
  import { logger } from '../utils/logger.js';
13
+ import { resolveProviderService } from '../config/providers.js';
14
+ import { catalogHash } from '../core/model/catalog-service.js';
13
15
  import { summarizeToolInputForAudit } from '../utils/tool-summary.js';
14
16
  import { auditCodexApprovalDecision, auditPermissionLifecycle, auditToolPreflightDenial } from '../core/auth/authorization-audit.js';
15
17
  import { classifyError, ErrorType, getToolResultErrorText, isOutputTokenLimitError, isRetryableError } from '../utils/error-utils.js';
@@ -31,12 +33,19 @@ import { createHash, randomBytes } from 'crypto';
31
33
  import { buildModelRequestHeaders } from './request-identity.js';
32
34
  import { normalizeToolErrorClassification, normalizeToolErrorCode, normalizeToolErrorDetailCode, } from '../core/permission/tool-error-code.js';
33
35
  import fs from 'fs';
36
+ import { assertOwnershipAuthorization } from '../core/ownership/owner-resolver.js';
34
37
  import path from 'path';
35
38
  import os from 'os';
36
39
  const APPROVAL_LOG_SUMMARY_MAX_LENGTH = 256;
37
40
  const CODEX_INTERRUPT_TIMEOUT_MS = 5_000;
38
41
  function toAgentErrorType(message) {
39
- switch (classifyError(new Error(message))) {
42
+ // Forgetting the provider thread is the only remedy for a missing model.
43
+ // classifyError must keep returning MODEL_UNAVAILABLE for it, but the runner
44
+ // must not present it as a generic unknown failure.
45
+ const classification = classifyError(new Error(message));
46
+ if (classification === ErrorType.MODEL_UNAVAILABLE)
47
+ return ErrorType.MODEL_UNAVAILABLE;
48
+ switch (classification) {
40
49
  case ErrorType.CONTEXT_TOO_LONG: return 'context_too_long';
41
50
  case ErrorType.AUTH_ERROR: return 'auth';
42
51
  case ErrorType.API_ERROR:
@@ -172,6 +181,13 @@ function isCodexReasoningNotification(method) {
172
181
  || method === 'item/reasoning/summaryPartAdded';
173
182
  }
174
183
  const CODEX_THREAD_HANDOFF_TIMEOUT_MS = 2_000;
184
+ /**
185
+ * A turn/start that never reached the backend leaves the previous writer being
186
+ * released asynchronously. The next resume in that same window is rejected with
187
+ * "already has an active writer"; retrying the resume — never the input — is safe
188
+ * because the failed turn consumed nothing.
189
+ */
190
+ const CODEX_RESUME_WRITER_RETRY_DELAYS_MS = [150, 500, 1_000];
175
191
  function stableSecurityValue(value) {
176
192
  if (value === undefined)
177
193
  return 'undefined';
@@ -430,6 +446,8 @@ export class CodexRunner {
430
446
  appServerClient = null;
431
447
  /** Trusted fullaccess calls use a separate unmasked app-server process. */
432
448
  fullAccessAppServerClient = null;
449
+ retiredProviderClients = new Set();
450
+ providerClientRevisions = new WeakMap();
433
451
  onSessionIdUpdate;
434
452
  onCompactStart;
435
453
  permissionGateway;
@@ -483,18 +501,27 @@ export class CodexRunner {
483
501
  this.onSessionIdUpdate = callbacks.onSessionIdUpdate;
484
502
  this.codexVersion = runtime?.codexVersion;
485
503
  }
486
- getAppServerClient(fullAccess = false) {
504
+ getAppServerClient(fullAccess = false, providerOverride) {
487
505
  const existing = fullAccess ? this.fullAccessAppServerClient : this.appServerClient;
488
- if (existing)
506
+ const connection = this.currentProviderConfig(providerOverride);
507
+ const revision = connection.providerId ? catalogHash({
508
+ providerId: connection.providerId,
509
+ baseUrl: connection.baseUrl, apiKey: connection.apiKey,
510
+ headers: connection.headers, queryParams: connection.queryParams,
511
+ }) : undefined;
512
+ if (existing && (!revision || this.providerClientRevisions.get(existing) === revision))
489
513
  return existing;
514
+ if (existing)
515
+ this.retiredProviderClients.add(existing);
490
516
  const client = new CodexAppServerClient({
491
- apiKey: this.resolvedConfig.apiKey,
517
+ apiKey: connection.apiKey,
492
518
  codexVersion: this.codexVersion,
493
- authType: this.resolvedConfig.authType,
494
- baseUrl: this.resolvedConfig.baseUrl,
495
- provider: this.resolvedConfig.provider,
496
- headers: this.resolvedConfig.headers,
497
- queryParams: this.resolvedConfig.queryParams,
519
+ authType: connection.authType,
520
+ baseUrl: connection.baseUrl,
521
+ provider: connection.providerId ? `evolcore_registry_${catalogHash(connection.providerId).slice(0, 20)}` : connection.provider,
522
+ isolatedProvider: connection.providerId !== undefined,
523
+ headers: connection.headers,
524
+ queryParams: connection.queryParams,
498
525
  model: this.model,
499
526
  effort: this.effort,
500
527
  enableRequestUserInput: this.resolvedConfig.enableRequestUserInput,
@@ -506,6 +533,8 @@ export class CodexRunner {
506
533
  // until the cross-client archive fallback runs.
507
534
  onServerRequest: request => this.handleAppServerRequest(request),
508
535
  });
536
+ if (revision)
537
+ this.providerClientRevisions.set(client, revision);
509
538
  client.onNotification(notification => {
510
539
  this.trackApprovalItemNotification(notification);
511
540
  if (notification.method !== 'thread/closed')
@@ -529,6 +558,21 @@ export class CodexRunner {
529
558
  }
530
559
  return client;
531
560
  }
561
+ currentProviderConfig(providerOverride) {
562
+ const providerId = providerOverride ?? this.resolvedConfig.providerId;
563
+ if (!providerId)
564
+ return this.resolvedConfig;
565
+ const provider = resolveProviderService(providerId, 'codex');
566
+ if (!provider.apiKey)
567
+ throw new Error(`Provider ${provider.providerId} has no API key`);
568
+ return {
569
+ ...this.resolvedConfig,
570
+ ...provider,
571
+ apiKey: provider.apiKey,
572
+ headers: buildModelRequestHeaders({ baseagent: 'codex', baseUrl: provider.baseUrl,
573
+ agentAid: this.resolvedConfig.agentAid, configuredHeaders: provider.headers }),
574
+ };
575
+ }
532
576
  getAppServerClientForThread(threadId) {
533
577
  const subscribed = this.threadSubscriptions.get(threadId);
534
578
  if (subscribed)
@@ -612,6 +656,43 @@ export class CodexRunner {
612
656
  });
613
657
  return await releasePromise;
614
658
  }
659
+ /**
660
+ * Resume a thread whose previous writer may still be releasing. Unlike the
661
+ * cross-client handoff, this only covers the same connection: the owner is
662
+ * unsubscribed (and awaited) once before the bounded retries, and any other
663
+ * active-writer rejection is released to the caller unchanged.
664
+ */
665
+ async resumeThreadAllowingWriterRelease(appServer, threadId, projectPath, threadOptions, previousAppServer) {
666
+ try {
667
+ return await appServer.threadResume(threadId, projectPath, threadOptions);
668
+ }
669
+ catch (error) {
670
+ if (!isCodexActiveWriterError(error) || (previousAppServer && previousAppServer !== appServer))
671
+ throw error;
672
+ }
673
+ const subscription = this.threadSubscriptions.get(threadId);
674
+ if (subscription?.client === appServer && subscription.state === 'subscribed') {
675
+ await this.releaseThreadSubscription(appServer, threadId, 'writer-release-wait', {
676
+ waitForClose: true,
677
+ timeoutMs: CODEX_THREAD_HANDOFF_TIMEOUT_MS,
678
+ });
679
+ }
680
+ for (const delayMs of CODEX_RESUME_WRITER_RETRY_DELAYS_MS) {
681
+ await new Promise(resolve => {
682
+ const timer = setTimeout(resolve, delayMs);
683
+ timer.unref?.();
684
+ });
685
+ try {
686
+ return await appServer.threadResume(threadId, projectPath, threadOptions);
687
+ }
688
+ catch (error) {
689
+ if (!isCodexActiveWriterError(error))
690
+ throw error;
691
+ logger.warn(`[CodexRunner] Thread writer still active after ${delayMs}ms: thread=${threadId}`);
692
+ }
693
+ }
694
+ return await appServer.threadResume(threadId, projectPath, threadOptions);
695
+ }
615
696
  async prepareThreadSubscription(client, threadId) {
616
697
  const existing = this.threadSubscriptions.get(threadId);
617
698
  if (!existing)
@@ -860,7 +941,7 @@ export class CodexRunner {
860
941
  const command = typeof toolInput.command === 'string' ? toolInput.command : '';
861
942
  return classifyEvolcoreShellCommand(command).kind !== 'none';
862
943
  }
863
- armApprovedDelegationCommand(sessionId, argv) {
944
+ armApprovedDelegationCommand(sessionId, argv, approvalId) {
864
945
  const threadId = this.activeSessions.get(sessionId) ?? this.provisionalSessions.get(sessionId);
865
946
  const sessionToken = threadId ? this.ensureThreadCredentialLoaded(threadId) : undefined;
866
947
  const commandHash = hashDelegatedCommandArgv(argv);
@@ -868,7 +949,7 @@ export class CodexRunner {
868
949
  if (!sessionToken || !commandHash || !arm)
869
950
  return false;
870
951
  try {
871
- return arm(sessionToken, commandHash);
952
+ return arm(sessionToken, commandHash, approvalId);
872
953
  }
873
954
  catch (error) {
874
955
  logger.warn(`[CodexRunner] delegation arm callback failed: session=${sessionId} error=${error instanceof Error ? error.message : String(error)}`);
@@ -959,8 +1040,9 @@ export class CodexRunner {
959
1040
  this.pruneThreadOperationLocks();
960
1041
  }
961
1042
  resetAppServerClient() {
962
- const clients = [this.appServerClient, this.fullAccessAppServerClient]
1043
+ const clients = [...this.retiredProviderClients, this.appServerClient, this.fullAccessAppServerClient]
963
1044
  .filter((client) => !!client);
1045
+ this.retiredProviderClients.clear();
964
1046
  this.appServerClient = null;
965
1047
  this.fullAccessAppServerClient = null;
966
1048
  this.threadSubscriptions.clear();
@@ -1232,7 +1314,7 @@ export class CodexRunner {
1232
1314
  }
1233
1315
  getModel() { return this.model; }
1234
1316
  getModelCatalog() {
1235
- return getRunnerCatalog('codex', this.resolvedConfig.agentAid, this.resolvedConfig);
1317
+ return getRunnerCatalog('codex', this.resolvedConfig.agentAid, this.currentProviderConfig());
1236
1318
  }
1237
1319
  async listModels() {
1238
1320
  const catalog = await this.getModelCatalog();
@@ -1356,6 +1438,7 @@ export class CodexRunner {
1356
1438
  // nested mount namespace; it can fail while creating a missing
1357
1439
  // target such as triggers/history.jsonl.
1358
1440
  expandLClassReadDeny: process.platform !== 'linux',
1441
+ outerHClassGuard: process.platform === 'linux',
1359
1442
  }),
1360
1443
  ...this.resolveGitMetadataWriteRules(projectPath, mode),
1361
1444
  ...this.resolveSystemSessionWriteRules(sessionId),
@@ -1532,6 +1615,12 @@ export class CodexRunner {
1532
1615
  const normalizedInput = toolInput && typeof toolInput === 'object' && !Array.isArray(toolInput)
1533
1616
  ? toolInput
1534
1617
  : {};
1618
+ try {
1619
+ await assertOwnershipAuthorization(context);
1620
+ }
1621
+ catch (error) {
1622
+ return { ok: true, applicable: true, decision: 'deny', reason: error instanceof Error ? error.message : String(error) };
1623
+ }
1535
1624
  const isShellTool = isShellToolName(toolName); // canonical normalisation via tool-canonical.ts
1536
1625
  const recordPreToolUseDenial = async (policyCode, reason) => {
1537
1626
  const summary = summarizeToolInputForAudit(toolName, normalizedInput).slice(0, 512);
@@ -1924,7 +2013,7 @@ export class CodexRunner {
1924
2013
  this.chatModes.set(sessionId, callMode);
1925
2014
  const callApprovalPolicy = this.toApprovalPolicy(callMode);
1926
2015
  const executionSandbox = this.buildExecutionSandboxOptions(sessionId, callMode, projectPath, modelOverride?.bootstrapAgentMdPath, modelOverride?.personalMdPath, undefined);
1927
- const appServer = this.getAppServerClient(callMode === 'fullaccess');
2016
+ const appServer = this.getAppServerClient(callMode === 'fullaccess', modelOverride?.provider);
1928
2017
  this.dropExpiredPendingInterrupt(sessionId);
1929
2018
  const effectiveApprovalPolicy = callApprovalPolicy;
1930
2019
  const capabilityConfig = await this.resolveCapabilityThreadConfig(projectPath);
@@ -1965,7 +2054,7 @@ export class CodexRunner {
1965
2054
  // Release that one thread before asking this client to resume it.
1966
2055
  previousAppServer = await this.prepareThreadSubscription(appServer, agentSessionId);
1967
2056
  try {
1968
- threadResponse = await appServer.threadResume(agentSessionId, projectPath, threadOptions);
2057
+ threadResponse = await this.resumeThreadAllowingWriterRelease(appServer, agentSessionId, projectPath, threadOptions, previousAppServer);
1969
2058
  }
1970
2059
  catch (error) {
1971
2060
  if (isCodexActiveWriterError(error) && previousAppServer && previousAppServer !== appServer) {
@@ -2075,6 +2164,7 @@ export class CodexRunner {
2075
2164
  completedTurnIds: new Set(),
2076
2165
  openToolCalls: new Map(),
2077
2166
  activeSubagentThreads: new Set(),
2167
+ subagentUsage: new Map(),
2078
2168
  turnCompleted: false,
2079
2169
  inputId: turn?.inputId,
2080
2170
  inputAcceptedEmitted: false,
@@ -2088,7 +2178,14 @@ export class CodexRunner {
2088
2178
  // 仅从 turn/started 锁定权威 turnId — resume 时会有上一轮 turn 的残留通知
2089
2179
  // (如 thread/tokenUsage/updated)先于新 turn 到达,不能用它们 latch turnId
2090
2180
  const params = notification.params || {};
2091
- const notifThreadId = params.threadId ?? params.thread_id;
2181
+ const notifThreadId = params.threadId ?? params.thread_id ?? params.thread?.id;
2182
+ const spawnedBy = params.thread?.source?.subAgent?.thread_spawn?.parent_thread_id;
2183
+ if (notification.method === 'thread/started' && typeof notifThreadId === 'string'
2184
+ && (spawnedBy === threadId || this.childThreadSessions.get(notifThreadId) === sessionId)) {
2185
+ const usage = state.subagentUsage.get(notifThreadId) ?? {};
2186
+ usage.model = typeof params.thread?.model === 'string' ? params.thread.model : usage.model;
2187
+ state.subagentUsage.set(notifThreadId, usage);
2188
+ }
2092
2189
  const item = params.item && typeof params.item === 'object' ? params.item : undefined;
2093
2190
  const emittedByChild = typeof notifThreadId === 'string'
2094
2191
  && this.childThreadSessions.get(notifThreadId) === sessionId;
@@ -2097,6 +2194,23 @@ export class CodexRunner {
2097
2194
  this.trackSubagentLifecycle(notification, state, appServer);
2098
2195
  if (emittedByChild && notifThreadId !== threadId) {
2099
2196
  const childTurnId = this.extractTurnId(notification);
2197
+ if (notification.method === 'thread/tokenUsage/updated') {
2198
+ const activeTurn = this.activeSubagentTurns.get(notifThreadId);
2199
+ if (childTurnId && activeTurn?.turnId === childTurnId) {
2200
+ this.recordSubagentUsage(state, notifThreadId, childTurnId, params.tokenUsage);
2201
+ }
2202
+ }
2203
+ if (notification.method === 'turn/completed') {
2204
+ const terminalUsage = params.turn?.tokenUsage ?? params.turn?.usage;
2205
+ if (terminalUsage && childTurnId && !state.subagentUsage?.get(notifThreadId)?.seenTurns?.has(childTurnId)) {
2206
+ this.recordSubagentUsage(state, notifThreadId, childTurnId, terminalUsage);
2207
+ }
2208
+ }
2209
+ if (notification.method === 'model/rerouted' && typeof params.toModel === 'string') {
2210
+ const childUsage = state.subagentUsage.get(notifThreadId) ?? {};
2211
+ childUsage.model = params.toModel;
2212
+ state.subagentUsage.set(notifThreadId, childUsage);
2213
+ }
2100
2214
  if (notification.method === 'turn/started' && childTurnId) {
2101
2215
  this.activeSubagentTurns.set(notifThreadId, {
2102
2216
  sessionId,
@@ -3010,6 +3124,7 @@ export class CodexRunner {
3010
3124
  return;
3011
3125
  }
3012
3126
  if (notification.method === 'item/completed' && key) {
3127
+ this.revokeApprovalForItem(threadId, itemId);
3013
3128
  this.trackedApprovalItems.delete(key);
3014
3129
  return;
3015
3130
  }
@@ -3021,6 +3136,7 @@ export class CodexRunner {
3021
3136
  : undefined;
3022
3137
  for (const [trackedKey, tracked] of this.trackedApprovalItems) {
3023
3138
  if (tracked.threadId === threadId && (!completedTurnId || tracked.turnId === completedTurnId)) {
3139
+ this.revokeApprovalForItem(threadId, tracked.itemId);
3024
3140
  this.trackedApprovalItems.delete(trackedKey);
3025
3141
  }
3026
3142
  }
@@ -3043,6 +3159,14 @@ export class CodexRunner {
3043
3159
  ? conversationIdValue
3044
3160
  : undefined;
3045
3161
  }
3162
+ revokeApprovalForItem(threadId, itemId) {
3163
+ if (!threadId || typeof itemId !== 'string' || !itemId)
3164
+ return;
3165
+ const sessionId = this.findSessionKeyByThread(threadId);
3166
+ if (!sessionId)
3167
+ return;
3168
+ this.permissionContexts.get(sessionId)?.revokeApprovedDelegationCommand?.(itemId);
3169
+ }
3046
3170
  clearPendingToolDenialsForTurn(threadId, turnId) {
3047
3171
  for (const key of this.pendingToolDenials.keys()) {
3048
3172
  let parsed;
@@ -3311,12 +3435,14 @@ export class CodexRunner {
3311
3435
  logger.info(`[CodexRunner] app-server approval request id=${request.id} method=${request.method} session=${sessionKey} mode=${sessionMode} tool=${toolName} summary=${logSummary}`);
3312
3436
  const isCommandApproval = request.method === 'item/commandExecution/requestApproval'
3313
3437
  || request.method === 'execCommandApproval';
3314
- const managedEcIntent = isCommandApproval && this.isManagedEvolcoreCommandIntent(toolInput);
3315
3438
  const sessionCredential = this.sessionTokenForSession(sessionKey, typeof params.threadId === 'string' ? params.threadId : undefined);
3316
3439
  const canonicalEcApproval = isCommandApproval
3317
3440
  ? this.resolveCanonicalEcApproval(toolInput, this.getManagedTempDir(sessionKey), sessionCredential)
3318
3441
  : undefined;
3319
3442
  const approvedCommand = canonicalEcApproval?.argv;
3443
+ // Canonical parsing is authoritative. Intent classification remains a
3444
+ // fail-closed signal for malformed EC-shaped commands that cannot be armed.
3445
+ const managedEcIntent = isCommandApproval && (approvedCommand?.[0] === 'ec' || this.isManagedEvolcoreCommandIntent(toolInput));
3320
3446
  const denyInfrastructure = async (policyCode, message, errorDetailCode) => {
3321
3447
  logger.warn(`[CodexRunner] ${message}: session=${sessionKey} requestId=${request.id ?? '<missing>'}`);
3322
3448
  try {
@@ -3395,7 +3521,7 @@ export class CodexRunner {
3395
3521
  return await denyInfrastructure('delegation_token_mismatch', 'EC command approval contains a delegation token different from the active thread credential');
3396
3522
  }
3397
3523
  if ((hasSessionCredential || canArmDelegation)
3398
- && !this.armApprovedDelegationCommand(sessionKey, approvedCommand)) {
3524
+ && !this.armApprovedDelegationCommand(sessionKey, approvedCommand, approvalCallId ?? approvalRequestId)) {
3399
3525
  return await denyInfrastructure('delegation_not_armed', 'EC command approval failed to arm delegation');
3400
3526
  }
3401
3527
  }
@@ -4084,6 +4210,12 @@ export class CodexRunner {
4084
4210
  }
4085
4211
  async resolvePermissionDecision(sessionKey, toolName, toolInput, summary, reason, workspacePath = process.cwd(), operationCwd = workspacePath, requestId, callId) {
4086
4212
  const permissionContext = this.permissionContexts.get(sessionKey);
4213
+ try {
4214
+ await assertOwnershipAuthorization(permissionContext);
4215
+ }
4216
+ catch {
4217
+ return 'deny';
4218
+ }
4087
4219
  // 系统会话:审批路径同样只看模块判定(FileChange / PermissionGrant 一律被模块拒绝)
4088
4220
  if (permissionContext?.systemSessionCheck) {
4089
4221
  const decision = permissionContext.systemSessionCheck(toolName, toolInput);
@@ -4267,7 +4399,7 @@ export class CodexRunner {
4267
4399
  if (policyToolName === 'FileChange') {
4268
4400
  return resolveRuntimeApproval(await this.permissionGateway.requestPermission(sessionKey, policyToolName, policyInput, permissionPrompt, this.permissionContexts.get(sessionKey), summary, reason || 'Codex 请求扩大当前命令或 turn 的文件系统权限', grantScope, undefined, { fileChangeCwd: workspacePath }));
4269
4401
  }
4270
- return resolveRuntimeApproval(await this.permissionGateway.requestPermission(sessionKey, toolName, checkedInput, permissionPrompt, this.permissionContexts.get(sessionKey), summary, reason || 'Codex 请求扩大当前命令或 turn 的文件系统权限', grantScope));
4402
+ return resolveRuntimeApproval(await this.permissionGateway.requestPermission(sessionKey, toolName, checkedInput, permissionPrompt, this.permissionContexts.get(sessionKey), summary, reason || 'Codex 请求扩大当前命令或 turn 的文件系统权限', grantScope, undefined, toolName === 'PermissionGrant' ? { filesystemCwd: operationCwd, workspacePath } : undefined));
4271
4403
  }
4272
4404
  if (mode === 'request' || mode === 'bypass') {
4273
4405
  const dangerous = await requestDangerousCommandPermission(this.permissionGateway, sessionKey, toolName, checkedInput, permissionPrompt, this.permissionContexts.get(sessionKey), grantScope, mode);
@@ -4735,8 +4867,16 @@ export class CodexRunner {
4735
4867
  }
4736
4868
  }
4737
4869
  trackSubagentLifecycle(notification, state, appServer) {
4870
+ const subagentUsage = state.subagentUsage ?? (state.subagentUsage = new Map());
4738
4871
  const params = (notification.params || {});
4739
4872
  const item = params.item && typeof params.item === 'object' ? params.item : undefined;
4873
+ if (item?.type === 'collabAgentToolCall' && typeof item.model === 'string') {
4874
+ for (const childThreadId of Array.isArray(item.receiverThreadIds) ? item.receiverThreadIds : []) {
4875
+ if (typeof childThreadId !== 'string')
4876
+ continue;
4877
+ subagentUsage.set(childThreadId, { ...subagentUsage.get(childThreadId), model: item.model });
4878
+ }
4879
+ }
4740
4880
  if (!this.isSubagentActivityItem(item))
4741
4881
  return;
4742
4882
  const childThreadId = this.subagentThreadId(item);
@@ -4745,18 +4885,29 @@ export class CodexRunner {
4745
4885
  const kind = typeof item.kind === 'string' ? item.kind.toLowerCase() : '';
4746
4886
  if (kind === 'started') {
4747
4887
  state.activeSubagentThreads.add(childThreadId);
4888
+ subagentUsage.set(childThreadId, {
4889
+ ...subagentUsage.get(childThreadId),
4890
+ subagentType: this.subagentType(item),
4891
+ status: 'started',
4892
+ });
4748
4893
  this.registerChildThread(state.sessionId, childThreadId, state.projectPath);
4749
4894
  if (appServer)
4750
4895
  this.markThreadSubscribed(appServer, childThreadId);
4751
4896
  }
4752
4897
  if (kind === 'completed' || kind === 'failed' || kind === 'stopped' || kind === 'killed') {
4753
4898
  state.activeSubagentThreads.delete(childThreadId);
4899
+ subagentUsage.set(childThreadId, {
4900
+ ...subagentUsage.get(childThreadId),
4901
+ subagentType: this.subagentType(item),
4902
+ status: kind,
4903
+ });
4754
4904
  if (appServer)
4755
4905
  void this.releaseThreadSubscription(appServer, childThreadId, 'subagent-finished');
4756
4906
  this.unregisterChildThread(childThreadId);
4757
4907
  }
4758
4908
  }
4759
4909
  primeSubagentStateFromTurn(turn, state, appServer) {
4910
+ const subagentUsage = state.subagentUsage ?? (state.subagentUsage = new Map());
4760
4911
  for (const item of this.getTurnItems(turn)) {
4761
4912
  if (!this.isSubagentActivityItem(item))
4762
4913
  continue;
@@ -4766,12 +4917,22 @@ export class CodexRunner {
4766
4917
  continue;
4767
4918
  if (kind === 'started') {
4768
4919
  state.activeSubagentThreads.add(childThreadId);
4920
+ subagentUsage.set(childThreadId, {
4921
+ ...subagentUsage.get(childThreadId),
4922
+ subagentType: this.subagentType(item),
4923
+ status: 'started',
4924
+ });
4769
4925
  this.registerChildThread(state.sessionId, childThreadId, state.projectPath);
4770
4926
  if (appServer)
4771
4927
  this.markThreadSubscribed(appServer, childThreadId);
4772
4928
  }
4773
4929
  else if (kind === 'completed' || kind === 'failed' || kind === 'stopped' || kind === 'killed') {
4774
4930
  state.activeSubagentThreads.delete(childThreadId);
4931
+ subagentUsage.set(childThreadId, {
4932
+ ...subagentUsage.get(childThreadId),
4933
+ subagentType: this.subagentType(item),
4934
+ status: kind,
4935
+ });
4775
4936
  if (appServer)
4776
4937
  void this.releaseThreadSubscription(appServer, childThreadId, 'subagent-finished');
4777
4938
  this.unregisterChildThread(childThreadId);
@@ -4790,6 +4951,7 @@ export class CodexRunner {
4790
4951
  }
4791
4952
  async *transformAppServerStream(notifications, sessionId, state, controller, unsubscribe, appServer) {
4792
4953
  try {
4954
+ let completedTurn;
4793
4955
  let sessionIdEmitted = state.committed;
4794
4956
  if (sessionIdEmitted)
4795
4957
  yield { type: 'session_id', sessionId: state.threadId };
@@ -4810,8 +4972,15 @@ export class CodexRunner {
4810
4972
  throw persistenceError;
4811
4973
  }
4812
4974
  }
4813
- yield* this.mapAppServerNotification(notification, sessionId, state);
4975
+ for (const event of this.mapAppServerNotification(notification, sessionId, state)) {
4976
+ if (event.type === 'complete')
4977
+ completedTurn = notification.params?.turn ?? {};
4978
+ else
4979
+ yield event;
4980
+ }
4814
4981
  }
4982
+ if (completedTurn)
4983
+ yield this.mapAppServerTurnComplete(completedTurn, state);
4815
4984
  }
4816
4985
  finally {
4817
4986
  if (!state.committed && !state.persistenceFinalized && state.confirmProvisional) {
@@ -5503,16 +5672,83 @@ export class CodexRunner {
5503
5672
  const effort = typeof raw.effort === 'string' ? raw.effort : undefined;
5504
5673
  return { totalTokens, maxTokens, percentage, model, effort };
5505
5674
  }
5675
+ recordSubagentUsage(state, threadId, turnId, raw) {
5676
+ if (threadId === state.threadId || !raw || typeof raw !== 'object')
5677
+ return;
5678
+ const entries = state.subagentUsage ?? (state.subagentUsage = new Map());
5679
+ const child = entries.get(threadId) ?? {};
5680
+ const total = this.mapCodexTokenUsage(raw.total);
5681
+ const last = this.mapCodexTokenUsage(raw.last ?? (raw.total ? undefined : raw));
5682
+ const fields = ['input_tokens', 'output_tokens', 'cache_read_input_tokens', 'cache_creation_input_tokens'];
5683
+ const previous = child.total;
5684
+ const reset = total && previous && fields.some(field => (total[field] ?? 0) < (previous[field] ?? 0));
5685
+ const usage = total && previous && !reset
5686
+ ? Object.fromEntries(fields.map(field => [field, Math.max(0, (total[field] ?? 0) - (previous[field] ?? 0))]))
5687
+ : last;
5688
+ child.tokenUsage = raw;
5689
+ if (total)
5690
+ child.total = total;
5691
+ child.model = typeof raw.model === 'string' ? raw.model
5692
+ : typeof raw.context?.model === 'string' ? raw.context.model : child.model;
5693
+ if (usage) {
5694
+ (child.seenTurns ??= new Set()).add(turnId);
5695
+ if (fields.some(field => (usage[field] ?? 0) > 0)) {
5696
+ const model = child.model || 'unknown';
5697
+ const byModel = child.usageByModel ?? (child.usageByModel = new Map());
5698
+ const prior = byModel.get(model);
5699
+ byModel.set(model, Object.fromEntries(fields.map(field => [field, (prior?.[field] ?? 0) + (usage[field] ?? 0)])));
5700
+ }
5701
+ }
5702
+ entries.set(threadId, child);
5703
+ }
5506
5704
  mapAppServerTurnComplete(turn, state) {
5705
+ const subagentUsage = state.subagentUsage ?? (state.subagentUsage = new Map());
5507
5706
  const status = turn.status || 'completed';
5508
5707
  const outputLimit = status === 'failed' && isOutputTokenLimitError(new Error(turn.error?.message ?? ''));
5509
- const tokenUsage = this.mapCodexTokenUsage(state.tokenUsage?.last ?? turn.tokenUsage ?? turn.usage);
5708
+ const parentTokenUsage = this.mapCodexTokenUsage(state.tokenUsage?.last ?? turn.tokenUsage ?? turn.usage);
5709
+ const subagentUsages = [...subagentUsage.entries()]
5710
+ .filter(([threadId]) => threadId !== state.threadId)
5711
+ .flatMap(([threadId, subagent]) => [...(subagent.usageByModel ?? new Map())]
5712
+ .map(([model, tokenUsage]) => ({ threadId, model, tokenUsage })));
5713
+ // 窗口标识与实时窗口由 main 侧补全:优先 modelContextId,原始窗口需包含
5714
+ // 子代理终端上报的 modelContextWindow。
5510
5715
  const terminalTokenUsage = turn.tokenUsage ?? turn.usage;
5511
5716
  const contextUsage = this.mapCodexContextUsage({
5512
5717
  ...state.tokenUsage,
5513
5718
  ...(terminalTokenUsage && typeof terminalTokenUsage === 'object' ? terminalTokenUsage : {}),
5514
5719
  ...(turn.contextUsage ?? state.tokenUsage?.contextUsage ?? state.tokenUsage?.context),
5515
5720
  }, state.modelContextId ?? state.model, this.pickNumber(state.tokenUsage?.modelContextWindow, state.tokenUsage?.model_context_window, terminalTokenUsage?.modelContextWindow, terminalTokenUsage?.model_context_window));
5721
+ const modelCalls = [
5722
+ ...(parentTokenUsage ? [{
5723
+ call_index: 0,
5724
+ model: state.model,
5725
+ source: 'turn',
5726
+ providerThreadId: state.threadId,
5727
+ tokenUsage: parentTokenUsage,
5728
+ contextUsage,
5729
+ degraded: true,
5730
+ }] : []),
5731
+ ...subagentUsages
5732
+ .filter(({ tokenUsage }) => !!tokenUsage)
5733
+ .map(({ threadId, model, tokenUsage }, index) => ({
5734
+ call_index: (parentTokenUsage ? 1 : 0) + index,
5735
+ model,
5736
+ source: 'subagent',
5737
+ providerThreadId: threadId,
5738
+ tokenUsage: tokenUsage,
5739
+ degraded: true,
5740
+ })),
5741
+ ];
5742
+ const reportedUsages = [parentTokenUsage, ...subagentUsages.map(item => item.tokenUsage)]
5743
+ .filter((usage) => !!usage);
5744
+ const tokenUsage = reportedUsages.length
5745
+ ? {
5746
+ input_tokens: reportedUsages.reduce((sum, usage) => sum + (usage.input_tokens ?? 0), 0),
5747
+ output_tokens: reportedUsages.reduce((sum, usage) => sum + (usage.output_tokens ?? 0), 0),
5748
+ cache_read_input_tokens: reportedUsages.reduce((sum, usage) => sum + (usage.cache_read_input_tokens ?? 0), 0),
5749
+ cache_creation_input_tokens: reportedUsages.reduce((sum, usage) => sum + (usage.cache_creation_input_tokens ?? 0), 0),
5750
+ }
5751
+ : undefined;
5516
5752
  const terminalReason = status === 'completed'
5517
5753
  ? undefined
5518
5754
  : status === 'interrupted'
@@ -5533,6 +5769,7 @@ export class CodexRunner {
5533
5769
  model: state.model,
5534
5770
  tokenUsage,
5535
5771
  contextUsage,
5772
+ modelCalls: modelCalls.length ? modelCalls : undefined,
5536
5773
  };
5537
5774
  }
5538
5775
  getManagedTempDir(sessionId) {
@@ -5555,6 +5792,8 @@ export class CodexRunner {
5555
5792
  set: {
5556
5793
  EVOLCORE_SESSION_ID: sessionId,
5557
5794
  EVOLCORE_HOME: resolveRoot(),
5795
+ // Let managed PowerShell resolve the native ec.ps1 shim without changing user policy.
5796
+ ...(process.platform === 'win32' ? { PSExecutionPolicyPreference: 'Bypass' } : {}),
5558
5797
  ...(managedTempDir ? { EVOLCORE_SESSION_RUNTIME_DIR: managedTempDir } : {}),
5559
5798
  ...(managedTempDir ? { EVOLCORE_RUNTIME_LOCK_DIR: path.join(managedTempDir, 'locks') } : {}),
5560
5799
  ...(taskDelegationToken ? { [AGENT_DELEGATION_TOKEN_ENV]: taskDelegationToken } : {}),
@@ -5642,9 +5881,11 @@ export class CodexRunner {
5642
5881
  this.pruneThreadOperationLocks();
5643
5882
  this.threadOperationLocks.clear();
5644
5883
  await Promise.all([
5884
+ ...[...this.retiredProviderClients].map(client => client.close()),
5645
5885
  this.appServerClient?.close(),
5646
5886
  this.fullAccessAppServerClient?.close(),
5647
5887
  ]);
5888
+ this.retiredProviderClients.clear();
5648
5889
  this.codexSessionFileAdapter.close();
5649
5890
  this.appServerClient = null;
5650
5891
  this.fullAccessAppServerClient = null;