@lamplitisles/dsh-nanocodex 0.1.0-beta.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 (276) hide show
  1. package/LICENSE +65 -0
  2. package/NOTICE +2 -0
  3. package/README.md +182 -0
  4. package/THIRD_PARTY_NOTICES.md +29 -0
  5. package/cordis.patch.yml +52 -0
  6. package/dist/index.d.ts +435 -0
  7. package/dist/index.js +3405 -0
  8. package/dist/standard-preset.d.ts +7 -0
  9. package/dist/standard-preset.js +25 -0
  10. package/engine-release.json +14 -0
  11. package/package.json +119 -0
  12. package/presets/standard/agent.cordis.yml +6 -0
  13. package/presets/standard/preset.yml +2 -0
  14. package/vendor/nanocodex/README.md +1344 -0
  15. package/vendor/nanocodex/actions/events.d.mts +10 -0
  16. package/vendor/nanocodex/actions/events.mjs +163 -0
  17. package/vendor/nanocodex/actions/index.d.mts +13 -0
  18. package/vendor/nanocodex/actions/index.mjs +35 -0
  19. package/vendor/nanocodex/actions/session.d.mts +66 -0
  20. package/vendor/nanocodex/actions/session.mjs +59 -0
  21. package/vendor/nanocodex/actions/turn.d.mts +59 -0
  22. package/vendor/nanocodex/actions/turn.mjs +37 -0
  23. package/vendor/nanocodex/actions/voice.d.mts +22 -0
  24. package/vendor/nanocodex/actions/voice.mjs +50 -0
  25. package/vendor/nanocodex/browser/Agent.d.mts +55 -0
  26. package/vendor/nanocodex/browser/Agent.mjs +11 -0
  27. package/vendor/nanocodex/browser/ChatGptSubscription.d.mts +7 -0
  28. package/vendor/nanocodex/browser/ChatGptSubscription.mjs +19 -0
  29. package/vendor/nanocodex/browser/InlineAgent.mjs +266 -0
  30. package/vendor/nanocodex/browser/Transport.d.mts +74 -0
  31. package/vendor/nanocodex/browser/Transport.mjs +61 -0
  32. package/vendor/nanocodex/browser/Voice.d.mts +71 -0
  33. package/vendor/nanocodex/browser/Voice.mjs +291 -0
  34. package/vendor/nanocodex/browser/VoiceSession.mjs +688 -0
  35. package/vendor/nanocodex/browser/WorkerAgent.d.mts +65 -0
  36. package/vendor/nanocodex/browser/WorkerAgent.mjs +1472 -0
  37. package/vendor/nanocodex/browser/agent.worker.mjs +3 -0
  38. package/vendor/nanocodex/browser/config.d.mts +36 -0
  39. package/vendor/nanocodex/browser/config.mjs +439 -0
  40. package/vendor/nanocodex/browser/engine.mjs +13 -0
  41. package/vendor/nanocodex/browser/harness.mjs +55 -0
  42. package/vendor/nanocodex/browser/host.d.mts +83 -0
  43. package/vendor/nanocodex/browser/host.mjs +555 -0
  44. package/vendor/nanocodex/browser/hostManagedWebSocket.d.mts +14 -0
  45. package/vendor/nanocodex/browser/hostManagedWebSocket.mjs +110 -0
  46. package/vendor/nanocodex/browser/index.d.mts +92 -0
  47. package/vendor/nanocodex/browser/index.mjs +23 -0
  48. package/vendor/nanocodex/browser/indexeddb-durability-store.mjs +197 -0
  49. package/vendor/nanocodex/browser/workspace.d.mts +16 -0
  50. package/vendor/nanocodex/browser/workspace.mjs +107 -0
  51. package/vendor/nanocodex/cloud/Client.d.mts +83 -0
  52. package/vendor/nanocodex/cloud/Client.mjs +231 -0
  53. package/vendor/nanocodex/cloud/Decorator.d.mts +31 -0
  54. package/vendor/nanocodex/cloud/Decorator.mjs +37 -0
  55. package/vendor/nanocodex/cloud/Dialog.d.mts +113 -0
  56. package/vendor/nanocodex/cloud/Dialog.mjs +366 -0
  57. package/vendor/nanocodex/cloud/Errors.d.mts +22 -0
  58. package/vendor/nanocodex/cloud/Errors.mjs +39 -0
  59. package/vendor/nanocodex/cloud/Principal.d.mts +26 -0
  60. package/vendor/nanocodex/cloud/Principal.mjs +88 -0
  61. package/vendor/nanocodex/cloud/RemoteProvider.mjs +88 -0
  62. package/vendor/nanocodex/cloud/Transport.d.mts +47 -0
  63. package/vendor/nanocodex/cloud/Transport.mjs +454 -0
  64. package/vendor/nanocodex/cloud/actions/account.d.mts +9 -0
  65. package/vendor/nanocodex/cloud/actions/account.mjs +19 -0
  66. package/vendor/nanocodex/cloud/actions/agent.d.mts +18 -0
  67. package/vendor/nanocodex/cloud/actions/agent.mjs +428 -0
  68. package/vendor/nanocodex/cloud/actions/connection.d.mts +133 -0
  69. package/vendor/nanocodex/cloud/actions/connection.mjs +580 -0
  70. package/vendor/nanocodex/cloud/actions/grant.d.mts +10 -0
  71. package/vendor/nanocodex/cloud/actions/grant.mjs +12 -0
  72. package/vendor/nanocodex/cloud/actions/index.d.mts +7 -0
  73. package/vendor/nanocodex/cloud/actions/index.mjs +7 -0
  74. package/vendor/nanocodex/cloud/actions/machineUsd.d.mts +23 -0
  75. package/vendor/nanocodex/cloud/actions/machineUsd.mjs +37 -0
  76. package/vendor/nanocodex/cloud/actions/model.d.mts +12 -0
  77. package/vendor/nanocodex/cloud/actions/model.mjs +50 -0
  78. package/vendor/nanocodex/cloud/actions/mpp.d.mts +28 -0
  79. package/vendor/nanocodex/cloud/actions/mpp.mjs +39 -0
  80. package/vendor/nanocodex/cloud/index.d.mts +30 -0
  81. package/vendor/nanocodex/cloud/index.mjs +9 -0
  82. package/vendor/nanocodex/cloud/internal.mjs +533 -0
  83. package/vendor/nanocodex/cloud/mercator.mjs +108 -0
  84. package/vendor/nanocodex/cloud/server/HostPrincipal.d.mts +34 -0
  85. package/vendor/nanocodex/cloud/server/HostPrincipal.mjs +202 -0
  86. package/vendor/nanocodex/cloud/server/index.d.mts +1 -0
  87. package/vendor/nanocodex/cloud/server/index.mjs +1 -0
  88. package/vendor/nanocodex/cloud/types.d.mts +211 -0
  89. package/vendor/nanocodex/cloudflare/Agent.d.mts +133 -0
  90. package/vendor/nanocodex/cloudflare/Agent.mjs +811 -0
  91. package/vendor/nanocodex/cloudflare/egress-subject.mjs +19 -0
  92. package/vendor/nanocodex/cloudflare/egress.d.mts +41 -0
  93. package/vendor/nanocodex/cloudflare/egress.mjs +119 -0
  94. package/vendor/nanocodex/cloudflare/event-socket.mjs +316 -0
  95. package/vendor/nanocodex/cloudflare/index.d.mts +7 -0
  96. package/vendor/nanocodex/cloudflare/index.mjs +6 -0
  97. package/vendor/nanocodex/host/Agent.d.mts +55 -0
  98. package/vendor/nanocodex/host/Agent.mjs +1 -0
  99. package/vendor/nanocodex/host/index.d.mts +82 -0
  100. package/vendor/nanocodex/host/index.mjs +10 -0
  101. package/vendor/nanocodex/index.d.mts +81 -0
  102. package/vendor/nanocodex/index.mjs +12 -0
  103. package/vendor/nanocodex/internal.mjs +1275 -0
  104. package/vendor/nanocodex/managed/Agent.d.mts +380 -0
  105. package/vendor/nanocodex/managed/Agent.mjs +1694 -0
  106. package/vendor/nanocodex/managed/ManagedError.d.mts +9 -0
  107. package/vendor/nanocodex/managed/ManagedError.mjs +8 -0
  108. package/vendor/nanocodex/managed/README.md +241 -0
  109. package/vendor/nanocodex/managed/Voice.mjs +202 -0
  110. package/vendor/nanocodex/managed/index.d.mts +20 -0
  111. package/vendor/nanocodex/managed/index.mjs +2 -0
  112. package/vendor/nanocodex/managed/internal.mjs +119 -0
  113. package/vendor/nanocodex/node/Agent.d.mts +50 -0
  114. package/vendor/nanocodex/node/Agent.mjs +203 -0
  115. package/vendor/nanocodex/node/ChatGptSubscription.d.mts +9 -0
  116. package/vendor/nanocodex/node/ChatGptSubscription.mjs +17 -0
  117. package/vendor/nanocodex/node/Transport.d.mts +44 -0
  118. package/vendor/nanocodex/node/Transport.mjs +46 -0
  119. package/vendor/nanocodex/node/host.mjs +731 -0
  120. package/vendor/nanocodex/node/index.d.mts +73 -0
  121. package/vendor/nanocodex/node/index.mjs +17 -0
  122. package/vendor/nanocodex/node/workspace.d.mts +10 -0
  123. package/vendor/nanocodex/node/workspace.mjs +198 -0
  124. package/vendor/nanocodex/package.json +200 -0
  125. package/vendor/nanocodex/pkg-node/nanocodex.d.ts +675 -0
  126. package/vendor/nanocodex/pkg-node/nanocodex.js +2628 -0
  127. package/vendor/nanocodex/pkg-node/nanocodex_bg.wasm.d.ts +105 -0
  128. package/vendor/nanocodex/pkg-node/package.json +1 -0
  129. package/vendor/nanocodex/pkg-web/.nanocodex-bindgen-stamp +6 -0
  130. package/vendor/nanocodex/pkg-web/nanocodex-build.json +1 -0
  131. package/vendor/nanocodex/pkg-web/nanocodex.d.ts +805 -0
  132. package/vendor/nanocodex/pkg-web/nanocodex.js +2714 -0
  133. package/vendor/nanocodex/pkg-web/nanocodex_bg.js +2615 -0
  134. package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm +0 -0
  135. package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm.d.ts +105 -0
  136. package/vendor/nanocodex/pkg-web/nanocodex_worker.js +9 -0
  137. package/vendor/nanocodex/pkg-web/package.json +1 -0
  138. package/vendor/nanocodex/runtime/chatgpt-subscription.mjs +212 -0
  139. package/vendor/nanocodex/runtime/cloudflare-durability-store.d.mts +26 -0
  140. package/vendor/nanocodex/runtime/cloudflare-durability-store.mjs +168 -0
  141. package/vendor/nanocodex/runtime/code-evaluator.worker.mjs +137 -0
  142. package/vendor/nanocodex/runtime/code-runtime.mjs +1 -0
  143. package/vendor/nanocodex/runtime/durability-store.d.mts +85 -0
  144. package/vendor/nanocodex/runtime/durability-store.mjs +631 -0
  145. package/vendor/nanocodex/runtime/durability.mjs +153 -0
  146. package/vendor/nanocodex/runtime/managed-transport.mjs +460 -0
  147. package/vendor/nanocodex/runtime/mcp-runtime.mjs +534 -0
  148. package/vendor/nanocodex/runtime/postgres-durability-store.d.mts +64 -0
  149. package/vendor/nanocodex/runtime/postgres-durability-store.mjs +532 -0
  150. package/vendor/nanocodex/runtime/quickjs-evaluator.d.mts +17 -0
  151. package/vendor/nanocodex/runtime/quickjs-evaluator.mjs +236 -0
  152. package/vendor/nanocodex/runtime/responses-transport.mjs +22 -0
  153. package/vendor/nanocodex/runtime/subagents.d.mts +107 -0
  154. package/vendor/nanocodex/runtime/subagents.mjs +54 -0
  155. package/vendor/nanocodex/runtime/subscription-store.d.mts +8 -0
  156. package/vendor/nanocodex/runtime/subscription-store.mjs +42 -0
  157. package/vendor/nanocodex/runtime/tempo-provider.d.mts +125 -0
  158. package/vendor/nanocodex/runtime/tempo-provider.mjs +264 -0
  159. package/vendor/nanocodex/runtime/tool-configuration.mjs +1 -0
  160. package/vendor/nanocodex/runtime/tool-router.mjs +1 -0
  161. package/vendor/nanocodex/runtime/utf8.mjs +1 -0
  162. package/vendor/nanocodex/runtime/worker-evaluator.mjs +162 -0
  163. package/vendor/nanocodex/runtime/workspace.d.mts +1 -0
  164. package/vendor/nanocodex/runtime/workspace.mjs +1 -0
  165. package/vendor/nanocodex/tools/Tools.d.mts +56 -0
  166. package/vendor/nanocodex/tools/Tools.mjs +136 -0
  167. package/vendor/nanocodex/tools/artifact.d.mts +1 -0
  168. package/vendor/nanocodex/tools/artifact.mjs +1 -0
  169. package/vendor/nanocodex/tools/attachment.mjs +1 -0
  170. package/vendor/nanocodex/tools/bash.d.mts +1 -0
  171. package/vendor/nanocodex/tools/bash.mjs +1 -0
  172. package/vendor/nanocodex/tools/browser/accountInfo.mjs +795 -0
  173. package/vendor/nanocodex/tools/browser/browserBuffer.mjs +18 -0
  174. package/vendor/nanocodex/tools/browser/browserCompiler.mjs +155 -0
  175. package/vendor/nanocodex/tools/browser/browserEgress.mjs +161 -0
  176. package/vendor/nanocodex/tools/browser/browserPython.mjs +133 -0
  177. package/vendor/nanocodex/tools/browser/browserShell.mjs +1075 -0
  178. package/vendor/nanocodex/tools/browser/browserSprintf.mjs +4 -0
  179. package/vendor/nanocodex/tools/browser/browserSsh.mjs +201 -0
  180. package/vendor/nanocodex/tools/browser/browserZlib.mjs +136 -0
  181. package/vendor/nanocodex/tools/browser/compiler.worker.mjs +160 -0
  182. package/vendor/nanocodex/tools/browser/devTunnelsSshBrowser.mjs +13 -0
  183. package/vendor/nanocodex/tools/browser/index.d.mts +209 -0
  184. package/vendor/nanocodex/tools/browser/index.mjs +174 -0
  185. package/vendor/nanocodex/tools/browser/opfsGit.mjs +248 -0
  186. package/vendor/nanocodex/tools/browser/python.worker.mjs +114 -0
  187. package/vendor/nanocodex/tools/browser/threadGit.mjs +197 -0
  188. package/vendor/nanocodex/tools/browser/unsupportedNodeRsa.mjs +5 -0
  189. package/vendor/nanocodex/tools/browser/workspace.mjs +83 -0
  190. package/vendor/nanocodex/tools/dataset.d.mts +1 -0
  191. package/vendor/nanocodex/tools/dataset.mjs +1 -0
  192. package/vendor/nanocodex/tools/datasetContract.mjs +1 -0
  193. package/vendor/nanocodex/tools/datasetEngine.mjs +1 -0
  194. package/vendor/nanocodex/tools/hostedCatalog.d.mts +1 -0
  195. package/vendor/nanocodex/tools/hostedCatalog.mjs +1 -0
  196. package/vendor/nanocodex/tools/index.d.mts +49 -0
  197. package/vendor/nanocodex/tools/index.mjs +19 -0
  198. package/vendor/nanocodex/tools/namedTool.mjs +1 -0
  199. package/vendor/nanocodex/tools/repository-workspace.d.mts +1 -0
  200. package/vendor/nanocodex/tools/repository-workspace.mjs +1 -0
  201. package/vendor/nanocodex/tools/ssh.d.mts +1 -0
  202. package/vendor/nanocodex/tools/ssh.mjs +1 -0
  203. package/vendor/nanocodex/tools/standard.mjs +1 -0
  204. package/vendor/nanocodex/tools/standardDescriptions.mjs +1 -0
  205. package/vendor/nanocodex/types.d.mts +663 -0
  206. package/vendor/nanocodex/wasm.d.mts +4 -0
  207. package/vendor/nanocodex/worker/ChatGptSubscription.d.mts +9 -0
  208. package/vendor/nanocodex/worker/ChatGptSubscription.mjs +29 -0
  209. package/vendor/nanocodex/worker/index.d.mts +18 -0
  210. package/vendor/nanocodex/worker/index.mjs +5 -0
  211. package/vendor/nanocodex-tools/README.md +65 -0
  212. package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.d.ts +7 -0
  213. package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.js +14 -0
  214. package/vendor/nanocodex-tools/dist/hosted/broker-core.d.ts +172 -0
  215. package/vendor/nanocodex-tools/dist/hosted/broker-core.js +1278 -0
  216. package/vendor/nanocodex-tools/dist/hosted/index.d.ts +3 -0
  217. package/vendor/nanocodex-tools/dist/hosted/index.js +3 -0
  218. package/vendor/nanocodex-tools/dist/hosted/protocol.d.ts +120 -0
  219. package/vendor/nanocodex-tools/dist/hosted/protocol.js +415 -0
  220. package/vendor/nanocodex-tools/dist/index.d.ts +19 -0
  221. package/vendor/nanocodex-tools/dist/index.js +14 -0
  222. package/vendor/nanocodex-tools/dist/memory.d.ts +204 -0
  223. package/vendor/nanocodex-tools/dist/memory.js +411 -0
  224. package/vendor/nanocodex-tools/dist/namespace.d.ts +87 -0
  225. package/vendor/nanocodex-tools/dist/namespace.js +338 -0
  226. package/vendor/nanocodex-tools/dist/repository-archive.d.ts +4 -0
  227. package/vendor/nanocodex-tools/dist/repository-archive.js +104 -0
  228. package/vendor/nanocodex-tools/dist/runtime.d.ts +30 -0
  229. package/vendor/nanocodex-tools/dist/runtime.js +37 -0
  230. package/vendor/nanocodex-tools/dist/session.d.ts +167 -0
  231. package/vendor/nanocodex-tools/dist/session.js +286 -0
  232. package/vendor/nanocodex-tools/dist/shell.d.ts +51 -0
  233. package/vendor/nanocodex-tools/dist/shell.js +553 -0
  234. package/vendor/nanocodex-tools/dist/ssh.d.ts +29 -0
  235. package/vendor/nanocodex-tools/dist/ssh.js +66 -0
  236. package/vendor/nanocodex-tools/dist/workspace.d.ts +45 -0
  237. package/vendor/nanocodex-tools/dist/workspace.js +237 -0
  238. package/vendor/nanocodex-tools/package.json +122 -0
  239. package/vendor/nanocodex-tools/runtime/code-runtime.mjs +817 -0
  240. package/vendor/nanocodex-tools/runtime/tool-configuration.mjs +50 -0
  241. package/vendor/nanocodex-tools/runtime/tool-router.mjs +730 -0
  242. package/vendor/nanocodex-tools/runtime/utf8.d.mts +2 -0
  243. package/vendor/nanocodex-tools/runtime/utf8.mjs +25 -0
  244. package/vendor/nanocodex-tools/tools/artifact.d.mts +69 -0
  245. package/vendor/nanocodex-tools/tools/artifact.mjs +270 -0
  246. package/vendor/nanocodex-tools/tools/attachment.mjs +603 -0
  247. package/vendor/nanocodex-tools/tools/bash.d.mts +90 -0
  248. package/vendor/nanocodex-tools/tools/bash.mjs +742 -0
  249. package/vendor/nanocodex-tools/tools/dataset.d.mts +9 -0
  250. package/vendor/nanocodex-tools/tools/dataset.mjs +47 -0
  251. package/vendor/nanocodex-tools/tools/datasetContract.mjs +54 -0
  252. package/vendor/nanocodex-tools/tools/datasetEngine.mjs +1167 -0
  253. package/vendor/nanocodex-tools/tools/execution-contract.d.mts +5 -0
  254. package/vendor/nanocodex-tools/tools/execution-contract.mjs +63 -0
  255. package/vendor/nanocodex-tools/tools/hostedCatalog.d.mts +20 -0
  256. package/vendor/nanocodex-tools/tools/hostedCatalog.mjs +67 -0
  257. package/vendor/nanocodex-tools/tools/hostedMachine.d.mts +10 -0
  258. package/vendor/nanocodex-tools/tools/hostedMachine.mjs +56 -0
  259. package/vendor/nanocodex-tools/tools/just-bash-browser.d.mts +1 -0
  260. package/vendor/nanocodex-tools/tools/just-bash-browser.mjs +1 -0
  261. package/vendor/nanocodex-tools/tools/namedTool.d.mts +3 -0
  262. package/vendor/nanocodex-tools/tools/namedTool.mjs +3 -0
  263. package/vendor/nanocodex-tools/tools/nodeProcess.d.mts +10 -0
  264. package/vendor/nanocodex-tools/tools/nodeProcess.mjs +314 -0
  265. package/vendor/nanocodex-tools/tools/processOutput.mjs +56 -0
  266. package/vendor/nanocodex-tools/tools/repository-workspace.d.mts +55 -0
  267. package/vendor/nanocodex-tools/tools/repository-workspace.mjs +397 -0
  268. package/vendor/nanocodex-tools/tools/ssh.d.mts +56 -0
  269. package/vendor/nanocodex-tools/tools/ssh.mjs +503 -0
  270. package/vendor/nanocodex-tools/tools/standard.mjs +458 -0
  271. package/vendor/nanocodex-tools/tools/standardDescriptions.mjs +3 -0
  272. package/vendor/nanocodex-tools/tools/types.d.mts +83 -0
  273. package/vendor/nanocodex-tools/tools/workspace.d.mts +25 -0
  274. package/vendor/nanocodex-tools/tools/workspace.mjs +282 -0
  275. package/vendor/nanocodex-tools/tools/x.d.mts +30 -0
  276. package/vendor/nanocodex-tools/tools/x.mjs +91 -0
@@ -0,0 +1,534 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
+ import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker";
4
+ import MiniSearch from "minisearch";
5
+
6
+ import { toolResult } from "./code-runtime.mjs";
7
+
8
+ const DEFAULT_SEARCH_LIMIT = 8;
9
+ const MAX_SEARCH_LIMIT = 32;
10
+ const DEFAULT_STARTUP_TIMEOUT_MS = 30_000;
11
+ const DEFAULT_TOOL_TIMEOUT_MS = 5 * 60_000;
12
+ const SEARCH_DESCRIPTION_PREFIX = "# Tool discovery\n\nSearches over deferred tool metadata with BM25 and exposes matching tools for the next model call.";
13
+
14
+ export async function createMcpRuntime(configuration, options = {}) {
15
+ const servers = normalizeServers(configuration);
16
+ if (options.catalogProvider !== undefined && typeof options.catalogProvider !== "function") {
17
+ throw new TypeError("MCP catalogProvider must be a function");
18
+ }
19
+ const jsonSchemaValidator = options.jsonSchemaValidator
20
+ ?? new CfWorkerJsonSchemaValidator();
21
+ const entries = [];
22
+ const failures = Object.create(null);
23
+ const ownedClients = [];
24
+ const pendingServers = new Set();
25
+ const initializationControllers = new Map();
26
+ const initializationTasks = new Map();
27
+ const byName = new Map();
28
+ const search = createSearchIndex(entries);
29
+ let closed = false;
30
+
31
+ function startServer(server) {
32
+ const current = initializationTasks.get(server.name);
33
+ if (current) return current;
34
+ delete failures[server.name];
35
+ pendingServers.add(server.name);
36
+ const controller = new AbortController();
37
+ initializationControllers.set(server.name, controller);
38
+ let retryWhenAvailable = false;
39
+ const task = (async () => {
40
+ try {
41
+ const { connection, tools } = await initializeServer(
42
+ server,
43
+ { ...options, jsonSchemaValidator },
44
+ controller.signal,
45
+ );
46
+ if (closed) {
47
+ if (connection.owned) await connection.client.close().catch(() => {});
48
+ return;
49
+ }
50
+ const nextEntries = tools
51
+ .filter((tool) => includesTool(server, tool.name))
52
+ .map((tool) => createEntry(
53
+ server,
54
+ connection.client,
55
+ tool,
56
+ options.catalogProvider?.(server.name),
57
+ ));
58
+ for (const entry of nextEntries) {
59
+ const existing = byName.get(entry.canonicalName);
60
+ if (existing) {
61
+ throw new Error(
62
+ `MCP tool name collision: ${existing.server.name}/${existing.remoteName} and ${entry.server.name}/${entry.remoteName} both normalize to ${entry.canonicalName}`,
63
+ );
64
+ }
65
+ }
66
+ if (connection.owned) ownedClients.push(connection.client);
67
+ for (const entry of nextEntries) {
68
+ entries.push(entry);
69
+ byName.set(entry.canonicalName, entry);
70
+ search.add({ id: entry.canonicalName, searchText: entry.searchText });
71
+ }
72
+ entries.sort((left, right) => left.canonicalName.localeCompare(right.canonicalName));
73
+ } catch (error) {
74
+ if (!closed) {
75
+ failures[server.name] = errorMessage(error);
76
+ // Dynamically authorized servers can lose access or hit a transient
77
+ // broker failure during lazy discovery. Let a later authorized turn
78
+ // start a fresh client; fixed public servers keep their established
79
+ // one-attempt failure behavior.
80
+ retryWhenAvailable = server.isAvailable !== undefined;
81
+ }
82
+ } finally {
83
+ pendingServers.delete(server.name);
84
+ initializationControllers.delete(server.name);
85
+ if (retryWhenAvailable && initializationTasks.get(server.name) === task) {
86
+ initializationTasks.delete(server.name);
87
+ }
88
+ }
89
+ })();
90
+ initializationTasks.set(server.name, task);
91
+ return task;
92
+ }
93
+
94
+ function startAvailableServers() {
95
+ if (closed) return [];
96
+ return servers
97
+ .filter((server) => isServerAvailable(server))
98
+ .map((server) => startServer(server));
99
+ }
100
+
101
+ const initialization = Promise.allSettled(startAvailableServers());
102
+ const toolSearch = {
103
+ name: "tool_search",
104
+ parallelSafe: true,
105
+ handler: ({ query, limit }) => searchTools(query, limit),
106
+ };
107
+
108
+ function searchTools(query, limit = DEFAULT_SEARCH_LIMIT) {
109
+ if (typeof query !== "string" || !query.trim()) {
110
+ throw new TypeError("tool_search query must not be empty");
111
+ }
112
+ if (!Number.isInteger(limit) || limit < 1) {
113
+ throw new TypeError("tool_search limit must be a positive integer");
114
+ }
115
+ startAvailableServers();
116
+ const availableServers = new Set(servers
117
+ .filter((server) => isServerAvailable(server))
118
+ .map((server) => server.name));
119
+ const selected = search
120
+ .search(query, { combineWith: "OR", prefix: true })
121
+ .map(({ id }) => byName.get(id))
122
+ .filter((entry) => entry && availableServers.has(entry.server.name))
123
+ .slice(0, Math.min(limit, MAX_SEARCH_LIMIT));
124
+ const result = {
125
+ tools: selected.map((entry) => ({
126
+ name: entry.canonicalName,
127
+ server: entry.server.name,
128
+ tool: entry.remoteName,
129
+ description: entry.description,
130
+ supports_parallel_tool_calls: entry.parallelSafe,
131
+ input_schema: entry.inputSchema,
132
+ })),
133
+ pending_servers: [...pendingServers]
134
+ .filter((name) => availableServers.has(name)).length,
135
+ failed_servers: Object.fromEntries(Object.entries(failures)
136
+ .filter(([name]) => availableServers.has(name))),
137
+ };
138
+ return toolResult(result, loadableNamespaces(selected));
139
+ }
140
+
141
+ return Object.freeze({
142
+ search: ({ query, limit }) => searchTools(query, limit),
143
+ definitions() {
144
+ startAvailableServers();
145
+ const availableServers = new Set(servers
146
+ .filter((server) => isServerAvailable(server))
147
+ .map((server) => server.name));
148
+ return [
149
+ toolSearchDefinition(servers.filter((server) => availableServers.has(server.name))),
150
+ ...entries
151
+ .filter((entry) => availableServers.has(entry.server.name))
152
+ .map((entry) => entry.definition),
153
+ ];
154
+ },
155
+ resolve(name) {
156
+ startAvailableServers();
157
+ if (name === "tool_search") return toolSearch;
158
+ const entry = byName.get(name);
159
+ if (!entry || !isServerAvailable(entry.server)) return undefined;
160
+ return {
161
+ name,
162
+ parallelSafe: entry.parallelSafe,
163
+ ...(entry.catalogProvider === undefined ? {} : {
164
+ provider: entry.catalogProvider,
165
+ remoteName: entry.remoteName,
166
+ }),
167
+ handler: (input, context) => callRemoteTool(entry, input, context),
168
+ };
169
+ },
170
+ settled() {
171
+ return Promise.all([initialization, Promise.allSettled(startAvailableServers())])
172
+ .then(() => undefined);
173
+ },
174
+ async close() {
175
+ closed = true;
176
+ for (const controller of initializationControllers.values()) {
177
+ controller.abort(new Error("MCP runtime closed"));
178
+ }
179
+ await Promise.allSettled(ownedClients.map((client) => client.close()));
180
+ },
181
+ });
182
+ }
183
+
184
+ async function initializeServer(server, options, outerSignal) {
185
+ const controller = new AbortController();
186
+ const abort = () => controller.abort(outerSignal?.reason);
187
+ if (outerSignal?.aborted) abort();
188
+ else outerSignal?.addEventListener("abort", abort, { once: true });
189
+ let timeout;
190
+ const deadline = new Promise((_resolve, reject) => {
191
+ timeout = setTimeout(() => {
192
+ controller.abort();
193
+ reject(new Error("MCP startup deadline exceeded"));
194
+ }, server.startupTimeoutMs);
195
+ });
196
+ let rejectCancellation;
197
+ const cancellation = new Promise((_resolve, reject) => {
198
+ rejectCancellation = () => reject(
199
+ controller.signal.reason ?? new Error("MCP startup was cancelled"),
200
+ );
201
+ controller.signal.addEventListener("abort", rejectCancellation, { once: true });
202
+ });
203
+ let connection;
204
+ try {
205
+ return await Promise.race([
206
+ (async () => {
207
+ connection = await connectServer(server, options, controller.signal);
208
+ const tools = await listAllTools(
209
+ connection.client,
210
+ server.startupTimeoutMs,
211
+ controller.signal,
212
+ );
213
+ return { connection, tools };
214
+ })(),
215
+ deadline,
216
+ cancellation,
217
+ ]);
218
+ } catch (error) {
219
+ if (connection?.owned) await connection.client.close().catch(() => {});
220
+ if (controller.signal.aborted) {
221
+ throw new Error(
222
+ `MCP server ${server.name} startup exceeded ${server.startupTimeoutMs} milliseconds`,
223
+ { cause: error },
224
+ );
225
+ }
226
+ throw error;
227
+ } finally {
228
+ clearTimeout(timeout);
229
+ controller.signal.removeEventListener("abort", rejectCancellation);
230
+ outerSignal?.removeEventListener("abort", abort);
231
+ }
232
+ }
233
+
234
+ async function listAllTools(client, timeoutMs, signal) {
235
+ const tools = [];
236
+ const seen = new Set();
237
+ let cursor;
238
+ for (let page = 0; page < 100; page += 1) {
239
+ const listed = await client.listTools(
240
+ cursor ? { cursor } : undefined,
241
+ { maxTotalTimeout: timeoutMs, signal, timeout: timeoutMs },
242
+ );
243
+ tools.push(...listed.tools);
244
+ if (!listed.nextCursor) return tools;
245
+ if (seen.has(listed.nextCursor)) throw new Error("MCP tools/list returned a repeated cursor");
246
+ seen.add(listed.nextCursor);
247
+ cursor = listed.nextCursor;
248
+ }
249
+ throw new Error("MCP tools/list exceeded 100 pages");
250
+ }
251
+
252
+ async function connectServer(server, options, signal) {
253
+ const client = server.client ?? new Client({
254
+ name: options.clientName ?? "nanocodex-js",
255
+ version: options.clientVersion ?? "0.0.0",
256
+ }, {
257
+ jsonSchemaValidator: options.jsonSchemaValidator,
258
+ });
259
+ if (server.payment) {
260
+ const { McpClient } = await import("mppx/mcp/client");
261
+ const { context: _context, ...payment } = server.payment;
262
+ McpClient.wrap(client, payment);
263
+ }
264
+ if (server.client) return { client, owned: false };
265
+ const transport = new StreamableHTTPClientTransport(new URL(server.url), {
266
+ ...(server.fetch ? { fetch: server.fetch } : {}),
267
+ ...(server.headers ? { requestInit: { headers: server.headers } } : {}),
268
+ });
269
+ try {
270
+ await client.connect(transport, {
271
+ maxTotalTimeout: server.startupTimeoutMs,
272
+ signal,
273
+ timeout: server.startupTimeoutMs,
274
+ });
275
+ return { client, owned: true };
276
+ } catch (error) {
277
+ await client.close().catch(() => {});
278
+ throw error;
279
+ }
280
+ }
281
+
282
+ function normalizeServers(configuration) {
283
+ if (!configuration || typeof configuration !== "object" || Array.isArray(configuration)) {
284
+ throw new TypeError("mcp must be an object keyed by server name");
285
+ }
286
+ const servers = Object.entries(configuration).map(([name, value]) => {
287
+ if (!name.trim()) throw new TypeError("MCP server name must not be empty");
288
+ const server = typeof value === "string" || value instanceof URL ? { url: value } : value;
289
+ if (!server || typeof server !== "object" || Array.isArray(server)) {
290
+ throw new TypeError(`MCP server ${name} must be a URL or configuration object`);
291
+ }
292
+ if (!server.client && !server.url) {
293
+ throw new TypeError(`MCP server ${name} requires url or client`);
294
+ }
295
+ if (server.payment && (!Array.isArray(server.payment.methods) || !server.payment.methods.length)) {
296
+ throw new TypeError(`MCP server ${name} payment requires at least one method`);
297
+ }
298
+ if (server.enabledTools && !isStringArray(server.enabledTools)) {
299
+ throw new TypeError(`MCP server ${name} enabledTools must be an array of strings`);
300
+ }
301
+ if (server.disabledTools && !isStringArray(server.disabledTools)) {
302
+ throw new TypeError(`MCP server ${name} disabledTools must be an array of strings`);
303
+ }
304
+ if (server.parallelTools && !isStringArray(server.parallelTools)) {
305
+ throw new TypeError(`MCP server ${name} parallelTools must be an array of strings`);
306
+ }
307
+ if (server.supportsParallelToolCalls !== undefined
308
+ && typeof server.supportsParallelToolCalls !== "boolean") {
309
+ throw new TypeError(`MCP server ${name} supportsParallelToolCalls must be boolean`);
310
+ }
311
+ if (server.isAvailable !== undefined && typeof server.isAvailable !== "function") {
312
+ throw new TypeError(`MCP server ${name} isAvailable must be a function`);
313
+ }
314
+ if (server.timeoutMs !== undefined
315
+ && (!Number.isFinite(server.timeoutMs) || server.timeoutMs <= 0)) {
316
+ throw new TypeError(`MCP server ${name} timeoutMs must be a positive number`);
317
+ }
318
+ if (server.startupTimeoutMs !== undefined
319
+ && (!Number.isFinite(server.startupTimeoutMs) || server.startupTimeoutMs <= 0)) {
320
+ throw new TypeError(`MCP server ${name} startupTimeoutMs must be a positive number`);
321
+ }
322
+ return {
323
+ ...server,
324
+ name,
325
+ url: server.url?.toString(),
326
+ startupTimeoutMs: server.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS,
327
+ timeoutMs: server.timeoutMs ?? DEFAULT_TOOL_TIMEOUT_MS,
328
+ };
329
+ });
330
+ if (!servers.length) throw new TypeError("mcp requires at least one server");
331
+ return servers;
332
+ }
333
+
334
+ function isStringArray(value) {
335
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
336
+ }
337
+
338
+ function createEntry(server, client, tool, catalogProvider) {
339
+ if (catalogProvider !== undefined
340
+ && (typeof catalogProvider !== "string" || !catalogProvider.trim())) {
341
+ throw new TypeError(`MCP server ${server.name} catalog provider must be a non-empty string`);
342
+ }
343
+ const remoteName = tool.name;
344
+ const canonicalName = `${canonicalNamespace(server.name)}${normalizeName(remoteName)}`;
345
+ const inputSchema = normalizeInputSchema(tool.inputSchema);
346
+ const description = tool.description ?? "";
347
+ return {
348
+ canonicalName,
349
+ ...(catalogProvider === undefined ? {} : { catalogProvider }),
350
+ client,
351
+ definition: Object.freeze({
352
+ type: "function",
353
+ name: canonicalName,
354
+ description,
355
+ strict: false,
356
+ defer_loading: true,
357
+ parameters: inputSchema,
358
+ }),
359
+ description,
360
+ inputSchema,
361
+ remoteName,
362
+ parallelSafe: server.supportsParallelToolCalls === true
363
+ || server.parallelTools?.includes(remoteName) === true
364
+ || tool.annotations?.readOnlyHint === true,
365
+ searchText: [
366
+ canonicalName,
367
+ server.name,
368
+ remoteName,
369
+ tool.title ?? "",
370
+ description,
371
+ ...Object.keys(inputSchema.properties ?? {}),
372
+ ].join(" "),
373
+ server,
374
+ };
375
+ }
376
+
377
+ function createSearchIndex(entries) {
378
+ const index = new MiniSearch({
379
+ fields: ["searchText"],
380
+ idField: "id",
381
+ tokenize: tokenizeSearchText,
382
+ });
383
+ index.addAll(entries.map((entry) => ({ id: entry.canonicalName, searchText: entry.searchText })));
384
+ return index;
385
+ }
386
+
387
+ async function callRemoteTool(entry, input, context) {
388
+ const result = await withMcpRequest(entry.server, context?.signal, async (requestOptions) => {
389
+ if (!isServerAvailable(entry.server)) {
390
+ throw new Error(`MCP server ${entry.server.name} is unavailable`);
391
+ }
392
+ const options = {
393
+ ...requestOptions,
394
+ ...(entry.server.payment?.context !== undefined
395
+ ? { context: entry.server.payment.context }
396
+ : {}),
397
+ };
398
+ return entry.client.callTool(
399
+ { name: entry.remoteName, arguments: input ?? {} },
400
+ undefined,
401
+ options,
402
+ );
403
+ });
404
+ return toolResult(result, result, {
405
+ success: result?.isError !== true,
406
+ metadata: {
407
+ mcp_server: entry.server.name,
408
+ mcp_tool: entry.remoteName,
409
+ },
410
+ });
411
+ }
412
+
413
+ function isServerAvailable(server) {
414
+ if (server.isAvailable === undefined) return true;
415
+ const available = server.isAvailable();
416
+ if (typeof available !== "boolean") {
417
+ throw new TypeError(`MCP server ${server.name} isAvailable must return boolean`);
418
+ }
419
+ return available;
420
+ }
421
+
422
+ async function withMcpRequest(server, outerSignal, operation) {
423
+ const controller = new AbortController();
424
+ let rejectInterruption;
425
+ const interruption = new Promise((_, reject) => { rejectInterruption = reject; });
426
+ const abort = () => {
427
+ controller.abort(outerSignal?.reason);
428
+ rejectInterruption(new Error(`MCP request to ${server.name} was cancelled`));
429
+ };
430
+ if (outerSignal?.aborted) abort();
431
+ else outerSignal?.addEventListener("abort", abort, { once: true });
432
+ const timeout = setTimeout(() => {
433
+ controller.abort(new Error(`MCP request exceeded ${server.timeoutMs} milliseconds`));
434
+ rejectInterruption(new Error(
435
+ `MCP request to ${server.name} exceeded ${server.timeoutMs} milliseconds`,
436
+ ));
437
+ }, server.timeoutMs);
438
+ // An injected client is not required to honor AbortSignal. The SDK owns the
439
+ // deadline and observes any eventual rejection after the race is settled.
440
+ const execution = Promise.resolve().then(() => operation({
441
+ signal: controller.signal,
442
+ timeout: server.timeoutMs,
443
+ }));
444
+ void execution.catch(() => {});
445
+ try {
446
+ return await Promise.race([execution, interruption]);
447
+ } catch (error) {
448
+ throw error;
449
+ } finally {
450
+ clearTimeout(timeout);
451
+ outerSignal?.removeEventListener("abort", abort);
452
+ }
453
+ }
454
+
455
+ function toolSearchDefinition(servers) {
456
+ const sources = servers.map((server) => {
457
+ const description = server.description?.trim();
458
+ return `- ${server.name}${description ? `: ${description}` : ""}`;
459
+ }).join("\n");
460
+ return Object.freeze({
461
+ type: "tool_search",
462
+ execution: "client",
463
+ description: `${SEARCH_DESCRIPTION_PREFIX}\n\nYou have access to tools from the following sources:\n${sources}\nSome tools are omitted from the initial request. Use \`tool_search\` for MCP discovery before calling them from Code Mode.`,
464
+ parameters: {
465
+ type: "object",
466
+ properties: {
467
+ query: { type: "string", description: "Search query for deferred tools." },
468
+ limit: { type: "number", description: "Maximum number of tools to return. Defaults to 8." },
469
+ },
470
+ required: ["query"],
471
+ additionalProperties: false,
472
+ },
473
+ });
474
+ }
475
+
476
+ function loadableNamespaces(entries) {
477
+ const namespaces = new Map();
478
+ for (const entry of entries) {
479
+ const name = canonicalNamespace(entry.server.name);
480
+ let namespace = namespaces.get(name);
481
+ if (!namespace) {
482
+ namespace = {
483
+ type: "namespace",
484
+ name,
485
+ description: entry.server.description?.trim() || `Tools in the ${name} namespace.`,
486
+ tools: [],
487
+ };
488
+ namespaces.set(name, namespace);
489
+ }
490
+ namespace.tools.push({
491
+ type: "function",
492
+ name: normalizeName(entry.remoteName),
493
+ description: entry.description,
494
+ strict: false,
495
+ defer_loading: true,
496
+ parameters: entry.inputSchema,
497
+ });
498
+ }
499
+ return [...namespaces.values()];
500
+ }
501
+
502
+ function normalizeInputSchema(schema) {
503
+ const input = schema && typeof schema === "object" && !Array.isArray(schema)
504
+ ? JSON.parse(JSON.stringify(schema))
505
+ : { type: "object" };
506
+ input.properties ??= {};
507
+ return input;
508
+ }
509
+
510
+ function includesTool(server, name) {
511
+ return (!server.enabledTools || server.enabledTools.includes(name))
512
+ && !server.disabledTools?.includes(name);
513
+ }
514
+
515
+ function canonicalNamespace(serverName) {
516
+ return `mcp__${normalizeName(serverName)}__`;
517
+ }
518
+
519
+ function normalizeName(name) {
520
+ return [...name].map((character) => /[A-Za-z0-9_-]/.test(character) ? character : "_").join("");
521
+ }
522
+
523
+ function tokenizeSearchText(text) {
524
+ return text
525
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
526
+ .replace(/([A-Z])([A-Z][a-z])/g, "$1 $2")
527
+ .toLowerCase()
528
+ .split(/[^\p{L}\p{N}]+/u)
529
+ .filter(Boolean);
530
+ }
531
+
532
+ function errorMessage(error) {
533
+ return error instanceof Error ? error.message : String(error);
534
+ }
@@ -0,0 +1,64 @@
1
+ import type { DurabilityPortableStore } from "../types.mjs";
2
+
3
+ /** A PostgreSQL result row. Column values remain owned by the pool implementation. */
4
+ export type PostgresDurabilityRow = Readonly<Record<string, unknown>>;
5
+
6
+ /** The only query result shape read by the PostgreSQL durability adapter. */
7
+ export type PostgresDurabilityQueryResult<
8
+ Row extends PostgresDurabilityRow = PostgresDurabilityRow,
9
+ > = Readonly<{
10
+ rows: readonly Row[];
11
+ }>;
12
+
13
+ /**
14
+ * A dedicated PostgreSQL connection held for one transaction.
15
+ *
16
+ * `release(true)` asks a node-postgres-compatible pool to discard a connection
17
+ * whose transaction state or COMMIT outcome cannot be trusted.
18
+ */
19
+ export type PostgresDurabilityClient = Readonly<{
20
+ query<Row extends PostgresDurabilityRow = PostgresDurabilityRow>(
21
+ text: string,
22
+ values?: unknown[] | undefined,
23
+ ): PromiseLike<PostgresDurabilityQueryResult<Row>>;
24
+ release(discard?: boolean | Error | undefined): void;
25
+ }>;
26
+
27
+ /**
28
+ * Minimal structural PostgreSQL pool capability consumed by the adapter.
29
+ *
30
+ * This is intentionally compatible with `pg.Pool` without importing `pg` or
31
+ * owning its lifecycle. `connect()` must reserve one client until `release()`,
32
+ * while `query()` executes a standalone load query through the pool.
33
+ */
34
+ export type PostgresDurabilityPool = Readonly<{
35
+ connect(): PromiseLike<PostgresDurabilityClient>;
36
+ query<Row extends PostgresDurabilityRow = PostgresDurabilityRow>(
37
+ text: string,
38
+ values?: unknown[] | undefined,
39
+ ): PromiseLike<PostgresDurabilityQueryResult<Row>>;
40
+ }>;
41
+
42
+ /**
43
+ * PostgreSQL remained unavailable while the adapter retried an idempotent
44
+ * operation to verify a lost COMMIT response. Retrying the same request is safe.
45
+ */
46
+ export declare class PostgresDurabilityUnavailableError extends Error {
47
+ override readonly name: "PostgresDurabilityUnavailableError";
48
+ constructor(stateId: string, cause: unknown);
49
+ }
50
+
51
+ /**
52
+ * Creates a concrete PostgreSQL-backed Nanocodex durability store.
53
+ *
54
+ * The schema is initialized lazily under a PostgreSQL transaction advisory
55
+ * lock. Replacements atomically compare and advance the complete opaque state in one
56
+ * transaction. Lost COMMIT responses are reconciled internally by retrying the
57
+ * same idempotent operation; callers never receive an ambiguous write result.
58
+ *
59
+ * The supplied pool is structural and caller-owned. Constructing the store
60
+ * does not connect, query, or import a PostgreSQL driver.
61
+ */
62
+ export declare function createPostgresDurabilityStore(
63
+ pool: PostgresDurabilityPool,
64
+ ): DurabilityPortableStore;