flock-core 0.5.0b28__py3-none-any.whl → 0.5.0b51__py3-none-any.whl

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.

Potentially problematic release.


This version of flock-core might be problematic. Click here for more details.

Files changed (469) hide show
  1. flock/__init__.py +12 -217
  2. flock/agent.py +678 -0
  3. flock/api/themes.py +71 -0
  4. flock/artifacts.py +79 -0
  5. flock/cli.py +75 -0
  6. flock/components.py +173 -0
  7. flock/dashboard/__init__.py +28 -0
  8. flock/dashboard/collector.py +283 -0
  9. flock/dashboard/events.py +182 -0
  10. flock/dashboard/launcher.py +230 -0
  11. flock/dashboard/service.py +537 -0
  12. flock/dashboard/websocket.py +235 -0
  13. flock/engines/__init__.py +6 -0
  14. flock/engines/dspy_engine.py +856 -0
  15. flock/examples.py +128 -0
  16. flock/frontend/README.md +678 -0
  17. flock/frontend/docs/DESIGN_SYSTEM.md +1980 -0
  18. flock/frontend/index.html +12 -0
  19. flock/frontend/package-lock.json +4347 -0
  20. flock/frontend/package.json +48 -0
  21. flock/frontend/src/App.tsx +79 -0
  22. flock/frontend/src/__tests__/e2e/critical-scenarios.test.tsx +587 -0
  23. flock/frontend/src/__tests__/integration/filtering-e2e.test.tsx +387 -0
  24. flock/frontend/src/__tests__/integration/graph-rendering.test.tsx +640 -0
  25. flock/frontend/src/__tests__/integration/indexeddb-persistence.test.tsx +699 -0
  26. flock/frontend/src/components/common/BuildInfo.tsx +39 -0
  27. flock/frontend/src/components/common/EmptyState.module.css +115 -0
  28. flock/frontend/src/components/common/EmptyState.tsx +128 -0
  29. flock/frontend/src/components/common/ErrorBoundary.module.css +169 -0
  30. flock/frontend/src/components/common/ErrorBoundary.tsx +118 -0
  31. flock/frontend/src/components/common/KeyboardShortcutsDialog.css +251 -0
  32. flock/frontend/src/components/common/KeyboardShortcutsDialog.tsx +151 -0
  33. flock/frontend/src/components/common/LoadingSpinner.module.css +97 -0
  34. flock/frontend/src/components/common/LoadingSpinner.tsx +29 -0
  35. flock/frontend/src/components/controls/PublishControl.css +547 -0
  36. flock/frontend/src/components/controls/PublishControl.test.tsx +543 -0
  37. flock/frontend/src/components/controls/PublishControl.tsx +432 -0
  38. flock/frontend/src/components/details/DetailWindowContainer.tsx +62 -0
  39. flock/frontend/src/components/details/LiveOutputTab.test.tsx +792 -0
  40. flock/frontend/src/components/details/LiveOutputTab.tsx +220 -0
  41. flock/frontend/src/components/details/MessageHistoryTab.tsx +299 -0
  42. flock/frontend/src/components/details/NodeDetailWindow.test.tsx +501 -0
  43. flock/frontend/src/components/details/NodeDetailWindow.tsx +218 -0
  44. flock/frontend/src/components/details/RunStatusTab.tsx +307 -0
  45. flock/frontend/src/components/details/tabs.test.tsx +1015 -0
  46. flock/frontend/src/components/filters/CorrelationIDFilter.module.css +102 -0
  47. flock/frontend/src/components/filters/CorrelationIDFilter.test.tsx +197 -0
  48. flock/frontend/src/components/filters/CorrelationIDFilter.tsx +121 -0
  49. flock/frontend/src/components/filters/FilterBar.module.css +29 -0
  50. flock/frontend/src/components/filters/FilterBar.test.tsx +133 -0
  51. flock/frontend/src/components/filters/FilterBar.tsx +33 -0
  52. flock/frontend/src/components/filters/FilterPills.module.css +79 -0
  53. flock/frontend/src/components/filters/FilterPills.test.tsx +173 -0
  54. flock/frontend/src/components/filters/FilterPills.tsx +67 -0
  55. flock/frontend/src/components/filters/TimeRangeFilter.module.css +91 -0
  56. flock/frontend/src/components/filters/TimeRangeFilter.test.tsx +154 -0
  57. flock/frontend/src/components/filters/TimeRangeFilter.tsx +105 -0
  58. flock/frontend/src/components/graph/AgentNode.test.tsx +75 -0
  59. flock/frontend/src/components/graph/AgentNode.tsx +322 -0
  60. flock/frontend/src/components/graph/GraphCanvas.tsx +406 -0
  61. flock/frontend/src/components/graph/MessageFlowEdge.tsx +128 -0
  62. flock/frontend/src/components/graph/MessageNode.test.tsx +62 -0
  63. flock/frontend/src/components/graph/MessageNode.tsx +116 -0
  64. flock/frontend/src/components/graph/MiniMap.tsx +47 -0
  65. flock/frontend/src/components/graph/TransformEdge.tsx +123 -0
  66. flock/frontend/src/components/layout/DashboardLayout.css +407 -0
  67. flock/frontend/src/components/layout/DashboardLayout.tsx +300 -0
  68. flock/frontend/src/components/layout/Header.module.css +88 -0
  69. flock/frontend/src/components/layout/Header.tsx +52 -0
  70. flock/frontend/src/components/modules/EventLogModule.test.tsx +401 -0
  71. flock/frontend/src/components/modules/EventLogModule.tsx +396 -0
  72. flock/frontend/src/components/modules/EventLogModuleWrapper.tsx +17 -0
  73. flock/frontend/src/components/modules/ModuleRegistry.test.ts +333 -0
  74. flock/frontend/src/components/modules/ModuleRegistry.ts +85 -0
  75. flock/frontend/src/components/modules/ModuleWindow.tsx +155 -0
  76. flock/frontend/src/components/modules/registerModules.ts +20 -0
  77. flock/frontend/src/components/settings/AdvancedSettings.tsx +175 -0
  78. flock/frontend/src/components/settings/AppearanceSettings.tsx +185 -0
  79. flock/frontend/src/components/settings/GraphSettings.tsx +110 -0
  80. flock/frontend/src/components/settings/SettingsPanel.css +327 -0
  81. flock/frontend/src/components/settings/SettingsPanel.tsx +131 -0
  82. flock/frontend/src/components/settings/ThemeSelector.tsx +298 -0
  83. flock/frontend/src/hooks/useKeyboardShortcuts.ts +148 -0
  84. flock/frontend/src/hooks/useModulePersistence.test.ts +442 -0
  85. flock/frontend/src/hooks/useModulePersistence.ts +154 -0
  86. flock/frontend/src/hooks/useModules.ts +139 -0
  87. flock/frontend/src/hooks/usePersistence.ts +139 -0
  88. flock/frontend/src/main.tsx +13 -0
  89. flock/frontend/src/services/api.ts +213 -0
  90. flock/frontend/src/services/indexeddb.test.ts +793 -0
  91. flock/frontend/src/services/indexeddb.ts +794 -0
  92. flock/frontend/src/services/layout.test.ts +437 -0
  93. flock/frontend/src/services/layout.ts +146 -0
  94. flock/frontend/src/services/themeApplicator.ts +140 -0
  95. flock/frontend/src/services/themeService.ts +77 -0
  96. flock/frontend/src/services/websocket.test.ts +595 -0
  97. flock/frontend/src/services/websocket.ts +685 -0
  98. flock/frontend/src/store/filterStore.test.ts +242 -0
  99. flock/frontend/src/store/filterStore.ts +103 -0
  100. flock/frontend/src/store/graphStore.test.ts +186 -0
  101. flock/frontend/src/store/graphStore.ts +414 -0
  102. flock/frontend/src/store/moduleStore.test.ts +253 -0
  103. flock/frontend/src/store/moduleStore.ts +57 -0
  104. flock/frontend/src/store/settingsStore.ts +188 -0
  105. flock/frontend/src/store/streamStore.ts +68 -0
  106. flock/frontend/src/store/uiStore.test.ts +54 -0
  107. flock/frontend/src/store/uiStore.ts +110 -0
  108. flock/frontend/src/store/wsStore.ts +34 -0
  109. flock/frontend/src/styles/index.css +15 -0
  110. flock/frontend/src/styles/scrollbar.css +47 -0
  111. flock/frontend/src/styles/variables.css +488 -0
  112. flock/frontend/src/test/setup.ts +1 -0
  113. flock/frontend/src/types/filters.ts +14 -0
  114. flock/frontend/src/types/graph.ts +55 -0
  115. flock/frontend/src/types/modules.ts +7 -0
  116. flock/frontend/src/types/theme.ts +55 -0
  117. flock/frontend/src/utils/mockData.ts +85 -0
  118. flock/frontend/src/utils/performance.ts +16 -0
  119. flock/frontend/src/utils/transforms.test.ts +860 -0
  120. flock/frontend/src/utils/transforms.ts +323 -0
  121. flock/frontend/src/vite-env.d.ts +17 -0
  122. flock/frontend/tsconfig.json +27 -0
  123. flock/frontend/tsconfig.node.json +11 -0
  124. flock/frontend/vite.config.ts +25 -0
  125. flock/frontend/vitest.config.ts +11 -0
  126. flock/{core/util → helper}/cli_helper.py +4 -3
  127. flock/{core/logging → logging}/__init__.py +2 -3
  128. flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
  129. flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
  130. flock/{core/logging → logging}/formatters/themed_formatter.py +69 -115
  131. flock/{core/logging → logging}/logging.py +77 -61
  132. flock/{core/logging → logging}/telemetry.py +20 -26
  133. flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
  134. flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +6 -9
  135. flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
  136. flock/{core/logging → logging}/trace_and_logged.py +20 -24
  137. flock/mcp/__init__.py +91 -0
  138. flock/{core/mcp/mcp_client.py → mcp/client.py} +103 -154
  139. flock/{core/mcp/mcp_config.py → mcp/config.py} +62 -117
  140. flock/mcp/manager.py +255 -0
  141. flock/mcp/servers/sse/__init__.py +1 -1
  142. flock/mcp/servers/sse/flock_sse_server.py +11 -53
  143. flock/mcp/servers/stdio/__init__.py +1 -1
  144. flock/mcp/servers/stdio/flock_stdio_server.py +8 -48
  145. flock/mcp/servers/streamable_http/flock_streamable_http_server.py +17 -62
  146. flock/mcp/servers/websockets/flock_websocket_server.py +7 -40
  147. flock/{core/mcp/flock_mcp_tool.py → mcp/tool.py} +16 -26
  148. flock/mcp/types/__init__.py +42 -0
  149. flock/{core/mcp → mcp}/types/callbacks.py +9 -15
  150. flock/{core/mcp → mcp}/types/factories.py +7 -6
  151. flock/{core/mcp → mcp}/types/handlers.py +13 -18
  152. flock/{core/mcp → mcp}/types/types.py +70 -74
  153. flock/{core/mcp → mcp}/util/helpers.py +1 -1
  154. flock/orchestrator.py +645 -0
  155. flock/registry.py +148 -0
  156. flock/runtime.py +262 -0
  157. flock/service.py +140 -0
  158. flock/store.py +69 -0
  159. flock/subscription.py +111 -0
  160. flock/themes/andromeda.toml +1 -1
  161. flock/themes/apple-system-colors.toml +1 -1
  162. flock/themes/arcoiris.toml +1 -1
  163. flock/themes/atomonelight.toml +1 -1
  164. flock/themes/ayu copy.toml +1 -1
  165. flock/themes/ayu-light.toml +1 -1
  166. flock/themes/belafonte-day.toml +1 -1
  167. flock/themes/belafonte-night.toml +1 -1
  168. flock/themes/blulocodark.toml +1 -1
  169. flock/themes/breeze.toml +1 -1
  170. flock/themes/broadcast.toml +1 -1
  171. flock/themes/brogrammer.toml +1 -1
  172. flock/themes/builtin-dark.toml +1 -1
  173. flock/themes/builtin-pastel-dark.toml +1 -1
  174. flock/themes/catppuccin-latte.toml +1 -1
  175. flock/themes/catppuccin-macchiato.toml +1 -1
  176. flock/themes/catppuccin-mocha.toml +1 -1
  177. flock/themes/cga.toml +1 -1
  178. flock/themes/chalk.toml +1 -1
  179. flock/themes/ciapre.toml +1 -1
  180. flock/themes/coffee-theme.toml +1 -1
  181. flock/themes/cyberpunkscarletprotocol.toml +1 -1
  182. flock/themes/dark+.toml +1 -1
  183. flock/themes/darkermatrix.toml +1 -1
  184. flock/themes/darkside.toml +1 -1
  185. flock/themes/desert.toml +1 -1
  186. flock/themes/django.toml +1 -1
  187. flock/themes/djangosmooth.toml +1 -1
  188. flock/themes/doomone.toml +1 -1
  189. flock/themes/dotgov.toml +1 -1
  190. flock/themes/dracula+.toml +1 -1
  191. flock/themes/duckbones.toml +1 -1
  192. flock/themes/encom.toml +1 -1
  193. flock/themes/espresso.toml +1 -1
  194. flock/themes/everblush.toml +1 -1
  195. flock/themes/fairyfloss.toml +1 -1
  196. flock/themes/fideloper.toml +1 -1
  197. flock/themes/fishtank.toml +1 -1
  198. flock/themes/flexoki-light.toml +1 -1
  199. flock/themes/floraverse.toml +1 -1
  200. flock/themes/framer.toml +1 -1
  201. flock/themes/galizur.toml +1 -1
  202. flock/themes/github.toml +1 -1
  203. flock/themes/grass.toml +1 -1
  204. flock/themes/grey-green.toml +1 -1
  205. flock/themes/gruvboxlight.toml +1 -1
  206. flock/themes/guezwhoz.toml +1 -1
  207. flock/themes/harper.toml +1 -1
  208. flock/themes/hax0r-blue.toml +1 -1
  209. flock/themes/hopscotch.256.toml +1 -1
  210. flock/themes/ic-green-ppl.toml +1 -1
  211. flock/themes/iceberg-dark.toml +1 -1
  212. flock/themes/japanesque.toml +1 -1
  213. flock/themes/jubi.toml +1 -1
  214. flock/themes/kibble.toml +1 -1
  215. flock/themes/kolorit.toml +1 -1
  216. flock/themes/kurokula.toml +1 -1
  217. flock/themes/materialdesigncolors.toml +1 -1
  218. flock/themes/matrix.toml +1 -1
  219. flock/themes/mellifluous.toml +1 -1
  220. flock/themes/midnight-in-mojave.toml +1 -1
  221. flock/themes/monokai-remastered.toml +1 -1
  222. flock/themes/monokai-soda.toml +1 -1
  223. flock/themes/neon.toml +1 -1
  224. flock/themes/neopolitan.toml +1 -1
  225. flock/themes/nord-light.toml +1 -1
  226. flock/themes/ocean.toml +1 -1
  227. flock/themes/onehalfdark.toml +1 -1
  228. flock/themes/onehalflight.toml +1 -1
  229. flock/themes/palenighthc.toml +1 -1
  230. flock/themes/paulmillr.toml +1 -1
  231. flock/themes/pencildark.toml +1 -1
  232. flock/themes/pnevma.toml +1 -1
  233. flock/themes/purple-rain.toml +1 -1
  234. flock/themes/purplepeter.toml +1 -1
  235. flock/themes/raycast-dark.toml +1 -1
  236. flock/themes/red-sands.toml +1 -1
  237. flock/themes/relaxed.toml +1 -1
  238. flock/themes/retro.toml +1 -1
  239. flock/themes/rose-pine.toml +1 -1
  240. flock/themes/royal.toml +1 -1
  241. flock/themes/ryuuko.toml +1 -1
  242. flock/themes/sakura.toml +1 -1
  243. flock/themes/scarlet-protocol.toml +1 -1
  244. flock/themes/seoulbones-dark.toml +1 -1
  245. flock/themes/shades-of-purple.toml +1 -1
  246. flock/themes/smyck.toml +1 -1
  247. flock/themes/softserver.toml +1 -1
  248. flock/themes/solarized-darcula.toml +1 -1
  249. flock/themes/square.toml +1 -1
  250. flock/themes/sugarplum.toml +1 -1
  251. flock/themes/thayer-bright.toml +1 -1
  252. flock/themes/tokyonight.toml +1 -1
  253. flock/themes/tomorrow.toml +1 -1
  254. flock/themes/ubuntu.toml +1 -1
  255. flock/themes/ultradark.toml +1 -1
  256. flock/themes/ultraviolent.toml +1 -1
  257. flock/themes/unikitty.toml +1 -1
  258. flock/themes/urple.toml +1 -1
  259. flock/themes/vesper.toml +1 -1
  260. flock/themes/vimbones.toml +1 -1
  261. flock/themes/wildcherry.toml +1 -1
  262. flock/themes/wilmersdorf.toml +1 -1
  263. flock/themes/wryan.toml +1 -1
  264. flock/themes/xcodedarkhc.toml +1 -1
  265. flock/themes/xcodelight.toml +1 -1
  266. flock/themes/zenbones-light.toml +1 -1
  267. flock/themes/zenwritten-dark.toml +1 -1
  268. flock/utilities.py +301 -0
  269. flock/{components/utility → utility}/output_utility_component.py +68 -53
  270. flock/visibility.py +107 -0
  271. flock_core-0.5.0b51.dist-info/METADATA +747 -0
  272. flock_core-0.5.0b51.dist-info/RECORD +508 -0
  273. flock_core-0.5.0b51.dist-info/entry_points.txt +2 -0
  274. {flock_core-0.5.0b28.dist-info → flock_core-0.5.0b51.dist-info}/licenses/LICENSE +1 -1
  275. flock/adapter/__init__.py +0 -14
  276. flock/adapter/azure_adapter.py +0 -68
  277. flock/adapter/chroma_adapter.py +0 -73
  278. flock/adapter/faiss_adapter.py +0 -97
  279. flock/adapter/pinecone_adapter.py +0 -51
  280. flock/adapter/vector_base.py +0 -47
  281. flock/cli/assets/release_notes.md +0 -140
  282. flock/cli/config.py +0 -8
  283. flock/cli/constants.py +0 -36
  284. flock/cli/create_agent.py +0 -1
  285. flock/cli/create_flock.py +0 -280
  286. flock/cli/execute_flock.py +0 -620
  287. flock/cli/load_agent.py +0 -1
  288. flock/cli/load_examples.py +0 -1
  289. flock/cli/load_flock.py +0 -192
  290. flock/cli/load_release_notes.py +0 -20
  291. flock/cli/loaded_flock_cli.py +0 -254
  292. flock/cli/manage_agents.py +0 -459
  293. flock/cli/registry_management.py +0 -889
  294. flock/cli/runner.py +0 -41
  295. flock/cli/settings.py +0 -857
  296. flock/cli/utils.py +0 -135
  297. flock/cli/view_results.py +0 -29
  298. flock/cli/yaml_editor.py +0 -396
  299. flock/components/__init__.py +0 -30
  300. flock/components/evaluation/__init__.py +0 -9
  301. flock/components/evaluation/declarative_evaluation_component.py +0 -606
  302. flock/components/routing/__init__.py +0 -15
  303. flock/components/routing/conditional_routing_component.py +0 -494
  304. flock/components/routing/default_routing_component.py +0 -103
  305. flock/components/routing/llm_routing_component.py +0 -206
  306. flock/components/utility/__init__.py +0 -22
  307. flock/components/utility/example_utility_component.py +0 -250
  308. flock/components/utility/feedback_utility_component.py +0 -206
  309. flock/components/utility/memory_utility_component.py +0 -550
  310. flock/components/utility/metrics_utility_component.py +0 -700
  311. flock/config.py +0 -61
  312. flock/core/__init__.py +0 -110
  313. flock/core/agent/__init__.py +0 -16
  314. flock/core/agent/default_agent.py +0 -216
  315. flock/core/agent/flock_agent_components.py +0 -104
  316. flock/core/agent/flock_agent_execution.py +0 -101
  317. flock/core/agent/flock_agent_integration.py +0 -260
  318. flock/core/agent/flock_agent_lifecycle.py +0 -186
  319. flock/core/agent/flock_agent_serialization.py +0 -381
  320. flock/core/api/__init__.py +0 -10
  321. flock/core/api/custom_endpoint.py +0 -45
  322. flock/core/api/endpoints.py +0 -254
  323. flock/core/api/main.py +0 -162
  324. flock/core/api/models.py +0 -97
  325. flock/core/api/run_store.py +0 -224
  326. flock/core/api/runner.py +0 -44
  327. flock/core/api/service.py +0 -214
  328. flock/core/component/__init__.py +0 -15
  329. flock/core/component/agent_component_base.py +0 -309
  330. flock/core/component/evaluation_component.py +0 -62
  331. flock/core/component/routing_component.py +0 -74
  332. flock/core/component/utility_component.py +0 -69
  333. flock/core/config/flock_agent_config.py +0 -58
  334. flock/core/config/scheduled_agent_config.py +0 -40
  335. flock/core/context/context.py +0 -213
  336. flock/core/context/context_manager.py +0 -37
  337. flock/core/context/context_vars.py +0 -10
  338. flock/core/evaluation/utils.py +0 -396
  339. flock/core/execution/batch_executor.py +0 -369
  340. flock/core/execution/evaluation_executor.py +0 -438
  341. flock/core/execution/local_executor.py +0 -31
  342. flock/core/execution/opik_executor.py +0 -103
  343. flock/core/execution/temporal_executor.py +0 -164
  344. flock/core/flock.py +0 -634
  345. flock/core/flock_agent.py +0 -336
  346. flock/core/flock_factory.py +0 -613
  347. flock/core/flock_scheduler.py +0 -166
  348. flock/core/flock_server_manager.py +0 -136
  349. flock/core/interpreter/python_interpreter.py +0 -689
  350. flock/core/mcp/__init__.py +0 -1
  351. flock/core/mcp/flock_mcp_server.py +0 -680
  352. flock/core/mcp/mcp_client_manager.py +0 -201
  353. flock/core/mcp/types/__init__.py +0 -1
  354. flock/core/mixin/dspy_integration.py +0 -403
  355. flock/core/mixin/prompt_parser.py +0 -125
  356. flock/core/orchestration/__init__.py +0 -15
  357. flock/core/orchestration/flock_batch_processor.py +0 -94
  358. flock/core/orchestration/flock_evaluator.py +0 -113
  359. flock/core/orchestration/flock_execution.py +0 -295
  360. flock/core/orchestration/flock_initialization.py +0 -149
  361. flock/core/orchestration/flock_server_manager.py +0 -67
  362. flock/core/orchestration/flock_web_server.py +0 -117
  363. flock/core/registry/__init__.py +0 -45
  364. flock/core/registry/agent_registry.py +0 -69
  365. flock/core/registry/callable_registry.py +0 -139
  366. flock/core/registry/component_discovery.py +0 -142
  367. flock/core/registry/component_registry.py +0 -64
  368. flock/core/registry/config_mapping.py +0 -64
  369. flock/core/registry/decorators.py +0 -137
  370. flock/core/registry/registry_hub.py +0 -205
  371. flock/core/registry/server_registry.py +0 -57
  372. flock/core/registry/type_registry.py +0 -86
  373. flock/core/serialization/__init__.py +0 -13
  374. flock/core/serialization/callable_registry.py +0 -52
  375. flock/core/serialization/flock_serializer.py +0 -832
  376. flock/core/serialization/json_encoder.py +0 -41
  377. flock/core/serialization/secure_serializer.py +0 -175
  378. flock/core/serialization/serializable.py +0 -342
  379. flock/core/serialization/serialization_utils.py +0 -412
  380. flock/core/util/file_path_utils.py +0 -223
  381. flock/core/util/hydrator.py +0 -309
  382. flock/core/util/input_resolver.py +0 -164
  383. flock/core/util/loader.py +0 -59
  384. flock/core/util/splitter.py +0 -219
  385. flock/di.py +0 -27
  386. flock/platform/docker_tools.py +0 -49
  387. flock/platform/jaeger_install.py +0 -86
  388. flock/webapp/__init__.py +0 -1
  389. flock/webapp/app/__init__.py +0 -0
  390. flock/webapp/app/api/__init__.py +0 -0
  391. flock/webapp/app/api/agent_management.py +0 -241
  392. flock/webapp/app/api/execution.py +0 -709
  393. flock/webapp/app/api/flock_management.py +0 -129
  394. flock/webapp/app/api/registry_viewer.py +0 -30
  395. flock/webapp/app/chat.py +0 -665
  396. flock/webapp/app/config.py +0 -104
  397. flock/webapp/app/dependencies.py +0 -117
  398. flock/webapp/app/main.py +0 -1070
  399. flock/webapp/app/middleware.py +0 -113
  400. flock/webapp/app/models_ui.py +0 -7
  401. flock/webapp/app/services/__init__.py +0 -0
  402. flock/webapp/app/services/feedback_file_service.py +0 -363
  403. flock/webapp/app/services/flock_service.py +0 -337
  404. flock/webapp/app/services/sharing_models.py +0 -81
  405. flock/webapp/app/services/sharing_store.py +0 -762
  406. flock/webapp/app/templates/theme_mapper.html +0 -326
  407. flock/webapp/app/theme_mapper.py +0 -812
  408. flock/webapp/app/utils.py +0 -85
  409. flock/webapp/run.py +0 -215
  410. flock/webapp/static/css/chat.css +0 -301
  411. flock/webapp/static/css/components.css +0 -167
  412. flock/webapp/static/css/header.css +0 -39
  413. flock/webapp/static/css/layout.css +0 -46
  414. flock/webapp/static/css/sidebar.css +0 -127
  415. flock/webapp/static/css/two-pane.css +0 -48
  416. flock/webapp/templates/base.html +0 -200
  417. flock/webapp/templates/chat.html +0 -152
  418. flock/webapp/templates/chat_settings.html +0 -19
  419. flock/webapp/templates/flock_editor.html +0 -16
  420. flock/webapp/templates/index.html +0 -12
  421. flock/webapp/templates/partials/_agent_detail_form.html +0 -93
  422. flock/webapp/templates/partials/_agent_list.html +0 -18
  423. flock/webapp/templates/partials/_agent_manager_view.html +0 -51
  424. flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
  425. flock/webapp/templates/partials/_chat_container.html +0 -15
  426. flock/webapp/templates/partials/_chat_messages.html +0 -57
  427. flock/webapp/templates/partials/_chat_settings_form.html +0 -85
  428. flock/webapp/templates/partials/_create_flock_form.html +0 -50
  429. flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
  430. flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
  431. flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
  432. flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
  433. flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
  434. flock/webapp/templates/partials/_env_vars_table.html +0 -23
  435. flock/webapp/templates/partials/_execution_form.html +0 -118
  436. flock/webapp/templates/partials/_execution_view_container.html +0 -28
  437. flock/webapp/templates/partials/_flock_file_list.html +0 -23
  438. flock/webapp/templates/partials/_flock_properties_form.html +0 -52
  439. flock/webapp/templates/partials/_flock_upload_form.html +0 -16
  440. flock/webapp/templates/partials/_header_flock_status.html +0 -5
  441. flock/webapp/templates/partials/_load_manager_view.html +0 -49
  442. flock/webapp/templates/partials/_registry_table.html +0 -25
  443. flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
  444. flock/webapp/templates/partials/_results_display.html +0 -78
  445. flock/webapp/templates/partials/_settings_env_content.html +0 -9
  446. flock/webapp/templates/partials/_settings_theme_content.html +0 -14
  447. flock/webapp/templates/partials/_settings_view.html +0 -36
  448. flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
  449. flock/webapp/templates/partials/_share_link_snippet.html +0 -35
  450. flock/webapp/templates/partials/_sidebar.html +0 -74
  451. flock/webapp/templates/partials/_streaming_results_container.html +0 -195
  452. flock/webapp/templates/partials/_structured_data_view.html +0 -40
  453. flock/webapp/templates/partials/_theme_preview.html +0 -36
  454. flock/webapp/templates/registry_viewer.html +0 -84
  455. flock/webapp/templates/shared_run_page.html +0 -140
  456. flock/workflow/__init__.py +0 -0
  457. flock/workflow/activities.py +0 -196
  458. flock/workflow/agent_activities.py +0 -24
  459. flock/workflow/agent_execution_activity.py +0 -202
  460. flock/workflow/flock_workflow.py +0 -214
  461. flock/workflow/temporal_config.py +0 -96
  462. flock/workflow/temporal_setup.py +0 -68
  463. flock_core-0.5.0b28.dist-info/METADATA +0 -274
  464. flock_core-0.5.0b28.dist-info/RECORD +0 -561
  465. flock_core-0.5.0b28.dist-info/entry_points.txt +0 -2
  466. /flock/{core/logging → logging}/formatters/themes.py +0 -0
  467. /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
  468. /flock/{core/mcp → mcp}/util/__init__.py +0 -0
  469. {flock_core-0.5.0b28.dist-info → flock_core-0.5.0b51.dist-info}/WHEEL +0 -0
@@ -0,0 +1,414 @@
1
+ import { create } from 'zustand';
2
+ import { devtools } from 'zustand/middleware';
3
+ import { Node, Edge } from '@xyflow/react';
4
+ import { Agent, Message, AgentNodeData, MessageNodeData } from '../types/graph';
5
+ import { deriveAgentViewEdges, deriveBlackboardViewEdges, Artifact, Run, DashboardState } from '../utils/transforms';
6
+ import { useFilterStore } from './filterStore';
7
+
8
+ interface GraphState {
9
+ // Core data
10
+ agents: Map<string, Agent>;
11
+ messages: Map<string, Message>;
12
+ events: Message[];
13
+ runs: Map<string, Run>;
14
+
15
+ // Phase 11 Bug Fix: Track actual consumption (artifact_id -> consumer_ids[])
16
+ // Updated by agent_activated events to reflect filtering and actual consumption
17
+ consumptions: Map<string, string[]>;
18
+
19
+ // Message node positions (message_id -> {x, y})
20
+ // Messages don't have position in their data model, so we track it separately
21
+ messagePositions: Map<string, { x: number; y: number }>;
22
+
23
+ // Graph representation
24
+ nodes: Node[];
25
+ edges: Edge[];
26
+
27
+ // Actions
28
+ addAgent: (agent: Agent) => void;
29
+ updateAgent: (id: string, updates: Partial<Agent>) => void;
30
+ removeAgent: (id: string) => void;
31
+
32
+ addMessage: (message: Message) => void;
33
+ updateMessage: (id: string, updates: Partial<Message>) => void;
34
+ addRun: (run: Run) => void;
35
+
36
+ // Phase 11 Bug Fix: Track actual consumption from agent_activated events
37
+ recordConsumption: (artifactIds: string[], consumerId: string) => void;
38
+
39
+ // Transform streaming message to final message (changes ID)
40
+ finalizeStreamingMessage: (oldId: string, newMessage: Message) => void;
41
+
42
+ updateNodePosition: (nodeId: string, position: { x: number; y: number }) => void;
43
+
44
+ // Mode-specific graph generation
45
+ generateAgentViewGraph: () => void;
46
+ generateBlackboardViewGraph: () => void;
47
+
48
+ // Filter application
49
+ applyFilters: () => void;
50
+
51
+ // Bulk updates
52
+ batchUpdate: (update: { agents?: Agent[]; messages?: Message[]; runs?: Run[] }) => void;
53
+ }
54
+
55
+ // Helper function to convert Message to Artifact
56
+ function messageToArtifact(message: Message, consumptions: Map<string, string[]>): Artifact {
57
+ // BUG FIX: Use ACTUAL consumption data from consumptions Map, not inferred from subscriptions!
58
+ // This ensures edges reflect what actually happened, not what "should" happen based on current subscriptions.
59
+ const actualConsumers = consumptions.get(message.id) || [];
60
+
61
+ return {
62
+ artifact_id: message.id,
63
+ artifact_type: message.type,
64
+ produced_by: message.producedBy,
65
+ consumed_by: actualConsumers, // Use actual consumption data
66
+ published_at: new Date(message.timestamp).toISOString(),
67
+ payload: message.payload,
68
+ correlation_id: message.correlationId,
69
+ };
70
+ }
71
+
72
+ // Helper function to convert store state to DashboardState
73
+ function toDashboardState(
74
+ messages: Map<string, Message>,
75
+ runs: Map<string, Run>,
76
+ consumptions: Map<string, string[]>
77
+ ): DashboardState {
78
+ const artifacts = new Map<string, Artifact>();
79
+
80
+ messages.forEach((message) => {
81
+ artifacts.set(message.id, messageToArtifact(message, consumptions));
82
+ });
83
+
84
+ return {
85
+ artifacts,
86
+ runs,
87
+ consumptions, // Phase 11: Pass actual consumption data for filtered count calculation
88
+ };
89
+ }
90
+
91
+ export const useGraphStore = create<GraphState>()(
92
+ devtools(
93
+ (set, get) => ({
94
+ agents: new Map(),
95
+ messages: new Map(),
96
+ events: [],
97
+ runs: new Map(),
98
+ consumptions: new Map(), // Phase 11: Track actual artifact consumption
99
+ messagePositions: new Map(), // Track message node positions
100
+ nodes: [],
101
+ edges: [],
102
+
103
+ addAgent: (agent) =>
104
+ set((state) => {
105
+ const agents = new Map(state.agents);
106
+ agents.set(agent.id, agent);
107
+ return { agents };
108
+ }),
109
+
110
+ updateAgent: (id, updates) =>
111
+ set((state) => {
112
+ const agents = new Map(state.agents);
113
+ const agent = agents.get(id);
114
+ if (agent) {
115
+ agents.set(id, { ...agent, ...updates });
116
+ }
117
+ return { agents };
118
+ }),
119
+
120
+ removeAgent: (id) =>
121
+ set((state) => {
122
+ const agents = new Map(state.agents);
123
+ agents.delete(id);
124
+ return { agents };
125
+ }),
126
+
127
+ addMessage: (message) =>
128
+ set((state) => {
129
+ const messages = new Map(state.messages);
130
+ messages.set(message.id, message);
131
+
132
+ // Only add to events if this is a NEW message (not already in the array)
133
+ // This prevents streaming token updates from flooding the Event Log
134
+ const isDuplicate = state.events.some(e => e.id === message.id);
135
+ const events = isDuplicate
136
+ ? state.events // Skip if already in events array
137
+ : [message, ...state.events].slice(0, 100); // Add new message
138
+
139
+ return { messages, events };
140
+ }),
141
+
142
+ updateMessage: (id, updates) =>
143
+ set((state) => {
144
+ const messages = new Map(state.messages);
145
+ const message = messages.get(id);
146
+ if (message) {
147
+ messages.set(id, { ...message, ...updates });
148
+ }
149
+ // Note: updateMessage does NOT touch the events array
150
+ // This allows streaming updates without flooding the Event Log
151
+ return { messages };
152
+ }),
153
+
154
+ addRun: (run) =>
155
+ set((state) => {
156
+ const runs = new Map(state.runs);
157
+ runs.set(run.run_id, run);
158
+ return { runs };
159
+ }),
160
+
161
+ // Phase 11 Bug Fix: Record actual consumption from agent_activated events
162
+ recordConsumption: (artifactIds, consumerId) =>
163
+ set((state) => {
164
+ const consumptions = new Map(state.consumptions);
165
+ artifactIds.forEach((artifactId) => {
166
+ const existing = consumptions.get(artifactId) || [];
167
+ if (!existing.includes(consumerId)) {
168
+ consumptions.set(artifactId, [...existing, consumerId]);
169
+ }
170
+ });
171
+ return { consumptions };
172
+ }),
173
+
174
+ finalizeStreamingMessage: (oldId, newMessage) =>
175
+ set((state) => {
176
+ // Remove old streaming message, add final message with new ID
177
+ const messages = new Map(state.messages);
178
+ messages.delete(oldId);
179
+ messages.set(newMessage.id, newMessage);
180
+
181
+ // Transfer position from old ID to new ID
182
+ const messagePositions = new Map(state.messagePositions);
183
+ const oldPos = messagePositions.get(oldId);
184
+ if (oldPos) {
185
+ messagePositions.delete(oldId);
186
+ messagePositions.set(newMessage.id, oldPos);
187
+ }
188
+
189
+ // Update events array: replace streaming ID with final message ID
190
+ const events = state.events.map(e =>
191
+ e.id === oldId ? newMessage : e
192
+ );
193
+
194
+ return { messages, messagePositions, events };
195
+ }),
196
+
197
+ updateNodePosition: (nodeId, position) =>
198
+ set((state) => {
199
+ const agents = new Map(state.agents);
200
+ const agent = agents.get(nodeId);
201
+ if (agent) {
202
+ // Update agent position
203
+ agents.set(nodeId, { ...agent, position });
204
+ return { agents };
205
+ } else {
206
+ // Must be a message node - update message position
207
+ const messagePositions = new Map(state.messagePositions);
208
+ messagePositions.set(nodeId, position);
209
+ return { messagePositions };
210
+ }
211
+ }),
212
+
213
+ generateAgentViewGraph: () => {
214
+ const { agents, messages, runs, consumptions, nodes: currentNodes } = get();
215
+
216
+ // Create a map of current node positions to preserve them during regeneration
217
+ const currentPositions = new Map<string, { x: number; y: number }>();
218
+ currentNodes.forEach(node => {
219
+ currentPositions.set(node.id, node.position);
220
+ });
221
+
222
+ const nodes: Node<AgentNodeData>[] = [];
223
+
224
+ // Create nodes from agents
225
+ agents.forEach((agent) => {
226
+ // Preserve position priority: saved position > current React Flow position > default
227
+ const position = agent.position
228
+ || currentPositions.get(agent.id)
229
+ || { x: 400 + Math.random() * 200, y: 300 + Math.random() * 200 };
230
+
231
+ nodes.push({
232
+ id: agent.id,
233
+ type: 'agent',
234
+ position,
235
+ data: {
236
+ name: agent.name,
237
+ status: agent.status,
238
+ subscriptions: agent.subscriptions,
239
+ outputTypes: agent.outputTypes,
240
+ sentCount: agent.sentCount,
241
+ recvCount: agent.recvCount,
242
+ receivedByType: agent.receivedByType,
243
+ sentByType: agent.sentByType,
244
+ streamingTokens: agent.streamingTokens,
245
+ },
246
+ });
247
+ });
248
+
249
+ // Derive edges using transform algorithm
250
+ const dashboardState = toDashboardState(messages, runs, consumptions);
251
+ const edges = deriveAgentViewEdges(dashboardState);
252
+
253
+ set({ nodes, edges });
254
+ },
255
+
256
+ generateBlackboardViewGraph: () => {
257
+ const { messages, runs, consumptions, messagePositions, nodes: currentNodes } = get();
258
+
259
+ // Create a map of current node positions to preserve them during regeneration
260
+ const currentPositions = new Map<string, { x: number; y: number }>();
261
+ currentNodes.forEach(node => {
262
+ currentPositions.set(node.id, node.position);
263
+ });
264
+
265
+ const nodes: Node<MessageNodeData>[] = [];
266
+
267
+ // Create nodes from messages
268
+ messages.forEach((message) => {
269
+ const payloadStr = JSON.stringify(message.payload);
270
+
271
+ // BUG FIX: Use ACTUAL consumption data from consumptions Map, not inferred from subscriptions!
272
+ const consumedBy = consumptions.get(message.id) || [];
273
+
274
+ // Preserve position priority: saved position > current React Flow position > default
275
+ const position = messagePositions.get(message.id)
276
+ || currentPositions.get(message.id)
277
+ || { x: 400 + Math.random() * 200, y: 300 + Math.random() * 200 };
278
+
279
+ nodes.push({
280
+ id: message.id,
281
+ type: 'message',
282
+ position,
283
+ data: {
284
+ artifactType: message.type,
285
+ payloadPreview: payloadStr.slice(0, 100),
286
+ payload: message.payload, // Full payload for display
287
+ producedBy: message.producedBy,
288
+ consumedBy, // Use actual consumption data
289
+ timestamp: message.timestamp,
290
+ isStreaming: message.isStreaming || false,
291
+ streamingText: message.streamingText || '',
292
+ },
293
+ });
294
+ });
295
+
296
+ // Derive edges using transform algorithm
297
+ const dashboardState = toDashboardState(messages, runs, consumptions);
298
+ const edges = deriveBlackboardViewEdges(dashboardState);
299
+
300
+ set({ nodes, edges });
301
+ },
302
+
303
+ batchUpdate: (update) =>
304
+ set((state) => {
305
+ const newState: Partial<GraphState> = {};
306
+
307
+ if (update.agents) {
308
+ const agents = new Map(state.agents);
309
+ update.agents.forEach((a) => agents.set(a.id, a));
310
+ newState.agents = agents;
311
+ }
312
+
313
+ if (update.messages) {
314
+ const messages = new Map(state.messages);
315
+ update.messages.forEach((m) => messages.set(m.id, m));
316
+ newState.messages = messages;
317
+ newState.events = [...update.messages, ...state.events].slice(0, 100);
318
+ }
319
+
320
+ if (update.runs) {
321
+ const runs = new Map(state.runs);
322
+ update.runs.forEach((r) => runs.set(r.run_id, r));
323
+ newState.runs = runs;
324
+ }
325
+
326
+ return newState;
327
+ }),
328
+
329
+ applyFilters: () => {
330
+ const { nodes, edges, messages } = get();
331
+ const { correlationId, timeRange } = useFilterStore.getState();
332
+
333
+ // Helper to calculate time range boundaries
334
+ const getTimeRangeBoundaries = (): { start: number; end: number } => {
335
+ const now = Date.now();
336
+ if (timeRange.preset === 'last5min') {
337
+ return { start: now - 5 * 60 * 1000, end: now };
338
+ } else if (timeRange.preset === 'last10min') {
339
+ return { start: now - 10 * 60 * 1000, end: now };
340
+ } else if (timeRange.preset === 'last1hour') {
341
+ return { start: now - 60 * 60 * 1000, end: now };
342
+ } else if (timeRange.preset === 'custom' && timeRange.start && timeRange.end) {
343
+ return { start: timeRange.start, end: timeRange.end };
344
+ }
345
+ return { start: now - 10 * 60 * 1000, end: now };
346
+ };
347
+
348
+ const { start: timeStart, end: timeEnd } = getTimeRangeBoundaries();
349
+
350
+ // Filter messages based on correlation ID and time range
351
+ const visibleMessageIds = new Set<string>();
352
+ messages.forEach((message) => {
353
+ let visible = true;
354
+
355
+ // Apply correlation ID filter (selective)
356
+ if (correlationId && message.correlationId !== correlationId) {
357
+ visible = false;
358
+ }
359
+
360
+ // Apply time range filter (in-memory)
361
+ if (visible && (message.timestamp < timeStart || message.timestamp > timeEnd)) {
362
+ visible = false;
363
+ }
364
+
365
+ if (visible) {
366
+ visibleMessageIds.add(message.id);
367
+ }
368
+ });
369
+
370
+ // Update nodes visibility
371
+ const updatedNodes = nodes.map((node) => {
372
+ if (node.type === 'message') {
373
+ // For message nodes, check if message is visible
374
+ return {
375
+ ...node,
376
+ hidden: !visibleMessageIds.has(node.id),
377
+ };
378
+ } else if (node.type === 'agent') {
379
+ // For agent nodes, show if any visible messages involve this agent
380
+ let hasVisibleMessages = false;
381
+ messages.forEach((message) => {
382
+ if (visibleMessageIds.has(message.id)) {
383
+ if (message.producedBy === node.id) {
384
+ hasVisibleMessages = true;
385
+ }
386
+ }
387
+ });
388
+ return {
389
+ ...node,
390
+ hidden: !hasVisibleMessages,
391
+ };
392
+ }
393
+ return node;
394
+ });
395
+
396
+ // Update edges visibility
397
+ const updatedEdges = edges.map((edge) => {
398
+ // Hide edge if either source or target node is hidden
399
+ const sourceNode = updatedNodes.find((n) => n.id === edge.source);
400
+ const targetNode = updatedNodes.find((n) => n.id === edge.target);
401
+ const hidden = sourceNode?.hidden || targetNode?.hidden || false;
402
+
403
+ return {
404
+ ...edge,
405
+ hidden,
406
+ };
407
+ });
408
+
409
+ set({ nodes: updatedNodes, edges: updatedEdges });
410
+ },
411
+ }),
412
+ { name: 'graphStore' }
413
+ )
414
+ );
@@ -0,0 +1,253 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { useModuleStore } from './moduleStore';
3
+ import type { ModuleInstance } from '../types/modules';
4
+
5
+ describe('moduleStore', () => {
6
+ beforeEach(() => {
7
+ // Reset store before each test
8
+ useModuleStore.setState({
9
+ instances: new Map(),
10
+ });
11
+ });
12
+
13
+ it('should have an empty Map as initial state', () => {
14
+ const instances = useModuleStore.getState().instances;
15
+ expect(instances.size).toBe(0);
16
+ expect(instances instanceof Map).toBe(true);
17
+ });
18
+
19
+ it('should add a new module instance', () => {
20
+ const module: ModuleInstance = {
21
+ id: 'module-1',
22
+ type: 'eventlog',
23
+ position: { x: 100, y: 100 },
24
+ size: { width: 600, height: 400 },
25
+ visible: true,
26
+ };
27
+
28
+ useModuleStore.getState().addModule(module);
29
+
30
+ const instances = useModuleStore.getState().instances;
31
+ expect(instances.size).toBe(1);
32
+ expect(instances.get('module-1')).toEqual(module);
33
+ });
34
+
35
+ it('should add multiple module instances', () => {
36
+ const module1: ModuleInstance = {
37
+ id: 'module-1',
38
+ type: 'eventlog',
39
+ position: { x: 100, y: 100 },
40
+ size: { width: 600, height: 400 },
41
+ visible: true,
42
+ };
43
+
44
+ const module2: ModuleInstance = {
45
+ id: 'module-2',
46
+ type: 'eventlog',
47
+ position: { x: 200, y: 200 },
48
+ size: { width: 600, height: 400 },
49
+ visible: true,
50
+ };
51
+
52
+ useModuleStore.getState().addModule(module1);
53
+ useModuleStore.getState().addModule(module2);
54
+
55
+ const instances = useModuleStore.getState().instances;
56
+ expect(instances.size).toBe(2);
57
+ expect(instances.get('module-1')).toEqual(module1);
58
+ expect(instances.get('module-2')).toEqual(module2);
59
+ });
60
+
61
+ it('should update module position', () => {
62
+ const module: ModuleInstance = {
63
+ id: 'module-1',
64
+ type: 'eventlog',
65
+ position: { x: 100, y: 100 },
66
+ size: { width: 600, height: 400 },
67
+ visible: true,
68
+ };
69
+
70
+ useModuleStore.getState().addModule(module);
71
+ useModuleStore.getState().updateModule('module-1', {
72
+ position: { x: 300, y: 300 },
73
+ });
74
+
75
+ const updated = useModuleStore.getState().instances.get('module-1');
76
+ expect(updated?.position).toEqual({ x: 300, y: 300 });
77
+ expect(updated?.size).toEqual({ width: 600, height: 400 }); // Other properties unchanged
78
+ expect(updated?.visible).toBe(true);
79
+ });
80
+
81
+ it('should update module size', () => {
82
+ const module: ModuleInstance = {
83
+ id: 'module-1',
84
+ type: 'eventlog',
85
+ position: { x: 100, y: 100 },
86
+ size: { width: 600, height: 400 },
87
+ visible: true,
88
+ };
89
+
90
+ useModuleStore.getState().addModule(module);
91
+ useModuleStore.getState().updateModule('module-1', {
92
+ size: { width: 800, height: 600 },
93
+ });
94
+
95
+ const updated = useModuleStore.getState().instances.get('module-1');
96
+ expect(updated?.size).toEqual({ width: 800, height: 600 });
97
+ expect(updated?.position).toEqual({ x: 100, y: 100 }); // Other properties unchanged
98
+ });
99
+
100
+ it('should update multiple module properties at once', () => {
101
+ const module: ModuleInstance = {
102
+ id: 'module-1',
103
+ type: 'eventlog',
104
+ position: { x: 100, y: 100 },
105
+ size: { width: 600, height: 400 },
106
+ visible: true,
107
+ };
108
+
109
+ useModuleStore.getState().addModule(module);
110
+ useModuleStore.getState().updateModule('module-1', {
111
+ position: { x: 300, y: 300 },
112
+ size: { width: 800, height: 600 },
113
+ visible: false,
114
+ });
115
+
116
+ const updated = useModuleStore.getState().instances.get('module-1');
117
+ expect(updated?.position).toEqual({ x: 300, y: 300 });
118
+ expect(updated?.size).toEqual({ width: 800, height: 600 });
119
+ expect(updated?.visible).toBe(false);
120
+ });
121
+
122
+ it('should toggle module visibility', () => {
123
+ const module: ModuleInstance = {
124
+ id: 'module-1',
125
+ type: 'eventlog',
126
+ position: { x: 100, y: 100 },
127
+ size: { width: 600, height: 400 },
128
+ visible: true,
129
+ };
130
+
131
+ useModuleStore.getState().addModule(module);
132
+
133
+ // Toggle visibility to false
134
+ useModuleStore.getState().toggleVisibility('module-1');
135
+ expect(useModuleStore.getState().instances.get('module-1')?.visible).toBe(false);
136
+
137
+ // Toggle visibility back to true
138
+ useModuleStore.getState().toggleVisibility('module-1');
139
+ expect(useModuleStore.getState().instances.get('module-1')?.visible).toBe(true);
140
+ });
141
+
142
+ it('should remove a module instance', () => {
143
+ const module1: ModuleInstance = {
144
+ id: 'module-1',
145
+ type: 'eventlog',
146
+ position: { x: 100, y: 100 },
147
+ size: { width: 600, height: 400 },
148
+ visible: true,
149
+ };
150
+
151
+ const module2: ModuleInstance = {
152
+ id: 'module-2',
153
+ type: 'eventlog',
154
+ position: { x: 200, y: 200 },
155
+ size: { width: 600, height: 400 },
156
+ visible: true,
157
+ };
158
+
159
+ useModuleStore.getState().addModule(module1);
160
+ useModuleStore.getState().addModule(module2);
161
+
162
+ expect(useModuleStore.getState().instances.size).toBe(2);
163
+
164
+ useModuleStore.getState().removeModule('module-1');
165
+
166
+ const instances = useModuleStore.getState().instances;
167
+ expect(instances.size).toBe(1);
168
+ expect(instances.get('module-1')).toBeUndefined();
169
+ expect(instances.get('module-2')).toEqual(module2);
170
+ });
171
+
172
+ it('should get all module instances', () => {
173
+ const module1: ModuleInstance = {
174
+ id: 'module-1',
175
+ type: 'eventlog',
176
+ position: { x: 100, y: 100 },
177
+ size: { width: 600, height: 400 },
178
+ visible: true,
179
+ };
180
+
181
+ const module2: ModuleInstance = {
182
+ id: 'module-2',
183
+ type: 'eventlog',
184
+ position: { x: 200, y: 200 },
185
+ size: { width: 600, height: 400 },
186
+ visible: false,
187
+ };
188
+
189
+ useModuleStore.getState().addModule(module1);
190
+ useModuleStore.getState().addModule(module2);
191
+
192
+ const instances = useModuleStore.getState().instances;
193
+ const allInstances = Array.from(instances.values());
194
+
195
+ expect(allInstances.length).toBe(2);
196
+ expect(allInstances).toContainEqual(module1);
197
+ expect(allInstances).toContainEqual(module2);
198
+ });
199
+
200
+ it('should handle updating non-existent module gracefully', () => {
201
+ useModuleStore.getState().updateModule('non-existent', {
202
+ position: { x: 100, y: 100 },
203
+ });
204
+
205
+ // Should not throw error and instances should remain empty
206
+ expect(useModuleStore.getState().instances.size).toBe(0);
207
+ });
208
+
209
+ it('should handle removing non-existent module gracefully', () => {
210
+ const module: ModuleInstance = {
211
+ id: 'module-1',
212
+ type: 'eventlog',
213
+ position: { x: 100, y: 100 },
214
+ size: { width: 600, height: 400 },
215
+ visible: true,
216
+ };
217
+
218
+ useModuleStore.getState().addModule(module);
219
+ useModuleStore.getState().removeModule('non-existent');
220
+
221
+ // Should not affect existing modules
222
+ expect(useModuleStore.getState().instances.size).toBe(1);
223
+ expect(useModuleStore.getState().instances.get('module-1')).toEqual(module);
224
+ });
225
+
226
+ it('should handle toggling visibility of non-existent module gracefully', () => {
227
+ useModuleStore.getState().toggleVisibility('non-existent');
228
+
229
+ // Should not throw error
230
+ expect(useModuleStore.getState().instances.size).toBe(0);
231
+ });
232
+
233
+ it('should maintain Map state immutability', () => {
234
+ const module: ModuleInstance = {
235
+ id: 'module-1',
236
+ type: 'eventlog',
237
+ position: { x: 100, y: 100 },
238
+ size: { width: 600, height: 400 },
239
+ visible: true,
240
+ };
241
+
242
+ useModuleStore.getState().addModule(module);
243
+ const instancesBefore = useModuleStore.getState().instances;
244
+
245
+ useModuleStore.getState().updateModule('module-1', {
246
+ position: { x: 200, y: 200 },
247
+ });
248
+ const instancesAfter = useModuleStore.getState().instances;
249
+
250
+ // New Map instance should be created (immutability)
251
+ expect(instancesBefore).not.toBe(instancesAfter);
252
+ });
253
+ });