@ai-setting/roy-agent-core 1.0.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 (378) hide show
  1. package/dist/index.js +99145 -0
  2. package/package.json +114 -0
  3. package/src/config/config-component.test.ts +627 -0
  4. package/src/config/config-component.ts +906 -0
  5. package/src/config/config-parser.test.ts +319 -0
  6. package/src/config/config-parser.ts +203 -0
  7. package/src/config/decentralized-config.test.ts +740 -0
  8. package/src/config/env-key.ts +210 -0
  9. package/src/config/env-source.test.ts +252 -0
  10. package/src/config/env-source.ts +301 -0
  11. package/src/config/file-source.test.ts +357 -0
  12. package/src/config/file-source.ts +421 -0
  13. package/src/config/index.ts +24 -0
  14. package/src/config/protocol-resolver.test.ts +217 -0
  15. package/src/config/protocol-resolver.ts +228 -0
  16. package/src/env/agent/agent-component.abort.test.ts +511 -0
  17. package/src/env/agent/agent-component.record-session.test.ts +349 -0
  18. package/src/env/agent/agent-component.test.ts +1389 -0
  19. package/src/env/agent/agent-component.tool-error.test.ts +327 -0
  20. package/src/env/agent/agent-component.ts +1711 -0
  21. package/src/env/agent/agent-config-registration.test.ts +226 -0
  22. package/src/env/agent/agent-config-registration.ts +46 -0
  23. package/src/env/agent/agent-reminder-plugin.integration.test.ts +243 -0
  24. package/src/env/agent/index.ts +10 -0
  25. package/src/env/agent/summary-agent.parse-hint.test.ts +360 -0
  26. package/src/env/agent/summary-agent.ts +508 -0
  27. package/src/env/agent/types.ts +536 -0
  28. package/src/env/commands/commands-component.test.ts +364 -0
  29. package/src/env/commands/commands-component.ts +604 -0
  30. package/src/env/commands/commands-config-registration.test.ts +198 -0
  31. package/src/env/commands/commands-config-registration.ts +38 -0
  32. package/src/env/commands/index.ts +21 -0
  33. package/src/env/commands/parser.test.ts +203 -0
  34. package/src/env/commands/parser.ts +115 -0
  35. package/src/env/commands/types.ts +184 -0
  36. package/src/env/commands-prompt-integration.test.ts +243 -0
  37. package/src/env/component-env.test.ts +119 -0
  38. package/src/env/component.ts +335 -0
  39. package/src/env/constants.test.ts +72 -0
  40. package/src/env/constants.ts +123 -0
  41. package/src/env/debug/debug-component.test.ts +114 -0
  42. package/src/env/debug/debug-component.ts +547 -0
  43. package/src/env/debug/formatters/index.ts +9 -0
  44. package/src/env/debug/formatters/repl-formatter.test.ts +139 -0
  45. package/src/env/debug/formatters/repl-formatter.ts +358 -0
  46. package/src/env/debug/formatters/trace-formatter.test.ts +119 -0
  47. package/src/env/debug/formatters/trace-formatter.ts +191 -0
  48. package/src/env/debug/formatters/tree-formatter.test.ts +107 -0
  49. package/src/env/debug/formatters/tree-formatter.ts +325 -0
  50. package/src/env/debug/index.ts +38 -0
  51. package/src/env/debug/parser/regex-parser.test.ts +201 -0
  52. package/src/env/debug/parser/regex-parser.ts +196 -0
  53. package/src/env/debug/parser/span-builder.test.ts +241 -0
  54. package/src/env/debug/parser/span-builder.ts +386 -0
  55. package/src/env/debug/reader/log-reader.test.ts +170 -0
  56. package/src/env/debug/reader/log-reader.ts +186 -0
  57. package/src/env/debug/reader/span-db-reader.test.ts +118 -0
  58. package/src/env/debug/reader/span-db-reader.ts +201 -0
  59. package/src/env/debug/types.test.ts +187 -0
  60. package/src/env/debug/types.ts +171 -0
  61. package/src/env/environment-init.test.ts +183 -0
  62. package/src/env/environment-lifecycle.test.ts +516 -0
  63. package/src/env/environment-service.test.ts +332 -0
  64. package/src/env/environment.handle-query.test.ts +96 -0
  65. package/src/env/environment.test.ts +232 -0
  66. package/src/env/environment.ts +708 -0
  67. package/src/env/errors.test.ts +165 -0
  68. package/src/env/errors.ts +157 -0
  69. package/src/env/event-source/event-source-agent-handler.test.ts +193 -0
  70. package/src/env/event-source/event-source-agent-handler.ts +111 -0
  71. package/src/env/event-source/event-source-component.process-cleanup.test.ts +236 -0
  72. package/src/env/event-source/event-source-component.stop.test.ts +346 -0
  73. package/src/env/event-source/event-source-component.test.ts +1207 -0
  74. package/src/env/event-source/event-source-component.ts +1379 -0
  75. package/src/env/event-source/event-source-config-registration.test.ts +242 -0
  76. package/src/env/event-source/event-source-config-registration.ts +37 -0
  77. package/src/env/event-source/event-source-integration.test.ts +320 -0
  78. package/src/env/event-source/event-source-platform.test.ts +630 -0
  79. package/src/env/event-source/types.ts +298 -0
  80. package/src/env/hook/global-hook-manager.ts +162 -0
  81. package/src/env/hook/hook-manager.test.ts +374 -0
  82. package/src/env/hook/hook-manager.ts +309 -0
  83. package/src/env/hook/index.ts +38 -0
  84. package/src/env/hook/types.ts +138 -0
  85. package/src/env/index.ts +144 -0
  86. package/src/env/interface.ts +203 -0
  87. package/src/env/llm/hooks.test.ts +293 -0
  88. package/src/env/llm/hooks.ts +316 -0
  89. package/src/env/llm/index.ts +61 -0
  90. package/src/env/llm/invoke-threshold-check.test.ts +88 -0
  91. package/src/env/llm/invoke-timeout.test.ts +54 -0
  92. package/src/env/llm/invoke.test.ts +71 -0
  93. package/src/env/llm/invoke.ts +1039 -0
  94. package/src/env/llm/llm-config.test.ts +523 -0
  95. package/src/env/llm/llm.test.ts +233 -0
  96. package/src/env/llm/llm.ts +568 -0
  97. package/src/env/llm/provider.test.ts +182 -0
  98. package/src/env/llm/provider.ts +108 -0
  99. package/src/env/llm/transform.test.ts +251 -0
  100. package/src/env/llm/transform.ts +286 -0
  101. package/src/env/llm/types.test.ts +580 -0
  102. package/src/env/llm/types.ts +424 -0
  103. package/src/env/log-trace/decorator-otel.test.ts +182 -0
  104. package/src/env/log-trace/decorator.ts +230 -0
  105. package/src/env/log-trace/index.ts +79 -0
  106. package/src/env/log-trace/log-trace-component.test.ts +242 -0
  107. package/src/env/log-trace/log-trace-component.ts +497 -0
  108. package/src/env/log-trace/log-trace-config-registration.test.ts +348 -0
  109. package/src/env/log-trace/log-trace-config-registration.ts +45 -0
  110. package/src/env/log-trace/logger.test.ts +149 -0
  111. package/src/env/log-trace/logger.ts +522 -0
  112. package/src/env/log-trace/opentelemetry/cli-propagation.test.ts +147 -0
  113. package/src/env/log-trace/opentelemetry/cli-propagation.ts +194 -0
  114. package/src/env/log-trace/opentelemetry/integration.test.ts +668 -0
  115. package/src/env/log-trace/opentelemetry/mod.ts +25 -0
  116. package/src/env/log-trace/opentelemetry/propagation-env.test.ts +181 -0
  117. package/src/env/log-trace/opentelemetry/propagation-env.ts +136 -0
  118. package/src/env/log-trace/opentelemetry/propagation.test.ts +259 -0
  119. package/src/env/log-trace/opentelemetry/propagation.ts +215 -0
  120. package/src/env/log-trace/opentelemetry/tracer-provider-context.test.ts +166 -0
  121. package/src/env/log-trace/opentelemetry/tracer-provider.test.ts +379 -0
  122. package/src/env/log-trace/opentelemetry/tracer-provider.ts +612 -0
  123. package/src/env/log-trace/span-storage.test.ts +145 -0
  124. package/src/env/log-trace/span-storage.ts +230 -0
  125. package/src/env/log-trace/trace-context.test.ts +187 -0
  126. package/src/env/log-trace/trace-context.ts +162 -0
  127. package/src/env/log-trace/types.test.ts +63 -0
  128. package/src/env/log-trace/types.ts +172 -0
  129. package/src/env/mcp/README.md +244 -0
  130. package/src/env/mcp/__integration__/mcp-component.integration.test.ts +373 -0
  131. package/src/env/mcp/config.test.ts +74 -0
  132. package/src/env/mcp/config.ts +116 -0
  133. package/src/env/mcp/index.ts +41 -0
  134. package/src/env/mcp/loader.test.ts +161 -0
  135. package/src/env/mcp/loader.ts +209 -0
  136. package/src/env/mcp/mcp-component.test.ts +111 -0
  137. package/src/env/mcp/mcp-component.ts +358 -0
  138. package/src/env/mcp/mcp-config-registration.test.ts +304 -0
  139. package/src/env/mcp/mcp-config-registration.ts +50 -0
  140. package/src/env/mcp/scanner.test.ts +170 -0
  141. package/src/env/mcp/scanner.ts +246 -0
  142. package/src/env/mcp/tool/adapter.test.ts +520 -0
  143. package/src/env/mcp/tool/adapter.ts +521 -0
  144. package/src/env/mcp/tool/index.ts +5 -0
  145. package/src/env/mcp/types.test.ts +171 -0
  146. package/src/env/mcp/types.ts +79 -0
  147. package/src/env/memory/README.md +177 -0
  148. package/src/env/memory/built-in/index.ts +59 -0
  149. package/src/env/memory/built-in/recall-memory.ts +103 -0
  150. package/src/env/memory/built-in/record-memory.ts +148 -0
  151. package/src/env/memory/index.ts +20 -0
  152. package/src/env/memory/memory-component.test.ts +239 -0
  153. package/src/env/memory/memory-component.ts +503 -0
  154. package/src/env/memory/memory-config-registration.test.ts +67 -0
  155. package/src/env/memory/memory-config-registration.ts +48 -0
  156. package/src/env/memory/memory-config.ts +45 -0
  157. package/src/env/memory/memory-file.test.ts +268 -0
  158. package/src/env/memory/plugin/index.ts +48 -0
  159. package/src/env/memory/plugin/memory-agent.test.ts +249 -0
  160. package/src/env/memory/plugin/memory-agent.ts +365 -0
  161. package/src/env/memory/plugin/memory-manager.ts +198 -0
  162. package/src/env/memory/plugin/memory-plugin-agent.test.ts +145 -0
  163. package/src/env/memory/plugin/memory-plugin.ts +210 -0
  164. package/src/env/memory/plugin/plugin-simplified.test.ts +51 -0
  165. package/src/env/memory/plugin/recall-memory.test.ts +106 -0
  166. package/src/env/memory/plugin/recall-memory.ts +53 -0
  167. package/src/env/memory/plugin/types.ts +101 -0
  168. package/src/env/memory/tools/memory-agent-tools.ts +228 -0
  169. package/src/env/memory/types.ts +85 -0
  170. package/src/env/paths.ts +118 -0
  171. package/src/env/prompt/index.ts +18 -0
  172. package/src/env/prompt/memory-prompts.test.ts +91 -0
  173. package/src/env/prompt/prompt-component.test.ts +491 -0
  174. package/src/env/prompt/prompt-component.ts +619 -0
  175. package/src/env/prompt/prompt-config-registration.test.ts +213 -0
  176. package/src/env/prompt/prompt-config-registration.ts +39 -0
  177. package/src/env/prompt/prompts-index.ts +504 -0
  178. package/src/env/prompt/renderer.ts +67 -0
  179. package/src/env/prompt/types.ts +136 -0
  180. package/src/env/session/hooks.ts +18 -0
  181. package/src/env/session/index.ts +37 -0
  182. package/src/env/session/search-query-parser.test.ts +425 -0
  183. package/src/env/session/search-query-parser.ts +171 -0
  184. package/src/env/session/session-checkpoint.test.ts +523 -0
  185. package/src/env/session/session-component.extract-recent-messages.test.ts +209 -0
  186. package/src/env/session/session-component.test.ts +132 -0
  187. package/src/env/session/session-component.ts +1249 -0
  188. package/src/env/session/session-config-registration.test.ts +138 -0
  189. package/src/env/session/session-config-registration.ts +52 -0
  190. package/src/env/session/session-message-converter.test.ts +763 -0
  191. package/src/env/session/session-message-converter.ts +415 -0
  192. package/src/env/session/session-message-e2e.test.ts +448 -0
  193. package/src/env/session/session-search.test.ts +391 -0
  194. package/src/env/session/session-store.test.ts +362 -0
  195. package/src/env/session/session-store.ts +141 -0
  196. package/src/env/session/storage/index.ts +6 -0
  197. package/src/env/session/storage/memory.ts +502 -0
  198. package/src/env/session/storage/sqlite.ts +794 -0
  199. package/src/env/session/types.ts +742 -0
  200. package/src/env/skill/config.ts +39 -0
  201. package/src/env/skill/index.ts +6 -0
  202. package/src/env/skill/parser.test.ts +116 -0
  203. package/src/env/skill/parser.ts +77 -0
  204. package/src/env/skill/scanner.test.ts +211 -0
  205. package/src/env/skill/scanner.ts +119 -0
  206. package/src/env/skill/skill-component.test.ts +234 -0
  207. package/src/env/skill/skill-component.ts +352 -0
  208. package/src/env/skill/skill-config-registration.test.ts +60 -0
  209. package/src/env/skill/skill-config-registration.ts +43 -0
  210. package/src/env/skill/tool/index.ts +1 -0
  211. package/src/env/skill/tool/skill-tool.test.ts +100 -0
  212. package/src/env/skill/tool/skill-tool.ts +72 -0
  213. package/src/env/skill/types.ts +64 -0
  214. package/src/env/task/delegate/delegate-tool.test.ts +498 -0
  215. package/src/env/task/delegate/delegate-tool.ts +1014 -0
  216. package/src/env/task/delegate/index.ts +18 -0
  217. package/src/env/task/delegate/stop-tool.test.ts +140 -0
  218. package/src/env/task/delegate/stop-tool.ts +119 -0
  219. package/src/env/task/delegate/task-events.test.ts +178 -0
  220. package/src/env/task/delegate/task-events.ts +143 -0
  221. package/src/env/task/hooks/contexts.test.ts +92 -0
  222. package/src/env/task/hooks/contexts.ts +192 -0
  223. package/src/env/task/hooks/index.ts +23 -0
  224. package/src/env/task/hooks/task-hook-points.test.ts +32 -0
  225. package/src/env/task/hooks/task-hook-points.ts +54 -0
  226. package/src/env/task/index.ts +7 -0
  227. package/src/env/task/plugins/index.ts +13 -0
  228. package/src/env/task/plugins/task-plugin.test.ts +74 -0
  229. package/src/env/task/plugins/task-plugin.ts +89 -0
  230. package/src/env/task/plugins/task-tag-plugin.test.ts +377 -0
  231. package/src/env/task/plugins/task-tag-plugin.ts +319 -0
  232. package/src/env/task/plugins/task-workflow-extractor.integration.test.ts +226 -0
  233. package/src/env/task/plugins/workflow-extractor-agent.test.ts +107 -0
  234. package/src/env/task/plugins/workflow-extractor-agent.ts +225 -0
  235. package/src/env/task/storage/index.ts +6 -0
  236. package/src/env/task/storage/sqlite-task-store.test.ts +283 -0
  237. package/src/env/task/storage/sqlite-task-store.ts +903 -0
  238. package/src/env/task/storage/task-search.test.ts +291 -0
  239. package/src/env/task/tag-service.test.ts +198 -0
  240. package/src/env/task/tag-service.ts +264 -0
  241. package/src/env/task/task-component.test.ts +193 -0
  242. package/src/env/task/task-component.ts +658 -0
  243. package/src/env/task/task-config-registration.test.ts +57 -0
  244. package/src/env/task/task-config-registration.ts +37 -0
  245. package/src/env/task/task-types.test.ts +137 -0
  246. package/src/env/task/tools/complete-tool.ts +44 -0
  247. package/src/env/task/tools/create-tool.ts +49 -0
  248. package/src/env/task/tools/delete-tool.ts +43 -0
  249. package/src/env/task/tools/get-tool.ts +59 -0
  250. package/src/env/task/tools/index.ts +10 -0
  251. package/src/env/task/tools/list-tool.ts +40 -0
  252. package/src/env/task/tools/operation/create-tool.ts +48 -0
  253. package/src/env/task/tools/operation/delete-tool.ts +43 -0
  254. package/src/env/task/tools/operation/get-tool.ts +43 -0
  255. package/src/env/task/tools/operation/index.ts +9 -0
  256. package/src/env/task/tools/operation/list-tool.ts +40 -0
  257. package/src/env/task/tools/operation/operation-tools.test.ts +274 -0
  258. package/src/env/task/tools/operation/operation-types.ts +75 -0
  259. package/src/env/task/tools/operation/update-tool.ts +47 -0
  260. package/src/env/task/tools/task-tools.test.ts +203 -0
  261. package/src/env/task/tools/task-types.test.ts +75 -0
  262. package/src/env/task/tools/task-types.ts +68 -0
  263. package/src/env/task/tools/update-tool.ts +70 -0
  264. package/src/env/task/types.ts +160 -0
  265. package/src/env/tool/built-in/bash.ts +201 -0
  266. package/src/env/tool/built-in/echo.ts +29 -0
  267. package/src/env/tool/built-in/edit-file.test.ts +136 -0
  268. package/src/env/tool/built-in/edit-file.ts +92 -0
  269. package/src/env/tool/built-in/glob.test.ts +94 -0
  270. package/src/env/tool/built-in/glob.ts +65 -0
  271. package/src/env/tool/built-in/grep.test.ts +122 -0
  272. package/src/env/tool/built-in/grep.ts +108 -0
  273. package/src/env/tool/built-in/index.ts +44 -0
  274. package/src/env/tool/built-in/read-file.test.ts +84 -0
  275. package/src/env/tool/built-in/read-file.ts +75 -0
  276. package/src/env/tool/built-in/write-file.test.ts +119 -0
  277. package/src/env/tool/built-in/write-file.ts +68 -0
  278. package/src/env/tool/index.ts +24 -0
  279. package/src/env/tool/registry.test.ts +257 -0
  280. package/src/env/tool/registry.ts +167 -0
  281. package/src/env/tool/tool-component.test.ts +559 -0
  282. package/src/env/tool/tool-component.ts +563 -0
  283. package/src/env/tool/tool-config-registration.test.ts +249 -0
  284. package/src/env/tool/tool-config-registration.ts +46 -0
  285. package/src/env/tool/types.ts +267 -0
  286. package/src/env/tool/validator.test.ts +143 -0
  287. package/src/env/tool/validator.ts +44 -0
  288. package/src/env/types.ts +180 -0
  289. package/src/env/workflow/ask-user-tool-registration.test.ts +216 -0
  290. package/src/env/workflow/complex-workflow.integration.test.ts +1900 -0
  291. package/src/env/workflow/decorators/decorator-node.ts +229 -0
  292. package/src/env/workflow/decorators/decorator.test.ts +196 -0
  293. package/src/env/workflow/decorators/edge.ts +82 -0
  294. package/src/env/workflow/decorators/index.ts +31 -0
  295. package/src/env/workflow/decorators/node-as.ts +98 -0
  296. package/src/env/workflow/decorators/workflow.ts +54 -0
  297. package/src/env/workflow/engine/dag-manager.test.ts +570 -0
  298. package/src/env/workflow/engine/dag-manager.ts +594 -0
  299. package/src/env/workflow/engine/engine.ts +1422 -0
  300. package/src/env/workflow/engine/event-bus.test.ts +359 -0
  301. package/src/env/workflow/engine/event-bus.ts +156 -0
  302. package/src/env/workflow/engine/executor-agent-session.test.ts +84 -0
  303. package/src/env/workflow/engine/executor.test.ts +619 -0
  304. package/src/env/workflow/engine/executor.ts +593 -0
  305. package/src/env/workflow/engine/index.ts +24 -0
  306. package/src/env/workflow/engine/node-registry.test.ts +560 -0
  307. package/src/env/workflow/engine/node-registry.ts +289 -0
  308. package/src/env/workflow/engine/resume-removed.test.ts +22 -0
  309. package/src/env/workflow/engine/scheduler.test.ts +715 -0
  310. package/src/env/workflow/engine/scheduler.ts +318 -0
  311. package/src/env/workflow/engine/workflow-engine.test.ts +815 -0
  312. package/src/env/workflow/extractor/workflow-converter.ts +306 -0
  313. package/src/env/workflow/fixtures.ts +380 -0
  314. package/src/env/workflow/index.ts +38 -0
  315. package/src/env/workflow/integration/run-resume-unified.test.ts +186 -0
  316. package/src/env/workflow/integration/service-integration.test.ts +267 -0
  317. package/src/env/workflow/metadata/keys.ts +12 -0
  318. package/src/env/workflow/nodes/agent-component-adapter.test.ts +318 -0
  319. package/src/env/workflow/nodes/agent-component-adapter.ts +448 -0
  320. package/src/env/workflow/nodes/agent-node.test.ts +371 -0
  321. package/src/env/workflow/nodes/agent-node.ts +598 -0
  322. package/src/env/workflow/nodes/ask-user-node.ts +113 -0
  323. package/src/env/workflow/nodes/condition-node.ts +200 -0
  324. package/src/env/workflow/nodes/index.ts +9 -0
  325. package/src/env/workflow/nodes/merge-node.ts +141 -0
  326. package/src/env/workflow/nodes/skill-node.test.ts +253 -0
  327. package/src/env/workflow/nodes/skill-node.ts +393 -0
  328. package/src/env/workflow/nodes/tool-node.test.ts +251 -0
  329. package/src/env/workflow/nodes/tool-node.ts +493 -0
  330. package/src/env/workflow/nodes/workflow-llm-history.test.ts +455 -0
  331. package/src/env/workflow/nodes/workflow-node.test.ts +315 -0
  332. package/src/env/workflow/nodes/workflow-node.ts +311 -0
  333. package/src/env/workflow/service/index.ts +27 -0
  334. package/src/env/workflow/service/registry.test.ts +133 -0
  335. package/src/env/workflow/service/registry.ts +71 -0
  336. package/src/env/workflow/service/workflow-service.test.ts +310 -0
  337. package/src/env/workflow/service/workflow-service.ts +393 -0
  338. package/src/env/workflow/storage/index.ts +28 -0
  339. package/src/env/workflow/storage/mock-repositories.ts +385 -0
  340. package/src/env/workflow/storage/sqlite.test.ts +179 -0
  341. package/src/env/workflow/storage/sqlite.ts +163 -0
  342. package/src/env/workflow/storage/workflow-repo.test.ts +780 -0
  343. package/src/env/workflow/storage/workflow-repo.ts +342 -0
  344. package/src/env/workflow/tools/ask-user-tool.ts +82 -0
  345. package/src/env/workflow/tools/index.ts +26 -0
  346. package/src/env/workflow/tools/run-workflow.test.ts +352 -0
  347. package/src/env/workflow/tools/run-workflow.ts +214 -0
  348. package/src/env/workflow/types/context.ts +18 -0
  349. package/src/env/workflow/types/decorators-types.ts +198 -0
  350. package/src/env/workflow/types/event.test.ts +515 -0
  351. package/src/env/workflow/types/event.ts +193 -0
  352. package/src/env/workflow/types/index.ts +49 -0
  353. package/src/env/workflow/types/run.test.ts +437 -0
  354. package/src/env/workflow/types/run.ts +173 -0
  355. package/src/env/workflow/types/workflow-hil.ts +114 -0
  356. package/src/env/workflow/types/workflow-message.test.ts +138 -0
  357. package/src/env/workflow/types/workflow-message.ts +196 -0
  358. package/src/env/workflow/types/workflow-session.test.ts +95 -0
  359. package/src/env/workflow/types/workflow-session.ts +59 -0
  360. package/src/env/workflow/types/workflow.test.ts +495 -0
  361. package/src/env/workflow/types/workflow.ts +195 -0
  362. package/src/env/workflow/types_compat.ts +51 -0
  363. package/src/env/workflow/utils/create-workflow.ts +47 -0
  364. package/src/env/workflow/utils/execution-state.ts +245 -0
  365. package/src/env/workflow/utils/index.ts +18 -0
  366. package/src/env/workflow/utils/node-registry-helper.ts +58 -0
  367. package/src/env/workflow/utils/recovery-validator.test.ts +460 -0
  368. package/src/env/workflow/utils/recovery-validator.ts +377 -0
  369. package/src/env/workflow/utils/session-parser.test.ts +111 -0
  370. package/src/env/workflow/utils/session-parser.ts +94 -0
  371. package/src/env/workflow/utils/session-recovery.test.ts +334 -0
  372. package/src/env/workflow/utils/session-recovery.ts +188 -0
  373. package/src/env/workflow/utils/template-resolver.test.ts +258 -0
  374. package/src/env/workflow/utils/template-resolver.ts +436 -0
  375. package/src/env/workflow/utils/validation-rules.ts +149 -0
  376. package/src/env/workflow/workflow-component.ts +544 -0
  377. package/src/index.ts +422 -0
  378. package/src/utils/id.ts +21 -0
@@ -0,0 +1,521 @@
1
+ /**
2
+ * @fileoverview MCP Tool 适配器
3
+ *
4
+ * 将 MCP 工具转换为 Environment Tool
5
+ * 完整保留参数描述等信息,供 LLM 正确调用
6
+ */
7
+
8
+ import { z, ZodType, ZodTypeDef } from "zod";
9
+ import type { Tool as McpTool, CallToolResult as McpCallToolResult } from "@modelcontextprotocol/sdk/types.js";
10
+ import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
11
+ import type { ToolInfo, ToolContext, ToolResult } from "../../tool/types";
12
+ import { createLogger } from "../../log-trace/logger";
13
+
14
+ const logger = createLogger("mcp-adapter");
15
+
16
+ /**
17
+ * 扩展的 JSON Schema 定义
18
+ */
19
+ interface JSONSchema7 {
20
+ type?: string;
21
+ types?: string[]; // MCP 可能使用 types 代替 type
22
+ properties?: Record<string, JSONSchema7>;
23
+ required?: string[];
24
+ items?: JSONSchema7;
25
+ additionalProperties?: boolean | JSONSchema7;
26
+ description?: string;
27
+ title?: string;
28
+ enum?: unknown[];
29
+ default?: unknown;
30
+ minimum?: number;
31
+ maximum?: number;
32
+ minLength?: number;
33
+ maxLength?: number;
34
+ pattern?: string;
35
+ format?: string;
36
+ anyOf?: JSONSchema7[];
37
+ oneOf?: JSONSchema7[];
38
+ allOf?: JSONSchema7[];
39
+ const?: unknown;
40
+ nullable?: boolean;
41
+ examples?: unknown[];
42
+ }
43
+
44
+ /**
45
+ * 增强的 Zod 类型定义,支持描述
46
+ */
47
+ interface ZodTypeWithDescription {
48
+ schema: z.ZodType;
49
+ description?: string;
50
+ }
51
+
52
+ /**
53
+ * 将 MCP 工具转换为 Environment Tool
54
+ *
55
+ * 命名策略: mcp_{serverName}_{toolName}
56
+ */
57
+ export function adaptMcpTool(
58
+ mcpTool: McpTool,
59
+ mcpClient: Client,
60
+ serverName: string
61
+ ): ToolInfo {
62
+ const toolName = `mcp_${serverName}_${mcpTool.name}`;
63
+ const description = `MCP tool [${serverName}/${mcpTool.name}]: ${mcpTool.description ?? ""}`;
64
+
65
+ // 转换参数 schema(包含描述信息)
66
+ const paramsSchema = convertInputSchemaToZod(mcpTool.inputSchema);
67
+
68
+ return {
69
+ name: toolName,
70
+ description,
71
+ parameters: paramsSchema,
72
+ execute: async (args: unknown, _ctx: ToolContext): Promise<ToolResult> => {
73
+ try {
74
+ const result = await mcpClient.callTool({
75
+ name: mcpTool.name,
76
+ arguments: (args as Record<string, unknown>) ?? {},
77
+ });
78
+
79
+ // 转换结果
80
+ return convertMcpCallResult(result as unknown as McpCallToolResult);
81
+ } catch (error) {
82
+ logger.error(`[McpAdapter] Tool call failed: ${toolName}`, {
83
+ error: error instanceof Error ? error.message : String(error),
84
+ });
85
+ return {
86
+ success: false,
87
+ output: "",
88
+ error: error instanceof Error ? error.message : String(error),
89
+ };
90
+ }
91
+ },
92
+ metadata: {
93
+ category: "mcp",
94
+ tags: ["mcp", serverName],
95
+ // 保留原始 MCP 工具信息,供 LLM 使用
96
+ mcpTool: {
97
+ originalName: mcpTool.name,
98
+ originalDescription: mcpTool.description || "",
99
+ inputSchema: mcpTool.inputSchema,
100
+ },
101
+ },
102
+ };
103
+ }
104
+
105
+ /**
106
+ * 转换 MCP inputSchema 为 Zod schema
107
+ *
108
+ * 关键:保留参数描述,让 LLM 知道每个参数的用途
109
+ */
110
+ export function convertInputSchemaToZod(inputSchema: McpTool["inputSchema"]): z.ZodType<unknown> {
111
+ if (!inputSchema) {
112
+ return z.unknown();
113
+ }
114
+
115
+ const schema = inputSchema as JSONSchema7;
116
+ const properties = schema.properties ?? {};
117
+ const required = schema.required ?? [];
118
+
119
+ // 检查是否有 anyOf/oneOf - 表示联合类型
120
+ if (schema.anyOf || schema.oneOf) {
121
+ const unions = schema.anyOf || schema.oneOf || [];
122
+ const zodUnions = unions.map((s) => jsonSchemaToZod(s, false)).filter((t) => t);
123
+ if (zodUnions.length > 0) {
124
+ // 使用 any 避免复杂的类型问题
125
+ return z.union(zodUnions as any);
126
+ }
127
+ }
128
+
129
+ // 处理 anyOf/oneOf 作为联合类型
130
+ if (schema.allOf) {
131
+ // allOf 表示组合多个 schema
132
+ const schemas: z.ZodTypeAny[] = [];
133
+ for (const subSchema of schema.allOf) {
134
+ const sub = jsonSchemaToZod(subSchema, false);
135
+ schemas.push(sub);
136
+ }
137
+ if (schemas.length === 1) {
138
+ return schemas[0];
139
+ }
140
+ // 使用 intersect 替代 merge
141
+ let combined: z.ZodTypeAny = schemas[0];
142
+ for (let i = 1; i < schemas.length; i++) {
143
+ combined = z.intersection(combined as z.ZodType<unknown>, schemas[i] as z.ZodType<unknown>);
144
+ }
145
+ return combined;
146
+ }
147
+
148
+ // 构建对象 schema
149
+ const zodFields: Record<string, z.ZodType> = {};
150
+ const fieldDescriptions: Record<string, string> = {};
151
+
152
+ for (const [key, prop] of Object.entries(properties)) {
153
+ const isRequired = required.includes(key);
154
+ const fieldResult = jsonSchemaToZod(prop as JSONSchema7, !isRequired);
155
+
156
+ // 保留参数描述
157
+ const propSchema = prop as JSONSchema7;
158
+ if (propSchema.description) {
159
+ fieldDescriptions[key] = propSchema.description;
160
+ }
161
+
162
+ // 如果不是 required,添加 optional
163
+ if (!isRequired) {
164
+ zodFields[key] = fieldResult.optional();
165
+ } else {
166
+ zodFields[key] = fieldResult;
167
+ }
168
+ }
169
+
170
+ // 使用 describe 构建 schema
171
+ if (Object.keys(zodFields).length === 0) {
172
+ return schema.description ? z.unknown().describe(schema.description) : z.unknown();
173
+ }
174
+
175
+ // 构建带描述的 Zod schema
176
+ const result = z.object(zodFields);
177
+
178
+ // 添加 schema 级别的描述
179
+ if (schema.description) {
180
+ return result.describe(schema.description);
181
+ }
182
+
183
+ return result;
184
+ }
185
+
186
+ /**
187
+ * JSON Schema 属性转 Zod 类型
188
+ *
189
+ * 保留描述信息
190
+ */
191
+ function jsonSchemaToZod(prop: JSONSchema7, isOptional: boolean): z.ZodTypeAny {
192
+ const description = prop.description;
193
+ let baseType: z.ZodType;
194
+
195
+ // 处理 nullable
196
+ if (prop.nullable === true) {
197
+ const innerType = jsonSchemaToZod({ ...prop, nullable: undefined }, isOptional);
198
+ baseType = z.union([innerType, z.null()]);
199
+ if (description) {
200
+ return baseType.describe(description);
201
+ }
202
+ return baseType;
203
+ }
204
+
205
+ // 处理 anyOf/oneOf
206
+ if (prop.anyOf || prop.oneOf) {
207
+ const unions = prop.anyOf || prop.oneOf || [];
208
+ const zodUnions = unions
209
+ .map((s) => jsonSchemaToZod(s, false))
210
+ .filter((t) => t);
211
+ if (zodUnions.length > 0) {
212
+ baseType = z.union(zodUnions as any);
213
+ if (description) {
214
+ return baseType.describe(description);
215
+ }
216
+ return baseType;
217
+ }
218
+ }
219
+
220
+ // 处理 allOf
221
+ if (prop.allOf) {
222
+ const schemas: z.ZodTypeAny[] = [];
223
+ for (const subSchema of prop.allOf) {
224
+ const sub = jsonSchemaToZod(subSchema, false);
225
+ schemas.push(sub);
226
+ }
227
+ if (schemas.length === 1) {
228
+ baseType = schemas[0];
229
+ } else {
230
+ // 使用 intersect 组合
231
+ baseType = z.intersection(schemas[0] as z.ZodType<unknown>, schemas[1] as z.ZodType<unknown>);
232
+ for (let i = 2; i < schemas.length; i++) {
233
+ baseType = z.intersection(baseType, schemas[i] as z.ZodType<unknown>);
234
+ }
235
+ }
236
+ if (description) {
237
+ return baseType.describe(description);
238
+ }
239
+ return baseType;
240
+ }
241
+
242
+ // 获取类型(支持 type 或 types)
243
+ const types = prop.types || (prop.type ? [prop.type] : []);
244
+
245
+ // 处理多个类型
246
+ if (types.length > 1) {
247
+ const zodTypes = types
248
+ .map((t) => getZodTypeForBasicType(t, prop))
249
+ .filter((t) => t);
250
+ if (zodTypes.length > 0) {
251
+ baseType = z.union(zodTypes as any);
252
+ if (description) {
253
+ return baseType.describe(description);
254
+ }
255
+ return baseType;
256
+ }
257
+ }
258
+
259
+ // 单类型处理
260
+ const type = types[0];
261
+ if (!type) {
262
+ // 没有类型但有 enum
263
+ if (prop.enum) {
264
+ // handleEnum 内部会处理描述
265
+ return handleEnum(prop, description);
266
+ }
267
+ // 没有类型也没有 enum,返回 unknown
268
+ baseType = z.unknown();
269
+ if (description) {
270
+ return baseType.describe(description);
271
+ }
272
+ return baseType;
273
+ }
274
+
275
+ baseType = getZodTypeForBasicType(type, prop);
276
+
277
+ // 添加描述(但保留 handleEnum 已经添加的有效值描述)
278
+ if (description) {
279
+ // 检查 schema 是否有描述(来自 handleEnum)
280
+ const schemaDescription = (baseType as any)._def?.description;
281
+ if (schemaDescription) {
282
+ // 如果 schema 已有描述,说明是 enum,追加而不是覆盖
283
+ return baseType.describe(`${schemaDescription}. ${description}`);
284
+ }
285
+ return baseType.describe(description);
286
+ }
287
+
288
+ return baseType;
289
+ }
290
+
291
+ /**
292
+ * 根据基本类型获取 Zod 类型
293
+ * 注意:不处理描述,描述由调用方统一处理
294
+ */
295
+ function getZodTypeForBasicType(type: string, prop: JSONSchema7): z.ZodType {
296
+ switch (type) {
297
+ case "string": {
298
+ // 优先处理 enum - 使用 handleEnum 来确保添加有效值描述
299
+ if (prop.enum && prop.enum.length > 0 && prop.enum.every((v) => typeof v === "string")) {
300
+ // handleEnum 会自动添加有效值列表到描述
301
+ return handleEnum(prop, prop.description);
302
+ }
303
+
304
+ let schema = z.string();
305
+
306
+ // 处理 minLength
307
+ if (typeof prop.minLength === "number") {
308
+ schema = schema.min(prop.minLength);
309
+ }
310
+
311
+ // 处理 maxLength
312
+ if (typeof prop.maxLength === "number") {
313
+ schema = schema.max(prop.maxLength);
314
+ }
315
+
316
+ // 处理 pattern (正则)
317
+ if (prop.pattern) {
318
+ try {
319
+ schema = schema.regex(new RegExp(prop.pattern));
320
+ } catch {
321
+ // 无效的正则,忽略
322
+ }
323
+ }
324
+
325
+ // 处理 format - 添加到 schema 描述
326
+ if (prop.format) {
327
+ schema = schema.describe(`Format: ${prop.format}`);
328
+ }
329
+
330
+ // 处理 default
331
+ if (prop.default !== undefined) {
332
+ schema = schema.default(prop.default as string) as any;
333
+ }
334
+
335
+ return schema;
336
+ }
337
+
338
+ case "number":
339
+ case "integer": {
340
+ let schema = type === "integer" ? z.number().int() : z.number();
341
+
342
+ // 处理 minimum
343
+ if (typeof prop.minimum === "number") {
344
+ schema = schema.min(prop.minimum);
345
+ }
346
+
347
+ // 处理 maximum
348
+ if (typeof prop.maximum === "number") {
349
+ schema = schema.max(prop.maximum);
350
+ }
351
+
352
+ // 处理 default
353
+ if (prop.default !== undefined) {
354
+ schema = schema.default(prop.default as number) as any;
355
+ }
356
+
357
+ return schema;
358
+ }
359
+
360
+ case "boolean": {
361
+ let schema = z.boolean();
362
+ if (prop.default !== undefined) {
363
+ schema = schema.default(prop.default as boolean) as any;
364
+ }
365
+ return schema;
366
+ }
367
+
368
+ case "array": {
369
+ let itemSchema: z.ZodType = z.unknown();
370
+
371
+ if (prop.items) {
372
+ itemSchema = jsonSchemaToZod(prop.items as JSONSchema7, false);
373
+ }
374
+
375
+ let schema = z.array(itemSchema);
376
+
377
+ // 处理 additionalProperties 作为数组成员类型
378
+ if (prop.additionalProperties && typeof prop.additionalProperties !== "boolean") {
379
+ const additionalItems = jsonSchemaToZod(prop.additionalProperties, false);
380
+ // 混合数组
381
+ schema = z.array(z.union([itemSchema, additionalItems]) as any);
382
+ }
383
+
384
+ return schema;
385
+ }
386
+
387
+ case "object": {
388
+ if (prop.properties) {
389
+ const fields: Record<string, z.ZodType> = {};
390
+ const required = prop.required ?? [];
391
+
392
+ for (const [key, value] of Object.entries(prop.properties)) {
393
+ const isRequired = required.includes(key);
394
+ fields[key] = isRequired
395
+ ? jsonSchemaToZod(value as JSONSchema7, false)
396
+ : jsonSchemaToZod(value as JSONSchema7, true).optional();
397
+ }
398
+
399
+ return z.object(fields);
400
+ }
401
+
402
+ // 没有 properties,检查 additionalProperties
403
+ if (prop.additionalProperties) {
404
+ if (typeof prop.additionalProperties === "boolean") {
405
+ return z.record(z.string(), z.unknown());
406
+ }
407
+ return z.record(z.string(), jsonSchemaToZod(prop.additionalProperties, false));
408
+ }
409
+
410
+ return z.record(z.string(), z.unknown());
411
+ }
412
+
413
+ case "null":
414
+ return z.null();
415
+
416
+ case "null | string":
417
+ case "string | null":
418
+ return z.union([z.string(), z.null()]);
419
+
420
+ case "null | number":
421
+ case "number | null":
422
+ return z.union([z.number(), z.null()]);
423
+
424
+ default:
425
+ // 处理 enum
426
+ if (prop.enum) {
427
+ return handleEnum(prop);
428
+ }
429
+ return z.unknown();
430
+ }
431
+ }
432
+
433
+ /**
434
+ * 处理 enum 类型
435
+ *
436
+ * 关键改进:自动在描述中添加有效值列表,帮助 LLM 正确理解参数值
437
+ * 例如:enum: ["24h", "week", "month"] -> 描述变为 "Valid values: 24h, week, month"
438
+ */
439
+ function handleEnum(prop: JSONSchema7, existingDescription?: string): z.ZodType {
440
+ if (!prop.enum || prop.enum.length === 0) {
441
+ return z.unknown();
442
+ }
443
+
444
+ // 检查是否是字符串枚举
445
+ const stringValues = prop.enum.filter((v) => typeof v === "string") as string[];
446
+ if (stringValues.length === 0) {
447
+ return z.any();
448
+ }
449
+
450
+ let schema: z.ZodType;
451
+ if (stringValues.length === 1) {
452
+ schema = z.literal(stringValues[0]);
453
+ } else {
454
+ schema = z.enum([stringValues[0], ...stringValues.slice(1)]);
455
+ }
456
+
457
+ // 构建有效值描述
458
+ const valuesList = stringValues.map((v) => `"${v}"`).join(", ");
459
+ const valuesDescription = `Valid values: ${valuesList}`;
460
+
461
+ // 组合描述:如果有原始描述,追加有效值;如果没有,直接使用有效值
462
+ if (existingDescription) {
463
+ return schema.describe(`${existingDescription}. ${valuesDescription}`);
464
+ }
465
+ return schema.describe(valuesDescription);
466
+ }
467
+
468
+ /**
469
+ * 转换 MCP 调用结果为 ToolResult
470
+ */
471
+ function convertMcpCallResult(result: McpCallToolResult): ToolResult {
472
+ const content = result.content;
473
+ const textContent = content
474
+ ?.filter((c) => c.type === "text")
475
+ ?.map((c) => c.text)
476
+ ?.join("") ?? "";
477
+
478
+ return {
479
+ success: !result.isError,
480
+ output: textContent,
481
+ error: result.isError ? textContent : undefined,
482
+ };
483
+ }
484
+
485
+ /**
486
+ * 创建 MCP 工具描述
487
+ */
488
+ export function createMcpToolsDescription(tools: ToolInfo[]): string {
489
+ if (tools.length === 0) {
490
+ return " No MCP tools currently available.";
491
+ }
492
+
493
+ return tools
494
+ .map((t) => ` - ${t.name}: ${t.description}`)
495
+ .join("\n");
496
+ }
497
+
498
+ /**
499
+ * 获取工具的完整参数描述(供 LLM 使用)
500
+ *
501
+ * 从 Zod schema 中提取参数描述
502
+ */
503
+ export function getToolParamDescriptions(tool: ToolInfo): Record<string, string> {
504
+ const descriptions: Record<string, string> = {};
505
+
506
+ // 从 metadata 中获取原始 schema
507
+ const mcpMeta = tool.metadata?.mcpTool as {
508
+ inputSchema?: JSONSchema7;
509
+ } | undefined;
510
+
511
+ if (mcpMeta?.inputSchema?.properties) {
512
+ for (const [key, prop] of Object.entries(mcpMeta.inputSchema.properties)) {
513
+ const propSchema = prop as JSONSchema7;
514
+ if (propSchema.description) {
515
+ descriptions[key] = propSchema.description;
516
+ }
517
+ }
518
+ }
519
+
520
+ return descriptions;
521
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @fileoverview MCP Tool 适配器导出
3
+ */
4
+
5
+ export { adaptMcpTool, convertInputSchemaToZod, createMcpToolsDescription } from "./adapter";
@@ -0,0 +1,171 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { z } from "zod";
3
+ import {
4
+ McpServerLocalConfigSchema,
5
+ McpServerRemoteConfigSchema,
6
+ McpServerConfigSchema,
7
+ type DiscoveredMcpServer,
8
+ type McpServerStatus,
9
+ } from "./types";
10
+
11
+ /**
12
+ * TDD: 验证 MCP 类型定义
13
+ */
14
+
15
+ describe("McpServerLocalConfigSchema", () => {
16
+ it("should validate valid local server config", () => {
17
+ const localConfig = {
18
+ type: "local",
19
+ command: ["bun", "run", "server.ts"],
20
+ };
21
+
22
+ const result = McpServerLocalConfigSchema.safeParse(localConfig);
23
+ expect(result.success).toBe(true);
24
+ });
25
+
26
+ it("should accept optional fields", () => {
27
+ const localConfig = {
28
+ type: "local",
29
+ command: ["bun", "run", "server.ts"],
30
+ environment: { NODE_ENV: "production" },
31
+ enabled: true,
32
+ timeout: 60000,
33
+ };
34
+
35
+ const result = McpServerLocalConfigSchema.safeParse(localConfig);
36
+ expect(result.success).toBe(true);
37
+ });
38
+
39
+ it("should reject empty command", () => {
40
+ const localConfig = {
41
+ type: "local",
42
+ command: [],
43
+ };
44
+
45
+ const result = McpServerLocalConfigSchema.safeParse(localConfig);
46
+ expect(result.success).toBe(false);
47
+ });
48
+
49
+ it("should reject wrong type", () => {
50
+ const localConfig = {
51
+ type: "remote",
52
+ command: ["bun", "run", "server.ts"],
53
+ };
54
+
55
+ const result = McpServerLocalConfigSchema.safeParse(localConfig);
56
+ expect(result.success).toBe(false);
57
+ });
58
+ });
59
+
60
+ describe("McpServerRemoteConfigSchema", () => {
61
+ it("should validate valid remote server config", () => {
62
+ const remoteConfig = {
63
+ type: "remote",
64
+ url: "https://mcp.example.com",
65
+ };
66
+
67
+ const result = McpServerRemoteConfigSchema.safeParse(remoteConfig);
68
+ expect(result.success).toBe(true);
69
+ });
70
+
71
+ it("should accept optional headers", () => {
72
+ const remoteConfig = {
73
+ type: "remote",
74
+ url: "https://mcp.example.com",
75
+ headers: { Authorization: "Bearer token" },
76
+ };
77
+
78
+ const result = McpServerRemoteConfigSchema.safeParse(remoteConfig);
79
+ expect(result.success).toBe(true);
80
+ });
81
+
82
+ it("should reject invalid url", () => {
83
+ const remoteConfig = {
84
+ type: "remote",
85
+ url: "not-a-url",
86
+ };
87
+
88
+ const result = McpServerRemoteConfigSchema.safeParse(remoteConfig);
89
+ expect(result.success).toBe(false);
90
+ });
91
+ });
92
+
93
+ describe("McpServerConfigSchema", () => {
94
+ it("should validate local config", () => {
95
+ const config = {
96
+ type: "local",
97
+ command: ["bun", "run", "server.ts"],
98
+ };
99
+
100
+ const result = McpServerConfigSchema.safeParse(config);
101
+ expect(result.success).toBe(true);
102
+ });
103
+
104
+ it("should validate remote config", () => {
105
+ const config = {
106
+ type: "remote",
107
+ url: "https://mcp.example.com",
108
+ };
109
+
110
+ const result = McpServerConfigSchema.safeParse(config);
111
+ expect(result.success).toBe(true);
112
+ });
113
+
114
+ it("should reject invalid discriminated union", () => {
115
+ const config = {
116
+ type: "invalid",
117
+ };
118
+
119
+ const result = McpServerConfigSchema.safeParse(config);
120
+ expect(result.success).toBe(false);
121
+ });
122
+ });
123
+
124
+ describe("DiscoveredMcpServer", () => {
125
+ it("should have required name field", () => {
126
+ const server: DiscoveredMcpServer = {
127
+ name: "test-mcp",
128
+ };
129
+
130
+ expect(server.name).toBe("test-mcp");
131
+ expect(server.entryPath).toBeUndefined();
132
+ });
133
+
134
+ it("should allow optional fields", () => {
135
+ const server: DiscoveredMcpServer = {
136
+ name: "test-mcp",
137
+ entryPath: "/path/to/server.ts",
138
+ configPath: "/path/to/config.jsonc",
139
+ packagePath: "/path/to/package.json",
140
+ directoryConfig: { enabled: true },
141
+ };
142
+
143
+ expect(server.entryPath).toBe("/path/to/server.ts");
144
+ expect(server.directoryConfig?.enabled).toBe(true);
145
+ });
146
+ });
147
+
148
+ describe("McpServerStatus", () => {
149
+ it("should have required fields", () => {
150
+ const status: McpServerStatus = {
151
+ name: "test-server",
152
+ status: "connected",
153
+ };
154
+
155
+ expect(status.name).toBe("test-server");
156
+ expect(status.status).toBe("connected");
157
+ });
158
+
159
+ it("should allow optional fields", () => {
160
+ const status: McpServerStatus = {
161
+ name: "test-server",
162
+ status: "error",
163
+ error: "Connection failed",
164
+ toolsCount: 5,
165
+ };
166
+
167
+ expect(status.status).toBe("error");
168
+ expect(status.error).toBe("Connection failed");
169
+ expect(status.toolsCount).toBe(5);
170
+ });
171
+ });