@x-code-cli/core 0.2.10 → 0.3.1

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 (258) hide show
  1. package/dist/agent/compression.d.ts +12 -2
  2. package/dist/agent/compression.d.ts.map +1 -1
  3. package/dist/agent/compression.js +51 -2
  4. package/dist/agent/compression.js.map +1 -1
  5. package/dist/agent/file-ingest.js +2 -2
  6. package/dist/agent/file-ingest.js.map +1 -1
  7. package/dist/agent/loop-state.d.ts +3 -2
  8. package/dist/agent/loop-state.d.ts.map +1 -1
  9. package/dist/agent/loop-state.js.map +1 -1
  10. package/dist/agent/loop.d.ts.map +1 -1
  11. package/dist/agent/loop.js +134 -5
  12. package/dist/agent/loop.js.map +1 -1
  13. package/dist/agent/memory-extractor.js +5 -5
  14. package/dist/agent/memory-extractor.js.map +1 -1
  15. package/dist/agent/plan-storage.js +1 -1
  16. package/dist/agent/plan-storage.js.map +1 -1
  17. package/dist/agent/sub-agents/index.d.ts +2 -1
  18. package/dist/agent/sub-agents/index.d.ts.map +1 -1
  19. package/dist/agent/sub-agents/index.js +1 -1
  20. package/dist/agent/sub-agents/index.js.map +1 -1
  21. package/dist/agent/sub-agents/loader.d.ts +13 -3
  22. package/dist/agent/sub-agents/loader.d.ts.map +1 -1
  23. package/dist/agent/sub-agents/loader.js +36 -9
  24. package/dist/agent/sub-agents/loader.js.map +1 -1
  25. package/dist/agent/sub-agents/registry.d.ts +18 -1
  26. package/dist/agent/sub-agents/registry.d.ts.map +1 -1
  27. package/dist/agent/sub-agents/registry.js +38 -5
  28. package/dist/agent/sub-agents/registry.js.map +1 -1
  29. package/dist/agent/sub-agents/runner.d.ts.map +1 -1
  30. package/dist/agent/sub-agents/runner.js +45 -1
  31. package/dist/agent/sub-agents/runner.js.map +1 -1
  32. package/dist/agent/sub-agents/types.d.ts +4 -1
  33. package/dist/agent/sub-agents/types.d.ts.map +1 -1
  34. package/dist/agent/system-prompt.d.ts +21 -0
  35. package/dist/agent/system-prompt.d.ts.map +1 -1
  36. package/dist/agent/system-prompt.js +68 -2
  37. package/dist/agent/system-prompt.js.map +1 -1
  38. package/dist/agent/tool-execution.d.ts.map +1 -1
  39. package/dist/agent/tool-execution.js +220 -1
  40. package/dist/agent/tool-execution.js.map +1 -1
  41. package/dist/commands/index.d.ts +6 -0
  42. package/dist/commands/index.d.ts.map +1 -0
  43. package/dist/commands/index.js +3 -0
  44. package/dist/commands/index.js.map +1 -0
  45. package/dist/commands/loader.d.ts +19 -0
  46. package/dist/commands/loader.d.ts.map +1 -0
  47. package/dist/commands/loader.js +109 -0
  48. package/dist/commands/loader.js.map +1 -0
  49. package/dist/commands/registry.d.ts +44 -0
  50. package/dist/commands/registry.d.ts.map +1 -0
  51. package/dist/commands/registry.js +102 -0
  52. package/dist/commands/registry.js.map +1 -0
  53. package/dist/commands/types.d.ts +23 -0
  54. package/dist/commands/types.d.ts.map +1 -0
  55. package/dist/commands/types.js +26 -0
  56. package/dist/commands/types.js.map +1 -0
  57. package/dist/config/index.d.ts +9 -0
  58. package/dist/config/index.d.ts.map +1 -1
  59. package/dist/config/index.js +12 -10
  60. package/dist/config/index.js.map +1 -1
  61. package/dist/hooks/bus.d.ts +54 -0
  62. package/dist/hooks/bus.d.ts.map +1 -0
  63. package/dist/hooks/bus.js +165 -0
  64. package/dist/hooks/bus.js.map +1 -0
  65. package/dist/hooks/config-schema.d.ts +854 -0
  66. package/dist/hooks/config-schema.d.ts.map +1 -0
  67. package/dist/hooks/config-schema.js +79 -0
  68. package/dist/hooks/config-schema.js.map +1 -0
  69. package/dist/hooks/executor.d.ts +16 -0
  70. package/dist/hooks/executor.d.ts.map +1 -0
  71. package/dist/hooks/executor.js +183 -0
  72. package/dist/hooks/executor.js.map +1 -0
  73. package/dist/hooks/index.d.ts +10 -0
  74. package/dist/hooks/index.d.ts.map +1 -0
  75. package/dist/hooks/index.js +6 -0
  76. package/dist/hooks/index.js.map +1 -0
  77. package/dist/hooks/registry.d.ts +23 -0
  78. package/dist/hooks/registry.d.ts.map +1 -0
  79. package/dist/hooks/registry.js +49 -0
  80. package/dist/hooks/registry.js.map +1 -0
  81. package/dist/hooks/types.d.ts +165 -0
  82. package/dist/hooks/types.d.ts.map +1 -0
  83. package/dist/hooks/types.js +25 -0
  84. package/dist/hooks/types.js.map +1 -0
  85. package/dist/hooks/variables.d.ts +22 -0
  86. package/dist/hooks/variables.d.ts.map +1 -0
  87. package/dist/hooks/variables.js +80 -0
  88. package/dist/hooks/variables.js.map +1 -0
  89. package/dist/index.d.ts +57 -2
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +38 -2
  92. package/dist/index.js.map +1 -1
  93. package/dist/knowledge/auto-memory.d.ts +1 -1
  94. package/dist/knowledge/auto-memory.d.ts.map +1 -1
  95. package/dist/knowledge/auto-memory.js +10 -10
  96. package/dist/knowledge/auto-memory.js.map +1 -1
  97. package/dist/knowledge/loader.js +12 -12
  98. package/dist/knowledge/loader.js.map +1 -1
  99. package/dist/mcp/arg-parser.d.ts +49 -0
  100. package/dist/mcp/arg-parser.d.ts.map +1 -0
  101. package/dist/mcp/arg-parser.js +357 -0
  102. package/dist/mcp/arg-parser.js.map +1 -0
  103. package/dist/mcp/client.d.ts +73 -0
  104. package/dist/mcp/client.d.ts.map +1 -0
  105. package/dist/mcp/client.js +376 -0
  106. package/dist/mcp/client.js.map +1 -0
  107. package/dist/mcp/config-schema.d.ts +64 -0
  108. package/dist/mcp/config-schema.d.ts.map +1 -0
  109. package/dist/mcp/config-schema.js +86 -0
  110. package/dist/mcp/config-schema.js.map +1 -0
  111. package/dist/mcp/config-writer.d.ts +41 -0
  112. package/dist/mcp/config-writer.d.ts.map +1 -0
  113. package/dist/mcp/config-writer.js +138 -0
  114. package/dist/mcp/config-writer.js.map +1 -0
  115. package/dist/mcp/env-safety.d.ts +12 -0
  116. package/dist/mcp/env-safety.d.ts.map +1 -0
  117. package/dist/mcp/env-safety.js +80 -0
  118. package/dist/mcp/env-safety.js.map +1 -0
  119. package/dist/mcp/expand-env.d.ts +14 -0
  120. package/dist/mcp/expand-env.d.ts.map +1 -0
  121. package/dist/mcp/expand-env.js +52 -0
  122. package/dist/mcp/expand-env.js.map +1 -0
  123. package/dist/mcp/loader.d.ts +81 -0
  124. package/dist/mcp/loader.d.ts.map +1 -0
  125. package/dist/mcp/loader.js +223 -0
  126. package/dist/mcp/loader.js.map +1 -0
  127. package/dist/mcp/name-mangling.d.ts +11 -0
  128. package/dist/mcp/name-mangling.d.ts.map +1 -0
  129. package/dist/mcp/name-mangling.js +82 -0
  130. package/dist/mcp/name-mangling.js.map +1 -0
  131. package/dist/mcp/oauth/callback-server.d.ts +25 -0
  132. package/dist/mcp/oauth/callback-server.d.ts.map +1 -0
  133. package/dist/mcp/oauth/callback-server.js +118 -0
  134. package/dist/mcp/oauth/callback-server.js.map +1 -0
  135. package/dist/mcp/oauth/provider.d.ts +80 -0
  136. package/dist/mcp/oauth/provider.d.ts.map +1 -0
  137. package/dist/mcp/oauth/provider.js +292 -0
  138. package/dist/mcp/oauth/provider.js.map +1 -0
  139. package/dist/mcp/oauth/token-storage.d.ts +42 -0
  140. package/dist/mcp/oauth/token-storage.d.ts.map +1 -0
  141. package/dist/mcp/oauth/token-storage.js +121 -0
  142. package/dist/mcp/oauth/token-storage.js.map +1 -0
  143. package/dist/mcp/permissions.d.ts +28 -0
  144. package/dist/mcp/permissions.d.ts.map +1 -0
  145. package/dist/mcp/permissions.js +105 -0
  146. package/dist/mcp/permissions.js.map +1 -0
  147. package/dist/mcp/registry.d.ts +150 -0
  148. package/dist/mcp/registry.d.ts.map +1 -0
  149. package/dist/mcp/registry.js +334 -0
  150. package/dist/mcp/registry.js.map +1 -0
  151. package/dist/mcp/resources.d.ts +7 -0
  152. package/dist/mcp/resources.d.ts.map +1 -0
  153. package/dist/mcp/resources.js +40 -0
  154. package/dist/mcp/resources.js.map +1 -0
  155. package/dist/mcp/tool-bridge.d.ts +16 -0
  156. package/dist/mcp/tool-bridge.d.ts.map +1 -0
  157. package/dist/mcp/tool-bridge.js +56 -0
  158. package/dist/mcp/tool-bridge.js.map +1 -0
  159. package/dist/mcp/trust.d.ts +31 -0
  160. package/dist/mcp/trust.d.ts.map +1 -0
  161. package/dist/mcp/trust.js +103 -0
  162. package/dist/mcp/trust.js.map +1 -0
  163. package/dist/mcp/types.d.ts +73 -0
  164. package/dist/mcp/types.d.ts.map +1 -0
  165. package/dist/mcp/types.js +13 -0
  166. package/dist/mcp/types.js.map +1 -0
  167. package/dist/permissions/index.d.ts +1 -1
  168. package/dist/permissions/index.d.ts.map +1 -1
  169. package/dist/permissions/index.js +10 -4
  170. package/dist/permissions/index.js.map +1 -1
  171. package/dist/permissions/session-store.d.ts +79 -17
  172. package/dist/permissions/session-store.d.ts.map +1 -1
  173. package/dist/permissions/session-store.js +298 -38
  174. package/dist/permissions/session-store.js.map +1 -1
  175. package/dist/plugins/consent.d.ts +87 -0
  176. package/dist/plugins/consent.d.ts.map +1 -0
  177. package/dist/plugins/consent.js +181 -0
  178. package/dist/plugins/consent.js.map +1 -0
  179. package/dist/plugins/enable-state.d.ts +34 -0
  180. package/dist/plugins/enable-state.d.ts.map +1 -0
  181. package/dist/plugins/enable-state.js +159 -0
  182. package/dist/plugins/enable-state.js.map +1 -0
  183. package/dist/plugins/installer.d.ts +64 -0
  184. package/dist/plugins/installer.d.ts.map +1 -0
  185. package/dist/plugins/installer.js +416 -0
  186. package/dist/plugins/installer.js.map +1 -0
  187. package/dist/plugins/integration.d.ts +91 -0
  188. package/dist/plugins/integration.d.ts.map +1 -0
  189. package/dist/plugins/integration.js +233 -0
  190. package/dist/plugins/integration.js.map +1 -0
  191. package/dist/plugins/loader.d.ts +69 -0
  192. package/dist/plugins/loader.d.ts.map +1 -0
  193. package/dist/plugins/loader.js +243 -0
  194. package/dist/plugins/loader.js.map +1 -0
  195. package/dist/plugins/manifest.d.ts +23 -0
  196. package/dist/plugins/manifest.d.ts.map +1 -0
  197. package/dist/plugins/manifest.js +143 -0
  198. package/dist/plugins/manifest.js.map +1 -0
  199. package/dist/plugins/marketplace.d.ts +103 -0
  200. package/dist/plugins/marketplace.d.ts.map +1 -0
  201. package/dist/plugins/marketplace.js +532 -0
  202. package/dist/plugins/marketplace.js.map +1 -0
  203. package/dist/plugins/paths.d.ts +44 -0
  204. package/dist/plugins/paths.d.ts.map +1 -0
  205. package/dist/plugins/paths.js +89 -0
  206. package/dist/plugins/paths.js.map +1 -0
  207. package/dist/plugins/refresh.d.ts +61 -0
  208. package/dist/plugins/refresh.d.ts.map +1 -0
  209. package/dist/plugins/refresh.js +98 -0
  210. package/dist/plugins/refresh.js.map +1 -0
  211. package/dist/plugins/registry.d.ts +40 -0
  212. package/dist/plugins/registry.d.ts.map +1 -0
  213. package/dist/plugins/registry.js +80 -0
  214. package/dist/plugins/registry.js.map +1 -0
  215. package/dist/plugins/types.d.ts +225 -0
  216. package/dist/plugins/types.d.ts.map +1 -0
  217. package/dist/plugins/types.js +16 -0
  218. package/dist/plugins/types.js.map +1 -0
  219. package/dist/plugins/user-config.d.ts +22 -0
  220. package/dist/plugins/user-config.d.ts.map +1 -0
  221. package/dist/plugins/user-config.js +96 -0
  222. package/dist/plugins/user-config.js.map +1 -0
  223. package/dist/skills/loader.d.ts +19 -0
  224. package/dist/skills/loader.d.ts.map +1 -0
  225. package/dist/skills/loader.js +197 -0
  226. package/dist/skills/loader.js.map +1 -0
  227. package/dist/skills/registry.d.ts +74 -0
  228. package/dist/skills/registry.d.ts.map +1 -0
  229. package/dist/skills/registry.js +136 -0
  230. package/dist/skills/registry.js.map +1 -0
  231. package/dist/skills/settings.d.ts +13 -0
  232. package/dist/skills/settings.d.ts.map +1 -0
  233. package/dist/skills/settings.js +100 -0
  234. package/dist/skills/settings.js.map +1 -0
  235. package/dist/tools/activate-skill.d.ts +5 -0
  236. package/dist/tools/activate-skill.d.ts.map +1 -0
  237. package/dist/tools/activate-skill.js +33 -0
  238. package/dist/tools/activate-skill.js.map +1 -0
  239. package/dist/tools/index.d.ts +1 -1
  240. package/dist/tools/shell-utils.d.ts.map +1 -1
  241. package/dist/tools/shell-utils.js +157 -6
  242. package/dist/tools/shell-utils.js.map +1 -1
  243. package/dist/tools/todo-write.d.ts +1 -1
  244. package/dist/tools/web-fetch.d.ts.map +1 -1
  245. package/dist/tools/web-fetch.js +2 -1
  246. package/dist/tools/web-fetch.js.map +1 -1
  247. package/dist/types/index.d.ts +46 -1
  248. package/dist/types/index.d.ts.map +1 -1
  249. package/dist/types/index.js.map +1 -1
  250. package/dist/utils.d.ts +23 -2
  251. package/dist/utils.d.ts.map +1 -1
  252. package/dist/utils.js +76 -20
  253. package/dist/utils.js.map +1 -1
  254. package/dist/version.d.ts +2 -0
  255. package/dist/version.d.ts.map +1 -0
  256. package/dist/version.js +47 -0
  257. package/dist/version.js.map +1 -0
  258. package/package.json +2 -1
@@ -0,0 +1,150 @@
1
+ import type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
2
+ import { McpClient } from './client.js';
3
+ import { type McpCallResult, type McpResourceEntry, type McpServerConfig, type McpServerStatus, type McpToolEntry } from './types.js';
4
+ /** Build an OAuth provider for one HTTP server. Stdio servers get
5
+ * `undefined`. Returns `undefined` for HTTP servers too when OAuth is
6
+ * not wired up at the CLI level (no token storage configured). */
7
+ export type OAuthProviderFactory = (serverName: string, serverUrl: string) => OAuthClientProvider | undefined;
8
+ export interface RegisteredServer {
9
+ name: string;
10
+ client: McpClient;
11
+ status: McpServerStatus;
12
+ /** When status is `failed`, the most recent stderr tail (stdio only).
13
+ * Used by /mcp list to show why a server failed. */
14
+ stderrTail?: string;
15
+ }
16
+ /** Hooks the /mcp auth handler hands in so the registry can surface
17
+ * human-visible progress without depending on the CLI layer. */
18
+ export interface AuthHooks {
19
+ /** Called once just before the browser is opened. Receives the
20
+ * authorization URL the SDK is about to redirect to. */
21
+ onBrowserOpen?: (url: string) => void;
22
+ }
23
+ /** Summary of what `restartAll` actually changed, for the /mcp refresh
24
+ * output line. */
25
+ export interface RestartSummary {
26
+ /** Server names present after restart that weren't present before. */
27
+ added: string[];
28
+ /** Server names removed (present before, not in new config). */
29
+ removed: string[];
30
+ /** Server names present in both but whose config differs. */
31
+ changed: string[];
32
+ /** Server names that survived restart unchanged. */
33
+ unchanged: string[];
34
+ }
35
+ export declare class McpRegistry {
36
+ /** callableName → entry. callableName is the model-facing
37
+ * `<server>__<tool>` form; collisions resolved at insert time. */
38
+ private readonly entries;
39
+ /** uri → entry. URIs are unique per spec; if two servers genuinely
40
+ * expose the same URI we keep the first and warn (handled by loader). */
41
+ private readonly resources;
42
+ private readonly servers;
43
+ /** Most-recently-loaded config per server. The source of truth for
44
+ * `restartServer` (which reconnects with the same config) and for
45
+ * diff'ing in `restartAll` when fresh configs are handed in. */
46
+ private readonly configs;
47
+ /** Factory for per-server OAuth providers. Optional — undefined means
48
+ * HTTP servers requiring auth will surface as `needs_auth` and the
49
+ * /mcp auth handler can't drive them. */
50
+ private oauthFactory;
51
+ constructor(input: {
52
+ servers: RegisteredServer[];
53
+ tools: McpToolEntry[];
54
+ resources: McpResourceEntry[];
55
+ /** Per-server config used at boot. Required for `restartServer` /
56
+ * `authenticateServer` to know what to rebuild. */
57
+ configs?: Map<string, McpServerConfig>;
58
+ /** OAuth provider factory threaded through from the CLI. */
59
+ oauthFactory?: OAuthProviderFactory;
60
+ });
61
+ /** Snapshot of every model-facing tool name; stable iteration order.
62
+ * Consumed by `buildTools` (agent loop) and `buildSystemPrompt`. */
63
+ list(): McpToolEntry[];
64
+ get(callableName: string): McpToolEntry | undefined;
65
+ listResources(): McpResourceEntry[];
66
+ /** Find the server that owns a given URI so the resource tool can
67
+ * dispatch the read. Returns undefined for unknown URIs. */
68
+ resourceServer(uri: string): McpClient | undefined;
69
+ serverStatus(): Array<{
70
+ name: string;
71
+ status: McpServerStatus;
72
+ stderrTail?: string;
73
+ }>;
74
+ getServer(serverName: string): RegisteredServer | undefined;
75
+ getConfig(serverName: string): McpServerConfig | undefined;
76
+ /** Call an MCP tool by its model-facing callable name. Looks up the
77
+ * entry, finds its owning server, and forwards to the SDK client. */
78
+ callTool(callableName: string, args: unknown, signal?: AbortSignal): Promise<McpCallResult>;
79
+ /** Disconnect every server cleanly. Best-effort: one bad shutdown
80
+ * doesn't prevent others from running. Called from the CLI exit hook
81
+ * and (internally) by `restartAll` before rebuilding. */
82
+ shutdown(): Promise<void>;
83
+ /** Reconnect one server in-place using its current config. Used by
84
+ * `authenticateServer` (after fresh tokens are saved) and exposed for
85
+ * callers that want a per-server reload without a full refresh.
86
+ *
87
+ * Tool / resource entries from the old connection are dropped and
88
+ * replaced with whatever the new connection enumerates — tool names
89
+ * may change if the server's `tools/list` output changes between
90
+ * reconnects. Callers must invalidate the agent's systemPromptCache
91
+ * after this returns. */
92
+ restartServer(name: string, opts?: {
93
+ driveOAuth?: AuthHooks;
94
+ }): Promise<RegisteredServer>;
95
+ /** Disconnect everything and rebuild against `newConfigs` (or the
96
+ * existing configs if omitted). Returns a diff summary so the UI
97
+ * can tell the user what actually changed.
98
+ *
99
+ * Used by `/mcp refresh`: re-read the user + project config files,
100
+ * hand the merged map in here, and we'll add / remove / restart the
101
+ * appropriate set. Servers whose config bytes didn't change are
102
+ * still reconnected — fresher to the user, simpler than diffing
103
+ * every nested field. */
104
+ restartAll(newConfigs?: Map<string, McpServerConfig>): Promise<RestartSummary>;
105
+ /** Drive a fresh OAuth round-trip for one HTTP server, then reconnect
106
+ * it. Used by `/mcp auth <name>`.
107
+ *
108
+ * Pre-condition: the caller should have just cleared any stale
109
+ * tokens for this server via the token storage's `clear()` —
110
+ * otherwise an existing-but-expired token could short-circuit the
111
+ * re-auth path and reuse the bad state.
112
+ *
113
+ * Returns the post-auth server state. Throws if the server is stdio
114
+ * (no OAuth needed), if no OAuth factory is wired up, or if the
115
+ * user closes the browser tab / the callback times out. */
116
+ authenticateServer(name: string, hooks?: AuthHooks): Promise<RegisteredServer>;
117
+ /** Replace the OAuth factory wholesale. Used by the CLI when the
118
+ * token storage / onBrowserOpen wiring is built lazily after the
119
+ * registry has been constructed (rare, but the test harness needs
120
+ * to swap it). */
121
+ setOAuthFactory(factory: OAuthProviderFactory | undefined): void;
122
+ /** Drop every tool + resource owned by this server. Idempotent. */
123
+ private removeServerEntries;
124
+ /** Install a fresh ConnectResult into the maps. Caller is responsible
125
+ * for having removed any previous entries for the same server first. */
126
+ private installServer;
127
+ }
128
+ /** Empty registry — used when MCP is disabled entirely (no mcpServers
129
+ * in config, or trust dialog rejected). Cheaper than null-checking the
130
+ * registry everywhere downstream. */
131
+ export declare function emptyRegistry(): McpRegistry;
132
+ /** One server's worth of "connect + enumerate" output. Shared between
133
+ * initial boot (`loadMcpServers`) and the registry's restart paths so
134
+ * the connect-shape stays consistent. */
135
+ export interface ConnectResult {
136
+ server: RegisteredServer;
137
+ tools: ReadonlyArray<{
138
+ name: string;
139
+ description?: string;
140
+ inputSchema: Record<string, unknown>;
141
+ }>;
142
+ resources: ReadonlyArray<McpResourceEntry>;
143
+ }
144
+ /** Build a client for one server, run the connect handshake, and report
145
+ * the enumerated capabilities. `driveOAuth` (when set) opts into the
146
+ * full browser-based OAuth flow on UnauthorizedError; without it,
147
+ * UnauthorizedError surfaces as `status: needs_auth` and the user is
148
+ * expected to invoke /mcp auth explicitly. */
149
+ export declare function connectOneServer(name: string, rawConfig: McpServerConfig, oauthFactory: OAuthProviderFactory | undefined, driveOAuth?: AuthHooks): Promise<ConnectResult>;
150
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,334 @@
1
+ import { debugLog } from '../utils.js';
2
+ import { McpClient } from './client.js';
3
+ import { UnsafeEnvError, assertSafeEnv } from './env-safety.js';
4
+ import { EnvExpansionError, expandEnvDeep } from './expand-env.js';
5
+ import { buildCallableName } from './name-mangling.js';
6
+ import { isHttpConfig, isStdioConfig, } from './types.js';
7
+ export class McpRegistry {
8
+ /** callableName → entry. callableName is the model-facing
9
+ * `<server>__<tool>` form; collisions resolved at insert time. */
10
+ entries = new Map();
11
+ /** uri → entry. URIs are unique per spec; if two servers genuinely
12
+ * expose the same URI we keep the first and warn (handled by loader). */
13
+ resources = new Map();
14
+ servers = new Map();
15
+ /** Most-recently-loaded config per server. The source of truth for
16
+ * `restartServer` (which reconnects with the same config) and for
17
+ * diff'ing in `restartAll` when fresh configs are handed in. */
18
+ configs = new Map();
19
+ /** Factory for per-server OAuth providers. Optional — undefined means
20
+ * HTTP servers requiring auth will surface as `needs_auth` and the
21
+ * /mcp auth handler can't drive them. */
22
+ oauthFactory;
23
+ constructor(input) {
24
+ for (const s of input.servers)
25
+ this.servers.set(s.name, s);
26
+ for (const t of input.tools)
27
+ this.entries.set(t.callableName, t);
28
+ for (const r of input.resources)
29
+ this.resources.set(r.uri, r);
30
+ if (input.configs)
31
+ for (const [k, v] of input.configs)
32
+ this.configs.set(k, v);
33
+ this.oauthFactory = input.oauthFactory;
34
+ }
35
+ // ── Tool surface ───────────────────────────────────────────────────────
36
+ /** Snapshot of every model-facing tool name; stable iteration order.
37
+ * Consumed by `buildTools` (agent loop) and `buildSystemPrompt`. */
38
+ list() {
39
+ return [...this.entries.values()];
40
+ }
41
+ get(callableName) {
42
+ return this.entries.get(callableName);
43
+ }
44
+ // ── Resource surface ───────────────────────────────────────────────────
45
+ listResources() {
46
+ return [...this.resources.values()];
47
+ }
48
+ /** Find the server that owns a given URI so the resource tool can
49
+ * dispatch the read. Returns undefined for unknown URIs. */
50
+ resourceServer(uri) {
51
+ const r = this.resources.get(uri);
52
+ if (!r)
53
+ return undefined;
54
+ return this.servers.get(r.serverName)?.client;
55
+ }
56
+ // ── Server surface (for /mcp list / status) ───────────────────────────
57
+ serverStatus() {
58
+ return [...this.servers.values()].map((s) => ({
59
+ name: s.name,
60
+ status: s.status,
61
+ stderrTail: s.stderrTail,
62
+ }));
63
+ }
64
+ getServer(serverName) {
65
+ return this.servers.get(serverName);
66
+ }
67
+ getConfig(serverName) {
68
+ return this.configs.get(serverName);
69
+ }
70
+ // ── Dispatch ───────────────────────────────────────────────────────────
71
+ /** Call an MCP tool by its model-facing callable name. Looks up the
72
+ * entry, finds its owning server, and forwards to the SDK client. */
73
+ async callTool(callableName, args, signal) {
74
+ const entry = this.entries.get(callableName);
75
+ if (!entry)
76
+ throw new Error(`MCP tool not found: ${callableName}`);
77
+ const server = this.servers.get(entry.serverName);
78
+ if (!server)
79
+ throw new Error(`MCP server gone: ${entry.serverName}`);
80
+ return server.client.callTool(entry.rawName, args, signal);
81
+ }
82
+ // ── Lifecycle ──────────────────────────────────────────────────────────
83
+ /** Disconnect every server cleanly. Best-effort: one bad shutdown
84
+ * doesn't prevent others from running. Called from the CLI exit hook
85
+ * and (internally) by `restartAll` before rebuilding. */
86
+ async shutdown() {
87
+ const tasks = [];
88
+ for (const s of this.servers.values()) {
89
+ tasks.push(s.client.close().catch(() => {
90
+ // already logged in client.safeClose; nothing useful to do here
91
+ }));
92
+ }
93
+ await Promise.allSettled(tasks);
94
+ }
95
+ // ── Restart / refresh ──────────────────────────────────────────────────
96
+ /** Reconnect one server in-place using its current config. Used by
97
+ * `authenticateServer` (after fresh tokens are saved) and exposed for
98
+ * callers that want a per-server reload without a full refresh.
99
+ *
100
+ * Tool / resource entries from the old connection are dropped and
101
+ * replaced with whatever the new connection enumerates — tool names
102
+ * may change if the server's `tools/list` output changes between
103
+ * reconnects. Callers must invalidate the agent's systemPromptCache
104
+ * after this returns. */
105
+ async restartServer(name, opts = {}) {
106
+ const config = this.configs.get(name);
107
+ if (!config) {
108
+ throw new Error(`No MCP server registered as "${name}"`);
109
+ }
110
+ // Close the existing client (if any) before spawning a replacement —
111
+ // for stdio servers this kills the previous child process so we
112
+ // don't leave a zombie behind. Errors are non-fatal: a broken
113
+ // connection that can't be closed cleanly should still be replaced.
114
+ const existing = this.servers.get(name);
115
+ if (existing) {
116
+ try {
117
+ await existing.client.close();
118
+ }
119
+ catch (err) {
120
+ debugLog('mcp.restart-close-failed', `${name}: ${String(err)}`);
121
+ }
122
+ }
123
+ // Strip old tools / resources owned by this server. Done *before*
124
+ // the new connect so a partial failure mid-reconnect leaves us in a
125
+ // consistent "nothing from this server" state rather than a mix of
126
+ // old + nothing.
127
+ this.removeServerEntries(name);
128
+ const result = await connectOneServer(name, config, this.oauthFactory, opts.driveOAuth);
129
+ this.installServer(result);
130
+ return result.server;
131
+ }
132
+ /** Disconnect everything and rebuild against `newConfigs` (or the
133
+ * existing configs if omitted). Returns a diff summary so the UI
134
+ * can tell the user what actually changed.
135
+ *
136
+ * Used by `/mcp refresh`: re-read the user + project config files,
137
+ * hand the merged map in here, and we'll add / remove / restart the
138
+ * appropriate set. Servers whose config bytes didn't change are
139
+ * still reconnected — fresher to the user, simpler than diffing
140
+ * every nested field. */
141
+ async restartAll(newConfigs) {
142
+ const oldNames = new Set(this.configs.keys());
143
+ const newNames = new Set((newConfigs ?? this.configs).keys());
144
+ const summary = {
145
+ added: [...newNames].filter((n) => !oldNames.has(n)),
146
+ removed: [...oldNames].filter((n) => !newNames.has(n)),
147
+ changed: [],
148
+ unchanged: [],
149
+ };
150
+ if (newConfigs) {
151
+ for (const name of newNames) {
152
+ if (!oldNames.has(name))
153
+ continue;
154
+ const before = JSON.stringify(this.configs.get(name));
155
+ const after = JSON.stringify(newConfigs.get(name));
156
+ if (before !== after)
157
+ summary.changed.push(name);
158
+ else
159
+ summary.unchanged.push(name);
160
+ }
161
+ }
162
+ else {
163
+ summary.unchanged = [...newNames];
164
+ }
165
+ // Tear down everything first. Doing close-all then connect-all
166
+ // (rather than per-server close+connect) is more predictable: we
167
+ // never have two clients for the same server alive at once, and
168
+ // stdio child processes definitely exit before their replacements
169
+ // spawn.
170
+ await this.shutdown();
171
+ // Reset internal state. We keep the OAuth factory because that
172
+ // came from the CLI process and isn't tied to any one config.
173
+ this.servers.clear();
174
+ this.entries.clear();
175
+ this.resources.clear();
176
+ this.configs.clear();
177
+ const effective = newConfigs ?? new Map();
178
+ for (const [k, v] of effective)
179
+ this.configs.set(k, v);
180
+ // Reconnect in parallel — same approach as initial boot. Each
181
+ // failure is recorded as `status: failed` rather than aborting the
182
+ // restart.
183
+ const tasks = [...effective.entries()].map(async ([name, config]) => {
184
+ try {
185
+ return await connectOneServer(name, config, this.oauthFactory);
186
+ }
187
+ catch (err) {
188
+ debugLog('mcp.restartAll-connect-failed', `${name}: ${String(err)}`);
189
+ return null;
190
+ }
191
+ });
192
+ const results = await Promise.all(tasks);
193
+ // Sort by name so tool insertion order is stable (matches initial-
194
+ // boot behaviour in loader.ts).
195
+ const installable = results
196
+ .filter((r) => r !== null)
197
+ .sort((a, b) => a.server.name.localeCompare(b.server.name));
198
+ for (const r of installable)
199
+ this.installServer(r);
200
+ return summary;
201
+ }
202
+ /** Drive a fresh OAuth round-trip for one HTTP server, then reconnect
203
+ * it. Used by `/mcp auth <name>`.
204
+ *
205
+ * Pre-condition: the caller should have just cleared any stale
206
+ * tokens for this server via the token storage's `clear()` —
207
+ * otherwise an existing-but-expired token could short-circuit the
208
+ * re-auth path and reuse the bad state.
209
+ *
210
+ * Returns the post-auth server state. Throws if the server is stdio
211
+ * (no OAuth needed), if no OAuth factory is wired up, or if the
212
+ * user closes the browser tab / the callback times out. */
213
+ async authenticateServer(name, hooks = {}) {
214
+ const config = this.configs.get(name);
215
+ if (!config)
216
+ throw new Error(`No MCP server registered as "${name}"`);
217
+ if (!isHttpConfig(config)) {
218
+ throw new Error(`MCP server "${name}" is stdio — OAuth applies to HTTP servers only`);
219
+ }
220
+ if (!this.oauthFactory) {
221
+ throw new Error(`OAuth not configured — set a token storage in the loader to use /mcp auth`);
222
+ }
223
+ return this.restartServer(name, { driveOAuth: hooks });
224
+ }
225
+ /** Replace the OAuth factory wholesale. Used by the CLI when the
226
+ * token storage / onBrowserOpen wiring is built lazily after the
227
+ * registry has been constructed (rare, but the test harness needs
228
+ * to swap it). */
229
+ setOAuthFactory(factory) {
230
+ this.oauthFactory = factory;
231
+ }
232
+ // ── internals ──────────────────────────────────────────────────────────
233
+ /** Drop every tool + resource owned by this server. Idempotent. */
234
+ removeServerEntries(name) {
235
+ for (const [key, entry] of this.entries) {
236
+ if (entry.serverName === name)
237
+ this.entries.delete(key);
238
+ }
239
+ for (const [key, res] of this.resources) {
240
+ if (res.serverName === name)
241
+ this.resources.delete(key);
242
+ }
243
+ }
244
+ /** Install a fresh ConnectResult into the maps. Caller is responsible
245
+ * for having removed any previous entries for the same server first. */
246
+ installServer(r) {
247
+ this.servers.set(r.server.name, r.server);
248
+ const taken = new Set(this.entries.keys());
249
+ for (const t of r.tools) {
250
+ const callable = buildCallableName(r.server.name, t.name, taken);
251
+ taken.add(callable);
252
+ this.entries.set(callable, {
253
+ callableName: callable,
254
+ rawName: t.name,
255
+ serverName: r.server.name,
256
+ description: t.description ?? '',
257
+ inputSchema: t.inputSchema,
258
+ });
259
+ }
260
+ for (const res of r.resources)
261
+ this.resources.set(res.uri, res);
262
+ }
263
+ }
264
+ /** Empty registry — used when MCP is disabled entirely (no mcpServers
265
+ * in config, or trust dialog rejected). Cheaper than null-checking the
266
+ * registry everywhere downstream. */
267
+ export function emptyRegistry() {
268
+ return new McpRegistry({ servers: [], tools: [], resources: [] });
269
+ }
270
+ /** Build a client for one server, run the connect handshake, and report
271
+ * the enumerated capabilities. `driveOAuth` (when set) opts into the
272
+ * full browser-based OAuth flow on UnauthorizedError; without it,
273
+ * UnauthorizedError surfaces as `status: needs_auth` and the user is
274
+ * expected to invoke /mcp auth explicitly. */
275
+ export async function connectOneServer(name, rawConfig, oauthFactory, driveOAuth) {
276
+ // Honour `enabled: false` — register but skip the connection.
277
+ if (rawConfig.enabled === false) {
278
+ const client = new McpClient(name, rawConfig);
279
+ return {
280
+ server: { name, client, status: { kind: 'disabled' } },
281
+ tools: [],
282
+ resources: [],
283
+ };
284
+ }
285
+ // Expand ${VAR} references before constructing the client. Then enforce
286
+ // the env safety check on stdio configs — this is the single chokepoint
287
+ // every env source (CLI flag, mcp.json, plugin manifest) flows through,
288
+ // so rejecting a bad key here covers them all. See env-safety.ts for the
289
+ // threat model.
290
+ let expanded;
291
+ try {
292
+ expanded = expandEnvDeep(rawConfig);
293
+ if (isStdioConfig(expanded))
294
+ assertSafeEnv(expanded.env);
295
+ }
296
+ catch (err) {
297
+ const msg = err instanceof EnvExpansionError || err instanceof UnsafeEnvError
298
+ ? err.message
299
+ : err instanceof Error
300
+ ? err.message
301
+ : String(err);
302
+ const client = new McpClient(name, rawConfig);
303
+ return {
304
+ server: { name, client, status: { kind: 'failed', error: msg } },
305
+ tools: [],
306
+ resources: [],
307
+ };
308
+ }
309
+ const authProvider = oauthFactory && isHttpConfig(expanded) ? oauthFactory(name, expanded.url) : undefined;
310
+ const client = new McpClient(name, expanded, authProvider);
311
+ try {
312
+ const info = driveOAuth ? await client.connectWithOAuth(driveOAuth) : await client.connect();
313
+ return {
314
+ server: {
315
+ name,
316
+ client,
317
+ status: { kind: 'connected', toolCount: info.toolCount, resourceCount: info.resourceCount },
318
+ },
319
+ tools: client.tools(),
320
+ resources: client.resources(),
321
+ };
322
+ }
323
+ catch (err) {
324
+ const msg = err instanceof Error ? err.message : String(err);
325
+ const needsAuth = /unauth|401|UnauthorizedError/i.test(msg) && isHttpConfig(expanded);
326
+ const status = needsAuth ? { kind: 'needs_auth' } : { kind: 'failed', error: msg };
327
+ return {
328
+ server: { name, client, status, stderrTail: client.stderr() || undefined },
329
+ tools: [],
330
+ resources: [],
331
+ };
332
+ }
333
+ }
334
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/mcp/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare const listMcpResources: import("ai").Tool<{
2
+ server?: string | undefined;
3
+ }, never>;
4
+ export declare const readMcpResource: import("ai").Tool<{
5
+ uri: string;
6
+ }, never>;
7
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../src/mcp/resources.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,gBAAgB;;SAa3B,CAAA;AAEF,eAAO,MAAM,eAAe;;SAO1B,CAAA"}
@@ -0,0 +1,40 @@
1
+ // @x-code-cli/core — MCP Resources surfaced as two built-in tools
2
+ //
3
+ // MCP "resources" are server-exposed data the model may want to pull
4
+ // (e.g. files exposed by filesystem-server, log entries, DB row dumps).
5
+ // Rather than auto-injecting every resource into the conversation
6
+ // (token-expensive, often irrelevant), we expose two tools:
7
+ //
8
+ // - listMcpResources({ server? }) — enumerate URIs the model can fetch
9
+ // - readMcpResource({ uri }) — fetch one by URI
10
+ //
11
+ // Both tools are defined without an `execute` function so the agent
12
+ // loop's processToolCalls dispatcher handles them — see
13
+ // BYPASS_LOOP_GUARD_HANDLERS in tool-execution.ts. They surface in the
14
+ // system prompt only when an MCP registry is configured (buildTools
15
+ // gates the inclusion).
16
+ import { tool } from 'ai';
17
+ import { z } from 'zod';
18
+ export const listMcpResources = tool({
19
+ description: `List resources exposed by connected MCP servers.
20
+
21
+ Output one resource per line: "<uri>\t[<server>] <name> (<mimeType>)" with a description on the next indented line when present.
22
+
23
+ Use this BEFORE readMcpResource so you have a URI to read. If the model already knows the URI (e.g. from a previous list call), readMcpResource directly is fine.`,
24
+ inputSchema: z.object({
25
+ server: z
26
+ .string()
27
+ .optional()
28
+ .describe('Optional server name to filter by. Omit to list resources from all servers.'),
29
+ }),
30
+ // No execute — handled in tool-execution.ts via BYPASS_LOOP_GUARD_HANDLERS.
31
+ });
32
+ export const readMcpResource = tool({
33
+ description: `Read the contents of an MCP resource by its URI.
34
+
35
+ URIs come from listMcpResources. Text resources return their text directly; binary resources surface a one-line marker noting the omitted content.`,
36
+ inputSchema: z.object({
37
+ uri: z.string().describe('The resource URI to read, as returned by listMcpResources.'),
38
+ }),
39
+ });
40
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../../src/mcp/resources.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,kEAAkE;AAClE,4DAA4D;AAC5D,EAAE;AACF,0EAA0E;AAC1E,wDAAwD;AACxD,EAAE;AACF,oEAAoE;AACpE,wDAAwD;AACxD,uEAAuE;AACvE,oEAAoE;AACpE,wBAAwB;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAEzB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;IACnC,WAAW,EAAE;;;;kKAImJ;IAChK,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,6EAA6E,CAAC;KAC3F,CAAC;IACF,4EAA4E;CAC7E,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;IAClC,WAAW,EAAE;;mJAEoI;IACjJ,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;KACvF,CAAC;CACH,CAAC,CAAA"}
@@ -0,0 +1,16 @@
1
+ import type { McpToolEntry } from './types.js';
2
+ export declare function truncateDescription(input: string): string;
3
+ /** Adapt one MCP tool into an AI SDK Tool. No execute — we hand-dispatch
4
+ * in tool-execution. The schema is passed through as raw JSON Schema
5
+ * (the SDK has first-class support via `jsonSchema(...)` so we don't
6
+ * need a zod conversion step). */
7
+ export declare function bridgeMcpTool(entry: McpToolEntry): import("ai").Tool<unknown, never>;
8
+ /** Build the system-prompt-friendly view of every MCP tool — short
9
+ * description + the model-facing name. Used by `system-prompt.ts` to
10
+ * render the `## MCP Tools` section. */
11
+ export declare function toSystemPromptEntries(entries: readonly McpToolEntry[]): {
12
+ callableName: string;
13
+ serverName: string;
14
+ description: string;
15
+ }[];
16
+ //# sourceMappingURL=tool-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-bridge.d.ts","sourceRoot":"","sources":["../../src/mcp/tool-bridge.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAY9C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED;;;mCAGmC;AACnC,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,qCAWhD;AAED;;yCAEyC;AACzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE;;;;IAMrE"}
@@ -0,0 +1,56 @@
1
+ // @x-code-cli/core — MCP tool ↔ AI SDK adapter
2
+ //
3
+ // Two responsibilities:
4
+ // 1. Convert each McpToolEntry into an AI-SDK `tool({...})` definition
5
+ // so streamText() advertises it to the model alongside built-ins.
6
+ // 2. Trim overlong server-supplied descriptions so they don't bloat
7
+ // the system prompt / tool list.
8
+ //
9
+ // The tools are deliberately defined WITHOUT an `execute` function. The
10
+ // AI SDK then routes the model's tool_call into `result.toolCalls` and
11
+ // our `processToolCalls` dispatcher handles it manually — same path as
12
+ // shell / writeFile / edit. This is what lets us gate every MCP call
13
+ // through the permission + loop-guard machinery.
14
+ import { jsonSchema, tool } from 'ai';
15
+ /** Hard cap on the model-facing description length per tool.
16
+ * - 200 chars is plenty for "what does this tool do?" guidance.
17
+ * - Some MCP servers in the wild paste multi-paragraph docs into the
18
+ * description field; left unbounded these blow up the system prompt
19
+ * and chew through the prompt cache window.
20
+ * - Truncation is character-based, with an ellipsis marker so the model
21
+ * knows the string was clipped (the marker also doubles as a hint
22
+ * to server authors when they see their own description in /mcp tools). */
23
+ const DESCRIPTION_MAX_CHARS = 200;
24
+ export function truncateDescription(input) {
25
+ if (input.length <= DESCRIPTION_MAX_CHARS)
26
+ return input;
27
+ // Keep room for the ellipsis marker so the result is still <= cap.
28
+ return input.slice(0, DESCRIPTION_MAX_CHARS - 1) + '…';
29
+ }
30
+ /** Adapt one MCP tool into an AI SDK Tool. No execute — we hand-dispatch
31
+ * in tool-execution. The schema is passed through as raw JSON Schema
32
+ * (the SDK has first-class support via `jsonSchema(...)` so we don't
33
+ * need a zod conversion step). */
34
+ export function bridgeMcpTool(entry) {
35
+ return tool({
36
+ description: truncateDescription(entry.description || `MCP tool from ${entry.serverName}`),
37
+ // The SDK's jsonSchema() helper takes a JSON Schema object and
38
+ // produces a Schema instance compatible with `tool()`. MCP servers
39
+ // hand us back well-formed JSON Schema by spec, so no preprocessing.
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ inputSchema: jsonSchema(entry.inputSchema),
42
+ // No execute — manual dispatch in tool-execution.ts gates the call
43
+ // through permissions + loop-guard.
44
+ });
45
+ }
46
+ /** Build the system-prompt-friendly view of every MCP tool — short
47
+ * description + the model-facing name. Used by `system-prompt.ts` to
48
+ * render the `## MCP Tools` section. */
49
+ export function toSystemPromptEntries(entries) {
50
+ return entries.map((e) => ({
51
+ callableName: e.callableName,
52
+ serverName: e.serverName,
53
+ description: truncateDescription(e.description),
54
+ }));
55
+ }
56
+ //# sourceMappingURL=tool-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-bridge.js","sourceRoot":"","sources":["../../src/mcp/tool-bridge.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,EAAE;AACF,wBAAwB;AACxB,yEAAyE;AACzE,uEAAuE;AACvE,sEAAsE;AACtE,sCAAsC;AACtC,EAAE;AACF,wEAAwE;AACxE,uEAAuE;AACvE,uEAAuE;AACvE,qEAAqE;AACrE,iDAAiD;AACjD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,IAAI,CAAA;AAIrC;;;;;;;8EAO8E;AAC9E,MAAM,qBAAqB,GAAG,GAAG,CAAA;AAEjC,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,IAAI,KAAK,CAAC,MAAM,IAAI,qBAAqB;QAAE,OAAO,KAAK,CAAA;IACvD,mEAAmE;IACnE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,GAAG,CAAC,CAAC,GAAG,GAAG,CAAA;AACxD,CAAC;AAED;;;mCAGmC;AACnC,MAAM,UAAU,aAAa,CAAC,KAAmB;IAC/C,OAAO,IAAI,CAAC;QACV,WAAW,EAAE,mBAAmB,CAAC,KAAK,CAAC,WAAW,IAAI,iBAAiB,KAAK,CAAC,UAAU,EAAE,CAAC;QAC1F,+DAA+D;QAC/D,mEAAmE;QACnE,qEAAqE;QACrE,8DAA8D;QAC9D,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC,WAAkB,CAAC;QACjD,mEAAmE;QACnE,oCAAoC;KACrC,CAAC,CAAA;AACJ,CAAC;AAED;;yCAEyC;AACzC,MAAM,UAAU,qBAAqB,CAAC,OAAgC;IACpE,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzB,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,UAAU,EAAE,CAAC,CAAC,UAAU;QACxB,WAAW,EAAE,mBAAmB,CAAC,CAAC,CAAC,WAAW,CAAC;KAChD,CAAC,CAAC,CAAA;AACL,CAAC"}