@syrin/cli 1.3.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 (438) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +302 -0
  3. package/dist/cli/commands/analyse.d.ts +16 -0
  4. package/dist/cli/commands/analyse.js +61 -0
  5. package/dist/cli/commands/dev.d.ts +23 -0
  6. package/dist/cli/commands/dev.js +419 -0
  7. package/dist/cli/commands/doctor.d.ts +10 -0
  8. package/dist/cli/commands/doctor.js +195 -0
  9. package/dist/cli/commands/index.d.ts +12 -0
  10. package/dist/cli/commands/index.js +12 -0
  11. package/dist/cli/commands/init.d.ts +16 -0
  12. package/dist/cli/commands/init.js +90 -0
  13. package/dist/cli/commands/list.d.ts +15 -0
  14. package/dist/cli/commands/list.js +50 -0
  15. package/dist/cli/commands/rollback.d.ts +12 -0
  16. package/dist/cli/commands/rollback.js +101 -0
  17. package/dist/cli/commands/test.d.ts +31 -0
  18. package/dist/cli/commands/test.js +88 -0
  19. package/dist/cli/commands/update.d.ts +9 -0
  20. package/dist/cli/commands/update.js +76 -0
  21. package/dist/cli/index.d.ts +13 -0
  22. package/dist/cli/index.js +342 -0
  23. package/dist/cli/prompts/index.d.ts +5 -0
  24. package/dist/cli/prompts/index.js +5 -0
  25. package/dist/cli/prompts/init-prompt.d.ts +17 -0
  26. package/dist/cli/prompts/init-prompt.js +263 -0
  27. package/dist/cli/utils/command-error-handler.d.ts +14 -0
  28. package/dist/cli/utils/command-error-handler.js +35 -0
  29. package/dist/cli/utils/common-types.d.ts +24 -0
  30. package/dist/cli/utils/common-types.js +6 -0
  31. package/dist/cli/utils/connection-handler.d.ts +37 -0
  32. package/dist/cli/utils/connection-handler.js +90 -0
  33. package/dist/cli/utils/index.d.ts +11 -0
  34. package/dist/cli/utils/index.js +11 -0
  35. package/dist/cli/utils/option-parsers.d.ts +41 -0
  36. package/dist/cli/utils/option-parsers.js +92 -0
  37. package/dist/cli/utils/output-utils.d.ts +12 -0
  38. package/dist/cli/utils/output-utils.js +21 -0
  39. package/dist/cli/utils/transport-resolver.d.ts +33 -0
  40. package/dist/cli/utils/transport-resolver.js +82 -0
  41. package/dist/cli/utils/version-banner.d.ts +10 -0
  42. package/dist/cli/utils/version-banner.js +26 -0
  43. package/dist/config/env-checker.d.ts +37 -0
  44. package/dist/config/env-checker.js +136 -0
  45. package/dist/config/generator.d.ts +19 -0
  46. package/dist/config/generator.js +196 -0
  47. package/dist/config/index.d.ts +9 -0
  48. package/dist/config/index.js +9 -0
  49. package/dist/config/loader.d.ts +19 -0
  50. package/dist/config/loader.js +57 -0
  51. package/dist/config/schema.d.ts +42 -0
  52. package/dist/config/schema.js +181 -0
  53. package/dist/config/syrin.template.yaml +127 -0
  54. package/dist/config/types.d.ts +87 -0
  55. package/dist/config/types.js +6 -0
  56. package/dist/constants/app.d.ts +9 -0
  57. package/dist/constants/app.js +9 -0
  58. package/dist/constants/commands.d.ts +43 -0
  59. package/dist/constants/commands.js +43 -0
  60. package/dist/constants/defaults.d.ts +18 -0
  61. package/dist/constants/defaults.js +18 -0
  62. package/dist/constants/env-vars.d.ts +11 -0
  63. package/dist/constants/env-vars.js +11 -0
  64. package/dist/constants/icons.d.ts +23 -0
  65. package/dist/constants/icons.js +23 -0
  66. package/dist/constants/index.d.ts +17 -0
  67. package/dist/constants/index.js +17 -0
  68. package/dist/constants/labels.d.ts +38 -0
  69. package/dist/constants/labels.js +42 -0
  70. package/dist/constants/links.d.ts +10 -0
  71. package/dist/constants/links.js +11 -0
  72. package/dist/constants/list.d.ts +10 -0
  73. package/dist/constants/list.js +9 -0
  74. package/dist/constants/llm.d.ts +26 -0
  75. package/dist/constants/llm.js +25 -0
  76. package/dist/constants/messages.d.ts +107 -0
  77. package/dist/constants/messages.js +138 -0
  78. package/dist/constants/paths.d.ts +29 -0
  79. package/dist/constants/paths.js +29 -0
  80. package/dist/constants/transport.d.ts +9 -0
  81. package/dist/constants/transport.js +8 -0
  82. package/dist/events/emitter.d.ts +64 -0
  83. package/dist/events/emitter.js +142 -0
  84. package/dist/events/event-type.d.ts +66 -0
  85. package/dist/events/event-type.js +81 -0
  86. package/dist/events/payloads/diagnostics.d.ts +24 -0
  87. package/dist/events/payloads/diagnostics.js +5 -0
  88. package/dist/events/payloads/index.d.ts +15 -0
  89. package/dist/events/payloads/index.js +6 -0
  90. package/dist/events/payloads/llm.d.ts +58 -0
  91. package/dist/events/payloads/llm.js +6 -0
  92. package/dist/events/payloads/registry.d.ts +28 -0
  93. package/dist/events/payloads/registry.js +5 -0
  94. package/dist/events/payloads/session.d.ts +32 -0
  95. package/dist/events/payloads/session.js +5 -0
  96. package/dist/events/payloads/testing.d.ts +17 -0
  97. package/dist/events/payloads/testing.js +5 -0
  98. package/dist/events/payloads/tool.d.ts +29 -0
  99. package/dist/events/payloads/tool.js +5 -0
  100. package/dist/events/payloads/transport.d.ts +30 -0
  101. package/dist/events/payloads/transport.js +5 -0
  102. package/dist/events/payloads/validation.d.ts +37 -0
  103. package/dist/events/payloads/validation.js +5 -0
  104. package/dist/events/payloads/workflow.d.ts +45 -0
  105. package/dist/events/payloads/workflow.js +5 -0
  106. package/dist/events/store/file-store.d.ts +37 -0
  107. package/dist/events/store/file-store.js +113 -0
  108. package/dist/events/store/index.d.ts +7 -0
  109. package/dist/events/store/index.js +6 -0
  110. package/dist/events/store/memory-store.d.ts +26 -0
  111. package/dist/events/store/memory-store.js +39 -0
  112. package/dist/events/store.d.ts +11 -0
  113. package/dist/events/store.js +2 -0
  114. package/dist/events/types.d.ts +14 -0
  115. package/dist/events/types.js +2 -0
  116. package/dist/index.d.ts +8 -0
  117. package/dist/index.js +30 -0
  118. package/dist/presentation/analysis-ui.d.ts +24 -0
  119. package/dist/presentation/analysis-ui.js +158 -0
  120. package/dist/presentation/dev/chat-ui-types.d.ts +68 -0
  121. package/dist/presentation/dev/chat-ui-types.js +5 -0
  122. package/dist/presentation/dev/chat-ui.d.ts +61 -0
  123. package/dist/presentation/dev/chat-ui.js +714 -0
  124. package/dist/presentation/dev/components/assistant-message.d.ts +19 -0
  125. package/dist/presentation/dev/components/assistant-message.js +36 -0
  126. package/dist/presentation/dev/components/header.d.ts +16 -0
  127. package/dist/presentation/dev/components/header.js +22 -0
  128. package/dist/presentation/dev/components/index.d.ts +13 -0
  129. package/dist/presentation/dev/components/index.js +13 -0
  130. package/dist/presentation/dev/components/input-panel.d.ts +22 -0
  131. package/dist/presentation/dev/components/input-panel.js +43 -0
  132. package/dist/presentation/dev/components/message-component.d.ts +16 -0
  133. package/dist/presentation/dev/components/message-component.js +51 -0
  134. package/dist/presentation/dev/components/messages-list.d.ts +24 -0
  135. package/dist/presentation/dev/components/messages-list.js +48 -0
  136. package/dist/presentation/dev/components/system-message.d.ts +16 -0
  137. package/dist/presentation/dev/components/system-message.js +26 -0
  138. package/dist/presentation/dev/components/user-message.d.ts +21 -0
  139. package/dist/presentation/dev/components/user-message.js +35 -0
  140. package/dist/presentation/dev/components/welcome-banner.d.ts +24 -0
  141. package/dist/presentation/dev/components/welcome-banner.js +146 -0
  142. package/dist/presentation/dev/goodbye-messages.d.ts +31 -0
  143. package/dist/presentation/dev/goodbye-messages.js +100 -0
  144. package/dist/presentation/dev/index.d.ts +5 -0
  145. package/dist/presentation/dev/index.js +5 -0
  146. package/dist/presentation/dev/text-wrapper.d.ts +30 -0
  147. package/dist/presentation/dev/text-wrapper.js +74 -0
  148. package/dist/presentation/dev-ui.d.ts +33 -0
  149. package/dist/presentation/dev-ui.js +246 -0
  150. package/dist/presentation/doctor-ui.d.ts +40 -0
  151. package/dist/presentation/doctor-ui.js +157 -0
  152. package/dist/presentation/init-ui.d.ts +14 -0
  153. package/dist/presentation/init-ui.js +41 -0
  154. package/dist/presentation/list-ui.d.ts +44 -0
  155. package/dist/presentation/list-ui.js +139 -0
  156. package/dist/presentation/test-ui.d.ts +49 -0
  157. package/dist/presentation/test-ui.js +358 -0
  158. package/dist/runtime/analysis/analyser.d.ts +14 -0
  159. package/dist/runtime/analysis/analyser.js +88 -0
  160. package/dist/runtime/analysis/dependencies.d.ts +10 -0
  161. package/dist/runtime/analysis/dependencies.js +140 -0
  162. package/dist/runtime/analysis/index.d.ts +10 -0
  163. package/dist/runtime/analysis/index.js +10 -0
  164. package/dist/runtime/analysis/indexer.d.ts +10 -0
  165. package/dist/runtime/analysis/indexer.js +62 -0
  166. package/dist/runtime/analysis/loader.d.ts +15 -0
  167. package/dist/runtime/analysis/loader.js +47 -0
  168. package/dist/runtime/analysis/normalizer.d.ts +14 -0
  169. package/dist/runtime/analysis/normalizer.js +184 -0
  170. package/dist/runtime/analysis/rules/__test-helpers__.d.ts +18 -0
  171. package/dist/runtime/analysis/rules/__test-helpers__.js +40 -0
  172. package/dist/runtime/analysis/rules/base.d.ts +38 -0
  173. package/dist/runtime/analysis/rules/base.js +23 -0
  174. package/dist/runtime/analysis/rules/error-codes.d.ts +64 -0
  175. package/dist/runtime/analysis/rules/error-codes.js +73 -0
  176. package/dist/runtime/analysis/rules/errors/e000-tool-not-found.d.ts +35 -0
  177. package/dist/runtime/analysis/rules/errors/e000-tool-not-found.js +32 -0
  178. package/dist/runtime/analysis/rules/errors/e001-missing-output-schema.d.ts +22 -0
  179. package/dist/runtime/analysis/rules/errors/e001-missing-output-schema.js +30 -0
  180. package/dist/runtime/analysis/rules/errors/e002-underspecified-input.d.ts +24 -0
  181. package/dist/runtime/analysis/rules/errors/e002-underspecified-input.js +52 -0
  182. package/dist/runtime/analysis/rules/errors/e003-type-mismatch.d.ts +23 -0
  183. package/dist/runtime/analysis/rules/errors/e003-type-mismatch.js +73 -0
  184. package/dist/runtime/analysis/rules/errors/e004-free-text-propagation.d.ts +23 -0
  185. package/dist/runtime/analysis/rules/errors/e004-free-text-propagation.js +47 -0
  186. package/dist/runtime/analysis/rules/errors/e005-tool-ambiguity.d.ts +25 -0
  187. package/dist/runtime/analysis/rules/errors/e005-tool-ambiguity.js +73 -0
  188. package/dist/runtime/analysis/rules/errors/e006-param-not-in-description.d.ts +22 -0
  189. package/dist/runtime/analysis/rules/errors/e006-param-not-in-description.js +57 -0
  190. package/dist/runtime/analysis/rules/errors/e007-output-not-guaranteed.d.ts +23 -0
  191. package/dist/runtime/analysis/rules/errors/e007-output-not-guaranteed.js +56 -0
  192. package/dist/runtime/analysis/rules/errors/e008-circular-dependency.d.ts +22 -0
  193. package/dist/runtime/analysis/rules/errors/e008-circular-dependency.js +84 -0
  194. package/dist/runtime/analysis/rules/errors/e009-implicit-user-input.d.ts +23 -0
  195. package/dist/runtime/analysis/rules/errors/e009-implicit-user-input.js +89 -0
  196. package/dist/runtime/analysis/rules/errors/e010-non-serializable.d.ts +25 -0
  197. package/dist/runtime/analysis/rules/errors/e010-non-serializable.js +46 -0
  198. package/dist/runtime/analysis/rules/errors/e011-missing-tool-description.d.ts +24 -0
  199. package/dist/runtime/analysis/rules/errors/e011-missing-tool-description.js +33 -0
  200. package/dist/runtime/analysis/rules/errors/e012-side-effect-detected.d.ts +39 -0
  201. package/dist/runtime/analysis/rules/errors/e012-side-effect-detected.js +40 -0
  202. package/dist/runtime/analysis/rules/errors/e013-non-deterministic-output.d.ts +37 -0
  203. package/dist/runtime/analysis/rules/errors/e013-non-deterministic-output.js +34 -0
  204. package/dist/runtime/analysis/rules/errors/e013-output-explosion.d.ts +39 -0
  205. package/dist/runtime/analysis/rules/errors/e013-output-explosion.js +36 -0
  206. package/dist/runtime/analysis/rules/errors/e014-hidden-dependency.d.ts +42 -0
  207. package/dist/runtime/analysis/rules/errors/e014-hidden-dependency.js +46 -0
  208. package/dist/runtime/analysis/rules/errors/e014-output-explosion.d.ts +39 -0
  209. package/dist/runtime/analysis/rules/errors/e014-output-explosion.js +36 -0
  210. package/dist/runtime/analysis/rules/errors/e015-hidden-dependency.d.ts +42 -0
  211. package/dist/runtime/analysis/rules/errors/e015-hidden-dependency.js +46 -0
  212. package/dist/runtime/analysis/rules/errors/e015-unbounded-execution.d.ts +44 -0
  213. package/dist/runtime/analysis/rules/errors/e015-unbounded-execution.js +66 -0
  214. package/dist/runtime/analysis/rules/errors/e016-output-validation-failed.d.ts +43 -0
  215. package/dist/runtime/analysis/rules/errors/e016-output-validation-failed.js +42 -0
  216. package/dist/runtime/analysis/rules/errors/e016-unbounded-execution.d.ts +44 -0
  217. package/dist/runtime/analysis/rules/errors/e016-unbounded-execution.js +66 -0
  218. package/dist/runtime/analysis/rules/errors/e017-input-validation-failed.d.ts +57 -0
  219. package/dist/runtime/analysis/rules/errors/e017-input-validation-failed.js +80 -0
  220. package/dist/runtime/analysis/rules/errors/e017-output-validation-failed.d.ts +43 -0
  221. package/dist/runtime/analysis/rules/errors/e017-output-validation-failed.js +42 -0
  222. package/dist/runtime/analysis/rules/errors/e018-input-validation-failed.d.ts +57 -0
  223. package/dist/runtime/analysis/rules/errors/e018-input-validation-failed.js +80 -0
  224. package/dist/runtime/analysis/rules/errors/e018-tool-execution-failed.d.ts +38 -0
  225. package/dist/runtime/analysis/rules/errors/e018-tool-execution-failed.js +37 -0
  226. package/dist/runtime/analysis/rules/errors/e019-tool-execution-failed.d.ts +38 -0
  227. package/dist/runtime/analysis/rules/errors/e019-tool-execution-failed.js +37 -0
  228. package/dist/runtime/analysis/rules/errors/e019-unexpected-test-result.d.ts +65 -0
  229. package/dist/runtime/analysis/rules/errors/e019-unexpected-test-result.js +109 -0
  230. package/dist/runtime/analysis/rules/errors/e020-unexpected-test-result.d.ts +65 -0
  231. package/dist/runtime/analysis/rules/errors/e020-unexpected-test-result.js +109 -0
  232. package/dist/runtime/analysis/rules/errors/e100-missing-output-schema.d.ts +22 -0
  233. package/dist/runtime/analysis/rules/errors/e100-missing-output-schema.js +30 -0
  234. package/dist/runtime/analysis/rules/errors/e101-missing-tool-description.d.ts +24 -0
  235. package/dist/runtime/analysis/rules/errors/e101-missing-tool-description.js +33 -0
  236. package/dist/runtime/analysis/rules/errors/e102-underspecified-input.d.ts +24 -0
  237. package/dist/runtime/analysis/rules/errors/e102-underspecified-input.js +52 -0
  238. package/dist/runtime/analysis/rules/errors/e103-type-mismatch.d.ts +23 -0
  239. package/dist/runtime/analysis/rules/errors/e103-type-mismatch.js +72 -0
  240. package/dist/runtime/analysis/rules/errors/e104-param-not-in-description.d.ts +22 -0
  241. package/dist/runtime/analysis/rules/errors/e104-param-not-in-description.js +57 -0
  242. package/dist/runtime/analysis/rules/errors/e105-free-text-propagation.d.ts +23 -0
  243. package/dist/runtime/analysis/rules/errors/e105-free-text-propagation.js +47 -0
  244. package/dist/runtime/analysis/rules/errors/e106-output-not-guaranteed.d.ts +23 -0
  245. package/dist/runtime/analysis/rules/errors/e106-output-not-guaranteed.js +58 -0
  246. package/dist/runtime/analysis/rules/errors/e107-circular-dependency.d.ts +22 -0
  247. package/dist/runtime/analysis/rules/errors/e107-circular-dependency.js +84 -0
  248. package/dist/runtime/analysis/rules/errors/e108-implicit-user-input.d.ts +23 -0
  249. package/dist/runtime/analysis/rules/errors/e108-implicit-user-input.js +94 -0
  250. package/dist/runtime/analysis/rules/errors/e109-non-serializable.d.ts +25 -0
  251. package/dist/runtime/analysis/rules/errors/e109-non-serializable.js +44 -0
  252. package/dist/runtime/analysis/rules/errors/e110-tool-ambiguity.d.ts +25 -0
  253. package/dist/runtime/analysis/rules/errors/e110-tool-ambiguity.js +73 -0
  254. package/dist/runtime/analysis/rules/errors/e200-input-validation-failed.d.ts +57 -0
  255. package/dist/runtime/analysis/rules/errors/e200-input-validation-failed.js +71 -0
  256. package/dist/runtime/analysis/rules/errors/e300-output-validation-failed.d.ts +43 -0
  257. package/dist/runtime/analysis/rules/errors/e300-output-validation-failed.js +44 -0
  258. package/dist/runtime/analysis/rules/errors/e301-output-explosion.d.ts +39 -0
  259. package/dist/runtime/analysis/rules/errors/e301-output-explosion.js +36 -0
  260. package/dist/runtime/analysis/rules/errors/e400-tool-execution-failed.d.ts +38 -0
  261. package/dist/runtime/analysis/rules/errors/e400-tool-execution-failed.js +37 -0
  262. package/dist/runtime/analysis/rules/errors/e403-unbounded-execution.d.ts +44 -0
  263. package/dist/runtime/analysis/rules/errors/e403-unbounded-execution.js +66 -0
  264. package/dist/runtime/analysis/rules/errors/e500-side-effect-detected.d.ts +39 -0
  265. package/dist/runtime/analysis/rules/errors/e500-side-effect-detected.js +40 -0
  266. package/dist/runtime/analysis/rules/errors/e501-hidden-dependency.d.ts +47 -0
  267. package/dist/runtime/analysis/rules/errors/e501-hidden-dependency.js +46 -0
  268. package/dist/runtime/analysis/rules/errors/e600-unexpected-test-result.d.ts +65 -0
  269. package/dist/runtime/analysis/rules/errors/e600-unexpected-test-result.js +109 -0
  270. package/dist/runtime/analysis/rules/index.d.ts +18 -0
  271. package/dist/runtime/analysis/rules/index.js +94 -0
  272. package/dist/runtime/analysis/rules/warnings/w001-implicit-dependency.d.ts +22 -0
  273. package/dist/runtime/analysis/rules/warnings/w001-implicit-dependency.js +39 -0
  274. package/dist/runtime/analysis/rules/warnings/w002-free-text-without-normalization.d.ts +24 -0
  275. package/dist/runtime/analysis/rules/warnings/w002-free-text-without-normalization.js +40 -0
  276. package/dist/runtime/analysis/rules/warnings/w003-missing-examples.d.ts +22 -0
  277. package/dist/runtime/analysis/rules/warnings/w003-missing-examples.js +84 -0
  278. package/dist/runtime/analysis/rules/warnings/w004-overloaded-responsibility.d.ts +23 -0
  279. package/dist/runtime/analysis/rules/warnings/w004-overloaded-responsibility.js +96 -0
  280. package/dist/runtime/analysis/rules/warnings/w005-generic-description.d.ts +53 -0
  281. package/dist/runtime/analysis/rules/warnings/w005-generic-description.js +108 -0
  282. package/dist/runtime/analysis/rules/warnings/w006-optional-as-required.d.ts +22 -0
  283. package/dist/runtime/analysis/rules/warnings/w006-optional-as-required.js +44 -0
  284. package/dist/runtime/analysis/rules/warnings/w007-broad-output-schema.d.ts +23 -0
  285. package/dist/runtime/analysis/rules/warnings/w007-broad-output-schema.js +37 -0
  286. package/dist/runtime/analysis/rules/warnings/w008-multiple-entry-points.d.ts +22 -0
  287. package/dist/runtime/analysis/rules/warnings/w008-multiple-entry-points.js +97 -0
  288. package/dist/runtime/analysis/rules/warnings/w009-hidden-side-effects.d.ts +23 -0
  289. package/dist/runtime/analysis/rules/warnings/w009-hidden-side-effects.js +88 -0
  290. package/dist/runtime/analysis/rules/warnings/w010-output-not-reusable.d.ts +22 -0
  291. package/dist/runtime/analysis/rules/warnings/w010-output-not-reusable.js +81 -0
  292. package/dist/runtime/analysis/rules/warnings/w021-weak-schema.d.ts +40 -0
  293. package/dist/runtime/analysis/rules/warnings/w021-weak-schema.js +32 -0
  294. package/dist/runtime/analysis/rules/warnings/w022-high-entropy-output.d.ts +39 -0
  295. package/dist/runtime/analysis/rules/warnings/w022-high-entropy-output.js +36 -0
  296. package/dist/runtime/analysis/rules/warnings/w023-unstable-defaults.d.ts +38 -0
  297. package/dist/runtime/analysis/rules/warnings/w023-unstable-defaults.js +36 -0
  298. package/dist/runtime/analysis/rules/warnings/w100-implicit-dependency.d.ts +22 -0
  299. package/dist/runtime/analysis/rules/warnings/w100-implicit-dependency.js +89 -0
  300. package/dist/runtime/analysis/rules/warnings/w101-free-text-without-normalization.d.ts +24 -0
  301. package/dist/runtime/analysis/rules/warnings/w101-free-text-without-normalization.js +40 -0
  302. package/dist/runtime/analysis/rules/warnings/w102-missing-examples.d.ts +22 -0
  303. package/dist/runtime/analysis/rules/warnings/w102-missing-examples.js +76 -0
  304. package/dist/runtime/analysis/rules/warnings/w103-overloaded-responsibility.d.ts +23 -0
  305. package/dist/runtime/analysis/rules/warnings/w103-overloaded-responsibility.js +91 -0
  306. package/dist/runtime/analysis/rules/warnings/w104-generic-description.d.ts +53 -0
  307. package/dist/runtime/analysis/rules/warnings/w104-generic-description.js +108 -0
  308. package/dist/runtime/analysis/rules/warnings/w105-optional-as-required.d.ts +22 -0
  309. package/dist/runtime/analysis/rules/warnings/w105-optional-as-required.js +45 -0
  310. package/dist/runtime/analysis/rules/warnings/w106-broad-output-schema.d.ts +23 -0
  311. package/dist/runtime/analysis/rules/warnings/w106-broad-output-schema.js +37 -0
  312. package/dist/runtime/analysis/rules/warnings/w107-multiple-entry-points.d.ts +22 -0
  313. package/dist/runtime/analysis/rules/warnings/w107-multiple-entry-points.js +97 -0
  314. package/dist/runtime/analysis/rules/warnings/w108-hidden-side-effects.d.ts +23 -0
  315. package/dist/runtime/analysis/rules/warnings/w108-hidden-side-effects.js +94 -0
  316. package/dist/runtime/analysis/rules/warnings/w109-output-not-reusable.d.ts +22 -0
  317. package/dist/runtime/analysis/rules/warnings/w109-output-not-reusable.js +63 -0
  318. package/dist/runtime/analysis/rules/warnings/w110-weak-schema.d.ts +40 -0
  319. package/dist/runtime/analysis/rules/warnings/w110-weak-schema.js +32 -0
  320. package/dist/runtime/analysis/rules/warnings/w300-high-entropy-output.d.ts +39 -0
  321. package/dist/runtime/analysis/rules/warnings/w300-high-entropy-output.js +47 -0
  322. package/dist/runtime/analysis/rules/warnings/w301-unstable-defaults.d.ts +38 -0
  323. package/dist/runtime/analysis/rules/warnings/w301-unstable-defaults.js +36 -0
  324. package/dist/runtime/analysis/strict-mode.d.ts +21 -0
  325. package/dist/runtime/analysis/strict-mode.js +44 -0
  326. package/dist/runtime/analysis/types.d.ts +133 -0
  327. package/dist/runtime/analysis/types.js +6 -0
  328. package/dist/runtime/analysis/utils.d.ts +19 -0
  329. package/dist/runtime/analysis/utils.js +21 -0
  330. package/dist/runtime/dev/data-manager.d.ts +55 -0
  331. package/dist/runtime/dev/data-manager.js +87 -0
  332. package/dist/runtime/dev/event-mapper.d.ts +100 -0
  333. package/dist/runtime/dev/event-mapper.js +400 -0
  334. package/dist/runtime/dev/formatter.d.ts +94 -0
  335. package/dist/runtime/dev/formatter.js +236 -0
  336. package/dist/runtime/dev/index.d.ts +9 -0
  337. package/dist/runtime/dev/index.js +9 -0
  338. package/dist/runtime/dev/repl.d.ts +114 -0
  339. package/dist/runtime/dev/repl.js +310 -0
  340. package/dist/runtime/dev/session.d.ts +86 -0
  341. package/dist/runtime/dev/session.js +447 -0
  342. package/dist/runtime/dev/stack-trace.d.ts +77 -0
  343. package/dist/runtime/dev/stack-trace.js +286 -0
  344. package/dist/runtime/dev/types.d.ts +54 -0
  345. package/dist/runtime/dev/types.js +5 -0
  346. package/dist/runtime/llm/claude.d.ts +27 -0
  347. package/dist/runtime/llm/claude.js +150 -0
  348. package/dist/runtime/llm/factory.d.ts +30 -0
  349. package/dist/runtime/llm/factory.js +78 -0
  350. package/dist/runtime/llm/index.d.ts +10 -0
  351. package/dist/runtime/llm/index.js +10 -0
  352. package/dist/runtime/llm/ollama.d.ts +45 -0
  353. package/dist/runtime/llm/ollama.js +449 -0
  354. package/dist/runtime/llm/openai.d.ts +27 -0
  355. package/dist/runtime/llm/openai.js +170 -0
  356. package/dist/runtime/llm/provider.d.ts +32 -0
  357. package/dist/runtime/llm/provider.js +6 -0
  358. package/dist/runtime/llm/types.d.ts +55 -0
  359. package/dist/runtime/llm/types.js +6 -0
  360. package/dist/runtime/mcp/client/base.d.ts +40 -0
  361. package/dist/runtime/mcp/client/base.js +157 -0
  362. package/dist/runtime/mcp/client/manager.d.ts +91 -0
  363. package/dist/runtime/mcp/client/manager.js +248 -0
  364. package/dist/runtime/mcp/client/process.d.ts +31 -0
  365. package/dist/runtime/mcp/client/process.js +82 -0
  366. package/dist/runtime/mcp/connection.d.ts +63 -0
  367. package/dist/runtime/mcp/connection.js +449 -0
  368. package/dist/runtime/mcp/index.d.ts +9 -0
  369. package/dist/runtime/mcp/index.js +9 -0
  370. package/dist/runtime/mcp/list.d.ts +50 -0
  371. package/dist/runtime/mcp/list.js +65 -0
  372. package/dist/runtime/mcp/stdio-transport.d.ts +23 -0
  373. package/dist/runtime/mcp/stdio-transport.js +71 -0
  374. package/dist/runtime/mcp/types.d.ts +85 -0
  375. package/dist/runtime/mcp/types.js +6 -0
  376. package/dist/runtime/sandbox/executor.d.ts +102 -0
  377. package/dist/runtime/sandbox/executor.js +537 -0
  378. package/dist/runtime/sandbox/index.d.ts +9 -0
  379. package/dist/runtime/sandbox/index.js +9 -0
  380. package/dist/runtime/sandbox/io-monitor.d.ts +78 -0
  381. package/dist/runtime/sandbox/io-monitor.js +98 -0
  382. package/dist/runtime/sandbox/time-parser.d.ts +19 -0
  383. package/dist/runtime/sandbox/time-parser.js +67 -0
  384. package/dist/runtime/sandbox/types.d.ts +58 -0
  385. package/dist/runtime/sandbox/types.js +23 -0
  386. package/dist/runtime/test/behavior-observer.d.ts +61 -0
  387. package/dist/runtime/test/behavior-observer.js +140 -0
  388. package/dist/runtime/test/contract-loader.d.ts +41 -0
  389. package/dist/runtime/test/contract-loader.js +158 -0
  390. package/dist/runtime/test/contract-schema.d.ts +46 -0
  391. package/dist/runtime/test/contract-schema.js +107 -0
  392. package/dist/runtime/test/contract-types.d.ts +106 -0
  393. package/dist/runtime/test/contract-types.js +6 -0
  394. package/dist/runtime/test/dependency-tracker.d.ts +66 -0
  395. package/dist/runtime/test/dependency-tracker.js +80 -0
  396. package/dist/runtime/test/formatters.d.ts +18 -0
  397. package/dist/runtime/test/formatters.js +172 -0
  398. package/dist/runtime/test/index.d.ts +12 -0
  399. package/dist/runtime/test/index.js +13 -0
  400. package/dist/runtime/test/input-generator.d.ts +33 -0
  401. package/dist/runtime/test/input-generator.js +498 -0
  402. package/dist/runtime/test/mcp-root-detector.d.ts +31 -0
  403. package/dist/runtime/test/mcp-root-detector.js +105 -0
  404. package/dist/runtime/test/orchestrator.d.ts +131 -0
  405. package/dist/runtime/test/orchestrator.js +738 -0
  406. package/dist/runtime/test/output-validator.d.ts +44 -0
  407. package/dist/runtime/test/output-validator.js +262 -0
  408. package/dist/runtime/test/retry-tester.d.ts +44 -0
  409. package/dist/runtime/test/retry-tester.js +103 -0
  410. package/dist/runtime/test/runner.d.ts +28 -0
  411. package/dist/runtime/test/runner.js +55 -0
  412. package/dist/runtime/test/synthetic-input-generator.d.ts +11 -0
  413. package/dist/runtime/test/synthetic-input-generator.js +154 -0
  414. package/dist/runtime/test/test-runner.d.ts +28 -0
  415. package/dist/runtime/test/test-runner.js +55 -0
  416. package/dist/types/factories.d.ts +16 -0
  417. package/dist/types/factories.js +43 -0
  418. package/dist/types/ids.d.ts +16 -0
  419. package/dist/types/ids.js +2 -0
  420. package/dist/types/opaque.d.ts +4 -0
  421. package/dist/types/opaque.js +2 -0
  422. package/dist/utils/errors.d.ts +92 -0
  423. package/dist/utils/errors.js +97 -0
  424. package/dist/utils/gitignore.d.ts +11 -0
  425. package/dist/utils/gitignore.js +59 -0
  426. package/dist/utils/json-file-saver.d.ts +17 -0
  427. package/dist/utils/json-file-saver.js +81 -0
  428. package/dist/utils/json-formatter.d.ts +63 -0
  429. package/dist/utils/json-formatter.js +344 -0
  430. package/dist/utils/logger.d.ts +184 -0
  431. package/dist/utils/logger.js +330 -0
  432. package/dist/utils/package-manager.d.ts +30 -0
  433. package/dist/utils/package-manager.js +157 -0
  434. package/dist/utils/version-checker.d.ts +47 -0
  435. package/dist/utils/version-checker.js +167 -0
  436. package/dist/utils/version-display.d.ts +10 -0
  437. package/dist/utils/version-display.js +20 -0
  438. package/package.json +106 -0
@@ -0,0 +1,738 @@
1
+ /**
2
+ * Test orchestrator.
3
+ * Coordinates contract loading, sandboxed execution, and rule evaluation.
4
+ */
5
+ import * as path from 'path';
6
+ import * as fs from 'fs';
7
+ import { loadConfig } from '../../config/loader.js';
8
+ import { loadAllContracts } from './contract-loader.js';
9
+ import { SandboxExecutor, ToolExecutionErrorType } from '../../runtime/sandbox/index.js';
10
+ import { IOMonitor } from '../../runtime/sandbox/index.js';
11
+ import { BehaviorObserver } from './behavior-observer.js';
12
+ import { runContractTests } from './runner.js';
13
+ import { validateOutputStructure } from './output-validator.js';
14
+ import { parseTimeString } from '../../runtime/sandbox/index.js';
15
+ // Error rule imports - these provide diagnostic generation methods
16
+ // Note: Error codes are centralized in ERROR_CODES/ERROR_TYPE_TO_CODE below
17
+ // to maintain a single source of truth. Individual error classes provide
18
+ // rule-specific diagnostic creation via checkWithBehavioralContext methods.
19
+ import { E000ToolNotFound } from '../../runtime/analysis/rules/errors/e000-tool-not-found.js';
20
+ import { E500SideEffectDetected } from '../../runtime/analysis/rules/errors/e500-side-effect-detected.js';
21
+ import { E301OutputExplosion } from '../../runtime/analysis/rules/errors/e301-output-explosion.js';
22
+ import { E403UnboundedExecution } from '../../runtime/analysis/rules/errors/e403-unbounded-execution.js';
23
+ import { E300OutputValidationFailed } from '../../runtime/analysis/rules/errors/e300-output-validation-failed.js';
24
+ import { E200InputValidationFailed } from '../../runtime/analysis/rules/errors/e200-input-validation-failed.js';
25
+ import { E400ToolExecutionFailed } from '../../runtime/analysis/rules/errors/e400-tool-execution-failed.js';
26
+ import { E600UnexpectedTestResult } from '../../runtime/analysis/rules/errors/e600-unexpected-test-result.js';
27
+ // Centralized error code constants - single source of truth for error codes
28
+ import { ERROR_CODES, ERROR_TYPE_TO_CODE, } from '../../runtime/analysis/rules/error-codes.js';
29
+ import { applyStrictMode, computeVerdict, } from '../../runtime/analysis/strict-mode.js';
30
+ import { logger } from '../../utils/logger.js';
31
+ import { ConfigurationError } from '../../utils/errors.js';
32
+ /**
33
+ * Test orchestrator for tool validation.
34
+ */
35
+ export class TestOrchestrator {
36
+ options;
37
+ constructor(options) {
38
+ this.options = options;
39
+ }
40
+ /**
41
+ * Extract expectedOutputSchema from TestExecutionResult.
42
+ * @param result - Test execution result
43
+ * @returns Expected output schema name, or undefined if not present
44
+ */
45
+ getExpectedOutputSchema(result) {
46
+ return result.expectedOutputSchema;
47
+ }
48
+ /**
49
+ * Run tool validation tests.
50
+ */
51
+ async run() {
52
+ const { projectRoot, toolsDir, toolName, strictMode } = this.options;
53
+ // Load configuration
54
+ const config = loadConfig(projectRoot);
55
+ // Determine tools directory (relative to project root)
56
+ const finalToolsDir = toolsDir || config.check?.tools_dir || 'tools';
57
+ const toolsDirPath = path.resolve(projectRoot, finalToolsDir);
58
+ // Determine target directory for loading contracts
59
+ let targetContractsDir = toolsDirPath;
60
+ if (this.options.toolPath) {
61
+ const pathFilter = this.options.toolPath.replace(/^\/+|\/+$/g, ''); // Remove leading/trailing slashes
62
+ const targetPath = path.resolve(toolsDirPath, pathFilter);
63
+ // Verify the path exists
64
+ if (!fs.existsSync(targetPath)) {
65
+ throw new ConfigurationError(`Tool path not found: ${this.options.toolPath} (resolved to: ${targetPath})`);
66
+ }
67
+ if (!fs.statSync(targetPath).isDirectory()) {
68
+ throw new ConfigurationError(`Tool path is not a directory: ${this.options.toolPath} (resolved to: ${targetPath})`);
69
+ }
70
+ // Only load contracts from the specified path
71
+ targetContractsDir = targetPath;
72
+ }
73
+ // Load contracts from target directory (only the specified path if toolPath is provided)
74
+ const parsedContracts = loadAllContracts(targetContractsDir);
75
+ const contracts = parsedContracts;
76
+ // Filter by tool name if specified
77
+ const contractsToTest = toolName
78
+ ? contracts.filter(c => c.tool === toolName)
79
+ : contracts;
80
+ if (contractsToTest.length === 0) {
81
+ if (toolName) {
82
+ throw new ConfigurationError(`No contract found for tool: ${toolName}`);
83
+ }
84
+ throw new ConfigurationError(`No tool contracts found in ${toolsDirPath}. Create contract files (e.g., tools/<tool-name>.yaml).`);
85
+ }
86
+ // Get MCP command from config or options
87
+ // For tool testing, we need to spawn the server regardless of transport type
88
+ // (sandboxed execution requires spawning the process)
89
+ const mcpCommand = this.options.mcpCommand || config.script;
90
+ if (!mcpCommand) {
91
+ throw new ConfigurationError('MCP command is required for tool testing. Set script in syrin.yaml or use --mcp-command option.');
92
+ }
93
+ // Initialize sandbox executor first (this starts the MCP server process)
94
+ // Suppress stderr by default, unless user explicitly requests to see errors
95
+ const suppressStderr = this.options.showErrors !== true;
96
+ const sandboxExecutor = new SandboxExecutor({
97
+ timeout: this.options.timeout || config.check?.timeout_ms || 30000,
98
+ memoryLimitMB: this.options.memoryLimitMB || config.check?.memory_limit_mb,
99
+ mcpCommand,
100
+ env: this.options.env,
101
+ projectRoot,
102
+ suppressStderr,
103
+ });
104
+ try {
105
+ // Initialize sandbox (start MCP server process once)
106
+ await sandboxExecutor.initialize();
107
+ // Get available tools from the sandbox executor's client
108
+ // (reuse the same connection instead of creating a new one)
109
+ const client = sandboxExecutor.getClient();
110
+ if (!client) {
111
+ throw new ConfigurationError('Failed to get MCP client from sandbox executor');
112
+ }
113
+ const availableTools = await client.listTools();
114
+ // Create tool schema map
115
+ const toolSchemaMap = new Map(availableTools.tools.map(tool => [
116
+ tool.name,
117
+ {
118
+ inputSchema: tool.inputSchema,
119
+ outputSchema: tool.outputSchema,
120
+ },
121
+ ]));
122
+ const toolResults = [];
123
+ const allDiagnostics = [];
124
+ // Test each contract
125
+ for (const contract of contractsToTest) {
126
+ const toolResult = await this.testTool(contract, toolSchemaMap, sandboxExecutor, projectRoot, config);
127
+ toolResults.push(toolResult);
128
+ allDiagnostics.push(...toolResult.diagnostics);
129
+ }
130
+ // Apply strict mode
131
+ const processedDiagnostics = applyStrictMode(allDiagnostics, strictMode || config.check?.strict_mode || false);
132
+ // Compute verdict
133
+ const verdict = computeVerdict(processedDiagnostics, strictMode || config.check?.strict_mode || false);
134
+ const toolsPassed = toolResults.filter(r => r.passed).length;
135
+ const toolsFailed = toolResults.filter(r => !r.passed).length;
136
+ return {
137
+ verdict,
138
+ diagnostics: processedDiagnostics,
139
+ toolResults,
140
+ toolsTested: toolResults.length,
141
+ toolsPassed,
142
+ toolsFailed,
143
+ };
144
+ }
145
+ finally {
146
+ // Cleanup sandbox (this also closes the MCP connection)
147
+ await sandboxExecutor.cleanup();
148
+ }
149
+ }
150
+ /**
151
+ * Test a single tool.
152
+ */
153
+ async testTool(contract, toolSchemaMap, sandboxExecutor, projectRoot, config) {
154
+ const toolName = contract.tool;
155
+ const toolSchema = toolSchemaMap.get(toolName);
156
+ if (!toolSchema) {
157
+ // Get the MCP command being used (from options or config)
158
+ const mcpCommand = this.options.mcpCommand || config.script;
159
+ const scriptName = mcpCommand ? String(mcpCommand) : 'unknown';
160
+ if (!this.options.ci) {
161
+ logger.warn(`Tool "${toolName}" not found in MCP server. Running: ${scriptName}`);
162
+ }
163
+ // Create a diagnostic error for missing tool using E000 rule
164
+ const diagnostics = E000ToolNotFound.checkWithRuntimeContext({
165
+ toolName,
166
+ scriptName,
167
+ });
168
+ const diagnostic = diagnostics[0];
169
+ return {
170
+ toolName,
171
+ contract,
172
+ diagnostics: [diagnostic],
173
+ passed: false,
174
+ summary: {
175
+ totalExecutions: 0,
176
+ successfulExecutions: 0,
177
+ failedExecutions: 0,
178
+ timedOutExecutions: 0,
179
+ },
180
+ };
181
+ }
182
+ // Create I/O monitor
183
+ const tempDir = sandboxExecutor.getTempDir() || '';
184
+ const ioMonitor = new IOMonitor(tempDir, projectRoot);
185
+ // Create behavior observer
186
+ const behaviorObserver = new BehaviorObserver();
187
+ // Parse per-tool timeout if declared, otherwise use global default
188
+ let toolTimeoutMs;
189
+ if (contract.guarantees?.max_execution_time) {
190
+ try {
191
+ toolTimeoutMs = parseTimeString(contract.guarantees.max_execution_time);
192
+ if (!this.options.ci) {
193
+ logger.info(`Tool "${toolName}" declared max_execution_time: ${contract.guarantees.max_execution_time} (${toolTimeoutMs}ms)`);
194
+ }
195
+ }
196
+ catch (_error) {
197
+ if (!this.options.ci) {
198
+ logger.warn(`Invalid max_execution_time for tool "${toolName}": ${contract.guarantees.max_execution_time}. Using global default.`);
199
+ }
200
+ }
201
+ }
202
+ // Run contract-defined tests
203
+ const contractTestResults = await runContractTests(sandboxExecutor, contract, toolTimeoutMs);
204
+ // All results are from contract tests
205
+ const allResults = contractTestResults;
206
+ // Run behavioral observations
207
+ const sideEffectResult = behaviorObserver.detectSideEffects(ioMonitor, contract);
208
+ const outputSizeResults = behaviorObserver.checkOutputSize(allResults, contract, this.options.maxOutputSizeKB || 50);
209
+ const unboundedResult = behaviorObserver.detectUnboundedExecution(allResults);
210
+ const executionErrorResult = behaviorObserver.detectExecutionErrors(allResults);
211
+ // Run behavioral rules
212
+ const diagnostics = [];
213
+ const testResults = [];
214
+ // Match expectations against actual results
215
+ for (const result of allResults) {
216
+ const expectation = result.expectation;
217
+ // Use discriminated union to check result state
218
+ const hasError = !result.success;
219
+ const hasTimeout = !result.success && result.timedOut === true;
220
+ // Determine actual outcome
221
+ let actualOutcome;
222
+ let actualErrorCode;
223
+ let actualErrorType;
224
+ if (hasTimeout) {
225
+ actualOutcome = 'timeout';
226
+ actualErrorCode = ERROR_CODES.E403;
227
+ actualErrorType = 'timeout';
228
+ }
229
+ else if (hasError && !result.success) {
230
+ actualOutcome = 'error';
231
+ actualErrorCode =
232
+ result.error.errorType === ToolExecutionErrorType.INPUT_VALIDATION
233
+ ? ERROR_CODES.E200
234
+ : result.error.errorType ===
235
+ ToolExecutionErrorType.OUTPUT_VALIDATION
236
+ ? ERROR_CODES.E300
237
+ : ERROR_CODES.E600;
238
+ // Normalize enum value to expected string format (e.g., 'EXECUTION_ERROR' -> 'execution_error')
239
+ actualErrorType = result.error.errorType.toLowerCase();
240
+ }
241
+ else {
242
+ actualOutcome = 'success';
243
+ }
244
+ // Fix TypeScript: error is guaranteed to exist when actualOutcome is 'error'
245
+ // Determine expected outcome
246
+ // Some behavioral errors are tool-level (side_effect, output_explosion)
247
+ // Others are test-level (unbounded_execution, execution_error)
248
+ const toolLevelBehavioralErrors = ['side_effect', 'output_explosion'];
249
+ const testLevelBehavioralErrors = [
250
+ 'unbounded_execution',
251
+ 'execution_error',
252
+ ];
253
+ const expectedErrorType = expectation?.error?.type;
254
+ const isToolLevelBehavioralError = expectedErrorType &&
255
+ toolLevelBehavioralErrors.includes(expectedErrorType);
256
+ const isTestLevelBehavioralError = expectedErrorType &&
257
+ testLevelBehavioralErrors.includes(expectedErrorType);
258
+ let expectedOutcome;
259
+ if (isToolLevelBehavioralError) {
260
+ // For tool-level behavioral errors (side_effect, output_explosion),
261
+ // the test execution itself should succeed - the error is detected separately at tool level
262
+ expectedOutcome = 'success';
263
+ }
264
+ else if (isTestLevelBehavioralError) {
265
+ // For test-level behavioral errors (unbounded_execution, execution_error),
266
+ // the test execution itself should fail/timeout - that's how the error is detected
267
+ expectedOutcome = 'error';
268
+ }
269
+ else if (expectation?.error) {
270
+ expectedOutcome = 'error';
271
+ }
272
+ else if (expectation?.success === false) {
273
+ expectedOutcome = 'error';
274
+ }
275
+ else {
276
+ expectedOutcome = 'success'; // Default to success if no expectation or success=true
277
+ }
278
+ // Match expectation against actual result
279
+ // For tool-level behavioral errors, test execution should succeed
280
+ // For test-level behavioral errors, test execution should match the error type
281
+ let expectationMatched;
282
+ if (isToolLevelBehavioralError) {
283
+ expectationMatched = actualOutcome === 'success';
284
+ }
285
+ else if (isTestLevelBehavioralError) {
286
+ // For unbounded_execution, expect timeout; for execution_error, expect error
287
+ if (expectedErrorType === 'unbounded_execution') {
288
+ expectationMatched = actualOutcome === 'timeout';
289
+ }
290
+ else if (expectedErrorType === 'execution_error') {
291
+ expectationMatched =
292
+ actualOutcome === 'error' && actualErrorType === 'execution_error';
293
+ }
294
+ else {
295
+ expectationMatched = false;
296
+ }
297
+ }
298
+ else {
299
+ expectationMatched = this.matchExpectation(expectation, actualOutcome, actualErrorCode, actualErrorType, !result.success ? result.error : undefined);
300
+ }
301
+ // Check if this is a synthetic input (no explicit expectation)
302
+ const isSyntheticInput = result.testName?.startsWith('synthetic_input_') && !expectation;
303
+ testResults.push({
304
+ testName: result.testName,
305
+ passed: expectationMatched,
306
+ expected: expectedOutcome,
307
+ actual: actualOutcome,
308
+ errorCode: actualErrorCode,
309
+ errorType: actualErrorType,
310
+ message: !result.success ? result.error.message : undefined,
311
+ });
312
+ // Only add diagnostics if expectation doesn't match
313
+ // For synthetic inputs without expectations, skip error reporting (they're exploratory)
314
+ if (!expectationMatched && !isSyntheticInput) {
315
+ if (expectedOutcome === 'error' && actualOutcome === 'success') {
316
+ // Expected error but got success
317
+ diagnostics.push(...E600UnexpectedTestResult.checkWithBehavioralContext({
318
+ toolName,
319
+ testName: result.testName || 'unknown',
320
+ testInput: result.testInput,
321
+ expectedOutcome: 'error',
322
+ actualOutcome: 'success',
323
+ expectedErrorType: expectation?.error?.type,
324
+ expectedErrorCode: expectation?.error?.code,
325
+ expectedError: expectation?.error,
326
+ }));
327
+ }
328
+ else if (expectedOutcome === 'success' && actualOutcome === 'error') {
329
+ // Expected success but got error
330
+ if (!result.success) {
331
+ const errorMessage = result.error.message;
332
+ const parsedError = this.parseValidationError(errorMessage);
333
+ // Use appropriate rule based on error type
334
+ if (result.error.errorType === ToolExecutionErrorType.INPUT_VALIDATION) {
335
+ diagnostics.push(...E200InputValidationFailed.checkWithBehavioralContext({
336
+ toolName,
337
+ testName: result.testName,
338
+ testInput: result.testInput,
339
+ error: errorMessage,
340
+ parsedError: parsedError,
341
+ details: {
342
+ expectedOutputSchema: this.getExpectedOutputSchema(result),
343
+ actualError: {
344
+ code: actualErrorCode,
345
+ type: actualErrorType,
346
+ message: errorMessage,
347
+ },
348
+ errorType: result.error.errorType,
349
+ ...result.error.context,
350
+ },
351
+ }));
352
+ }
353
+ else if (result.error.errorType ===
354
+ ToolExecutionErrorType.OUTPUT_VALIDATION) {
355
+ diagnostics.push(...E300OutputValidationFailed.checkWithBehavioralContext({
356
+ toolName,
357
+ testName: result.testName,
358
+ testInput: result.testInput,
359
+ expectedOutputSchema: this.getExpectedOutputSchema(result),
360
+ error: errorMessage,
361
+ details: {
362
+ actualError: {
363
+ code: actualErrorCode,
364
+ type: actualErrorType,
365
+ message: errorMessage,
366
+ },
367
+ ...result.error.context,
368
+ },
369
+ }));
370
+ }
371
+ else {
372
+ // For other errors, use E019 (execution errors are handled separately in the E019 rule section)
373
+ // This case should rarely happen as E019 is handled separately
374
+ const readableMessage = parsedError.summary || errorMessage;
375
+ diagnostics.push({
376
+ code: ERROR_CODES.E600,
377
+ severity: 'error',
378
+ message: parsedError.field
379
+ ? `${parsedError.field}: ${parsedError.message || readableMessage}`
380
+ : readableMessage,
381
+ tool: toolName,
382
+ context: {
383
+ testName: result.testName,
384
+ testInput: result.testInput,
385
+ expectedOutputSchema: this.getExpectedOutputSchema(result),
386
+ expectedResult: 'success',
387
+ actualError: {
388
+ code: actualErrorCode,
389
+ type: actualErrorType,
390
+ message: errorMessage,
391
+ },
392
+ errorType: result.error.errorType,
393
+ ...result.error.context,
394
+ },
395
+ });
396
+ }
397
+ }
398
+ }
399
+ else if (expectedOutcome === 'error' &&
400
+ actualOutcome === 'error' &&
401
+ !result.success) {
402
+ // Expected error but got different error
403
+ const expectedCode = expectation?.error?.code;
404
+ const expectedType = expectation?.error?.type;
405
+ // Check if error type matches (if specified)
406
+ let typeMatches = true;
407
+ if (expectedType && actualErrorType) {
408
+ const expectedTypeLower = String(expectedType).toLowerCase();
409
+ const actualTypeLower = String(actualErrorType).toLowerCase();
410
+ typeMatches =
411
+ actualTypeLower.includes(expectedTypeLower) ||
412
+ expectedTypeLower === actualTypeLower;
413
+ }
414
+ // Check if error code matches (if specified)
415
+ const codeMatches = !expectedCode || actualErrorCode === expectedCode;
416
+ // Check detailed error matching (if specified)
417
+ const detailsMatch = !expectation?.error?.details ||
418
+ this.matchExpectationDetails(expectation.error.details, result.error);
419
+ // If any part doesn't match, report E020
420
+ if (!typeMatches || !codeMatches || !detailsMatch) {
421
+ diagnostics.push(...E600UnexpectedTestResult.checkWithBehavioralContext({
422
+ toolName,
423
+ testName: result.testName || 'unknown',
424
+ testInput: result.testInput,
425
+ expectedOutcome: 'error',
426
+ actualOutcome: 'error',
427
+ expectedErrorType: expectedType,
428
+ expectedErrorCode: expectedCode,
429
+ actualErrorType: actualErrorType,
430
+ actualErrorCode: actualErrorCode,
431
+ expectedError: expectation?.error,
432
+ actualError: {
433
+ code: actualErrorCode,
434
+ type: actualErrorType,
435
+ message: result.error.message,
436
+ },
437
+ }));
438
+ }
439
+ }
440
+ }
441
+ }
442
+ // E012: Side Effect Detected
443
+ if (sideEffectResult.detected) {
444
+ diagnostics.push(...E500SideEffectDetected.checkWithBehavioralContext({
445
+ toolName,
446
+ sideEffects: sideEffectResult.sideEffects,
447
+ }));
448
+ }
449
+ // E301: Output Explosion
450
+ for (const sizeResult of outputSizeResults) {
451
+ if (sizeResult.exceedsLimit) {
452
+ diagnostics.push(...E301OutputExplosion.checkWithBehavioralContext({
453
+ toolName,
454
+ actualSize: sizeResult.actualSize,
455
+ maxSize: sizeResult.maxSize,
456
+ limitString: sizeResult.limitString,
457
+ }));
458
+ }
459
+ }
460
+ // E403: Unbounded Execution (timeouts and connection errors only)
461
+ if (unboundedResult.detected) {
462
+ diagnostics.push(...E403UnboundedExecution.checkWithBehavioralContext({
463
+ toolName,
464
+ timedOut: unboundedResult.timedOut,
465
+ declaredTimeout: contract.guarantees?.max_execution_time,
466
+ actualTimeoutMs: toolTimeoutMs,
467
+ errors: unboundedResult.errors.map(e => ({
468
+ message: e.message,
469
+ code: e.name,
470
+ })),
471
+ }));
472
+ }
473
+ // E400: Tool Execution Failed (execution errors, separate from E016)
474
+ if (executionErrorResult.detected) {
475
+ diagnostics.push(...E400ToolExecutionFailed.checkWithBehavioralContext({
476
+ toolName,
477
+ errors: executionErrorResult.errors.map(e => ({
478
+ message: e.message,
479
+ code: e.name,
480
+ })),
481
+ }));
482
+ }
483
+ // Validate output structure (if schema available and test expects success)
484
+ if (toolSchema.outputSchema) {
485
+ for (const result of allResults) {
486
+ if (!result)
487
+ continue;
488
+ // Only validate output if test expects success
489
+ const expectation = result.expectation;
490
+ const expectsSuccess = !expectation?.error && expectation?.success !== false;
491
+ if (result.success && expectsSuccess) {
492
+ // Use test-specific output schema or fall back to contract schema
493
+ const expectedOutputSchema = this.getExpectedOutputSchema(result);
494
+ const outputSchema = expectation?.output_schema
495
+ ? this.resolveSchemaByName(expectation.output_schema, toolSchema.outputSchema)
496
+ : expectedOutputSchema
497
+ ? this.resolveSchemaByName(expectedOutputSchema, toolSchema.outputSchema)
498
+ : toolSchema.outputSchema;
499
+ const validationResult = validateOutputStructure(result.output, outputSchema || toolSchema.outputSchema);
500
+ if (!validationResult.valid) {
501
+ // Check if this test result already failed expectation matching
502
+ const testResult = testResults.find(tr => tr.testName === result.testName);
503
+ if (!testResult || !testResult.passed) {
504
+ // Output validation failed - this is unexpected for success expectation
505
+ diagnostics.push(...E300OutputValidationFailed.checkWithBehavioralContext({
506
+ toolName,
507
+ testName: result.testName,
508
+ testInput: result.testInput,
509
+ expectedOutputSchema: this.getExpectedOutputSchema(result),
510
+ error: validationResult.error || 'Unknown error',
511
+ details: validationResult.details,
512
+ }));
513
+ }
514
+ }
515
+ }
516
+ }
517
+ }
518
+ // Compute summary based on test expectations
519
+ const totalExecutions = allResults.length;
520
+ const totalContractTests = testResults.length;
521
+ const passedTests = testResults.filter(tr => tr.passed).length;
522
+ const failedTests = testResults.filter(tr => !tr.passed).length;
523
+ const successfulExecutions = allResults.filter(r => r.success).length;
524
+ const failedExecutions = allResults.filter(r => !r.success).length;
525
+ const timedOutExecutions = allResults.filter(r => !r.success && r.timedOut === true).length;
526
+ // Determine if test passed based on expectations (no unmatched diagnostics)
527
+ // Filter out expected behavioral errors - check if any test expects them
528
+ // Use error type to code mapping from constants
529
+ const errorTypeToCode = ERROR_TYPE_TO_CODE;
530
+ // Collect expected behavioral errors from all test expectations
531
+ const expectedBehavioralErrors = new Set();
532
+ if (contract.tests) {
533
+ for (const test of contract.tests) {
534
+ if (test.expect?.error?.type) {
535
+ const errorType = test.expect.error.type;
536
+ const errorCode = errorTypeToCode[errorType];
537
+ if (errorCode) {
538
+ expectedBehavioralErrors.add(errorCode);
539
+ }
540
+ }
541
+ }
542
+ }
543
+ // Filter out expected behavioral errors from diagnostics
544
+ // This prevents them from being displayed and counted in the summary
545
+ const filteredDiagnostics = diagnostics.filter(d => !expectedBehavioralErrors.has(d.code || ''));
546
+ const errors = filteredDiagnostics.filter(d => d.severity === 'error');
547
+ const passed = errors.length === 0;
548
+ return {
549
+ toolName,
550
+ contract,
551
+ diagnostics: filteredDiagnostics, // Use filtered diagnostics to exclude expected errors
552
+ passed,
553
+ summary: {
554
+ totalExecutions,
555
+ successfulExecutions,
556
+ failedExecutions,
557
+ timedOutExecutions,
558
+ testsPassed: totalContractTests > 0 ? passedTests : undefined,
559
+ testsFailed: totalContractTests > 0 ? failedTests : undefined,
560
+ },
561
+ };
562
+ }
563
+ /**
564
+ * Parse Pydantic validation error message to extract key information.
565
+ */
566
+ parseValidationError(errorMessage) {
567
+ const parsed = {};
568
+ // Extract field name (usually on its own line)
569
+ const fieldMatch = errorMessage.match(/^(\w+)\s*$/m);
570
+ if (fieldMatch && fieldMatch[1]) {
571
+ parsed.field = fieldMatch[1];
572
+ }
573
+ // Extract error type and message
574
+ const typeMatch = errorMessage.match(/\[type=([^,]+)/);
575
+ if (typeMatch && typeMatch[1]) {
576
+ parsed.errorType = typeMatch[1];
577
+ }
578
+ // Extract input value and type
579
+ const inputValueMatch = errorMessage.match(/input_value=([^,]+)/);
580
+ if (inputValueMatch && inputValueMatch[1]) {
581
+ parsed.inputValue = inputValueMatch[1].trim();
582
+ }
583
+ const inputTypeMatch = errorMessage.match(/input_type=(\w+)/);
584
+ if (inputTypeMatch && inputTypeMatch[1]) {
585
+ parsed.inputType = inputTypeMatch[1];
586
+ }
587
+ // Build summary based on error type
588
+ if (parsed.errorType === 'missing_argument') {
589
+ parsed.summary = `Missing required field: ${parsed.field || 'unknown'}`;
590
+ parsed.message = `Field "${parsed.field || 'unknown'}" is required but was not provided`;
591
+ }
592
+ else if (parsed.errorType === 'string_type') {
593
+ parsed.summary = `Invalid type for ${parsed.field || 'field'}: expected string, got ${parsed.inputType || 'unknown'}`;
594
+ parsed.message = `Expected string but received ${parsed.inputType || 'unknown type'}`;
595
+ }
596
+ else if (parsed.errorType === 'unexpected_keyword_argument') {
597
+ parsed.summary = `Unexpected field: ${parsed.field || 'unknown'}`;
598
+ parsed.message = `Field "${parsed.field || 'unknown'}" is not allowed in the input schema`;
599
+ }
600
+ else {
601
+ // Generic error
602
+ const firstLine = errorMessage.split('\n')[0];
603
+ parsed.summary = firstLine || errorMessage;
604
+ parsed.message = errorMessage;
605
+ }
606
+ return parsed;
607
+ }
608
+ /**
609
+ * Match actual result against test expectation.
610
+ */
611
+ matchExpectation(expectation, actualOutcome, actualErrorCode, actualErrorType, error) {
612
+ // No expectation means expect success by default
613
+ if (!expectation) {
614
+ return actualOutcome === 'success';
615
+ }
616
+ // If error expectation is specified
617
+ if (expectation.error) {
618
+ // Must have an error
619
+ if (actualOutcome !== 'error') {
620
+ return false;
621
+ }
622
+ // Match by type first (most important for developer-friendly matching)
623
+ if (expectation.error.type && actualErrorType) {
624
+ const expectedType = String(expectation.error.type).toLowerCase();
625
+ const actualType = String(actualErrorType).toLowerCase();
626
+ // Normalize type names for matching
627
+ const typeMapping = {
628
+ input_validation: ['input_validation'],
629
+ output_validation: ['output_validation'],
630
+ execution_error: ['execution_error', 'unknown'],
631
+ side_effect: ['side_effect'],
632
+ output_explosion: ['output_explosion'],
633
+ unbounded_execution: ['unbounded_execution', 'timeout'],
634
+ };
635
+ const expectedTypes = typeMapping[expectedType] || [expectedType];
636
+ const typeMatches = expectedTypes.some(et => actualType.includes(et) || et === actualType);
637
+ if (!typeMatches) {
638
+ return false;
639
+ }
640
+ }
641
+ // Match error code if specified (optional - for backward compatibility)
642
+ if (expectation.error.code && actualErrorCode) {
643
+ const expectedCode = String(expectation.error.code)
644
+ .trim()
645
+ .toUpperCase();
646
+ const actualCode = String(actualErrorCode).trim().toUpperCase();
647
+ if (expectedCode !== actualCode) {
648
+ return false;
649
+ }
650
+ }
651
+ // Match error details if specified (most specific matching)
652
+ if (expectation.error.details && error) {
653
+ const detailsMatch = this.matchExpectationDetails(expectation.error.details, error);
654
+ if (!detailsMatch) {
655
+ return false;
656
+ }
657
+ }
658
+ // If we have type or details, that's sufficient for matching
659
+ // If only code was specified, we already checked it above
660
+ return true;
661
+ }
662
+ // If success is explicitly false, expect error
663
+ if (expectation.success === false) {
664
+ return actualOutcome === 'error';
665
+ }
666
+ // Default: expect success
667
+ return actualOutcome === 'success';
668
+ }
669
+ /**
670
+ * Match expectation details against actual error.
671
+ */
672
+ matchExpectationDetails(expectedDetails, error) {
673
+ if (!expectedDetails) {
674
+ return true; // No details to match
675
+ }
676
+ const parsedError = this.parseValidationError(error.message);
677
+ // Match error_type if specified
678
+ if (expectedDetails.error_type &&
679
+ expectedDetails.error_type !== parsedError.errorType) {
680
+ return false;
681
+ }
682
+ // Match field if specified
683
+ if (expectedDetails.field && expectedDetails.field !== parsedError.field) {
684
+ return false;
685
+ }
686
+ // Match expected type if specified (pattern match)
687
+ if (expectedDetails.expected) {
688
+ const expectedStr = String(expectedDetails.expected).toLowerCase();
689
+ if (!error.message.toLowerCase().includes(expectedStr)) {
690
+ return false;
691
+ }
692
+ }
693
+ // Match received type if specified
694
+ if (expectedDetails.received &&
695
+ expectedDetails.received !== parsedError.inputType) {
696
+ return false;
697
+ }
698
+ return true;
699
+ }
700
+ /**
701
+ * Resolve schema by name from JSON Schema $defs.
702
+ *
703
+ * Schema names in contracts are string references to named schemas defined in the
704
+ * tool's schema $defs section (e.g., "Username", "UserResponse").
705
+ *
706
+ * This function looks up the named schema from the root schema's $defs dictionary.
707
+ * If the schema name is not found in $defs, it falls back to the defaultSchema.
708
+ *
709
+ * @param schemaName - Schema name to resolve (e.g., "Username")
710
+ * @param defaultSchema - The root schema containing $defs (e.g., tool outputSchema)
711
+ * @returns The resolved schema from $defs, or defaultSchema if not found
712
+ */
713
+ resolveSchemaByName(schemaName, defaultSchema) {
714
+ // Check if defaultSchema is an object with $defs
715
+ if (defaultSchema &&
716
+ typeof defaultSchema === 'object' &&
717
+ !Array.isArray(defaultSchema)) {
718
+ const schema = defaultSchema;
719
+ // Look for $defs (JSON Schema 2020-12) or definitions (JSON Schema draft-07)
720
+ const defs = ('$defs' in schema ? schema.$defs : undefined) ||
721
+ ('definitions' in schema ? schema.definitions : undefined);
722
+ if (defs && typeof defs === 'object' && !Array.isArray(defs)) {
723
+ const defsDict = defs;
724
+ // Look up the schema by name in $defs
725
+ if (schemaName in defsDict) {
726
+ const resolvedSchema = defsDict[schemaName];
727
+ // Return the resolved schema, merging with any base schema context if needed
728
+ return resolvedSchema;
729
+ }
730
+ }
731
+ }
732
+ // Fallback to defaultSchema if schema name not found in $defs
733
+ // This handles cases where schemaName refers to the root schema itself
734
+ // or when $defs doesn't exist
735
+ return defaultSchema;
736
+ }
737
+ }
738
+ //# sourceMappingURL=orchestrator.js.map