@gajae-code/coding-agent 0.12.10 → 0.12.12

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 (120) hide show
  1. package/CHANGELOG.md +47 -2
  2. package/dist/types/cli/notify-cli.d.ts +42 -1
  3. package/dist/types/cli/update-cli.d.ts +9 -3
  4. package/dist/types/commands/notify.d.ts +6 -0
  5. package/dist/types/config/file-lock.d.ts +3 -0
  6. package/dist/types/coordinator/contract.d.ts +1 -1
  7. package/dist/types/coordinator-mcp/question-state.d.ts +3 -1
  8. package/dist/types/extensibility/extensions/index.d.ts +1 -0
  9. package/dist/types/extensibility/extensions/ouroboros-ooo-bridge.d.ts +13 -0
  10. package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +0 -1
  11. package/dist/types/extensibility/extensions/types.d.ts +2 -0
  12. package/dist/types/main.d.ts +6 -2
  13. package/dist/types/modes/components/session-selector.d.ts +1 -1
  14. package/dist/types/modes/utils/host-status.d.ts +23 -0
  15. package/dist/types/runtime-mcp/types.d.ts +2 -0
  16. package/dist/types/sdk/broker/lifecycle.d.ts +12 -0
  17. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +3 -0
  18. package/dist/types/sdk/bus/chat-daemon-command-channel.d.ts +244 -0
  19. package/dist/types/sdk/bus/chat-daemon-control.d.ts +13 -1
  20. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +7 -0
  21. package/dist/types/sdk/bus/control-plane-frames.d.ts +43 -0
  22. package/dist/types/sdk/bus/conversation-store.d.ts +18 -0
  23. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +71 -0
  24. package/dist/types/sdk/bus/notification-service.d.ts +10 -0
  25. package/dist/types/sdk/bus/slack-daemon.d.ts +27 -0
  26. package/dist/types/sdk/bus/slack-live-provider.d.ts +11 -0
  27. package/dist/types/sdk/bus/slack-provider.d.ts +14 -0
  28. package/dist/types/sdk/bus/slack-thread-binding.d.ts +140 -0
  29. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +2 -0
  30. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +25 -7
  31. package/dist/types/sdk/bus/telegram-daemon.d.ts +104 -16
  32. package/dist/types/sdk/bus/telegram-reference.d.ts +10 -1
  33. package/dist/types/sdk/bus/topic-registry.d.ts +130 -85
  34. package/dist/types/sdk/host/host.d.ts +52 -0
  35. package/dist/types/sdk/lifecycle-session.d.ts +6 -0
  36. package/dist/types/sdk/session-activation.d.ts +41 -0
  37. package/dist/types/sdk/session.d.ts +18 -0
  38. package/dist/types/sdk/startup-capability.d.ts +8 -1
  39. package/dist/types/session/agent-session.d.ts +7 -0
  40. package/dist/types/session/artifacts.d.ts +2 -2
  41. package/dist/types/session/internal/managed-session-storage.d.ts +12 -2
  42. package/dist/types/session/session-manager.d.ts +40 -5
  43. package/dist/types/session/session-storage.d.ts +1 -0
  44. package/dist/types/tools/computer.d.ts +35 -2
  45. package/dist/types/tools/index.d.ts +8 -0
  46. package/dist/types/tools/todo-write.d.ts +2 -0
  47. package/dist/types/utils/npm-registry.d.ts +71 -0
  48. package/examples/extensions/README.md +38 -4
  49. package/examples/extensions/ooo-bridge.ts +15 -0
  50. package/package.json +8 -8
  51. package/scripts/generate-sdk-operation-inventory.ts +4 -0
  52. package/src/async/job-manager.ts +9 -2
  53. package/src/cli/notify-cli.ts +226 -2
  54. package/src/cli/update-cli.ts +90 -23
  55. package/src/commands/notify.ts +27 -3
  56. package/src/commands/sdk.ts +1 -0
  57. package/src/config/file-lock-gc.ts +18 -0
  58. package/src/config/file-lock.ts +61 -16
  59. package/src/config/model-profiles.ts +31 -15
  60. package/src/coordinator/contract.ts +1 -0
  61. package/src/coordinator-mcp/question-state.ts +2 -0
  62. package/src/coordinator-mcp/server.ts +358 -7
  63. package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -0
  64. package/src/extensibility/extensions/index.ts +1 -0
  65. package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +235 -0
  66. package/src/extensibility/extensions/prefix-command-bridge.ts +4 -9
  67. package/src/extensibility/extensions/runner.ts +15 -2
  68. package/src/extensibility/extensions/types.ts +2 -0
  69. package/src/gjc-runtime/launch-tmux.ts +53 -1
  70. package/src/internal-urls/docs-index.generated.ts +13 -12
  71. package/src/main.ts +203 -67
  72. package/src/modes/DESIGN.md +8 -5
  73. package/src/modes/components/footer.ts +10 -18
  74. package/src/modes/components/session-selector.ts +26 -3
  75. package/src/modes/components/status-line/gh.ts +23 -2
  76. package/src/modes/controllers/event-controller.ts +3 -0
  77. package/src/modes/controllers/extension-ui-controller.ts +2 -0
  78. package/src/modes/controllers/input-controller.ts +11 -0
  79. package/src/modes/controllers/selector-controller.ts +8 -2
  80. package/src/modes/interactive-mode.ts +7 -1
  81. package/src/modes/utils/host-status.ts +38 -0
  82. package/src/prompts/tools/computer.md +6 -1
  83. package/src/runtime-mcp/types.ts +2 -0
  84. package/src/sdk/broker/lifecycle.ts +60 -3
  85. package/src/sdk/bus/chat-daemon-cli.ts +42 -0
  86. package/src/sdk/bus/chat-daemon-command-channel.ts +921 -0
  87. package/src/sdk/bus/chat-daemon-control.ts +18 -3
  88. package/src/sdk/bus/chat-daemon-runtime.ts +257 -21
  89. package/src/sdk/bus/control-plane-frames.ts +51 -0
  90. package/src/sdk/bus/conversation-store.ts +29 -1
  91. package/src/sdk/bus/existing-thread-readiness.ts +155 -0
  92. package/src/sdk/bus/index.ts +70 -0
  93. package/src/sdk/bus/notification-service.ts +28 -1
  94. package/src/sdk/bus/rich-render.ts +3 -2
  95. package/src/sdk/bus/slack-daemon.ts +99 -4
  96. package/src/sdk/bus/slack-live-provider.ts +32 -2
  97. package/src/sdk/bus/slack-provider.ts +11 -0
  98. package/src/sdk/bus/slack-thread-binding.ts +641 -0
  99. package/src/sdk/bus/telegram-daemon-cli.ts +11 -0
  100. package/src/sdk/bus/telegram-daemon-contract.ts +25 -7
  101. package/src/sdk/bus/telegram-daemon.ts +1961 -497
  102. package/src/sdk/bus/telegram-reference.ts +42 -6
  103. package/src/sdk/bus/topic-registry.ts +674 -181
  104. package/src/sdk/host/host.ts +180 -1
  105. package/src/sdk/lifecycle-session.ts +8 -2
  106. package/src/sdk/protocol/operation-inventory.generated.json +22 -0
  107. package/src/sdk/session-activation.ts +127 -0
  108. package/src/sdk/session.ts +139 -28
  109. package/src/sdk/startup-capability.ts +10 -1
  110. package/src/session/agent-session.ts +331 -30
  111. package/src/session/artifacts.ts +56 -13
  112. package/src/session/internal/managed-session-storage.ts +440 -243
  113. package/src/session/session-manager.ts +288 -44
  114. package/src/session/session-storage.ts +3 -0
  115. package/src/setup/provider-presets.json +1 -1
  116. package/src/task/index.ts +92 -44
  117. package/src/tools/computer.ts +322 -45
  118. package/src/tools/index.ts +8 -0
  119. package/src/tools/todo-write.ts +29 -11
  120. 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 }
@@ -1630,7 +1664,11 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1630
1664
  }
1631
1665
  },
1632
1666
  getArtifactManager: () => sessionManager.getArtifactManager(),
1633
- registerSessionCleanup: cleanup => session?.registerToolSessionCleanup(cleanup) ?? (() => {}),
1667
+ isArtifactManagerAuthorized: manager => sessionManager.isArtifactManagerAuthorized(manager),
1668
+ adoptArtifactManager: manager => sessionManager.adoptArtifactManager(manager),
1669
+ releaseArtifactManager: manager => sessionManager.releaseArtifactManager(manager),
1670
+ ensureArtifactManager: () => sessionManager.ensureArtifactManager(),
1671
+ registerSessionCleanup: cleanup => session?.registerToolSessionTransitionCleanup(cleanup) ?? (() => {}),
1634
1672
  settings,
1635
1673
  authStorage,
1636
1674
  modelRegistry,
@@ -1685,6 +1723,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1685
1723
  const customTools: CustomTool[] = [];
1686
1724
  const exactMcpToolNames: string[] = [];
1687
1725
  const pluginMcpToolNames: string[] = [];
1726
+ let deferredExactMcpConfig: { manager: MCPManager; configPath: string } | undefined;
1688
1727
 
1689
1728
  // Add image tools when the active model or configured image providers can generate images.
1690
1729
  const imageGenTools = await logger.time("getImageGenTools", () => getImageGenTools(modelRegistry, model));
@@ -1785,12 +1824,16 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
1785
1824
  mcpManager = owned;
1786
1825
  ownsMcpManager = true;
1787
1826
  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.");
1827
+ if (options.deferMcpConfigStartup) {
1828
+ deferredExactMcpConfig = { manager: owned, configPath: explicitMcpConfigPath };
1829
+ } else {
1830
+ const result = await owned.discoverAndConnect({ configPath: explicitMcpConfigPath });
1831
+ const resultTools = result.tools as CustomTool[];
1832
+ exactMcpToolNames.push(...resultTools.map(tool => tool.name));
1833
+ customTools.push(...resultTools);
1834
+ if (result.errors.size > 0 || result.tools.length === 0) {
1835
+ logger.warn("MCP tools could not be loaded.");
1836
+ }
1794
1837
  }
1795
1838
  } else if (!mcpManager && !isCanonicalSubSession) {
1796
1839
  // Always-on GJC plugin-bundle MCP servers. Top-level sessions own a manager
@@ -2198,13 +2241,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2198
2241
  }
2199
2242
  // Exact-config MCP tools cannot claim a name already represented by the final candidate catalog.
2200
2243
  // Other catalog collisions retain their legacy override behavior.
2244
+ const exactMcpCatalogToolNames = [
2245
+ ...builtinCandidateTools.map(tool => tool.name),
2246
+ ...preExactCustomToolNames,
2247
+ ...wrappedExtensionTools.map(tool => tool.name),
2248
+ ];
2201
2249
  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);
2250
+ const collidingToolNames = findExactMcpToolNameCollisions(exactMcpToolNames, exactMcpCatalogToolNames);
2208
2251
  if (collidingToolNames.length > 0) {
2209
2252
  throw new ExactMcpToolNameCollisionError(collidingToolNames);
2210
2253
  }
@@ -2397,10 +2440,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2397
2440
  );
2398
2441
  let initialToolNames = [...initialRequestedActiveToolNames];
2399
2442
  if (mcpDiscoveryEnabled) {
2400
- const restoredSelectedMCPToolNames = existingSession.selectedMCPToolNames.filter(
2401
- name => toolRegistry.has(name) && !mandatoryMCPToolNameSet.has(name),
2402
- );
2443
+ const restoredSelectedMCPToolNames = deferredExactMcpConfig
2444
+ ? existingSession.selectedMCPToolNames.filter(name => !mandatoryMCPToolNameSet.has(name))
2445
+ : existingSession.selectedMCPToolNames.filter(
2446
+ name => toolRegistry.has(name) && !mandatoryMCPToolNameSet.has(name),
2447
+ );
2403
2448
  if (
2449
+ !deferredExactMcpConfig &&
2404
2450
  existingSession.hasPersistedMCPToolSelection &&
2405
2451
  restoredSelectedMCPToolNames.length !== existingSession.selectedMCPToolNames.length
2406
2452
  ) {
@@ -2751,6 +2797,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2751
2797
  }
2752
2798
  }
2753
2799
 
2800
+ const deferredMcpTurnReady = deferredExactMcpConfig ? Promise.withResolvers<void>() : undefined;
2801
+ if (deferredMcpTurnReady) void deferredMcpTurnReady.promise.catch(() => {});
2802
+
2754
2803
  session = new AgentSession({
2755
2804
  agent,
2756
2805
  thinkingLevel,
@@ -2767,6 +2816,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2767
2816
  // subagents and callers that merely observe a manager must not (see
2768
2817
  // AgentSession.dispose).
2769
2818
  ownedMcpManager: ownsMcpManager ? mcpManager : undefined,
2819
+ startupTurnBarrier: deferredMcpTurnReady?.promise,
2770
2820
  scopedModels: options.scopedModels,
2771
2821
  promptTemplates,
2772
2822
  slashCommands,
@@ -2793,6 +2843,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2793
2843
  mcpDiscoveryEnabled,
2794
2844
  discoveryMode: effectiveDiscoveryMode,
2795
2845
  initialSelectedMCPToolNames,
2846
+ preserveUnavailableInitialMCPToolSelection: deferredExactMcpConfig !== undefined,
2796
2847
  initialMCPToolSelectionIsExplicit: hasExplicitMCPToolSelection,
2797
2848
  initialDiscoveredBuiltinToolSelectionIsExplicit: hasExplicitDiscoveredBuiltinToolSelection,
2798
2849
  initialSelectedDiscoveredBuiltinToolNames,
@@ -2884,18 +2935,24 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2884
2935
  ? discoverStartupLspServers(cwd)
2885
2936
  : undefined;
2886
2937
 
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
- );
2938
+ let memoryBackendStarted = false;
2939
+ const startMemoryBackend = () => {
2940
+ if (memoryBackendStarted) return;
2941
+ memoryBackendStarted = true;
2942
+ logger.time("startMemoryStartupTask", () =>
2943
+ Promise.resolve(
2944
+ resolveMemoryBackend(settings).start({
2945
+ session,
2946
+ settings,
2947
+ modelRegistry,
2948
+ agentDir,
2949
+ taskDepth,
2950
+ parentHindsightSessionState: options.parentHindsightSessionState,
2951
+ }),
2952
+ ),
2953
+ );
2954
+ };
2955
+ if (!options.deferMemoryBackendStartup) startMemoryBackend();
2899
2956
 
2900
2957
  // Exact-config managers do not receive reactive callbacks; their tools are
2901
2958
  // registered once in the session-owned catalog.
@@ -2949,6 +3006,58 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2949
3006
  // microtask (the ToolSession closure needs `session` assigned). Await it
2950
3007
  // so a resumed canonical workflow session returns with `ask` resident.
2951
3008
  await session.workflowGateToolRestoration;
3009
+ let startDeferredMcpConfig: (() => Promise<DeferredMcpConfigStartupResult>) | undefined;
3010
+ if (deferredExactMcpConfig) {
3011
+ const { manager, configPath } = deferredExactMcpConfig;
3012
+ let cancelled = false;
3013
+ let startupPromise: Promise<DeferredMcpConfigStartupResult> | undefined;
3014
+ session.registerToolSessionCleanup(async () => {
3015
+ cancelled = true;
3016
+ deferredMcpTurnReady?.resolve();
3017
+ if (startupPromise) {
3018
+ await manager.disconnectAll().catch(() => {});
3019
+ await startupPromise.catch(() => {});
3020
+ }
3021
+ });
3022
+ startDeferredMcpConfig = () => {
3023
+ if (!startupPromise && session.isDisposed) {
3024
+ return Promise.reject(new Error(DEFERRED_MCP_CONFIG_STARTUP_ERROR));
3025
+ }
3026
+ startupPromise ??= (async () => {
3027
+ try {
3028
+ const result = await manager.discoverAndConnect({ configPath });
3029
+ const resultTools = result.tools as CustomTool[];
3030
+ const toolNames = resultTools.map(tool => tool.name);
3031
+ const collidingToolNames = findDeferredExactMcpToolNameCollisions(
3032
+ toolNames,
3033
+ exactMcpCatalogToolNames,
3034
+ );
3035
+ if (collidingToolNames.length > 0) {
3036
+ throw new ExactMcpToolNameCollisionError(collidingToolNames);
3037
+ }
3038
+ if (!cancelled && !session.isDisposed) {
3039
+ await session.refreshMCPTools(resultTools);
3040
+ if (
3041
+ !session.isDisposed &&
3042
+ (!mcpDiscoveryEnabled || !existingSession.hasPersistedMCPToolSelection)
3043
+ ) {
3044
+ await session.activateDiscoveredTools(toolNames);
3045
+ }
3046
+ }
3047
+ deferredMcpTurnReady?.resolve();
3048
+ const hasErrors = result.errors.size > 0 || result.tools.length === 0;
3049
+ if (hasErrors) logger.warn(DEFERRED_MCP_CONFIG_STARTUP_ERROR);
3050
+ return { loadedToolCount: cancelled || session.isDisposed ? 0 : resultTools.length, hasErrors };
3051
+ } catch {
3052
+ const startupError = new Error(DEFERRED_MCP_CONFIG_STARTUP_ERROR);
3053
+ deferredMcpTurnReady?.reject(startupError);
3054
+ await manager.disconnectAll().catch(() => {});
3055
+ throw startupError;
3056
+ }
3057
+ })();
3058
+ return startupPromise;
3059
+ };
3060
+ }
2952
3061
  // Expose the published evidence on the session itself so UI surfaces that
2953
3062
  // only hold a session (Settings) can consume it without threading the
2954
3063
  // creation result through every controller.
@@ -2959,6 +3068,8 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
2959
3068
  extensionsResult,
2960
3069
  setToolUIContext,
2961
3070
  mcpManager: ownsMcpManager && mcpManager?.isToolsOnly() ? undefined : mcpManager,
3071
+ startDeferredMcpConfig,
3072
+ startDeferredMemoryBackend: options.deferMemoryBackendStartup ? startMemoryBackend : undefined,
2962
3073
  modelFallbackMessage,
2963
3074
  lspServers,
2964
3075
  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());