@gajae-code/coding-agent 0.15.5 → 0.16.0

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 (272) hide show
  1. package/CHANGELOG.md +85 -1
  2. package/dist/types/async/job-manager.d.ts +83 -0
  3. package/dist/types/cli/args.d.ts +2 -0
  4. package/dist/types/cli/auth-gateway-cli.d.ts +17 -0
  5. package/dist/types/cli/model-presets-cli.d.ts +9 -0
  6. package/dist/types/cli/root-flags.d.ts +14 -0
  7. package/dist/types/cli/update-cli.d.ts +15 -0
  8. package/dist/types/cli.d.ts +7 -0
  9. package/dist/types/commands/auth-gateway.d.ts +3 -0
  10. package/dist/types/commands/gc.d.ts +13 -0
  11. package/dist/types/commands/launch.d.ts +10 -0
  12. package/dist/types/commands/model-presets.d.ts +21 -0
  13. package/dist/types/config/autorouting-tier-map.d.ts +120 -0
  14. package/dist/types/config/file-lock.d.ts +54 -2
  15. package/dist/types/config/internal/model-preset-registry-test-state.d.ts +4 -0
  16. package/dist/types/config/internal/model-preset-registry-test-support.d.ts +3 -0
  17. package/dist/types/config/keybindings.d.ts +3 -2
  18. package/dist/types/config/model-preset-registry.d.ts +368 -0
  19. package/dist/types/config/model-profile-activation.d.ts +39 -0
  20. package/dist/types/config/model-profiles.d.ts +5 -3
  21. package/dist/types/config/model-registry.d.ts +17 -5
  22. package/dist/types/config/settings-schema.d.ts +19 -1
  23. package/dist/types/config/settings.d.ts +2 -0
  24. package/dist/types/coordinator-mcp/model-preset.d.ts +7 -5
  25. package/dist/types/coordinator-mcp/projection-scan.d.ts +54 -0
  26. package/dist/types/crash/record-loader.d.ts +15 -0
  27. package/dist/types/extensibility/extensions/types.d.ts +2 -5
  28. package/dist/types/gjc-runtime/empty-delete-gc.d.ts +58 -0
  29. package/dist/types/gjc-runtime/gc-runtime.d.ts +2 -0
  30. package/dist/types/gjc-runtime/launch-worktree-reservation.d.ts +21 -0
  31. package/dist/types/gjc-runtime/managed-owner-supervisor.d.ts +2 -0
  32. package/dist/types/gjc-runtime/session-state-lock.d.ts +35 -6
  33. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +72 -1
  34. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +1 -0
  35. package/dist/types/gjc-runtime/tmux-sessions.d.ts +27 -0
  36. package/dist/types/index.d.ts +1 -0
  37. package/dist/types/main.d.ts +3 -1
  38. package/dist/types/master-mode/context.d.ts +21 -0
  39. package/dist/types/master-mode/first-request.d.ts +34 -0
  40. package/dist/types/master-mode/snapshot.d.ts +32 -0
  41. package/dist/types/modes/components/frictionless-onboarding-selector.d.ts +10 -0
  42. package/dist/types/modes/components/jobs-overlay-model.d.ts +4 -2
  43. package/dist/types/modes/components/oauth-selector.d.ts +1 -0
  44. package/dist/types/modes/components/status-line/model-name.d.ts +18 -0
  45. package/dist/types/modes/components/status-line/priority-row.d.ts +34 -0
  46. package/dist/types/modes/components/status-line/segments.d.ts +10 -0
  47. package/dist/types/modes/jobs-observer.d.ts +36 -0
  48. package/dist/types/modes/print-mode.d.ts +17 -0
  49. package/dist/types/modes/ui-language.d.ts +7 -1
  50. package/dist/types/sdk/broker/broker.d.ts +80 -1
  51. package/dist/types/sdk/broker/endpoint-authority.d.ts +24 -0
  52. package/dist/types/sdk/broker/index.d.ts +3 -0
  53. package/dist/types/sdk/broker/lifecycle.d.ts +26 -0
  54. package/dist/types/sdk/broker/master-capability.d.ts +10 -0
  55. package/dist/types/sdk/broker/session-index.d.ts +40 -11
  56. package/dist/types/sdk/broker/session-scope.d.ts +72 -0
  57. package/dist/types/sdk/broker/spawn-authority.d.ts +201 -0
  58. package/dist/types/sdk/broker/spawn-substrate.d.ts +30 -0
  59. package/dist/types/sdk/broker/state-version.d.ts +4 -1
  60. package/dist/types/sdk/broker/worktree-occupancy.d.ts +28 -0
  61. package/dist/types/sdk/bus/chat-daemon-control.d.ts +3 -0
  62. package/dist/types/sdk/bus/index.d.ts +6 -0
  63. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +3 -0
  64. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +4 -0
  65. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  66. package/dist/types/sdk/cli/index.d.ts +1 -0
  67. package/dist/types/sdk/cli/master-cli.d.ts +63 -0
  68. package/dist/types/sdk/cli/rows.d.ts +4 -3
  69. package/dist/types/sdk/cli/session-cli.d.ts +18 -2
  70. package/dist/types/sdk/client/client.d.ts +3 -2
  71. package/dist/types/sdk/client/discovery.d.ts +1 -0
  72. package/dist/types/sdk/host/control/dispatch.d.ts +10 -0
  73. package/dist/types/sdk/host/control/index.d.ts +1 -1
  74. package/dist/types/sdk/host/control/operations.d.ts +2 -0
  75. package/dist/types/sdk/host/control/runtime-gate.d.ts +21 -7
  76. package/dist/types/sdk/host/host.d.ts +10 -0
  77. package/dist/types/sdk/host/model-pin.d.ts +7 -2
  78. package/dist/types/sdk/host/sdk-run-capability.d.ts +1 -0
  79. package/dist/types/sdk/host/session-runtime.d.ts +67 -1
  80. package/dist/types/sdk/lifecycle/broker-client.d.ts +6 -0
  81. package/dist/types/sdk/lifecycle/service.d.ts +15 -3
  82. package/dist/types/sdk/lifecycle-session.d.ts +2 -0
  83. package/dist/types/sdk/prompt-deadline-manager.d.ts +11 -1
  84. package/dist/types/sdk/protocol/adapter-validation.d.ts +2 -0
  85. package/dist/types/sdk/router/session-router.d.ts +11 -0
  86. package/dist/types/sdk/session.d.ts +16 -0
  87. package/dist/types/sdk/startup-capability.d.ts +2 -1
  88. package/dist/types/session/account-inventory.d.ts +1 -0
  89. package/dist/types/session/agent-session.d.ts +24 -7
  90. package/dist/types/session/credential-store-errors.d.ts +1 -0
  91. package/dist/types/session/fold-coordinator.d.ts +201 -0
  92. package/dist/types/session/sdk-run-capability-internal.d.ts +7 -0
  93. package/dist/types/session/sdk-run-capability.d.ts +2 -0
  94. package/dist/types/session/session-manager.d.ts +65 -0
  95. package/dist/types/session/yield-queue.d.ts +5 -4
  96. package/dist/types/setup/frictionless-onboarding.d.ts +1 -0
  97. package/dist/types/telemetry/control.d.ts +11 -0
  98. package/dist/types/telemetry/events.d.ts +20 -0
  99. package/dist/types/telemetry/index.d.ts +3 -0
  100. package/dist/types/telemetry/transport.d.ts +22 -0
  101. package/dist/types/tools/bash-interactive.d.ts +23 -0
  102. package/dist/types/tools/bash.d.ts +4 -0
  103. package/dist/types/tools/gh.d.ts +8 -0
  104. package/dist/types/tools/index.d.ts +10 -5
  105. package/dist/types/web/search/providers/base.d.ts +9 -4
  106. package/dist/types/web/search/providers/xai.d.ts +2 -1
  107. package/dist/types/web/search/types.d.ts +14 -0
  108. package/package.json +10 -7
  109. package/scripts/generate-hotkeys-docs.ts +4 -0
  110. package/scripts/generate-sdk-operation-inventory.ts +9 -3
  111. package/scripts/verify-gjc-sdk-canonicalization.ts +35 -1
  112. package/src/async/job-manager.ts +671 -39
  113. package/src/cli/accounts-cli.ts +9 -5
  114. package/src/cli/args.ts +17 -0
  115. package/src/cli/auth-broker-cli.ts +40 -12
  116. package/src/cli/auth-gateway-cli.ts +273 -97
  117. package/src/cli/config-cli.ts +2 -2
  118. package/src/cli/fast-help.ts +4 -0
  119. package/src/cli/model-presets-cli.ts +100 -0
  120. package/src/cli/root-flags.ts +5 -0
  121. package/src/cli/update-cli.ts +117 -16
  122. package/src/cli.ts +6 -2
  123. package/src/commands/auth-gateway.ts +12 -8
  124. package/src/commands/gc.ts +19 -0
  125. package/src/commands/launch.ts +86 -18
  126. package/src/commands/model-presets.ts +24 -0
  127. package/src/commands/sdk.ts +113 -21
  128. package/src/config/autorouting-tier-map.ts +44 -0
  129. package/src/config/file-lock-gc.ts +9 -4
  130. package/src/config/file-lock.ts +890 -99
  131. package/src/config/internal/model-preset-registry-test-state.ts +28 -0
  132. package/src/config/internal/model-preset-registry-test-support.ts +11 -0
  133. package/src/config/keybindings.ts +6 -2
  134. package/src/config/model-preset-registry.ts +2795 -0
  135. package/src/config/model-profile-activation.ts +115 -28
  136. package/src/config/model-profile-contract.ts +4 -1
  137. package/src/config/model-profiles.ts +56 -14
  138. package/src/config/model-registry.ts +1044 -122
  139. package/src/config/model-resolver.ts +5 -0
  140. package/src/config/settings-schema.ts +19 -1
  141. package/src/config/settings.ts +11 -1
  142. package/src/coordinator-mcp/model-preset.ts +32 -17
  143. package/src/coordinator-mcp/projection-scan.ts +592 -0
  144. package/src/coordinator-mcp/question-state.ts +9 -11
  145. package/src/coordinator-mcp/server.ts +111 -42
  146. package/src/coordinator-mcp/session-reaper.ts +9 -3
  147. package/src/crash/index-store.ts +2 -0
  148. package/src/crash/record-loader.ts +10 -0
  149. package/src/extensibility/extensions/loader.ts +0 -1
  150. package/src/extensibility/extensions/types.ts +2 -3
  151. package/src/extensibility/gjc-plugins/runtime-adapters.ts +1 -0
  152. package/src/gjc-runtime/empty-delete-gc.ts +301 -0
  153. package/src/gjc-runtime/gc-render.ts +29 -0
  154. package/src/gjc-runtime/gc-runtime.ts +174 -11
  155. package/src/gjc-runtime/launch-worktree-reservation.ts +242 -0
  156. package/src/gjc-runtime/managed-owner-supervisor.ts +63 -51
  157. package/src/gjc-runtime/session-state-lock.ts +1321 -147
  158. package/src/gjc-runtime/session-state-sidecar.ts +1004 -25
  159. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +4 -7
  160. package/src/gjc-runtime/tmux-owner-isolation.ts +2 -2
  161. package/src/gjc-runtime/tmux-sessions.ts +252 -13
  162. package/src/hooks/skill-state.ts +6 -0
  163. package/src/index.ts +1 -0
  164. package/src/internal-urls/docs-index.generated.ts +14 -13
  165. package/src/internal-urls/issue-pr-protocol.ts +4 -2
  166. package/src/lsp/config.ts +4 -3
  167. package/src/lsp/path-trust.ts +12 -6
  168. package/src/main.ts +66 -4
  169. package/src/master-mode/context.ts +50 -0
  170. package/src/master-mode/first-request.ts +65 -0
  171. package/src/master-mode/snapshot.ts +205 -0
  172. package/src/modes/acp/acp-agent.ts +616 -161
  173. package/src/modes/components/footer.ts +4 -2
  174. package/src/modes/components/frictionless-onboarding-selector.ts +48 -2
  175. package/src/modes/components/jobs-overlay-model.ts +99 -16
  176. package/src/modes/components/model-selector.ts +158 -18
  177. package/src/modes/components/oauth-selector.ts +6 -1
  178. package/src/modes/components/settings-selector.ts +1 -0
  179. package/src/modes/components/status-line/model-name.ts +53 -0
  180. package/src/modes/components/status-line/priority-row.ts +107 -0
  181. package/src/modes/components/status-line/segments.ts +29 -10
  182. package/src/modes/components/tool-status-header.ts +151 -15
  183. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  184. package/src/modes/controllers/input-controller.ts +51 -6
  185. package/src/modes/controllers/selector-controller.ts +191 -96
  186. package/src/modes/interactive-mode.ts +14 -1
  187. package/src/modes/jobs-observer.ts +149 -16
  188. package/src/modes/print-mode.ts +64 -0
  189. package/src/modes/runtime-init.ts +1 -1
  190. package/src/modes/ui-language.ts +49 -2
  191. package/src/modes/utils/injected-user-submission.ts +15 -1
  192. package/src/prompts/system/master-mode.md +28 -0
  193. package/src/prompts/tools/bash.md +2 -2
  194. package/src/prompts/tools/fold-receipt.md +3 -0
  195. package/src/prompts/tools/job.md +1 -1
  196. package/src/sdk/acp/adapter.ts +17 -2
  197. package/src/sdk/broker/broker.ts +1671 -34
  198. package/src/sdk/broker/endpoint-authority.ts +86 -0
  199. package/src/sdk/broker/ensure.ts +5 -0
  200. package/src/sdk/broker/index.ts +3 -0
  201. package/src/sdk/broker/lifecycle.ts +217 -46
  202. package/src/sdk/broker/master-capability.ts +232 -0
  203. package/src/sdk/broker/session-index.ts +121 -17
  204. package/src/sdk/broker/session-scope.ts +272 -0
  205. package/src/sdk/broker/spawn-authority.ts +1031 -0
  206. package/src/sdk/broker/spawn-substrate.ts +548 -0
  207. package/src/sdk/broker/state-version.ts +26 -14
  208. package/src/sdk/broker/transport.ts +1 -0
  209. package/src/sdk/broker/worktree-occupancy.ts +90 -0
  210. package/src/sdk/bus/chat-daemon-control.ts +5 -2
  211. package/src/sdk/bus/chat-daemon-runtime.ts +46 -5
  212. package/src/sdk/bus/index.ts +51 -4
  213. package/src/sdk/bus/kind-aware-reconciliation.ts +36 -6
  214. package/src/sdk/bus/prompt-reconciliation.ts +28 -4
  215. package/src/sdk/bus/slack-conversation.ts +5 -1
  216. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  217. package/src/sdk/cli/index.ts +1 -0
  218. package/src/sdk/cli/master-cli.ts +259 -0
  219. package/src/sdk/cli/rows.ts +11 -8
  220. package/src/sdk/cli/session-cli.ts +276 -6
  221. package/src/sdk/client/client.ts +14 -8
  222. package/src/sdk/client/discovery.ts +3 -1
  223. package/src/sdk/host/control/dispatch.ts +101 -37
  224. package/src/sdk/host/control/index.ts +2 -0
  225. package/src/sdk/host/control/operations.ts +2 -0
  226. package/src/sdk/host/control/runtime-gate.ts +203 -11
  227. package/src/sdk/host/host.ts +27 -2
  228. package/src/sdk/host/model-pin.ts +185 -25
  229. package/src/sdk/host/sdk-run-capability.ts +1 -0
  230. package/src/sdk/host/session-runtime.test.ts +581 -43
  231. package/src/sdk/host/session-runtime.ts +655 -101
  232. package/src/sdk/lifecycle/broker-client.ts +28 -0
  233. package/src/sdk/lifecycle/service.ts +279 -20
  234. package/src/sdk/lifecycle-session.ts +10 -2
  235. package/src/sdk/prompt-deadline-manager.ts +16 -1
  236. package/src/sdk/protocol/adapter-validation.ts +27 -0
  237. package/src/sdk/protocol/operation-inventory.generated.json +53 -2
  238. package/src/sdk/protocol/operation-registry.ts +17 -4
  239. package/src/sdk/router/session-router.ts +294 -154
  240. package/src/sdk/session.ts +440 -167
  241. package/src/sdk/startup-capability.ts +1 -0
  242. package/src/session/account-inventory.ts +27 -11
  243. package/src/session/agent-session.ts +1292 -180
  244. package/src/session/blob-store.ts +15 -5
  245. package/src/session/credential-store-errors.ts +2 -0
  246. package/src/session/fold-coordinator.ts +433 -0
  247. package/src/session/internal/managed-session-storage.ts +153 -78
  248. package/src/session/sdk-run-capability-internal.ts +15 -0
  249. package/src/session/sdk-run-capability.ts +2 -0
  250. package/src/session/session-manager.ts +342 -28
  251. package/src/session/yield-queue.ts +24 -10
  252. package/src/setup/frictionless-onboarding.ts +2 -0
  253. package/src/setup/provider-presets.json +1 -1
  254. package/src/slash-commands/helpers/credential-switch.ts +6 -1
  255. package/src/task/executor.ts +19 -3
  256. package/src/telemetry/control.ts +26 -0
  257. package/src/telemetry/events.ts +1268 -0
  258. package/src/telemetry/index.ts +3 -0
  259. package/src/telemetry/transport.ts +87 -0
  260. package/src/tools/bash-interactive.ts +182 -85
  261. package/src/tools/bash.ts +1028 -109
  262. package/src/tools/gh.ts +104 -48
  263. package/src/tools/github-cache.ts +2 -2
  264. package/src/tools/index.ts +11 -5
  265. package/src/tools/tool-catalog.generated.ts +1 -1
  266. package/src/web/search/provider.ts +120 -11
  267. package/src/web/search/providers/anthropic.ts +89 -17
  268. package/src/web/search/providers/base.ts +9 -4
  269. package/src/web/search/providers/gemini.ts +87 -15
  270. package/src/web/search/providers/openai-compatible.ts +23 -8
  271. package/src/web/search/providers/xai.ts +98 -12
  272. package/src/web/search/types.ts +16 -0
@@ -17,9 +17,19 @@ export interface SdkHostModelResolveContext {
17
17
  }
18
18
 
19
19
  /** Registry loader owned by the SDK host, not by machine-facing adapters. */
20
- export type SdkHostModelRegistryLoader = (
20
+ export type SdkHostModelRegistryLoader = ((
21
21
  context?: SdkHostModelResolveContext,
22
- ) => ModelRegistry | Promise<ModelRegistry>;
22
+ ) => ModelRegistry | Promise<ModelRegistry>) & {
23
+ acquire?: (context?: SdkHostModelResolveContext) => () => void;
24
+ dispose?: () => Promise<void>;
25
+ };
26
+
27
+ type OwnedModelRegistry = {
28
+ registry: ModelRegistry;
29
+ storage: AuthStorage;
30
+ };
31
+
32
+ const MAX_CACHED_MODEL_REGISTRIES = 32;
23
33
 
24
34
  /**
25
35
  * Builds an offline model resolver for a single SDK host process.
@@ -32,16 +42,112 @@ export function createSdkHostModelRegistryLoader(
32
42
  modelsPath?: string,
33
43
  loadSettings?: (context?: SdkHostModelResolveContext) => Promise<Pick<Settings, "get" | "getGlobal">>,
34
44
  ): SdkHostModelRegistryLoader {
35
- const cachedRegistries = new Map<string, Promise<ModelRegistry>>();
36
- return async (context?: SdkHostModelResolveContext) => {
37
- const scopeKey = context?.cwd ?? "";
45
+ const cachedRegistries = new Map<string, Promise<OwnedModelRegistry>>();
46
+ const retiredRegistries = new Map<string, Promise<OwnedModelRegistry>[]>();
47
+ const activeScopes = new Map<string, number>();
48
+ const disposedEntries = new WeakSet<Promise<OwnedModelRegistry>>();
49
+ const pendingDisposals = new Set<Promise<void>>();
50
+ const disposalBarrier = Promise.withResolvers<void>();
51
+ const registryAgentDir = path.resolve(path.dirname(modelsPath ?? "."));
52
+ let disposed = false;
53
+ const scopeKeyFor = (context?: SdkHostModelResolveContext): string =>
54
+ context?.cwd === undefined ? "" : path.resolve(context.cwd);
55
+ const disposeEntry = async (entry: Promise<OwnedModelRegistry>): Promise<void> => {
56
+ let owned: OwnedModelRegistry;
57
+ try {
58
+ owned = await entry;
59
+ } catch {
60
+ // Initialization failures close their storage before rejecting. Disposal is
61
+ // best-effort and must not block broker shutdown on one broken scope.
62
+ return;
63
+ }
64
+ try {
65
+ owned.registry.dispose();
66
+ } finally {
67
+ owned.storage.close();
68
+ }
69
+ };
70
+ const maybeResolveDisposal = (): void => {
71
+ if (
72
+ disposed &&
73
+ cachedRegistries.size === 0 &&
74
+ retiredRegistries.size === 0 &&
75
+ activeScopes.size === 0 &&
76
+ pendingDisposals.size === 0
77
+ )
78
+ disposalBarrier.resolve();
79
+ };
80
+ const disposeEntries = (entries: Promise<OwnedModelRegistry>[]): void => {
81
+ const seen = new Set<Promise<OwnedModelRegistry>>();
82
+ const unique = entries.filter(entry => {
83
+ if (seen.has(entry) || disposedEntries.has(entry)) return false;
84
+ seen.add(entry);
85
+ return true;
86
+ });
87
+ if (unique.length === 0) {
88
+ maybeResolveDisposal();
89
+ return;
90
+ }
91
+ for (const entry of unique) disposedEntries.add(entry);
92
+ const pending = Promise.all(unique.map(entry => disposeEntry(entry))).then(
93
+ () => undefined,
94
+ () => undefined,
95
+ );
96
+ pendingDisposals.add(pending);
97
+ void pending.finally(() => {
98
+ pendingDisposals.delete(pending);
99
+ maybeResolveDisposal();
100
+ });
101
+ };
102
+ const retireEntry = (scopeKey: string, entry: Promise<OwnedModelRegistry>): void => {
103
+ if ((activeScopes.get(scopeKey) ?? 0) > 0) {
104
+ const retired = retiredRegistries.get(scopeKey) ?? [];
105
+ if (!retired.includes(entry)) retired.push(entry);
106
+ retiredRegistries.set(scopeKey, retired);
107
+ return;
108
+ }
109
+ disposeEntries([entry]);
110
+ };
111
+ const disposeRetired = (scopeKey: string): void => {
112
+ const retired = retiredRegistries.get(scopeKey);
113
+ if (!retired || (activeScopes.get(scopeKey) ?? 0) > 0) return;
114
+ retiredRegistries.delete(scopeKey);
115
+ disposeEntries(retired);
116
+ };
117
+ const evictIdleEntries = (): Promise<OwnedModelRegistry>[] => {
118
+ const evicted: Promise<OwnedModelRegistry>[] = [];
119
+ while (cachedRegistries.size > MAX_CACHED_MODEL_REGISTRIES) {
120
+ const oldest = [...cachedRegistries.keys()].find(key => (activeScopes.get(key) ?? 0) === 0);
121
+ if (oldest === undefined) break;
122
+ const entry = cachedRegistries.get(oldest);
123
+ cachedRegistries.delete(oldest);
124
+ if (entry) evicted.push(entry);
125
+ }
126
+ return evicted;
127
+ };
128
+ const loadRegistry = async (context?: SdkHostModelResolveContext): Promise<ModelRegistry> => {
129
+ if (disposed) throw new Error("SDK host model registry loader is disposed.");
130
+ const scopeKey = scopeKeyFor(context);
38
131
  let cachedRegistry = cachedRegistries.get(scopeKey);
39
132
  if (cachedRegistry === undefined) {
40
- const initializing = Promise.all([discoverStorage(), loadSettings?.(context)]).then(
41
- ([storage, registrySettings]) => new ModelRegistry(storage, modelsPath, registrySettings),
42
- );
133
+ const initializing = discoverStorage().then(async storage => {
134
+ try {
135
+ const registrySettings = await loadSettings?.(context);
136
+ return {
137
+ storage,
138
+ registry: new ModelRegistry(storage, modelsPath, registrySettings, {
139
+ agentDir: registryAgentDir,
140
+ automaticRefresh: false,
141
+ }),
142
+ };
143
+ } catch (error) {
144
+ storage.close();
145
+ throw error;
146
+ }
147
+ });
43
148
  cachedRegistries.set(scopeKey, initializing);
44
149
  cachedRegistry = initializing;
150
+ disposeEntries(evictIdleEntries());
45
151
  try {
46
152
  await initializing;
47
153
  } catch (error) {
@@ -49,21 +155,67 @@ export function createSdkHostModelRegistryLoader(
49
155
  throw error;
50
156
  }
51
157
  }
52
- const registry = await cachedRegistry;
53
- if (loadSettings) registry.setScopedSettings(await loadSettings(context));
158
+ const owned = await cachedRegistry;
159
+ if (disposed || disposedEntries.has(cachedRegistry) || cachedRegistries.get(scopeKey) !== cachedRegistry) {
160
+ retireEntry(scopeKey, cachedRegistry);
161
+ throw new Error("SDK host model registry loader is disposed.");
162
+ }
163
+ cachedRegistries.delete(scopeKey);
164
+ cachedRegistries.set(scopeKey, cachedRegistry);
165
+ const registry = owned.registry;
166
+ if (loadSettings) {
167
+ const registrySettings = await loadSettings(context);
168
+ if (disposed || disposedEntries.has(cachedRegistry)) {
169
+ retireEntry(scopeKey, cachedRegistry);
170
+ throw new Error("SDK host model registry loader is disposed.");
171
+ }
172
+ registry.setScopedSettings(registrySettings);
173
+ }
54
174
  await registry.refresh("offline");
175
+ if (disposed || disposedEntries.has(cachedRegistry)) {
176
+ retireEntry(scopeKey, cachedRegistry);
177
+ throw new Error("SDK host model registry loader is disposed.");
178
+ }
55
179
  return registry;
56
180
  };
181
+ return Object.assign(loadRegistry, {
182
+ dispose: async (): Promise<void> => {
183
+ if (disposed) return await disposalBarrier.promise;
184
+ disposed = true;
185
+ for (const [scopeKey, entry] of cachedRegistries) retireEntry(scopeKey, entry);
186
+ cachedRegistries.clear();
187
+ for (const scopeKey of retiredRegistries.keys()) disposeRetired(scopeKey);
188
+ maybeResolveDisposal();
189
+ await disposalBarrier.promise;
190
+ },
191
+ acquire: (context?: SdkHostModelResolveContext): (() => void) => {
192
+ const scopeKey = scopeKeyFor(context);
193
+ activeScopes.set(scopeKey, (activeScopes.get(scopeKey) ?? 0) + 1);
194
+ let released = false;
195
+ return () => {
196
+ if (released) return;
197
+ released = true;
198
+ const next = (activeScopes.get(scopeKey) ?? 1) - 1;
199
+ if (next <= 0) activeScopes.delete(scopeKey);
200
+ else activeScopes.set(scopeKey, next);
201
+ disposeRetired(scopeKey);
202
+ disposeEntries(evictIdleEntries());
203
+ maybeResolveDisposal();
204
+ };
205
+ },
206
+ });
57
207
  }
58
208
 
59
209
  export type SdkHostModelResolution =
60
210
  | { ok: true; model: string | null }
61
211
  | { ok: false; reason: "unknown_model"; model: string; error: string };
62
212
 
63
- export type SdkHostModelResolver = (
213
+ export type SdkHostModelResolver = ((
64
214
  raw: unknown,
65
215
  context?: SdkHostModelResolveContext,
66
- ) => Promise<SdkHostModelResolution>;
216
+ ) => Promise<SdkHostModelResolution>) & {
217
+ dispose?: () => Promise<void>;
218
+ };
67
219
 
68
220
  /** Resolve the explicit model pin at the SDK host boundary. */
69
221
  export async function resolveSdkHostModel(
@@ -74,19 +226,24 @@ export async function resolveSdkHostModel(
74
226
  if (raw === undefined || raw === null) return { ok: true, model: null };
75
227
  const requested = typeof raw === "string" ? raw : "";
76
228
  const echoed = requested.trim().slice(0, MAX_ECHOED_MODEL_LENGTH);
77
- const registry = await loadRegistry(context);
78
- const resolved: ResolveCliModelResult = resolveCliModel({ cliModel: requested, modelRegistry: registry });
79
- if (!resolved.model)
229
+ const release = loadRegistry.acquire?.(context) ?? (() => {});
230
+ try {
231
+ const registry = await loadRegistry(context);
232
+ const resolved: ResolveCliModelResult = resolveCliModel({ cliModel: requested, modelRegistry: registry });
233
+ if (!resolved.model)
234
+ return {
235
+ ok: false,
236
+ reason: "unknown_model",
237
+ model: echoed,
238
+ error: resolved.error ?? "No models available. Check your installation or add models to models.json.",
239
+ };
80
240
  return {
81
- ok: false,
82
- reason: "unknown_model",
83
- model: echoed,
84
- error: resolved.error ?? "No models available. Check your installation or add models to models.json.",
241
+ ok: true,
242
+ model: formatModelSelectorValue(formatModelString(resolved.model), resolved.thinkingLevel),
85
243
  };
86
- return {
87
- ok: true,
88
- model: formatModelSelectorValue(formatModelString(resolved.model), resolved.thinkingLevel),
89
- };
244
+ } finally {
245
+ release();
246
+ }
90
247
  }
91
248
 
92
249
  /** Default resolver used by the SDK broker host. */
@@ -96,6 +253,9 @@ export function createDefaultSdkHostModelResolver(agentDir: string): SdkHostMode
96
253
  path.join(agentDir, "models.yml"),
97
254
  context => Settings.loadReadonly({ agentDir, cwd: context?.cwd }),
98
255
  );
99
- return (raw: unknown, context?: SdkHostModelResolveContext): Promise<SdkHostModelResolution> =>
100
- resolveSdkHostModel(raw, loadRegistry, context);
256
+ return Object.assign(
257
+ (raw: unknown, context?: SdkHostModelResolveContext): Promise<SdkHostModelResolution> =>
258
+ resolveSdkHostModel(raw, loadRegistry, context),
259
+ { dispose: loadRegistry.dispose },
260
+ );
101
261
  }
@@ -0,0 +1 @@
1
+ export { createSdkRunCapability } from "../../session/sdk-run-capability-internal";