@opensip-cli/simulation 0.1.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 (348) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/__tests__/internal-surface.test.d.ts +9 -0
  5. package/dist/__tests__/internal-surface.test.d.ts.map +1 -0
  6. package/dist/__tests__/internal-surface.test.js +38 -0
  7. package/dist/__tests__/internal-surface.test.js.map +1 -0
  8. package/dist/__tests__/plugin-loader.test.d.ts +2 -0
  9. package/dist/__tests__/plugin-loader.test.d.ts.map +1 -0
  10. package/dist/__tests__/plugin-loader.test.js +64 -0
  11. package/dist/__tests__/plugin-loader.test.js.map +1 -0
  12. package/dist/__tests__/public-api.test.d.ts +15 -0
  13. package/dist/__tests__/public-api.test.d.ts.map +1 -0
  14. package/dist/__tests__/public-api.test.js +73 -0
  15. package/dist/__tests__/public-api.test.js.map +1 -0
  16. package/dist/__tests__/registry-cross-kind.test.d.ts +6 -0
  17. package/dist/__tests__/registry-cross-kind.test.d.ts.map +1 -0
  18. package/dist/__tests__/registry-cross-kind.test.js +86 -0
  19. package/dist/__tests__/registry-cross-kind.test.js.map +1 -0
  20. package/dist/__tests__/scenario-execution.test.d.ts +10 -0
  21. package/dist/__tests__/scenario-execution.test.d.ts.map +1 -0
  22. package/dist/__tests__/scenario-execution.test.js +92 -0
  23. package/dist/__tests__/scenario-execution.test.js.map +1 -0
  24. package/dist/__tests__/sim-capability-contract.test.d.ts +10 -0
  25. package/dist/__tests__/sim-capability-contract.test.d.ts.map +1 -0
  26. package/dist/__tests__/sim-capability-contract.test.js +131 -0
  27. package/dist/__tests__/sim-capability-contract.test.js.map +1 -0
  28. package/dist/__tests__/sim-config-schema.test.d.ts +5 -0
  29. package/dist/__tests__/sim-config-schema.test.d.ts.map +1 -0
  30. package/dist/__tests__/sim-config-schema.test.js +23 -0
  31. package/dist/__tests__/sim-config-schema.test.js.map +1 -0
  32. package/dist/__tests__/sim-failure-signal.test.d.ts +10 -0
  33. package/dist/__tests__/sim-failure-signal.test.d.ts.map +1 -0
  34. package/dist/__tests__/sim-failure-signal.test.js +86 -0
  35. package/dist/__tests__/sim-failure-signal.test.js.map +1 -0
  36. package/dist/__tests__/surviving-surface-edges.test.d.ts +10 -0
  37. package/dist/__tests__/surviving-surface-edges.test.d.ts.map +1 -0
  38. package/dist/__tests__/surviving-surface-edges.test.js +122 -0
  39. package/dist/__tests__/surviving-surface-edges.test.js.map +1 -0
  40. package/dist/__tests__/test-utils/targets.d.ts +26 -0
  41. package/dist/__tests__/test-utils/targets.d.ts.map +1 -0
  42. package/dist/__tests__/test-utils/targets.js +38 -0
  43. package/dist/__tests__/test-utils/targets.js.map +1 -0
  44. package/dist/__tests__/test-utils/with-sim-scope.d.ts +12 -0
  45. package/dist/__tests__/test-utils/with-sim-scope.d.ts.map +1 -0
  46. package/dist/__tests__/test-utils/with-sim-scope.js +22 -0
  47. package/dist/__tests__/test-utils/with-sim-scope.js.map +1 -0
  48. package/dist/__tests__/tool-live-view.test.d.ts +20 -0
  49. package/dist/__tests__/tool-live-view.test.d.ts.map +1 -0
  50. package/dist/__tests__/tool-live-view.test.js +146 -0
  51. package/dist/__tests__/tool-live-view.test.js.map +1 -0
  52. package/dist/__tests__/tool-show-mode.test.d.ts +10 -0
  53. package/dist/__tests__/tool-show-mode.test.d.ts.map +1 -0
  54. package/dist/__tests__/tool-show-mode.test.js +156 -0
  55. package/dist/__tests__/tool-show-mode.test.js.map +1 -0
  56. package/dist/__tests__/tool.test.d.ts +15 -0
  57. package/dist/__tests__/tool.test.d.ts.map +1 -0
  58. package/dist/__tests__/tool.test.js +250 -0
  59. package/dist/__tests__/tool.test.js.map +1 -0
  60. package/dist/cli/__tests__/sim-config.test.d.ts +2 -0
  61. package/dist/cli/__tests__/sim-config.test.d.ts.map +1 -0
  62. package/dist/cli/__tests__/sim-config.test.js +94 -0
  63. package/dist/cli/__tests__/sim-config.test.js.map +1 -0
  64. package/dist/cli/__tests__/sim-runner.test.d.ts +23 -0
  65. package/dist/cli/__tests__/sim-runner.test.d.ts.map +1 -0
  66. package/dist/cli/__tests__/sim-runner.test.js +188 -0
  67. package/dist/cli/__tests__/sim-runner.test.js.map +1 -0
  68. package/dist/cli/__tests__/sim-worker.test.d.ts +12 -0
  69. package/dist/cli/__tests__/sim-worker.test.d.ts.map +1 -0
  70. package/dist/cli/__tests__/sim-worker.test.js +69 -0
  71. package/dist/cli/__tests__/sim-worker.test.js.map +1 -0
  72. package/dist/cli/__tests__/sim.test.d.ts +2 -0
  73. package/dist/cli/__tests__/sim.test.d.ts.map +1 -0
  74. package/dist/cli/__tests__/sim.test.js +232 -0
  75. package/dist/cli/__tests__/sim.test.js.map +1 -0
  76. package/dist/cli/sim-config-schema.d.ts +30 -0
  77. package/dist/cli/sim-config-schema.d.ts.map +1 -0
  78. package/dist/cli/sim-config-schema.js +33 -0
  79. package/dist/cli/sim-config-schema.js.map +1 -0
  80. package/dist/cli/sim-config.d.ts +22 -0
  81. package/dist/cli/sim-config.d.ts.map +1 -0
  82. package/dist/cli/sim-config.js +73 -0
  83. package/dist/cli/sim-config.js.map +1 -0
  84. package/dist/cli/sim-runner.d.ts +60 -0
  85. package/dist/cli/sim-runner.d.ts.map +1 -0
  86. package/dist/cli/sim-runner.js +175 -0
  87. package/dist/cli/sim-runner.js.map +1 -0
  88. package/dist/cli/sim-worker.d.ts +24 -0
  89. package/dist/cli/sim-worker.d.ts.map +1 -0
  90. package/dist/cli/sim-worker.js +65 -0
  91. package/dist/cli/sim-worker.js.map +1 -0
  92. package/dist/cli/sim.d.ts +56 -0
  93. package/dist/cli/sim.d.ts.map +1 -0
  94. package/dist/cli/sim.js +265 -0
  95. package/dist/cli/sim.js.map +1 -0
  96. package/dist/framework/__tests__/assertions.test.d.ts +2 -0
  97. package/dist/framework/__tests__/assertions.test.d.ts.map +1 -0
  98. package/dist/framework/__tests__/assertions.test.js +122 -0
  99. package/dist/framework/__tests__/assertions.test.js.map +1 -0
  100. package/dist/framework/__tests__/misc-coverage.test.d.ts +18 -0
  101. package/dist/framework/__tests__/misc-coverage.test.d.ts.map +1 -0
  102. package/dist/framework/__tests__/misc-coverage.test.js +142 -0
  103. package/dist/framework/__tests__/misc-coverage.test.js.map +1 -0
  104. package/dist/framework/__tests__/resolve-metric.test.d.ts +12 -0
  105. package/dist/framework/__tests__/resolve-metric.test.d.ts.map +1 -0
  106. package/dist/framework/__tests__/resolve-metric.test.js +124 -0
  107. package/dist/framework/__tests__/resolve-metric.test.js.map +1 -0
  108. package/dist/framework/__tests__/result-builder.test.d.ts +2 -0
  109. package/dist/framework/__tests__/result-builder.test.d.ts.map +1 -0
  110. package/dist/framework/__tests__/result-builder.test.js +180 -0
  111. package/dist/framework/__tests__/result-builder.test.js.map +1 -0
  112. package/dist/framework/__tests__/scenario-logger.test.d.ts +9 -0
  113. package/dist/framework/__tests__/scenario-logger.test.d.ts.map +1 -0
  114. package/dist/framework/__tests__/scenario-logger.test.js +110 -0
  115. package/dist/framework/__tests__/scenario-logger.test.js.map +1 -0
  116. package/dist/framework/__tests__/validation.test.d.ts +9 -0
  117. package/dist/framework/__tests__/validation.test.d.ts.map +1 -0
  118. package/dist/framework/__tests__/validation.test.js +126 -0
  119. package/dist/framework/__tests__/validation.test.js.map +1 -0
  120. package/dist/framework/assertions.d.ts +106 -0
  121. package/dist/framework/assertions.d.ts.map +1 -0
  122. package/dist/framework/assertions.js +256 -0
  123. package/dist/framework/assertions.js.map +1 -0
  124. package/dist/framework/execution/__tests__/execution-engine.test.d.ts +9 -0
  125. package/dist/framework/execution/__tests__/execution-engine.test.d.ts.map +1 -0
  126. package/dist/framework/execution/__tests__/execution-engine.test.js +138 -0
  127. package/dist/framework/execution/__tests__/execution-engine.test.js.map +1 -0
  128. package/dist/framework/execution/__tests__/fault-builders.test.d.ts +5 -0
  129. package/dist/framework/execution/__tests__/fault-builders.test.d.ts.map +1 -0
  130. package/dist/framework/execution/__tests__/fault-builders.test.js +23 -0
  131. package/dist/framework/execution/__tests__/fault-builders.test.js.map +1 -0
  132. package/dist/framework/execution/__tests__/fault-model.test.d.ts +6 -0
  133. package/dist/framework/execution/__tests__/fault-model.test.d.ts.map +1 -0
  134. package/dist/framework/execution/__tests__/fault-model.test.js +64 -0
  135. package/dist/framework/execution/__tests__/fault-model.test.js.map +1 -0
  136. package/dist/framework/execution/__tests__/http-target.test.d.ts +5 -0
  137. package/dist/framework/execution/__tests__/http-target.test.d.ts.map +1 -0
  138. package/dist/framework/execution/__tests__/http-target.test.js +36 -0
  139. package/dist/framework/execution/__tests__/http-target.test.js.map +1 -0
  140. package/dist/framework/execution/__tests__/run-load-window.test.d.ts +7 -0
  141. package/dist/framework/execution/__tests__/run-load-window.test.d.ts.map +1 -0
  142. package/dist/framework/execution/__tests__/run-load-window.test.js +89 -0
  143. package/dist/framework/execution/__tests__/run-load-window.test.js.map +1 -0
  144. package/dist/framework/execution/execution-engine.d.ts +55 -0
  145. package/dist/framework/execution/execution-engine.d.ts.map +1 -0
  146. package/dist/framework/execution/execution-engine.js +111 -0
  147. package/dist/framework/execution/execution-engine.js.map +1 -0
  148. package/dist/framework/execution/fault-builders.d.ts +26 -0
  149. package/dist/framework/execution/fault-builders.d.ts.map +1 -0
  150. package/dist/framework/execution/fault-builders.js +24 -0
  151. package/dist/framework/execution/fault-builders.js.map +1 -0
  152. package/dist/framework/execution/fault-model.d.ts +49 -0
  153. package/dist/framework/execution/fault-model.d.ts.map +1 -0
  154. package/dist/framework/execution/fault-model.js +108 -0
  155. package/dist/framework/execution/fault-model.js.map +1 -0
  156. package/dist/framework/execution/fault-spec.d.ts +40 -0
  157. package/dist/framework/execution/fault-spec.d.ts.map +1 -0
  158. package/dist/framework/execution/fault-spec.js +23 -0
  159. package/dist/framework/execution/fault-spec.js.map +1 -0
  160. package/dist/framework/execution/http-target.d.ts +34 -0
  161. package/dist/framework/execution/http-target.d.ts.map +1 -0
  162. package/dist/framework/execution/http-target.js +41 -0
  163. package/dist/framework/execution/http-target.js.map +1 -0
  164. package/dist/framework/execution/latency-tracker.d.ts +44 -0
  165. package/dist/framework/execution/latency-tracker.d.ts.map +1 -0
  166. package/dist/framework/execution/latency-tracker.js +76 -0
  167. package/dist/framework/execution/latency-tracker.js.map +1 -0
  168. package/dist/framework/execution/run-load-window.d.ts +45 -0
  169. package/dist/framework/execution/run-load-window.d.ts.map +1 -0
  170. package/dist/framework/execution/run-load-window.js +136 -0
  171. package/dist/framework/execution/run-load-window.js.map +1 -0
  172. package/dist/framework/execution/scenario-aborted-error.d.ts +14 -0
  173. package/dist/framework/execution/scenario-aborted-error.d.ts.map +1 -0
  174. package/dist/framework/execution/scenario-aborted-error.js +24 -0
  175. package/dist/framework/execution/scenario-aborted-error.js.map +1 -0
  176. package/dist/framework/execution/target.d.ts +35 -0
  177. package/dist/framework/execution/target.d.ts.map +1 -0
  178. package/dist/framework/execution/target.js +21 -0
  179. package/dist/framework/execution/target.js.map +1 -0
  180. package/dist/framework/registry.d.ts +67 -0
  181. package/dist/framework/registry.d.ts.map +1 -0
  182. package/dist/framework/registry.js +113 -0
  183. package/dist/framework/registry.js.map +1 -0
  184. package/dist/framework/resolve-metric.d.ts +79 -0
  185. package/dist/framework/resolve-metric.d.ts.map +1 -0
  186. package/dist/framework/resolve-metric.js +135 -0
  187. package/dist/framework/resolve-metric.js.map +1 -0
  188. package/dist/framework/result-builder.d.ts +72 -0
  189. package/dist/framework/result-builder.d.ts.map +1 -0
  190. package/dist/framework/result-builder.js +214 -0
  191. package/dist/framework/result-builder.js.map +1 -0
  192. package/dist/framework/result-renderers.d.ts +37 -0
  193. package/dist/framework/result-renderers.d.ts.map +1 -0
  194. package/dist/framework/result-renderers.js +62 -0
  195. package/dist/framework/result-renderers.js.map +1 -0
  196. package/dist/framework/runnable-scenario.d.ts +37 -0
  197. package/dist/framework/runnable-scenario.d.ts.map +1 -0
  198. package/dist/framework/runnable-scenario.js +9 -0
  199. package/dist/framework/runnable-scenario.js.map +1 -0
  200. package/dist/framework/scenario-executor-result.d.ts +44 -0
  201. package/dist/framework/scenario-executor-result.d.ts.map +1 -0
  202. package/dist/framework/scenario-executor-result.js +13 -0
  203. package/dist/framework/scenario-executor-result.js.map +1 -0
  204. package/dist/framework/scenario-logger.d.ts +18 -0
  205. package/dist/framework/scenario-logger.d.ts.map +1 -0
  206. package/dist/framework/scenario-logger.js +39 -0
  207. package/dist/framework/scenario-logger.js.map +1 -0
  208. package/dist/framework/scenario-metric-key.d.ts +24 -0
  209. package/dist/framework/scenario-metric-key.d.ts.map +1 -0
  210. package/dist/framework/scenario-metric-key.js +17 -0
  211. package/dist/framework/scenario-metric-key.js.map +1 -0
  212. package/dist/framework/validation.d.ts +83 -0
  213. package/dist/framework/validation.d.ts.map +1 -0
  214. package/dist/framework/validation.js +93 -0
  215. package/dist/framework/validation.js.map +1 -0
  216. package/dist/index.d.ts +35 -0
  217. package/dist/index.d.ts.map +1 -0
  218. package/dist/index.js +53 -0
  219. package/dist/index.js.map +1 -0
  220. package/dist/internal.d.ts +19 -0
  221. package/dist/internal.d.ts.map +1 -0
  222. package/dist/internal.js +16 -0
  223. package/dist/internal.js.map +1 -0
  224. package/dist/kinds/chaos/__tests__/executor.test.d.ts +6 -0
  225. package/dist/kinds/chaos/__tests__/executor.test.d.ts.map +1 -0
  226. package/dist/kinds/chaos/__tests__/executor.test.js +117 -0
  227. package/dist/kinds/chaos/__tests__/executor.test.js.map +1 -0
  228. package/dist/kinds/chaos/config.d.ts +48 -0
  229. package/dist/kinds/chaos/config.d.ts.map +1 -0
  230. package/dist/kinds/chaos/config.js +15 -0
  231. package/dist/kinds/chaos/config.js.map +1 -0
  232. package/dist/kinds/chaos/define.d.ts +32 -0
  233. package/dist/kinds/chaos/define.d.ts.map +1 -0
  234. package/dist/kinds/chaos/define.js +111 -0
  235. package/dist/kinds/chaos/define.js.map +1 -0
  236. package/dist/kinds/chaos/executor.d.ts +21 -0
  237. package/dist/kinds/chaos/executor.d.ts.map +1 -0
  238. package/dist/kinds/chaos/executor.js +107 -0
  239. package/dist/kinds/chaos/executor.js.map +1 -0
  240. package/dist/kinds/chaos/result.d.ts +43 -0
  241. package/dist/kinds/chaos/result.d.ts.map +1 -0
  242. package/dist/kinds/chaos/result.js +12 -0
  243. package/dist/kinds/chaos/result.js.map +1 -0
  244. package/dist/kinds/load/__tests__/executor.test.d.ts +6 -0
  245. package/dist/kinds/load/__tests__/executor.test.d.ts.map +1 -0
  246. package/dist/kinds/load/__tests__/executor.test.js +75 -0
  247. package/dist/kinds/load/__tests__/executor.test.js.map +1 -0
  248. package/dist/kinds/load/config.d.ts +30 -0
  249. package/dist/kinds/load/config.d.ts.map +1 -0
  250. package/dist/kinds/load/config.js +9 -0
  251. package/dist/kinds/load/config.js.map +1 -0
  252. package/dist/kinds/load/define.d.ts +47 -0
  253. package/dist/kinds/load/define.d.ts.map +1 -0
  254. package/dist/kinds/load/define.js +76 -0
  255. package/dist/kinds/load/define.js.map +1 -0
  256. package/dist/kinds/load/executor.d.ts +16 -0
  257. package/dist/kinds/load/executor.d.ts.map +1 -0
  258. package/dist/kinds/load/executor.js +90 -0
  259. package/dist/kinds/load/executor.js.map +1 -0
  260. package/dist/kinds/load/result.d.ts +21 -0
  261. package/dist/kinds/load/result.d.ts.map +1 -0
  262. package/dist/kinds/load/result.js +10 -0
  263. package/dist/kinds/load/result.js.map +1 -0
  264. package/dist/persistence/session-payload.d.ts +32 -0
  265. package/dist/persistence/session-payload.d.ts.map +1 -0
  266. package/dist/persistence/session-payload.js +46 -0
  267. package/dist/persistence/session-payload.js.map +1 -0
  268. package/dist/persistence/session-replay.d.ts +13 -0
  269. package/dist/persistence/session-replay.d.ts.map +1 -0
  270. package/dist/persistence/session-replay.js +76 -0
  271. package/dist/persistence/session-replay.js.map +1 -0
  272. package/dist/persistence/session-replay.test.d.ts +10 -0
  273. package/dist/persistence/session-replay.test.d.ts.map +1 -0
  274. package/dist/persistence/session-replay.test.js +169 -0
  275. package/dist/persistence/session-replay.test.js.map +1 -0
  276. package/dist/plugins/__tests__/loader-scenarios.test.d.ts +12 -0
  277. package/dist/plugins/__tests__/loader-scenarios.test.d.ts.map +1 -0
  278. package/dist/plugins/__tests__/loader-scenarios.test.js +61 -0
  279. package/dist/plugins/__tests__/loader-scenarios.test.js.map +1 -0
  280. package/dist/plugins/__tests__/scenario-package-discovery.test.d.ts +2 -0
  281. package/dist/plugins/__tests__/scenario-package-discovery.test.d.ts.map +1 -0
  282. package/dist/plugins/__tests__/scenario-package-discovery.test.js +43 -0
  283. package/dist/plugins/__tests__/scenario-package-discovery.test.js.map +1 -0
  284. package/dist/plugins/loader.d.ts +32 -0
  285. package/dist/plugins/loader.d.ts.map +1 -0
  286. package/dist/plugins/loader.js +119 -0
  287. package/dist/plugins/loader.js.map +1 -0
  288. package/dist/plugins/scenario-package-discovery.d.ts +23 -0
  289. package/dist/plugins/scenario-package-discovery.d.ts.map +1 -0
  290. package/dist/plugins/scenario-package-discovery.js +42 -0
  291. package/dist/plugins/scenario-package-discovery.js.map +1 -0
  292. package/dist/plugins/types.d.ts +24 -0
  293. package/dist/plugins/types.d.ts.map +1 -0
  294. package/dist/plugins/types.js +18 -0
  295. package/dist/plugins/types.js.map +1 -0
  296. package/dist/recipes/__tests__/recipes.test.d.ts +2 -0
  297. package/dist/recipes/__tests__/recipes.test.d.ts.map +1 -0
  298. package/dist/recipes/__tests__/recipes.test.js +515 -0
  299. package/dist/recipes/__tests__/recipes.test.js.map +1 -0
  300. package/dist/recipes/built-in-recipes.d.ts +16 -0
  301. package/dist/recipes/built-in-recipes.d.ts.map +1 -0
  302. package/dist/recipes/built-in-recipes.js +37 -0
  303. package/dist/recipes/built-in-recipes.js.map +1 -0
  304. package/dist/recipes/define-recipe.d.ts +29 -0
  305. package/dist/recipes/define-recipe.d.ts.map +1 -0
  306. package/dist/recipes/define-recipe.js +68 -0
  307. package/dist/recipes/define-recipe.js.map +1 -0
  308. package/dist/recipes/registry.d.ts +54 -0
  309. package/dist/recipes/registry.d.ts.map +1 -0
  310. package/dist/recipes/registry.js +89 -0
  311. package/dist/recipes/registry.js.map +1 -0
  312. package/dist/recipes/service.d.ts +61 -0
  313. package/dist/recipes/service.d.ts.map +1 -0
  314. package/dist/recipes/service.js +205 -0
  315. package/dist/recipes/service.js.map +1 -0
  316. package/dist/recipes/types.d.ts +62 -0
  317. package/dist/recipes/types.d.ts.map +1 -0
  318. package/dist/recipes/types.js +10 -0
  319. package/dist/recipes/types.js.map +1 -0
  320. package/dist/scaffold/examples.d.ts +22 -0
  321. package/dist/scaffold/examples.d.ts.map +1 -0
  322. package/dist/scaffold/examples.js +91 -0
  323. package/dist/scaffold/examples.js.map +1 -0
  324. package/dist/scope-augmentation.d.ts +70 -0
  325. package/dist/scope-augmentation.d.ts.map +1 -0
  326. package/dist/scope-augmentation.js +28 -0
  327. package/dist/scope-augmentation.js.map +1 -0
  328. package/dist/tool.d.ts +21 -0
  329. package/dist/tool.d.ts.map +1 -0
  330. package/dist/tool.js +347 -0
  331. package/dist/tool.js.map +1 -0
  332. package/dist/types/base-types.d.ts +35 -0
  333. package/dist/types/base-types.d.ts.map +1 -0
  334. package/dist/types/base-types.js +8 -0
  335. package/dist/types/base-types.js.map +1 -0
  336. package/dist/types/framework-types.d.ts +62 -0
  337. package/dist/types/framework-types.d.ts.map +1 -0
  338. package/dist/types/framework-types.js +15 -0
  339. package/dist/types/framework-types.js.map +1 -0
  340. package/dist/types/kind-types.d.ts +24 -0
  341. package/dist/types/kind-types.d.ts.map +1 -0
  342. package/dist/types/kind-types.js +22 -0
  343. package/dist/types/kind-types.js.map +1 -0
  344. package/dist/types/workload.d.ts +30 -0
  345. package/dist/types/workload.d.ts.map +1 -0
  346. package/dist/types/workload.js +20 -0
  347. package/dist/types/workload.js.map +1 -0
  348. package/package.json +120 -0
@@ -0,0 +1,250 @@
1
+ /**
2
+ * @fileoverview Smoke tests for simulationTool — the Tool plugin
3
+ * descriptor wired into the CLI dispatcher.
4
+ *
5
+ * Since release 2.11.0 Phase 3 (the reference migration) sim mounts via a
6
+ * declarative `CommandSpec` (`simulationTool.commandSpecs`) rather than the
7
+ * deprecated `register()` hook. The host-owned mount path
8
+ * (`mountCommandSpec` → parse → handler → dispatch) is covered in
9
+ * `cli/src/__tests__/mount-command-spec.test.ts`; this file exercises the
10
+ * descriptor metadata, the declared command surface, and the command
11
+ * handler directly with a fake ToolCliContext (the handler is what the host
12
+ * invokes after parsing).
13
+ */
14
+ import { readFileSync } from 'node:fs';
15
+ import { dirname, resolve } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+ import { enterScope, RunScope } from '@opensip-cli/core';
18
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
19
+ import { ASSERTIONS } from '../framework/assertions.js';
20
+ import { clearScenarioRegistry, currentScenarioRegistry } from '../framework/registry.js';
21
+ import { defineLoadScenario } from '../kinds/load/define.js';
22
+ import { simulationTool } from '../tool.js';
23
+ import { noopTarget } from './test-utils/targets.js';
24
+ const HERE = dirname(fileURLToPath(import.meta.url));
25
+ const PKG = JSON.parse(readFileSync(resolve(HERE, '../../package.json'), 'utf8'));
26
+ beforeEach(() => {
27
+ // Item 1: scenarioRegistry and recipe registry are per-RunScope.
28
+ // Construct a fresh scope (with simulation extended) and enter it via
29
+ // AsyncLocalStorage so the handler resolves them through currentScope()
30
+ // while it runs.
31
+ const scope = new RunScope();
32
+ Object.assign(scope, simulationTool.contributeScope?.() ?? {});
33
+ enterScope(scope);
34
+ });
35
+ afterEach(() => {
36
+ clearScenarioRegistry();
37
+ });
38
+ /** The single declarative `sim` command sim now exports. */
39
+ function simSpec() {
40
+ const spec = simulationTool.commandSpecs?.[0];
41
+ if (spec === undefined)
42
+ throw new Error('simulationTool exposes no commandSpecs');
43
+ return spec;
44
+ }
45
+ function makeFakeContext() {
46
+ const rendered = [];
47
+ const exitCodes = [];
48
+ const emitted = [];
49
+ const delivered = [];
50
+ const project = {
51
+ cwd: '/test',
52
+ cwdExplicit: false,
53
+ projectRoot: '/test',
54
+ configPath: undefined,
55
+ walkedUp: 0,
56
+ scope: 'none',
57
+ };
58
+ // The handler uses currentScope() (set by enterScope in beforeEach), not
59
+ // cli.scope, but ToolCliContext requires a scope value; mirror project
60
+ // into a throwaway scope here.
61
+ const ctxScope = new RunScope({ projectContext: project });
62
+ Object.assign(ctxScope, simulationTool.contributeScope?.() ?? {});
63
+ const ctx = {
64
+ scope: ctxScope,
65
+ render: vi.fn((result) => {
66
+ rendered.push(result);
67
+ return Promise.resolve();
68
+ }),
69
+ registerLiveView: vi.fn(),
70
+ renderLive: vi.fn(() => Promise.resolve()),
71
+ maybeOpenReport: vi.fn(() => Promise.resolve()),
72
+ logger: {
73
+ debug: vi.fn(),
74
+ info: vi.fn(),
75
+ warn: vi.fn(),
76
+ error: vi.fn(),
77
+ },
78
+ setExitCode: (code) => {
79
+ exitCodes.push(code);
80
+ },
81
+ emitJson: (value) => {
82
+ emitted.push(value);
83
+ },
84
+ emitRaw: (value) => {
85
+ emitted.push(value);
86
+ },
87
+ emitEnvelope: (value) => {
88
+ emitted.push(value);
89
+ },
90
+ emitError: (detail) => {
91
+ exitCodes.push(detail.exitCode);
92
+ emitted.push(detail);
93
+ },
94
+ deliverSignals: (_envelope, opts) => {
95
+ delivered.push(opts);
96
+ return Promise.resolve({ cloudAccepted: 0 });
97
+ },
98
+ writeSarif: () => Promise.resolve(),
99
+ saveBaseline: () => Promise.resolve(),
100
+ compareBaseline: () => Promise.resolve({
101
+ added: [],
102
+ resolved: [],
103
+ unchanged: [],
104
+ degraded: false,
105
+ }),
106
+ exportBaselineSarif: () => Promise.resolve(),
107
+ exportBaselineFingerprints: () => Promise.resolve(),
108
+ toolState: {
109
+ get: () => Promise.resolve(undefined),
110
+ put: () => Promise.resolve(),
111
+ delete: () => Promise.resolve(),
112
+ list: () => Promise.resolve([]),
113
+ },
114
+ runSession: {
115
+ timing: {
116
+ startedAt: new Date().toISOString(),
117
+ startedAtEpochMs: Date.now(),
118
+ elapsedMs: () => 0,
119
+ snapshot: () => ({
120
+ startedAt: new Date().toISOString(),
121
+ completedAt: new Date().toISOString(),
122
+ durationMs: 0,
123
+ }),
124
+ complete: () => ({
125
+ startedAt: new Date().toISOString(),
126
+ completedAt: new Date().toISOString(),
127
+ durationMs: 0,
128
+ }),
129
+ },
130
+ },
131
+ };
132
+ return { ctx, rendered, exitCodes, emitted, delivered };
133
+ }
134
+ /**
135
+ * Register one trivial load scenario into the current scope's registry so a
136
+ * `sim` run has work to do. Since the zero-scenario fail-closed guard (audit
137
+ * P1c), a run with an empty registry returns an ErrorResult (exit 2) rather
138
+ * than a sim-done pass — happy-path tests must supply at least one scenario.
139
+ */
140
+ function registerProbeScenario() {
141
+ currentScenarioRegistry().register(defineLoadScenario({
142
+ id: 'probe',
143
+ name: 'probe',
144
+ description: 'probe',
145
+ tags: [],
146
+ target: noopTarget,
147
+ workload: { rps: 1 },
148
+ duration: 1,
149
+ assertions: [ASSERTIONS.lowErrorRate(1)],
150
+ }));
151
+ }
152
+ describe('simulationTool metadata', () => {
153
+ it('exposes name (human), id (stable UUID), version, description', () => {
154
+ expect(simulationTool.metadata.name).toBe('simulation');
155
+ expect(simulationTool.metadata.id).toBe('715d32c2-692c-4ed4-985b-a35deaf186aa');
156
+ expect(simulationTool.metadata.version).toBe(PKG.version);
157
+ expect(simulationTool.metadata.description).toContain('simulation');
158
+ });
159
+ it('declares the user-facing sim subcommand (+ the internal worker)', () => {
160
+ const names = simulationTool.commands.map((c) => c.name);
161
+ expect(names).toContain('sim');
162
+ // The internal off-main-process worker (ADR-0028), forked by the live view.
163
+ expect(names).toContain('sim-run-worker');
164
+ expect(simulationTool.commands).toHaveLength(2);
165
+ });
166
+ });
167
+ describe('simulationTool command surface (Phase 3 — CommandSpec migration)', () => {
168
+ it('mounts via commandSpecs — the one command surface (register() removed in 3.0.0)', () => {
169
+ // `sim` + the internal `sim-run-worker` (ADR-0028).
170
+ expect(simulationTool.commandSpecs).toHaveLength(2);
171
+ // `register` is no longer a Tool member (3.0.0) — its absence is structural,
172
+ // enforced by the type system, not asserted at runtime.
173
+ });
174
+ it('declares the sim command name/description/output/scope', () => {
175
+ const spec = simSpec();
176
+ expect(spec.name).toBe('sim');
177
+ expect(spec.description).toBe('Run simulation scenarios');
178
+ // The handler owns its full output surface (TTY-vs-static branch + egress).
179
+ expect(spec.output).toBe('raw-stream');
180
+ expect(spec.scope).toBe('project');
181
+ expect(typeof spec.handler).toBe('function');
182
+ });
183
+ it('declares the ADR-0021 common flags and the --recipe option', () => {
184
+ const spec = simSpec();
185
+ // Cross-tool flags from the single registry (ADR-0021).
186
+ expect([...spec.commonFlags]).toEqual(expect.arrayContaining([
187
+ 'cwd',
188
+ 'json',
189
+ 'quiet',
190
+ 'verbose',
191
+ 'debug',
192
+ 'reportTo',
193
+ 'apiKey',
194
+ 'open',
195
+ ]));
196
+ const optionFlags = (spec.options ?? []).map((o) => o.flag);
197
+ expect(optionFlags).toContain('--recipe');
198
+ const recipe = (spec.options ?? []).find((o) => o.flag === '--recipe');
199
+ expect(recipe?.value).toBe('<name>');
200
+ });
201
+ });
202
+ describe('sim command handler', () => {
203
+ it('runs against the default recipe and renders the result', async () => {
204
+ const { ctx, rendered } = makeFakeContext();
205
+ registerProbeScenario();
206
+ // Non-TTY/non-json path: the handler runs the engine and renders statically.
207
+ await simSpec().handler({ cwd: process.cwd() }, ctx);
208
+ expect(rendered).toHaveLength(1);
209
+ const result = rendered[0];
210
+ expect(result.type).toBe('sim-done');
211
+ expect(result.recipeName).toBe('default');
212
+ });
213
+ it('emits the signal envelope through cli.emitEnvelope when --json is passed', async () => {
214
+ const { ctx, emitted } = makeFakeContext();
215
+ registerProbeScenario();
216
+ await simSpec().handler({ cwd: process.cwd(), json: true }, ctx);
217
+ // ADR-0011 (Phase 4): --json routes the SignalEnvelope (not the bespoke
218
+ // SimDoneResult) through the root's emitEnvelope → formatSignalJson.
219
+ expect(emitted).toHaveLength(1);
220
+ const payload = emitted[0];
221
+ expect(payload.schemaVersion).toBe(2);
222
+ expect(payload.tool).toBe('sim');
223
+ });
224
+ it('delivers static egress with the requested cwd', async () => {
225
+ const { ctx, delivered } = makeFakeContext();
226
+ registerProbeScenario();
227
+ await simSpec().handler({ cwd: HERE, json: true }, ctx);
228
+ expect(delivered).toHaveLength(1);
229
+ expect(delivered[0]).toMatchObject({ cwd: HERE });
230
+ });
231
+ it('returns exit code 2 in JSON mode when the recipe is unknown', async () => {
232
+ const { ctx, exitCodes, emitted } = makeFakeContext();
233
+ await simSpec().handler({ cwd: process.cwd(), json: true, recipe: 'nope' }, ctx);
234
+ expect(exitCodes).toContain(2);
235
+ expect(emitted).toHaveLength(1);
236
+ // 2.12.0: a failed --json run emits a structured error detail (`message`),
237
+ // not a bare `{ error }` (the host wraps it in a status:'error' outcome).
238
+ const payload = emitted[0];
239
+ expect(payload.message).toContain('Unknown sim recipe');
240
+ });
241
+ it('returns exit code 2 in non-JSON mode for unknown recipe', async () => {
242
+ const { ctx, exitCodes, rendered } = makeFakeContext();
243
+ await simSpec().handler({ cwd: process.cwd(), recipe: 'still-nope' }, ctx);
244
+ expect(exitCodes).toContain(2);
245
+ const errResult = rendered[0];
246
+ expect(errResult.type).toBe('error');
247
+ expect(errResult.message).toContain('still-nope');
248
+ });
249
+ });
250
+ //# sourceMappingURL=tool.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.test.js","sourceRoot":"","sources":["../../src/__tests__/tool.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEzE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAIrD,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,oBAAoB,CAAC,EAAE,MAAM,CAAC,CAE/E,CAAC;AAEF,UAAU,CAAC,GAAG,EAAE;IACd,iEAAiE;IACjE,sEAAsE;IACtE,wEAAwE;IACxE,iBAAiB;IACjB,MAAM,KAAK,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC7B,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,cAAc,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,UAAU,CAAC,KAAK,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,GAAG,EAAE;IACb,qBAAqB,EAAE,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEH,4DAA4D;AAC5D,SAAS,OAAO;IACd,MAAM,IAAI,GAAG,cAAc,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9C,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAClF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe;IAOtB,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAc,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAc,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG;QACd,GAAG,EAAE,OAAO;QACZ,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,OAAO;QACpB,UAAU,EAAE,SAAS;QACrB,QAAQ,EAAE,CAAC;QACX,KAAK,EAAE,MAAe;KACvB,CAAC;IACF,yEAAyE;IACzE,uEAAuE;IACvE,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3D,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,GAAG,GAAmB;QAC1B,KAAK,EAAE,QAAQ;QACf,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,MAAe,EAAE,EAAE;YAChC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC3B,CAAC,CAAC;QACF,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE;QACzB,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC1C,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAC/C,MAAM,EAAE;YACN,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;YACd,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;YACb,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE;YACb,KAAK,EAAE,EAAE,CAAC,EAAE,EAAE;SACf;QACD,WAAW,EAAE,CAAC,IAAY,EAAE,EAAE;YAC5B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QACD,QAAQ,EAAE,CAAC,KAAc,EAAE,EAAE;YAC3B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,OAAO,EAAE,CAAC,KAAc,EAAE,EAAE;YAC1B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,YAAY,EAAE,CAAC,KAAc,EAAE,EAAE;YAC/B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;QACD,SAAS,EAAE,CAAC,MAAkE,EAAE,EAAE;YAChF,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QACD,cAAc,EAAE,CAAC,SAAkB,EAAE,IAAa,EAAE,EAAE;YACpD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;QACnC,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;QACrC,eAAe,EAAE,GAAG,EAAE,CACpB,OAAO,CAAC,OAAO,CAAC;YACd,KAAK,EAAE,EAAE;YACT,QAAQ,EAAE,EAAE;YACZ,SAAS,EAAE,EAAE;YACb,QAAQ,EAAE,KAAK;SAChB,CAAC;QACJ,mBAAmB,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;QAC5C,0BAA0B,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;QACnD,SAAS,EAAE;YACT,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;YACrC,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;YAC5B,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;YAC/B,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;SAChC;QACD,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,gBAAgB,EAAE,IAAI,CAAC,GAAG,EAAE;gBAC5B,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;gBAClB,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;oBACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACrC,UAAU,EAAE,CAAC;iBACd,CAAC;gBACF,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;oBACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACnC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBACrC,UAAU,EAAE,CAAC;iBACd,CAAC;aACH;SACF;KACF,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AAC1D,CAAC;AAED;;;;;GAKG;AACH,SAAS,qBAAqB;IAC5B,uBAAuB,EAAE,CAAC,QAAQ,CAChC,kBAAkB,CAAC;QACjB,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,OAAO;QACpB,IAAI,EAAE,EAAE;QACR,MAAM,EAAE,UAAU;QAClB,QAAQ,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE;QACpB,QAAQ,EAAE,CAAC;QACX,UAAU,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;KACzC,CAAC,CACH,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;QAChF,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC1D,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,4EAA4E;QAC5E,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC1C,MAAM,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kEAAkE,EAAE,GAAG,EAAE;IAChF,EAAE,CAAC,iFAAiF,EAAE,GAAG,EAAE;QACzF,oDAAoD;QACpD,MAAM,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACpD,6EAA6E;QAC7E,wDAAwD;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC1D,4EAA4E;QAC5E,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;QACvB,wDAAwD;QACxD,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CACnC,MAAM,CAAC,eAAe,CAAC;YACrB,KAAK;YACL,MAAM;YACN,OAAO;YACP,SAAS;YACT,OAAO;YACP,UAAU;YACV,QAAQ;YACR,MAAM;SACP,CAAC,CACH,CAAC;QACF,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,CAAC,WAAW,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QACvE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE,CAAC;QAC5C,qBAAqB,EAAE,CAAC;QAExB,6EAA6E;QAC7E,MAAM,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QAErD,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAA0C,CAAC;QACpE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,eAAe,EAAE,CAAC;QAC3C,qBAAqB,EAAE,CAAC;QAExB,MAAM,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;QAEjE,wEAAwE;QACxE,qEAAqE;QACrE,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAA8C,CAAC;QACxE,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,eAAe,EAAE,CAAC;QAC7C,qBAAqB,EAAE,CAAC;QAExB,MAAM,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;QAExD,MAAM,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,eAAe,EAAE,CAAC;QAEtD,MAAM,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC;QAEjF,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,2EAA2E;QAC3E,0EAA0E;QAC1E,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAyB,CAAC;QACnD,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,KAAK,IAAI,EAAE;QACvE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,eAAe,EAAE,CAAC;QAEvD,MAAM,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,GAAG,CAAC,CAAC;QAE3E,MAAM,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAuC,CAAC;QACpE,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sim-config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sim-config.test.d.ts","sourceRoot":"","sources":["../../../src/cli/__tests__/sim-config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,94 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { runWithScopeSync } from '@opensip-cli/core';
5
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
6
+ import { makeSimTestScope } from '../../__tests__/test-utils/with-sim-scope.js';
7
+ import { resolveSimRecipeSelection } from '../sim-config.js';
8
+ /**
9
+ * `resolveSimRecipeSelection` reads `simulation.recipe` from the project config
10
+ * (permissively — sim must not depend on fitness's strict schema) and applies
11
+ * ADR-0022 precedence.
12
+ */
13
+ describe('resolveSimRecipeSelection (ADR-0022)', () => {
14
+ let dir;
15
+ beforeEach(() => {
16
+ dir = mkdtempSync(join(tmpdir(), 'opensip-sim-cfg-'));
17
+ });
18
+ afterEach(() => {
19
+ rmSync(dir, { recursive: true, force: true });
20
+ });
21
+ const write = (yaml) => {
22
+ writeFileSync(join(dir, 'opensip-cli.config.yml'), yaml);
23
+ };
24
+ it('explicit --recipe wins and is strict', () => {
25
+ write('simulation:\n recipe: from-config\n');
26
+ expect(resolveSimRecipeSelection(dir, 'explicit')).toMatchObject({
27
+ name: 'explicit',
28
+ source: 'flag',
29
+ tolerant: false,
30
+ });
31
+ });
32
+ it('reads simulation.recipe when no flag', () => {
33
+ write('simulation:\n recipe: smoke\n');
34
+ expect(resolveSimRecipeSelection(dir, undefined)).toMatchObject({
35
+ name: 'smoke',
36
+ source: 'tool-config',
37
+ tolerant: true,
38
+ });
39
+ });
40
+ it('ignores cli.recipe now that the fallback was removed', () => {
41
+ write('cli:\n recipe: opensip\n');
42
+ expect(resolveSimRecipeSelection(dir, undefined)).toMatchObject({
43
+ name: 'default',
44
+ source: 'builtin',
45
+ tolerant: true,
46
+ });
47
+ });
48
+ it('returns the builtin default when no config file exists', () => {
49
+ expect(resolveSimRecipeSelection(dir, undefined)).toMatchObject({
50
+ name: 'default',
51
+ source: 'builtin',
52
+ tolerant: true,
53
+ });
54
+ });
55
+ it('ignores a non-string simulation.recipe (malformed) and falls through', () => {
56
+ write('simulation:\n recipe:\n - not-a-string\ncli:\n recipe: from-cli\n');
57
+ expect(resolveSimRecipeSelection(dir, undefined)).toMatchObject({
58
+ name: 'default',
59
+ source: 'builtin',
60
+ });
61
+ });
62
+ it('returns builtin default when simulation: block is not a mapping', () => {
63
+ write('simulation: just-a-scalar\n');
64
+ expect(resolveSimRecipeSelection(dir, undefined)).toMatchObject({
65
+ name: 'default',
66
+ source: 'builtin',
67
+ });
68
+ });
69
+ // ADR-0023, Phase 4: when a RunScope is present, sim reads `simulation.recipe`
70
+ // off the host-RESOLVED `scope.toolConfig.simulation` block, NOT a second YAML
71
+ // read. These prove the value comes from the scope (and that the on-disk file
72
+ // is ignored when the scope is present).
73
+ describe('reads simulation.recipe off scope.toolConfig.simulation', () => {
74
+ it('returns the resolved scope recipe, ignoring the on-disk simulation.recipe', () => {
75
+ // On-disk says `from-file`; a second YAML read would surface it. The scope
76
+ // says `from-scope` — sim must return the SCOPE value.
77
+ write('simulation:\n recipe: from-file\n');
78
+ const scope = makeSimTestScope();
79
+ Object.assign(scope, { toolConfig: { simulation: { recipe: 'from-scope' } } });
80
+ const resolved = runWithScopeSync(scope, () => resolveSimRecipeSelection(dir, undefined));
81
+ expect(resolved).toMatchObject({ name: 'from-scope', source: 'tool-config' });
82
+ });
83
+ it('returns builtin default when the scope simulation block has no recipe', () => {
84
+ // Scope simulation block is empty → no tool recipe, so the builtin default
85
+ // supplies the fallback.
86
+ write('cli:\n recipe: from-cli\n');
87
+ const scope = makeSimTestScope();
88
+ Object.assign(scope, { toolConfig: { simulation: {} } });
89
+ const resolved = runWithScopeSync(scope, () => resolveSimRecipeSelection(dir, undefined));
90
+ expect(resolved).toMatchObject({ name: 'default', source: 'builtin' });
91
+ });
92
+ });
93
+ });
94
+ //# sourceMappingURL=sim-config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sim-config.test.js","sourceRoot":"","sources":["../../../src/cli/__tests__/sim-config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @fileoverview Behavioural tests for the `sim` live-view state machine
3
+ * (ADR-0016). Drives `<SimRunner>` directly under ink-testing-library — no real
4
+ * TTY `render()` host — and asserts the rendered frames reflect each phase:
5
+ *
6
+ * - loading → running → done: the banner/run-header, the live spinner, and
7
+ * the final pass/fail RunSummary, with the run's SignalEnvelope handed back
8
+ * via `onEnvelope`.
9
+ * - failing scenario: `setExitCode(RUNTIME_ERROR)` fires when a scenario
10
+ * fails (the run still completes and shows a summary).
11
+ * - unknown recipe: the error phase renders <ErrorMessage> and reports the
12
+ * configuration exit code.
13
+ * - `--quiet`: the banner/header block is suppressed, leaving only the
14
+ * summary.
15
+ * - `mini` banner with an available update: the inline UpdateHint renders.
16
+ *
17
+ * The assertions inspect event-driven frame content (labels, counters,
18
+ * pass/fail glyphs), never the animated spinner frame, so they're
19
+ * deterministic. `waitForFrame` polls the latest frame to absorb React's async
20
+ * re-renders.
21
+ */
22
+ export {};
23
+ //# sourceMappingURL=sim-runner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sim-runner.test.d.ts","sourceRoot":"","sources":["../../../src/cli/__tests__/sim-runner.test.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG"}
@@ -0,0 +1,188 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * @fileoverview Behavioural tests for the `sim` live-view state machine
4
+ * (ADR-0016). Drives `<SimRunner>` directly under ink-testing-library — no real
5
+ * TTY `render()` host — and asserts the rendered frames reflect each phase:
6
+ *
7
+ * - loading → running → done: the banner/run-header, the live spinner, and
8
+ * the final pass/fail RunSummary, with the run's SignalEnvelope handed back
9
+ * via `onEnvelope`.
10
+ * - failing scenario: `setExitCode(RUNTIME_ERROR)` fires when a scenario
11
+ * fails (the run still completes and shows a summary).
12
+ * - unknown recipe: the error phase renders <ErrorMessage> and reports the
13
+ * configuration exit code.
14
+ * - `--quiet`: the banner/header block is suppressed, leaving only the
15
+ * summary.
16
+ * - `mini` banner with an available update: the inline UpdateHint renders.
17
+ *
18
+ * The assertions inspect event-driven frame content (labels, counters,
19
+ * pass/fail glyphs), never the animated spinner frame, so they're
20
+ * deterministic. `waitForFrame` polls the latest frame to absorb React's async
21
+ * re-renders.
22
+ */
23
+ import { enterScope, RunScope } from '@opensip-cli/core';
24
+ import { render } from 'ink-testing-library';
25
+ import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest';
26
+ import { noopTarget } from '../../__tests__/test-utils/targets.js';
27
+ import { ASSERTIONS } from '../../framework/assertions.js';
28
+ import { clearScenarioRegistry, currentScenarioRegistry } from '../../framework/registry.js';
29
+ import { defineLoadScenario } from '../../kinds/load/define.js';
30
+ import { simulationTool } from '../../tool.js';
31
+ import { SimRunner } from '../sim-runner.js';
32
+ // The live runner forks `sim-run-worker` off the main process (ADR-0028), but in
33
+ // the test runner `process.argv[1]` is vitest, not the CLI — so force the
34
+ // in-process fallback, which exercises the SimRunner state machine directly
35
+ // against the scope each test sets up. (The fork path is covered by a dedicated
36
+ // subprocess harness, not the component unit tests.)
37
+ beforeAll(() => {
38
+ process.env.OPENSIP_CLI_NO_WORKER = '1';
39
+ });
40
+ afterAll(() => {
41
+ delete process.env.OPENSIP_CLI_NO_WORKER;
42
+ });
43
+ afterEach(() => {
44
+ // Each test enters its own scope; clear the scenario registry between runs.
45
+ try {
46
+ clearScenarioRegistry();
47
+ }
48
+ catch {
49
+ // No active scope (a test that never entered one) — nothing to clear.
50
+ }
51
+ });
52
+ /** Enter a fresh scope (with the simulation subscope attached) plus any
53
+ * presentation context the header branch under test needs. */
54
+ function enterSimScope(opts = {}) {
55
+ const scope = new RunScope(opts);
56
+ Object.assign(scope, simulationTool.contributeScope?.() ?? {});
57
+ enterScope(scope);
58
+ }
59
+ function registerProbe(id = 'probe') {
60
+ currentScenarioRegistry().register(defineLoadScenario({
61
+ id,
62
+ name: id,
63
+ description: id,
64
+ tags: [],
65
+ target: noopTarget,
66
+ workload: { rps: 1 },
67
+ duration: 1,
68
+ assertions: [ASSERTIONS.lowErrorRate(1)],
69
+ }));
70
+ }
71
+ const baseArgs = (overrides = {}) => ({
72
+ json: false,
73
+ cwd: process.cwd(),
74
+ debug: false,
75
+ ...overrides,
76
+ });
77
+ /** Poll the latest frame until it contains `substr` (or time out). */
78
+ async function waitForFrame(lastFrame, substr) {
79
+ for (let i = 0; i < 200; i++) {
80
+ if ((lastFrame() ?? '').includes(substr))
81
+ return;
82
+ await new Promise((resolve) => {
83
+ setTimeout(resolve, 5);
84
+ });
85
+ }
86
+ }
87
+ describe('<SimRunner> — live-view state machine', () => {
88
+ it('renders the run header, then the final pass summary, and returns the envelope', async () => {
89
+ enterSimScope();
90
+ registerProbe('runner-pass');
91
+ let captured;
92
+ const exitCodes = [];
93
+ const { lastFrame, unmount } = render(_jsx(SimRunner, { args: baseArgs(), setExitCode: (c) => exitCodes.push(c), onEnvelope: (e) => {
94
+ captured = e;
95
+ } }));
96
+ // Header (non-quiet, non-mini default) carries the tool title + recipe.
97
+ await waitForFrame(lastFrame, 'Simulation Scenarios');
98
+ expect(lastFrame()).toContain('Recipe');
99
+ expect(lastFrame()).toContain('default');
100
+ // The run completes; the summary shows the PASS verdict (ADR-0035).
101
+ await waitForFrame(lastFrame, 'PASS');
102
+ const frame = lastFrame() ?? '';
103
+ expect(frame).toContain('PASS');
104
+ // The completed run handed its envelope back to the composition root, and a
105
+ // green run sets no failure exit code.
106
+ expect(captured).toBeDefined();
107
+ expect(captured?.tool).toBe('sim');
108
+ expect(captured?.verdict.passed).toBe(true);
109
+ expect(exitCodes).not.toContain(1);
110
+ unmount();
111
+ });
112
+ it('yields a failing-verdict envelope when a scenario fails (host owns the exit)', async () => {
113
+ enterSimScope();
114
+ // A scenario whose run() rejects → recorded as failed.
115
+ currentScenarioRegistry().register({
116
+ id: 'runner-boom',
117
+ name: 'runner-boom',
118
+ description: 'boom',
119
+ kind: 'load',
120
+ tags: [],
121
+ run: () => Promise.reject(new Error('kaboom')),
122
+ });
123
+ const exitCodes = [];
124
+ let captured;
125
+ const { lastFrame, unmount } = render(_jsx(SimRunner, { args: baseArgs(), setExitCode: (c) => exitCodes.push(c), onEnvelope: (e) => {
126
+ captured = e;
127
+ } }));
128
+ await waitForFrame(lastFrame, 'FAIL');
129
+ // ADR-0035: the runner no longer sets the findings exit — it hands the
130
+ // envelope to the host (via onEnvelope → deliverSignals), which derives the
131
+ // exit from envelope.verdict.passed. The runner itself sets no findings code.
132
+ expect(exitCodes).not.toContain(1);
133
+ expect(captured).toBeDefined();
134
+ expect(captured?.verdict.summary.failed).toBe(1);
135
+ // A thrown scenario fails its unit → the run verdict fails → the host exits 1.
136
+ expect(captured?.verdict.passed).toBe(false);
137
+ unmount();
138
+ });
139
+ it('renders the error phase and reports the config exit code for an unknown recipe', async () => {
140
+ enterSimScope();
141
+ registerProbe('runner-unused');
142
+ const exitCodes = [];
143
+ const { lastFrame, unmount } = render(_jsx(SimRunner, { args: baseArgs({ recipe: 'does-not-exist' }), setExitCode: (c) => exitCodes.push(c) }));
144
+ await waitForFrame(lastFrame, 'does-not-exist');
145
+ expect(lastFrame()).toContain('does-not-exist');
146
+ // CONFIGURATION_ERROR === 2. The exit code is set in the same async tick as
147
+ // the error-phase transition; poll briefly to absorb the React re-render.
148
+ for (let i = 0; i < 50 && !exitCodes.includes(2); i++) {
149
+ await new Promise((resolve) => {
150
+ setTimeout(resolve, 5);
151
+ });
152
+ }
153
+ expect(exitCodes).toContain(2);
154
+ unmount();
155
+ });
156
+ it('suppresses the banner/header block under --quiet but still shows the summary', async () => {
157
+ enterSimScope();
158
+ registerProbe('runner-quiet');
159
+ const { lastFrame, unmount } = render(_jsx(SimRunner, { args: baseArgs({ quiet: true }) }));
160
+ await waitForFrame(lastFrame, 'PASS');
161
+ const frame = lastFrame() ?? '';
162
+ // Quiet drops the run-header chrome…
163
+ expect(frame).not.toContain('Simulation Scenarios');
164
+ // …but keeps the PASS/FAIL verdict summary.
165
+ expect(frame).toContain('PASS');
166
+ unmount();
167
+ });
168
+ it('renders the mini banner update hint when an update is available', async () => {
169
+ enterSimScope({
170
+ ui: { bannerSize: 'mini', version: '3.0.0', update: '3.1.0' },
171
+ projectContext: {
172
+ cwd: process.cwd(),
173
+ cwdExplicit: false,
174
+ projectRoot: process.cwd(),
175
+ configPath: undefined,
176
+ walkedUp: 0,
177
+ scope: 'none',
178
+ },
179
+ });
180
+ registerProbe('runner-mini');
181
+ const { lastFrame, unmount } = render(_jsx(SimRunner, { args: baseArgs() }));
182
+ // The mini banner surfaces the available update; the UpdateHint row renders.
183
+ await waitForFrame(lastFrame, '3.1.0');
184
+ expect(lastFrame()).toContain('3.1.0');
185
+ unmount();
186
+ });
187
+ });
188
+ //# sourceMappingURL=sim-runner.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sim-runner.test.js","sourceRoot":"","sources":["../../../src/cli/__tests__/sim-runner.test.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `sim-run-worker` — the headless sim run forked by the live view
3
+ * (`executeSimWorker`, ADR-0028). It reads a serializable sim-args spec, runs
4
+ * `executeSim` headless, streams pool progress over the fork IPC channel
5
+ * (`process.send`), and posts the final result. A bad spec is reported as a
6
+ * `{ kind: 'error' }` message, not a throw.
7
+ *
8
+ * The test stubs `process.send` (the process is not actually forked under vitest)
9
+ * and registers a scenario so the default recipe has work to run.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=sim-worker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sim-worker.test.d.ts","sourceRoot":"","sources":["../../../src/cli/__tests__/sim-worker.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}