@gajae-code/coding-agent 0.12.11 → 0.12.13

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 (140) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/dist/types/cli/marketplace-hint.d.ts +28 -0
  3. package/dist/types/cli/notify-cli.d.ts +42 -1
  4. package/dist/types/cli/update-cli.d.ts +9 -3
  5. package/dist/types/cli.d.ts +10 -0
  6. package/dist/types/commands/notify.d.ts +6 -0
  7. package/dist/types/config/file-lock-gc.d.ts +13 -1
  8. package/dist/types/config/file-lock.d.ts +3 -0
  9. package/dist/types/config/model-registry.d.ts +6 -0
  10. package/dist/types/config/models-config-schema.d.ts +99 -0
  11. package/dist/types/coordinator/contract.d.ts +1 -1
  12. package/dist/types/coordinator-mcp/question-state.d.ts +3 -1
  13. package/dist/types/extensibility/extensions/index.d.ts +1 -0
  14. package/dist/types/extensibility/extensions/ouroboros-ooo-bridge.d.ts +13 -0
  15. package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +0 -1
  16. package/dist/types/extensibility/extensions/types.d.ts +2 -0
  17. package/dist/types/gjc-runtime/deep-interview-state.d.ts +14 -0
  18. package/dist/types/gjc-runtime/gc-runtime.d.ts +11 -0
  19. package/dist/types/main.d.ts +6 -2
  20. package/dist/types/modes/acp/acp-agent.d.ts +24 -1
  21. package/dist/types/modes/components/session-selector.d.ts +1 -1
  22. package/dist/types/modes/utils/host-status.d.ts +23 -0
  23. package/dist/types/runtime-mcp/types.d.ts +2 -0
  24. package/dist/types/sdk/broker/lifecycle.d.ts +12 -0
  25. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +3 -0
  26. package/dist/types/sdk/bus/chat-daemon-command-channel.d.ts +244 -0
  27. package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -1
  28. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +7 -0
  29. package/dist/types/sdk/bus/control-plane-frames.d.ts +43 -0
  30. package/dist/types/sdk/bus/conversation-store.d.ts +18 -0
  31. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +71 -0
  32. package/dist/types/sdk/bus/html-format.d.ts +10 -0
  33. package/dist/types/sdk/bus/notification-service.d.ts +10 -0
  34. package/dist/types/sdk/bus/slack-daemon.d.ts +27 -0
  35. package/dist/types/sdk/bus/slack-live-provider.d.ts +11 -0
  36. package/dist/types/sdk/bus/slack-provider.d.ts +14 -0
  37. package/dist/types/sdk/bus/slack-thread-binding.d.ts +140 -0
  38. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +2 -0
  39. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +28 -7
  40. package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -17
  41. package/dist/types/sdk/bus/telegram-reference.d.ts +20 -1
  42. package/dist/types/sdk/bus/topic-registry.d.ts +130 -85
  43. package/dist/types/sdk/host/host.d.ts +52 -0
  44. package/dist/types/sdk/lifecycle-session.d.ts +6 -0
  45. package/dist/types/sdk/session-activation.d.ts +41 -0
  46. package/dist/types/sdk/session.d.ts +18 -0
  47. package/dist/types/sdk/startup-capability.d.ts +8 -1
  48. package/dist/types/session/agent-session.d.ts +7 -2
  49. package/dist/types/session/artifacts.d.ts +2 -2
  50. package/dist/types/session/session-manager.d.ts +40 -6
  51. package/dist/types/tools/index.d.ts +15 -0
  52. package/dist/types/utils/npm-registry.d.ts +71 -0
  53. package/examples/extensions/README.md +38 -4
  54. package/examples/extensions/ooo-bridge.ts +15 -0
  55. package/package.json +8 -8
  56. package/scripts/generate-sdk-operation-inventory.ts +4 -0
  57. package/src/async/job-manager.ts +9 -2
  58. package/src/cli/fast-help.ts +1 -0
  59. package/src/cli/marketplace-hint.ts +39 -0
  60. package/src/cli/notify-cli.ts +226 -2
  61. package/src/cli/plugin-cli.ts +10 -0
  62. package/src/cli/update-cli.ts +90 -23
  63. package/src/cli.ts +23 -0
  64. package/src/commands/notify.ts +27 -3
  65. package/src/commands/sdk.ts +1 -0
  66. package/src/config/file-lock-gc.ts +65 -26
  67. package/src/config/file-lock.ts +61 -16
  68. package/src/config/model-profiles.ts +46 -30
  69. package/src/config/model-registry.ts +17 -5
  70. package/src/config/models-config-schema.ts +9 -4
  71. package/src/coordinator/contract.ts +1 -0
  72. package/src/coordinator-mcp/question-state.ts +2 -0
  73. package/src/coordinator-mcp/server.ts +358 -7
  74. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  75. package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -0
  76. package/src/extensibility/extensions/index.ts +1 -0
  77. package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +235 -0
  78. package/src/extensibility/extensions/prefix-command-bridge.ts +4 -9
  79. package/src/extensibility/extensions/runner.ts +15 -2
  80. package/src/extensibility/extensions/types.ts +2 -0
  81. package/src/gjc-runtime/deep-interview-recorder.ts +9 -5
  82. package/src/gjc-runtime/deep-interview-state.ts +27 -3
  83. package/src/gjc-runtime/gc-render.ts +8 -1
  84. package/src/gjc-runtime/gc-runtime.ts +15 -1
  85. package/src/gjc-runtime/launch-tmux.ts +53 -1
  86. package/src/internal-urls/docs-index.generated.ts +14 -13
  87. package/src/main.ts +214 -70
  88. package/src/modes/DESIGN.md +8 -5
  89. package/src/modes/acp/acp-agent.ts +123 -7
  90. package/src/modes/components/footer.ts +10 -18
  91. package/src/modes/components/model-selector.ts +52 -5
  92. package/src/modes/components/session-selector.ts +26 -3
  93. package/src/modes/components/status-line/gh.ts +23 -2
  94. package/src/modes/controllers/event-controller.ts +3 -0
  95. package/src/modes/controllers/extension-ui-controller.ts +2 -0
  96. package/src/modes/controllers/input-controller.ts +11 -0
  97. package/src/modes/controllers/selector-controller.ts +8 -2
  98. package/src/modes/interactive-mode.ts +7 -1
  99. package/src/modes/print-mode.ts +10 -0
  100. package/src/modes/utils/host-status.ts +38 -0
  101. package/src/prompts/system/project-prompt.md +19 -0
  102. package/src/runtime-mcp/types.ts +2 -0
  103. package/src/sdk/broker/lifecycle.ts +60 -3
  104. package/src/sdk/bus/chat-daemon-cli.ts +42 -0
  105. package/src/sdk/bus/chat-daemon-command-channel.ts +921 -0
  106. package/src/sdk/bus/chat-daemon-control.ts +16 -3
  107. package/src/sdk/bus/chat-daemon-runtime.ts +257 -21
  108. package/src/sdk/bus/control-plane-frames.ts +51 -0
  109. package/src/sdk/bus/conversation-store.ts +29 -1
  110. package/src/sdk/bus/existing-thread-readiness.ts +155 -0
  111. package/src/sdk/bus/html-format.ts +19 -3
  112. package/src/sdk/bus/index.ts +91 -12
  113. package/src/sdk/bus/notification-service.ts +28 -1
  114. package/src/sdk/bus/rich-render.ts +3 -2
  115. package/src/sdk/bus/slack-daemon.ts +99 -4
  116. package/src/sdk/bus/slack-live-provider.ts +32 -2
  117. package/src/sdk/bus/slack-provider.ts +11 -0
  118. package/src/sdk/bus/slack-thread-binding.ts +641 -0
  119. package/src/sdk/bus/telegram-daemon-cli.ts +11 -0
  120. package/src/sdk/bus/telegram-daemon-contract.ts +28 -7
  121. package/src/sdk/bus/telegram-daemon.ts +2007 -509
  122. package/src/sdk/bus/telegram-reference.ts +114 -15
  123. package/src/sdk/bus/topic-registry.ts +674 -181
  124. package/src/sdk/host/host.ts +180 -1
  125. package/src/sdk/lifecycle-session.ts +8 -2
  126. package/src/sdk/protocol/operation-inventory.generated.json +22 -0
  127. package/src/sdk/session-activation.ts +127 -0
  128. package/src/sdk/session.ts +144 -29
  129. package/src/sdk/startup-capability.ts +10 -1
  130. package/src/session/agent-session.ts +220 -13
  131. package/src/session/artifacts.ts +56 -13
  132. package/src/session/internal/managed-session-storage.ts +228 -7
  133. package/src/session/session-manager.ts +225 -60
  134. package/src/setup/provider-presets.json +3 -3
  135. package/src/task/index.ts +92 -44
  136. package/src/thinking-metadata.ts +2 -1
  137. package/src/tools/ask.ts +10 -0
  138. package/src/tools/index.ts +15 -0
  139. package/src/tools/todo-write.ts +4 -4
  140. package/src/utils/npm-registry.ts +660 -0
@@ -408,6 +408,16 @@ export interface CreateAgentSessionOptions {
408
408
  /** Load MCP tools for a top-level session only from this caller-owned absolute config file path.
409
409
  * Mutually exclusive with mcpManager. */
410
410
  mcpConfigPath?: string;
411
+ /**
412
+ * Defer connecting an exact MCP config until the interactive UI is ready.
413
+ * @internal CLI-only startup optimization; SDK callers retain synchronous loading by default.
414
+ */
415
+ deferMcpConfigStartup?: boolean;
416
+ /**
417
+ * Defer memory backend startup until the caller has applied startup model profiles.
418
+ * @internal CLI-only ordering guard; SDK callers retain immediate startup by default.
419
+ */
420
+ deferMemoryBackendStartup?: boolean;
411
421
 
412
422
  /** Enable LSP integration (tool, formatting, diagnostics, warmup). Default: true */
413
423
  enableLsp?: boolean;
@@ -498,6 +508,10 @@ export interface CreateAgentSessionResult {
498
508
  setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
499
509
  /** MCP manager for server lifecycle management (undefined if MCP disabled or an exact tools-only config is session-owned) */
500
510
  mcpManager?: MCPManager;
511
+ /** Starts a deferred exact-config MCP connection. Present only when deferMcpConfigStartup was requested. */
512
+ startDeferredMcpConfig?: () => Promise<DeferredMcpConfigStartupResult>;
513
+ /** Starts a deferred memory backend. Present only when deferMemoryBackendStartup was requested. */
514
+ startDeferredMemoryBackend?: () => void;
501
515
  /** Warning if session was restored with a different model than saved */
502
516
  modelFallbackMessage?: string;
503
517
  /** LSP servers configured for lazy startup in interactive mode */
@@ -511,6 +525,11 @@ export interface CreateAgentSessionResult {
511
525
  gjcRuntimeSnapshot?: GjcRuntimeSnapshotProvider;
512
526
  }
513
527
 
528
+ export interface DeferredMcpConfigStartupResult {
529
+ loadedToolCount: number;
530
+ hasErrors: boolean;
531
+ }
532
+
514
533
  // Re-exports
515
534
 
516
535
  export type { PromptTemplate } from "../config/prompt-templates";
@@ -1007,6 +1026,7 @@ const MCP_CONFIG_PATH_ABSOLUTE_ERROR = "mcpConfigPath requires an absolute path"
1007
1026
  const MCP_TOOLS_ONLY_MANAGER_SUBSESSION_ERROR = "tools-only MCP managers cannot be reused in sub-sessions";
1008
1027
  const MCP_CONFIG_PATH_SUBSESSION_ERROR = "mcpConfigPath cannot be used in sub-sessions";
1009
1028
  const MAX_EXACT_MCP_TOOL_COLLISION_NAMES = 10;
1029
+ const DEFERRED_MCP_CONFIG_STARTUP_ERROR = "MCP tools could not be loaded.";
1010
1030
  const MAX_EXACT_MCP_TOOL_NAME_LENGTH = 100;
1011
1031
  const pluginMcpManagerServers = new WeakMap<MCPManager, ReadonlySet<string>>();
1012
1032
 
@@ -1041,6 +1061,20 @@ function findExactMcpToolNameCollisions(
1041
1061
  return collisions;
1042
1062
  }
1043
1063
 
1064
+ function findDeferredExactMcpToolNameCollisions(
1065
+ exactMcpToolNames: readonly string[],
1066
+ catalogToolNames: Iterable<string>,
1067
+ ): string[] {
1068
+ const catalog = new Set(catalogToolNames);
1069
+ const seen = new Set<string>();
1070
+ const collisions = new Set<string>();
1071
+ for (const toolName of exactMcpToolNames) {
1072
+ if (catalog.has(toolName) || seen.has(toolName)) collisions.add(toolName);
1073
+ seen.add(toolName);
1074
+ }
1075
+ return [...collisions];
1076
+ }
1077
+
1044
1078
  export async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {
1045
1079
  const lifecycleStartupCapability = (
1046
1080
  options as CreateAgentSessionOptions & { [lifecycleStartupCapabilityOption]?: SdkStartupCapability }
@@ -1219,7 +1253,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1219
1253
  return SessionManager.create(cwd, SessionManager.managedDestination(cwd, agentDir));
1220
1254
  }));
1221
1255
  const logicalSessionId = sessionManager.getSessionId();
1222
- const providerSessionId = options.providerSessionId ?? options.forkContextSeed?.cacheIdentity ?? logicalSessionId;
1256
+ // Fork-context seeds carry conversation content only, never provider identity:
1257
+ // a shared continuity id would make concurrent subagents present the same
1258
+ // session_id upstream, where session-owning transports reject the extra
1259
+ // downstreams (owner_busy) and degrade those turns to uncached HTTP.
1260
+ const providerSessionId = options.providerSessionId ?? logicalSessionId;
1223
1261
  const modelApiKeyAvailability = new Map<string, boolean>();
1224
1262
  const getModelAvailabilityKey = (candidate: Model): string =>
1225
1263
  `${candidate.provider}\u0000${candidate.baseUrl ?? ""}`;
@@ -1630,7 +1668,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1630
1668
  }
1631
1669
  },
1632
1670
  getArtifactManager: () => sessionManager.getArtifactManager(),
1633
- registerSessionCleanup: cleanup => session?.registerToolSessionCleanup(cleanup) ?? (() => {}),
1671
+ isArtifactManagerAuthorized: manager => sessionManager.isArtifactManagerAuthorized(manager),
1672
+ adoptArtifactManager: manager => sessionManager.adoptArtifactManager(manager),
1673
+ releaseArtifactManager: manager => sessionManager.releaseArtifactManager(manager),
1674
+ ensureArtifactManager: () => sessionManager.ensureArtifactManager(),
1675
+ registerSessionCleanup: cleanup => session?.registerToolSessionTransitionCleanup(cleanup) ?? (() => {}),
1634
1676
  settings,
1635
1677
  authStorage,
1636
1678
  modelRegistry,
@@ -1685,6 +1727,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1685
1727
  const customTools: CustomTool[] = [];
1686
1728
  const exactMcpToolNames: string[] = [];
1687
1729
  const pluginMcpToolNames: string[] = [];
1730
+ let deferredExactMcpConfig: { manager: MCPManager; configPath: string } | undefined;
1688
1731
 
1689
1732
  // Add image tools when the active model or configured image providers can generate images.
1690
1733
  const imageGenTools = await logger.time("getImageGenTools", () => getImageGenTools(modelRegistry, model));
@@ -1785,12 +1828,16 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1785
1828
  mcpManager = owned;
1786
1829
  ownsMcpManager = true;
1787
1830
  cleanupOwnedMcpManager = () => owned.disconnectAll();
1788
- const result = await owned.discoverAndConnect({ configPath: explicitMcpConfigPath });
1789
- const resultTools = result.tools as CustomTool[];
1790
- exactMcpToolNames.push(...resultTools.map(tool => tool.name));
1791
- customTools.push(...resultTools);
1792
- if (result.errors.size > 0 || result.tools.length === 0) {
1793
- logger.warn("MCP tools could not be loaded.");
1831
+ if (options.deferMcpConfigStartup) {
1832
+ deferredExactMcpConfig = { manager: owned, configPath: explicitMcpConfigPath };
1833
+ } else {
1834
+ const result = await owned.discoverAndConnect({ configPath: explicitMcpConfigPath });
1835
+ const resultTools = result.tools as CustomTool[];
1836
+ exactMcpToolNames.push(...resultTools.map(tool => tool.name));
1837
+ customTools.push(...resultTools);
1838
+ if (result.errors.size > 0 || result.tools.length === 0) {
1839
+ logger.warn("MCP tools could not be loaded.");
1840
+ }
1794
1841
  }
1795
1842
  } else if (!mcpManager && !isCanonicalSubSession) {
1796
1843
  // Always-on GJC plugin-bundle MCP servers. Top-level sessions own a manager
@@ -2198,13 +2245,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2198
2245
  }
2199
2246
  // Exact-config MCP tools cannot claim a name already represented by the final candidate catalog.
2200
2247
  // Other catalog collisions retain their legacy override behavior.
2248
+ const exactMcpCatalogToolNames = [
2249
+ ...builtinCandidateTools.map(tool => tool.name),
2250
+ ...preExactCustomToolNames,
2251
+ ...wrappedExtensionTools.map(tool => tool.name),
2252
+ ];
2201
2253
  if (exactMcpToolNames.length > 0) {
2202
- const catalogToolNames = [
2203
- ...builtinCandidateTools.map(tool => tool.name),
2204
- ...preExactCustomToolNames,
2205
- ...wrappedExtensionTools.map(tool => tool.name),
2206
- ];
2207
- const collidingToolNames = findExactMcpToolNameCollisions(exactMcpToolNames, catalogToolNames);
2254
+ const collidingToolNames = findExactMcpToolNameCollisions(exactMcpToolNames, exactMcpCatalogToolNames);
2208
2255
  if (collidingToolNames.length > 0) {
2209
2256
  throw new ExactMcpToolNameCollisionError(collidingToolNames);
2210
2257
  }
@@ -2397,10 +2444,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2397
2444
  );
2398
2445
  let initialToolNames = [...initialRequestedActiveToolNames];
2399
2446
  if (mcpDiscoveryEnabled) {
2400
- const restoredSelectedMCPToolNames = existingSession.selectedMCPToolNames.filter(
2401
- name => toolRegistry.has(name) && !mandatoryMCPToolNameSet.has(name),
2402
- );
2447
+ const restoredSelectedMCPToolNames = deferredExactMcpConfig
2448
+ ? existingSession.selectedMCPToolNames.filter(name => !mandatoryMCPToolNameSet.has(name))
2449
+ : existingSession.selectedMCPToolNames.filter(
2450
+ name => toolRegistry.has(name) && !mandatoryMCPToolNameSet.has(name),
2451
+ );
2403
2452
  if (
2453
+ !deferredExactMcpConfig &&
2404
2454
  existingSession.hasPersistedMCPToolSelection &&
2405
2455
  restoredSelectedMCPToolNames.length !== existingSession.selectedMCPToolNames.length
2406
2456
  ) {
@@ -2751,6 +2801,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2751
2801
  }
2752
2802
  }
2753
2803
 
2804
+ const deferredMcpTurnReady = deferredExactMcpConfig ? Promise.withResolvers<void>() : undefined;
2805
+ if (deferredMcpTurnReady) void deferredMcpTurnReady.promise.catch(() => {});
2806
+
2754
2807
  session = new AgentSession({
2755
2808
  agent,
2756
2809
  thinkingLevel,
@@ -2767,6 +2820,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2767
2820
  // subagents and callers that merely observe a manager must not (see
2768
2821
  // AgentSession.dispose).
2769
2822
  ownedMcpManager: ownsMcpManager ? mcpManager : undefined,
2823
+ startupTurnBarrier: deferredMcpTurnReady?.promise,
2770
2824
  scopedModels: options.scopedModels,
2771
2825
  promptTemplates,
2772
2826
  slashCommands,
@@ -2793,6 +2847,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2793
2847
  mcpDiscoveryEnabled,
2794
2848
  discoveryMode: effectiveDiscoveryMode,
2795
2849
  initialSelectedMCPToolNames,
2850
+ preserveUnavailableInitialMCPToolSelection: deferredExactMcpConfig !== undefined,
2796
2851
  initialMCPToolSelectionIsExplicit: hasExplicitMCPToolSelection,
2797
2852
  initialDiscoveredBuiltinToolSelectionIsExplicit: hasExplicitDiscoveredBuiltinToolSelection,
2798
2853
  initialSelectedDiscoveredBuiltinToolNames,
@@ -2884,18 +2939,24 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2884
2939
  ? discoverStartupLspServers(cwd)
2885
2940
  : undefined;
2886
2941
 
2887
- logger.time("startMemoryStartupTask", () =>
2888
- Promise.resolve(
2889
- resolveMemoryBackend(settings).start({
2890
- session,
2891
- settings,
2892
- modelRegistry,
2893
- agentDir,
2894
- taskDepth,
2895
- parentHindsightSessionState: options.parentHindsightSessionState,
2896
- }),
2897
- ),
2898
- );
2942
+ let memoryBackendStarted = false;
2943
+ const startMemoryBackend = () => {
2944
+ if (memoryBackendStarted) return;
2945
+ memoryBackendStarted = true;
2946
+ logger.time("startMemoryStartupTask", () =>
2947
+ Promise.resolve(
2948
+ resolveMemoryBackend(settings).start({
2949
+ session,
2950
+ settings,
2951
+ modelRegistry,
2952
+ agentDir,
2953
+ taskDepth,
2954
+ parentHindsightSessionState: options.parentHindsightSessionState,
2955
+ }),
2956
+ ),
2957
+ );
2958
+ };
2959
+ if (!options.deferMemoryBackendStartup) startMemoryBackend();
2899
2960
 
2900
2961
  // Exact-config managers do not receive reactive callbacks; their tools are
2901
2962
  // registered once in the session-owned catalog.
@@ -2949,6 +3010,58 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2949
3010
  // microtask (the ToolSession closure needs `session` assigned). Await it
2950
3011
  // so a resumed canonical workflow session returns with `ask` resident.
2951
3012
  await session.workflowGateToolRestoration;
3013
+ let startDeferredMcpConfig: (() => Promise<DeferredMcpConfigStartupResult>) | undefined;
3014
+ if (deferredExactMcpConfig) {
3015
+ const { manager, configPath } = deferredExactMcpConfig;
3016
+ let cancelled = false;
3017
+ let startupPromise: Promise<DeferredMcpConfigStartupResult> | undefined;
3018
+ session.registerToolSessionCleanup(async () => {
3019
+ cancelled = true;
3020
+ deferredMcpTurnReady?.resolve();
3021
+ if (startupPromise) {
3022
+ await manager.disconnectAll().catch(() => {});
3023
+ await startupPromise.catch(() => {});
3024
+ }
3025
+ });
3026
+ startDeferredMcpConfig = () => {
3027
+ if (!startupPromise && session.isDisposed) {
3028
+ return Promise.reject(new Error(DEFERRED_MCP_CONFIG_STARTUP_ERROR));
3029
+ }
3030
+ startupPromise ??= (async () => {
3031
+ try {
3032
+ const result = await manager.discoverAndConnect({ configPath });
3033
+ const resultTools = result.tools as CustomTool[];
3034
+ const toolNames = resultTools.map(tool => tool.name);
3035
+ const collidingToolNames = findDeferredExactMcpToolNameCollisions(
3036
+ toolNames,
3037
+ exactMcpCatalogToolNames,
3038
+ );
3039
+ if (collidingToolNames.length > 0) {
3040
+ throw new ExactMcpToolNameCollisionError(collidingToolNames);
3041
+ }
3042
+ if (!cancelled && !session.isDisposed) {
3043
+ await session.refreshMCPTools(resultTools);
3044
+ if (
3045
+ !session.isDisposed &&
3046
+ (!mcpDiscoveryEnabled || !existingSession.hasPersistedMCPToolSelection)
3047
+ ) {
3048
+ await session.activateDiscoveredTools(toolNames);
3049
+ }
3050
+ }
3051
+ deferredMcpTurnReady?.resolve();
3052
+ const hasErrors = result.errors.size > 0 || result.tools.length === 0;
3053
+ if (hasErrors) logger.warn(DEFERRED_MCP_CONFIG_STARTUP_ERROR);
3054
+ return { loadedToolCount: cancelled || session.isDisposed ? 0 : resultTools.length, hasErrors };
3055
+ } catch {
3056
+ const startupError = new Error(DEFERRED_MCP_CONFIG_STARTUP_ERROR);
3057
+ deferredMcpTurnReady?.reject(startupError);
3058
+ await manager.disconnectAll().catch(() => {});
3059
+ throw startupError;
3060
+ }
3061
+ })();
3062
+ return startupPromise;
3063
+ };
3064
+ }
2952
3065
  // Expose the published evidence on the session itself so UI surfaces that
2953
3066
  // only hold a session (Settings) can consume it without threading the
2954
3067
  // creation result through every controller.
@@ -2959,6 +3072,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2959
3072
  extensionsResult,
2960
3073
  setToolUIContext,
2961
3074
  mcpManager: ownsMcpManager && mcpManager?.isToolsOnly() ? undefined : mcpManager,
3075
+ startDeferredMcpConfig,
3076
+ startDeferredMemoryBackend: options.deferMemoryBackendStartup ? startMemoryBackend : undefined,
2962
3077
  modelFallbackMessage,
2963
3078
  lspServers,
2964
3079
  eventBus,
@@ -172,7 +172,16 @@ export class SdkStartupCapability {
172
172
  this.#cancelled = true;
173
173
  }
174
174
 
175
- constructor(readonly rollback?: SdkStartupRollbackTracker) {}
175
+ /**
176
+ * The broker-issued, session-scoped readiness intent this child was launched
177
+ * with. It is carried on the capability rather than read from the ambient
178
+ * environment so bus wiring can never mistake an inherited process-global
179
+ * flag for a broker-managed preparation.
180
+ */
181
+ constructor(
182
+ readonly rollback?: SdkStartupRollbackTracker,
183
+ readonly readiness: "immediate" | "deferred" = "immediate",
184
+ ) {}
176
185
 
177
186
  normalizeFailure(phase: SdkStartupPhase, reason: SdkStartupReason, error?: unknown): SdkStartupFailure {
178
187
  return normalizeSdkStartupFailure(phase, reason, error, lifecycleKnownSecrets());