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
flock/cli/settings.py DELETED
@@ -1,857 +0,0 @@
1
- """Settings editor for the Flock CLI.
2
-
3
- This module provides functionality to view, edit, add, and delete
4
- environment variables in the .env file.
5
- """
6
-
7
- import os
8
- import shutil
9
- from pathlib import Path
10
- from typing import Dict, List, Optional, Tuple
11
- import math
12
-
13
- import questionary
14
- from rich.console import Console
15
- from rich.panel import Panel
16
- from rich.table import Table
17
- from rich.text import Text
18
-
19
- from flock.core.util.cli_helper import init_console
20
-
21
- # Constants
22
- ENV_FILE = ".env"
23
- ENV_TEMPLATE_FILE = ".env_template"
24
- ENV_PROFILE_PREFIX = ".env_"
25
- DEFAULT_PROFILE_COMMENT = "# Profile: {profile_name}"
26
- SHOW_SECRETS_KEY = "SHOW_SECRETS"
27
- VARS_PER_PAGE_KEY = "VARS_PER_PAGE"
28
- DEFAULT_VARS_PER_PAGE = 20
29
-
30
- console = Console()
31
-
32
-
33
- def settings_editor():
34
- """Main entry point for the settings editor."""
35
- while True:
36
- init_console()
37
- console.print(Panel("[bold green]Environment Settings Editor[/]"), justify="center")
38
-
39
- # Get current profile name
40
- current_profile = get_current_profile()
41
- if current_profile:
42
- console.print(f"Current Profile: [bold cyan]{current_profile}[/]")
43
- else:
44
- console.print("No profile detected")
45
-
46
- console.line()
47
-
48
- choice = questionary.select(
49
- "What would you like to do?",
50
- choices=[
51
- questionary.Separator(line=" "),
52
- "View all environment variables",
53
- "Edit an environment variable",
54
- "Add a new environment variable",
55
- "Delete an environment variable",
56
- questionary.Separator(),
57
- "Manage environment profiles",
58
- questionary.Separator(),
59
- "Toggle show secrets",
60
- "Change variables per page",
61
- questionary.Separator(),
62
- "Back to main menu",
63
- ],
64
- ).ask()
65
-
66
- if choice == "View all environment variables":
67
- view_env_variables()
68
- elif choice == "Edit an environment variable":
69
- edit_env_variable()
70
- elif choice == "Add a new environment variable":
71
- add_env_variable()
72
- elif choice == "Delete an environment variable":
73
- delete_env_variable()
74
- elif choice == "Manage environment profiles":
75
- manage_profiles()
76
- elif choice == "Toggle show secrets":
77
- toggle_show_secrets()
78
- elif choice == "Change variables per page":
79
- change_vars_per_page()
80
- elif choice == "Back to main menu":
81
- break
82
-
83
- if choice != "Back to main menu":
84
- input("\nPress Enter to continue...")
85
-
86
-
87
- def view_env_variables(page: int = 1, page_size: Optional[int] = None):
88
- """View all environment variables with pagination.
89
-
90
- Args:
91
- page: Page number to display
92
- page_size: Number of variables per page (if None, use the setting in .env)
93
- """
94
- env_vars = load_env_file()
95
-
96
- # If page_size is not specified, get it from settings
97
- if page_size is None:
98
- page_size = get_vars_per_page_setting(env_vars)
99
-
100
- # Calculate pagination
101
- total_vars = len(env_vars)
102
- total_pages = math.ceil(total_vars / page_size) if total_vars > 0 else 1
103
-
104
- # Validate page number
105
- page = min(max(1, page), total_pages)
106
-
107
- start_idx = (page - 1) * page_size
108
- end_idx = min(start_idx + page_size, total_vars)
109
-
110
- # Get current page variables
111
- current_page_vars = list(env_vars.items())[start_idx:end_idx]
112
-
113
- # Check if secrets should be shown
114
- show_secrets = get_show_secrets_setting(env_vars)
115
-
116
- # Create table
117
- table = Table(title=f"Environment Variables (Page {page}/{total_pages}, {page_size} per page)")
118
- table.add_column("Name", style="cyan")
119
- table.add_column("Value", style="green")
120
-
121
- # Show secrets status
122
- secrets_status = "[green]ON[/]" if show_secrets else "[red]OFF[/]"
123
- init_console()
124
- console.print(f"Show Secrets: {secrets_status}")
125
-
126
- for key, value in current_page_vars:
127
- # Skip lines that are comments or empty
128
- if key.startswith('#') or not key:
129
- continue
130
-
131
- # Mask sensitive values if show_secrets is False
132
- if is_sensitive(key) and not show_secrets:
133
- masked_value = mask_sensitive_value(value)
134
- table.add_row(key, masked_value)
135
- else:
136
- table.add_row(key, value)
137
-
138
- console.print(table)
139
-
140
- # Pagination controls with more intuitive shortcuts
141
- console.print("\nNavigation: ", end="")
142
- if page > 1:
143
- console.print("[bold]Previous (p)[/] | ", end="")
144
- if page < total_pages:
145
- console.print("[bold]Next (n)[/] | ", end="")
146
- if show_secrets:
147
- console.print("[bold]Hide secrets (h)[/] | ", end="")
148
- else:
149
- console.print("[bold]Show secrets (s)[/] | ", end="")
150
- console.print("[bold]Change variables per page (v)[/] | ", end="")
151
- console.print("[bold]Back (b)[/]")
152
-
153
- # Handle navigation
154
- while True:
155
- key = input("Enter option: ").lower()
156
- if key == 'p' and page > 1:
157
- view_env_variables(page - 1, page_size)
158
- break
159
- elif key == 'n' and page < total_pages:
160
- view_env_variables(page + 1, page_size)
161
- break
162
- elif key == 's' and not show_secrets:
163
- # Confirm showing secrets
164
- confirm = questionary.confirm("Are you sure you want to show sensitive values?").ask()
165
- if confirm:
166
- set_show_secrets_setting(True)
167
- view_env_variables(page, page_size)
168
- break
169
- elif key == 'h' and show_secrets:
170
- set_show_secrets_setting(False)
171
- view_env_variables(page, page_size)
172
- break
173
- elif key == 'v':
174
- new_page_size = change_vars_per_page()
175
- if new_page_size:
176
- view_env_variables(1, new_page_size) # Reset to first page with new page size
177
- break
178
- elif key == 'b':
179
- break
180
-
181
-
182
- def change_vars_per_page():
183
- """Change the number of variables displayed per page.
184
-
185
- Returns:
186
- The new page size or None if cancelled
187
- """
188
- env_vars = load_env_file()
189
- current_setting = get_vars_per_page_setting(env_vars)
190
-
191
- console.print(f"Current variables per page: [cyan]{current_setting}[/]")
192
-
193
- # Predefined options plus custom option
194
- page_size_options = ["10", "20", "30", "50", "Custom", "Cancel"]
195
-
196
- choice = questionary.select(
197
- "Select number of variables per page:",
198
- choices=page_size_options,
199
- ).ask()
200
-
201
- if choice == "Cancel":
202
- return None
203
-
204
- if choice == "Custom":
205
- while True:
206
- try:
207
- custom_size = questionary.text(
208
- "Enter custom page size (5-100):",
209
- default=str(current_setting)
210
- ).ask()
211
-
212
- if not custom_size:
213
- return None
214
-
215
- new_size = int(custom_size)
216
- if 5 <= new_size <= 100:
217
- break
218
- else:
219
- console.print("[yellow]Page size must be between 5 and 100.[/]")
220
- except ValueError:
221
- console.print("[yellow]Please enter a valid number.[/]")
222
- else:
223
- new_size = int(choice)
224
-
225
- # Save the setting
226
- set_vars_per_page_setting(new_size)
227
- console.print(f"[green]Variables per page set to {new_size}.[/]")
228
-
229
- return new_size
230
-
231
-
232
- def get_vars_per_page_setting(env_vars: Dict[str, str] = None) -> int:
233
- """Get the current variables per page setting.
234
-
235
- Args:
236
- env_vars: Optional dictionary of environment variables
237
-
238
- Returns:
239
- Number of variables per page
240
- """
241
- if env_vars is None:
242
- env_vars = load_env_file()
243
-
244
- if VARS_PER_PAGE_KEY in env_vars:
245
- try:
246
- page_size = int(env_vars[VARS_PER_PAGE_KEY])
247
- # Ensure the value is within reasonable bounds
248
- if 5 <= page_size <= 100:
249
- return page_size
250
- except ValueError:
251
- pass
252
-
253
- return DEFAULT_VARS_PER_PAGE
254
-
255
-
256
- def set_vars_per_page_setting(page_size: int):
257
- """Set the variables per page setting.
258
-
259
- Args:
260
- page_size: Number of variables to display per page
261
- """
262
- env_vars = load_env_file()
263
- env_vars[VARS_PER_PAGE_KEY] = str(page_size)
264
- save_env_file(env_vars)
265
-
266
-
267
- def toggle_show_secrets():
268
- """Toggle the show secrets setting."""
269
- env_vars = load_env_file()
270
- current_setting = get_show_secrets_setting(env_vars)
271
-
272
- if current_setting:
273
- console.print("Currently showing sensitive values. Do you want to hide them?")
274
- confirm = questionary.confirm("Hide sensitive values?").ask()
275
- if confirm:
276
- set_show_secrets_setting(False)
277
- console.print("[green]Sensitive values will now be masked.[/]")
278
- else:
279
- console.print("[yellow]Warning:[/] Showing sensitive values can expose sensitive information.")
280
- confirm = questionary.confirm("Are you sure you want to show sensitive values?").ask()
281
- if confirm:
282
- set_show_secrets_setting(True)
283
- console.print("[green]Sensitive values will now be shown.[/]")
284
-
285
-
286
- def get_show_secrets_setting(env_vars: Dict[str, str] = None) -> bool:
287
- """Get the current show secrets setting.
288
-
289
- Args:
290
- env_vars: Optional dictionary of environment variables
291
-
292
- Returns:
293
- True if secrets should be shown, False otherwise
294
- """
295
- if env_vars is None:
296
- env_vars = load_env_file()
297
-
298
- if SHOW_SECRETS_KEY in env_vars:
299
- return env_vars[SHOW_SECRETS_KEY].lower() == 'true'
300
-
301
- return False
302
-
303
-
304
- def set_show_secrets_setting(show_secrets: bool):
305
- """Set the show secrets setting.
306
-
307
- Args:
308
- show_secrets: Whether to show secrets
309
- """
310
- env_vars = load_env_file()
311
- env_vars[SHOW_SECRETS_KEY] = str(show_secrets)
312
- save_env_file(env_vars)
313
-
314
-
315
- def edit_env_variable():
316
- """Edit an environment variable."""
317
- # Get list of variables
318
- env_vars = load_env_file()
319
-
320
- if not env_vars:
321
- console.print("[yellow]No environment variables found to edit.[/]")
322
- return
323
-
324
- # Filter out comments
325
- variables = [k for k in env_vars.keys() if not k.startswith('#') and k]
326
-
327
- # Display variables with selection
328
- init_console()
329
- console.print("Select a variable to edit:")
330
-
331
- # Let user select a variable to edit
332
- var_name = questionary.select(
333
- "Select a variable to edit:",
334
- choices=variables + ["Cancel"],
335
- ).ask()
336
-
337
- if var_name == "Cancel":
338
- return
339
-
340
- current_value = env_vars[var_name]
341
- is_sensitive_var = is_sensitive(var_name)
342
-
343
- if is_sensitive_var:
344
- console.print(f"[yellow]Warning:[/] You are editing a sensitive value: {var_name}")
345
- confirm = questionary.confirm("Are you sure you want to continue?").ask()
346
- if not confirm:
347
- return
348
-
349
- # Show current value (masked if sensitive and show_secrets is False)
350
- show_secrets = get_show_secrets_setting(env_vars)
351
- if is_sensitive_var and not show_secrets:
352
- console.print(f"Current value: {mask_sensitive_value(current_value)}")
353
- else:
354
- console.print(f"Current value: {current_value}")
355
-
356
- # Get new value with hint
357
- console.print("[italic]Enter new value (or leave empty to cancel)[/]")
358
- new_value = questionary.text("Enter new value:", default=current_value).ask()
359
-
360
- if new_value is None:
361
- console.print("[yellow]Edit cancelled.[/]")
362
- return
363
-
364
- if new_value == "":
365
- # Confirm if user wants to set an empty value or cancel
366
- confirm = questionary.confirm("Do you want to set an empty value? Select No to cancel.", default=False).ask()
367
- if not confirm:
368
- console.print("[yellow]Edit cancelled.[/]")
369
- return
370
-
371
- if new_value == current_value:
372
- console.print("[yellow]No changes made.[/]")
373
- return
374
-
375
- # Update the value
376
- env_vars[var_name] = new_value
377
- save_env_file(env_vars)
378
- console.print(f"[green]Updated {var_name} successfully.[/]")
379
-
380
-
381
- def add_env_variable():
382
- """Add a new environment variable."""
383
- env_vars = load_env_file()
384
-
385
- console.print("[italic]Enter variable name (or leave empty to go back)[/]")
386
-
387
- # Get variable name
388
- while True:
389
- var_name = questionary.text("Enter variable name:").ask()
390
-
391
- if not var_name:
392
- # Ask if user wants to go back
393
- go_back = questionary.confirm("Do you want to go back to the settings menu?", default=True).ask()
394
- if go_back:
395
- return
396
- else:
397
- console.print("[italic]Please enter a variable name (or leave empty to go back)[/]")
398
- continue
399
-
400
- if var_name in env_vars and not var_name.startswith('#'):
401
- console.print(f"[yellow]Variable {var_name} already exists. Please use edit instead.[/]")
402
- continue
403
-
404
- break
405
-
406
- # Get variable value
407
- var_value = questionary.text("Enter variable value:").ask()
408
-
409
- # Add to env_vars
410
- env_vars[var_name] = var_value
411
- save_env_file(env_vars)
412
- console.print(f"[green]Added {var_name} successfully.[/]")
413
-
414
-
415
- def delete_env_variable():
416
- """Delete an environment variable."""
417
- # Get list of variables
418
- env_vars = load_env_file()
419
-
420
- if not env_vars:
421
- console.print("[yellow]No environment variables found to delete.[/]")
422
- return
423
-
424
- # Filter out comments
425
- variables = [k for k in env_vars.keys() if not k.startswith('#') and k]
426
-
427
- # Display variables with selection
428
- init_console()
429
- console.print("Select a variable to delete:")
430
-
431
- # Let user select a variable to delete with hint
432
- var_name = questionary.select(
433
- "Select a variable to delete:",
434
- choices=variables + ["Cancel"],
435
- ).ask()
436
-
437
- if var_name == "Cancel":
438
- return
439
-
440
- # Confirm deletion
441
- confirm = questionary.confirm(f"Are you sure you want to delete {var_name}?").ask()
442
- if not confirm:
443
- console.print("[yellow]Deletion cancelled.[/]")
444
- return
445
-
446
- # Delete the variable
447
- del env_vars[var_name]
448
- save_env_file(env_vars)
449
- console.print(f"[green]Deleted {var_name} successfully.[/]")
450
-
451
-
452
- def manage_profiles():
453
- """Manage environment profiles."""
454
- init_console()
455
- console.print(Panel("[bold green]Environment Profile Management[/]"), justify="center")
456
-
457
- # Get current profile and available profiles
458
- current_profile = get_current_profile()
459
- available_profiles = get_available_profiles()
460
-
461
- if current_profile:
462
- console.print(f"Current Profile: [bold cyan]{current_profile}[/]")
463
-
464
- if not available_profiles:
465
- console.print("[yellow]No profiles found.[/]")
466
- else:
467
- console.print("Available Profiles:")
468
- for profile in available_profiles:
469
- if profile == current_profile:
470
- console.print(f" [bold cyan]{profile} (active)[/]")
471
- else:
472
- console.print(f" {profile}")
473
-
474
- console.line()
475
-
476
- # Profile management options
477
- choice = questionary.select(
478
- "What would you like to do?",
479
- choices=[
480
- questionary.Separator(line=" "),
481
- "Switch to a different profile",
482
- "Create a new profile",
483
- "Rename a profile",
484
- "Delete a profile",
485
- "Back to settings menu",
486
- ],
487
- ).ask()
488
-
489
- if choice == "Switch to a different profile":
490
- switch_profile()
491
- elif choice == "Create a new profile":
492
- create_profile()
493
- elif choice == "Rename a profile":
494
- rename_profile()
495
- elif choice == "Delete a profile":
496
- delete_profile()
497
-
498
-
499
- def switch_profile():
500
- """Switch to a different environment profile."""
501
- available_profiles = get_available_profiles()
502
- current_profile = get_current_profile()
503
-
504
- if not available_profiles:
505
- console.print("[yellow]No profiles available to switch to.[/]")
506
- return
507
-
508
- # Remove current profile from the list to avoid switching to the same profile
509
- selectable_profiles = [p for p in available_profiles if p != current_profile]
510
-
511
- if not selectable_profiles:
512
- console.print("[yellow]No other profiles available to switch to.[/]")
513
- return
514
-
515
- target_profile = questionary.select(
516
- "Select a profile to switch to:",
517
- choices=selectable_profiles + ["Cancel"],
518
- ).ask()
519
-
520
- if target_profile == "Cancel":
521
- return
522
-
523
- # Confirm switch
524
- confirm = questionary.confirm(f"Are you sure you want to switch to the {target_profile} profile?").ask()
525
- if not confirm:
526
- return
527
-
528
- # Backup current .env file
529
- backup_env_file()
530
-
531
- # Copy selected profile to .env
532
- source_file = f"{ENV_PROFILE_PREFIX}{target_profile}"
533
- if os.path.exists(source_file):
534
- shutil.copy2(source_file, ENV_FILE)
535
- console.print(f"[green]Switched to {target_profile} profile successfully.[/]")
536
- else:
537
- console.print(f"[red]Error: Could not find profile file {source_file}.[/]")
538
-
539
-
540
- def create_profile():
541
- """Create a new environment profile."""
542
- profile_name = questionary.text("Enter new profile name:").ask()
543
-
544
- if not profile_name:
545
- console.print("[yellow]Profile name cannot be empty.[/]")
546
- return
547
-
548
- # Check if profile already exists
549
- target_file = f"{ENV_PROFILE_PREFIX}{profile_name}"
550
- if os.path.exists(target_file):
551
- console.print(f"[yellow]Profile {profile_name} already exists.[/]")
552
- return
553
-
554
- # Determine source file - use current .env or template
555
- source_choices = ["Current environment (.env)", ".env_template"]
556
- if os.path.exists(ENV_TEMPLATE_FILE):
557
- source_choices.append(ENV_TEMPLATE_FILE)
558
-
559
- source_choice = questionary.select(
560
- "Create profile based on:",
561
- choices=source_choices + ["Cancel"],
562
- ).ask()
563
-
564
- if source_choice == "Cancel":
565
- return
566
-
567
- source_file = ENV_FILE if source_choice == "Current environment (.env)" else ENV_TEMPLATE_FILE
568
-
569
- if not os.path.exists(source_file):
570
- console.print(f"[red]Error: Source file {source_file} not found.[/]")
571
- return
572
-
573
- # Create new profile file
574
- try:
575
- # Copy source file
576
- shutil.copy2(source_file, target_file)
577
-
578
- # Add profile header if it doesn't exist
579
- with open(target_file, 'r') as file:
580
- content = file.read()
581
-
582
- if not content.startswith("# Profile:"):
583
- with open(target_file, 'w') as file:
584
- profile_header = DEFAULT_PROFILE_COMMENT.format(profile_name=profile_name)
585
- file.write(f"{profile_header}\n{content}")
586
-
587
- console.print(f"[green]Created {profile_name} profile successfully.[/]")
588
- except Exception as e:
589
- console.print(f"[red]Error creating profile: {str(e)}[/]")
590
-
591
-
592
- def rename_profile():
593
- """Rename an existing profile."""
594
- available_profiles = get_available_profiles()
595
- current_profile = get_current_profile()
596
-
597
- if not available_profiles:
598
- console.print("[yellow]No profiles available to rename.[/]")
599
- return
600
-
601
- # Let user select a profile to rename
602
- profile_to_rename = questionary.select(
603
- "Select a profile to rename:",
604
- choices=available_profiles + ["Cancel"],
605
- ).ask()
606
-
607
- if profile_to_rename == "Cancel":
608
- return
609
-
610
- # Get new name
611
- new_name = questionary.text("Enter new profile name:").ask()
612
-
613
- if not new_name:
614
- console.print("[yellow]New profile name cannot be empty.[/]")
615
- return
616
-
617
- if new_name in available_profiles:
618
- console.print(f"[yellow]Profile {new_name} already exists.[/]")
619
- return
620
-
621
- # Rename profile file
622
- source_file = f"{ENV_PROFILE_PREFIX}{profile_to_rename}"
623
- target_file = f"{ENV_PROFILE_PREFIX}{new_name}"
624
-
625
- try:
626
- # Read content of the source file
627
- with open(source_file, 'r') as file:
628
- content = file.readlines()
629
-
630
- # Update profile header if it exists
631
- if content and content[0].startswith("# Profile:"):
632
- content[0] = DEFAULT_PROFILE_COMMENT.format(profile_name=new_name) + "\n"
633
-
634
- # Write to new file
635
- with open(target_file, 'w') as file:
636
- file.writelines(content)
637
-
638
- # Remove old file
639
- os.remove(source_file)
640
-
641
- # If this was the current profile, update .env as well
642
- if profile_to_rename == current_profile:
643
- with open(ENV_FILE, 'r') as file:
644
- content = file.readlines()
645
-
646
- if content and content[0].startswith("# Profile:"):
647
- content[0] = DEFAULT_PROFILE_COMMENT.format(profile_name=new_name) + "\n"
648
-
649
- with open(ENV_FILE, 'w') as file:
650
- file.writelines(content)
651
-
652
- console.print(f"[green]Renamed {profile_to_rename} to {new_name} successfully.[/]")
653
- except Exception as e:
654
- console.print(f"[red]Error renaming profile: {str(e)}[/]")
655
-
656
-
657
- def delete_profile():
658
- """Delete an existing profile."""
659
- available_profiles = get_available_profiles()
660
- current_profile = get_current_profile()
661
-
662
- if not available_profiles:
663
- console.print("[yellow]No profiles available to delete.[/]")
664
- return
665
-
666
- # Let user select a profile to delete
667
- profile_to_delete = questionary.select(
668
- "Select a profile to delete:",
669
- choices=available_profiles + ["Cancel"],
670
- ).ask()
671
-
672
- if profile_to_delete == "Cancel":
673
- return
674
-
675
- # Confirm deletion
676
- confirm = questionary.confirm(
677
- f"Are you sure you want to delete the {profile_to_delete} profile? This cannot be undone."
678
- ).ask()
679
-
680
- if not confirm:
681
- return
682
-
683
- # Delete profile file
684
- profile_file = f"{ENV_PROFILE_PREFIX}{profile_to_delete}"
685
-
686
- try:
687
- os.remove(profile_file)
688
-
689
- # Warn if deleting the current profile
690
- if profile_to_delete == current_profile:
691
- console.print(
692
- f"[yellow]Warning: You deleted the currently active profile. "
693
- f"The .env file still contains those settings but is no longer marked as a profile.[/]"
694
- )
695
-
696
- # Remove profile header from .env
697
- with open(ENV_FILE, 'r') as file:
698
- content = file.readlines()
699
-
700
- if content and content[0].startswith("# Profile:"):
701
- content = content[1:]
702
- with open(ENV_FILE, 'w') as file:
703
- file.writelines(content)
704
-
705
- console.print(f"[green]Deleted {profile_to_delete} profile successfully.[/]")
706
- except Exception as e:
707
- console.print(f"[red]Error deleting profile: {str(e)}[/]")
708
-
709
-
710
- def is_sensitive(key: str) -> bool:
711
- """Check if a variable is considered sensitive.
712
-
713
- Args:
714
- key: The variable name
715
-
716
- Returns:
717
- True if sensitive, False otherwise
718
- """
719
- sensitive_patterns = ['key', 'token', 'secret', 'password', 'api', 'pat']
720
- key_lower = key.lower()
721
- return any(pattern in key_lower for pattern in sensitive_patterns)
722
-
723
-
724
- def mask_sensitive_value(value: str) -> str:
725
- """Mask a sensitive value.
726
-
727
- Args:
728
- value: The sensitive value
729
-
730
- Returns:
731
- Masked value
732
- """
733
- if not value:
734
- return value
735
-
736
- if len(value) <= 4:
737
- return "••••"
738
-
739
- # Show first 2 and last 2 characters
740
- return value[:2] + "•" * (len(value) - 4) + value[-2:]
741
-
742
-
743
- def get_current_profile() -> Optional[str]:
744
- """Get the name of the current active profile.
745
-
746
- Returns:
747
- Profile name or None if no profile is active
748
- """
749
- if not os.path.exists(ENV_FILE):
750
- return None
751
-
752
- try:
753
- with open(ENV_FILE, 'r') as file:
754
- first_line = file.readline().strip()
755
-
756
- if first_line.startswith("# Profile:"):
757
- return first_line.replace("# Profile:", "").strip()
758
- except Exception:
759
- pass
760
-
761
- return None
762
-
763
-
764
- def get_available_profiles() -> List[str]:
765
- """Get a list of available profiles.
766
-
767
- Returns:
768
- List of profile names
769
- """
770
- profiles = []
771
-
772
- for file in os.listdir():
773
- if file.startswith(ENV_PROFILE_PREFIX):
774
- profile_name = file[len(ENV_PROFILE_PREFIX):]
775
- profiles.append(profile_name)
776
-
777
- return profiles
778
-
779
-
780
- def backup_env_file():
781
- """Create a backup of the current .env file."""
782
- if not os.path.exists(ENV_FILE):
783
- return
784
-
785
- backup_file = f"{ENV_FILE}.bak"
786
- shutil.copy2(ENV_FILE, backup_file)
787
-
788
-
789
- def load_env_file() -> Dict[str, str]:
790
- """Load the .env file into a dictionary.
791
-
792
- Returns:
793
- Dictionary of environment variables
794
- """
795
- env_vars = {}
796
-
797
- if not os.path.exists(ENV_FILE):
798
- console.print(f"[yellow]Warning: {ENV_FILE} file not found.[/]")
799
- return env_vars
800
-
801
- try:
802
- with open(ENV_FILE, 'r') as file:
803
- lines = file.readlines()
804
-
805
- # Process each line
806
- for line in lines:
807
- line = line.strip()
808
-
809
- # Skip empty lines
810
- if not line:
811
- env_vars[""] = ""
812
- continue
813
-
814
- # Handle comments
815
- if line.startswith('#'):
816
- env_vars[line] = ""
817
- continue
818
-
819
- # Handle regular variables
820
- if '=' in line:
821
- key, value = line.split('=', 1)
822
- env_vars[key] = value
823
- else:
824
- # Handle lines without equals sign
825
- env_vars[line] = ""
826
-
827
- except Exception as e:
828
- console.print(f"[red]Error loading .env file: {str(e)}[/]")
829
-
830
- return env_vars
831
-
832
-
833
- def save_env_file(env_vars: Dict[str, str]):
834
- """Save environment variables back to the .env file.
835
-
836
- Args:
837
- env_vars: Dictionary of environment variables
838
- """
839
- # Create backup
840
- backup_env_file()
841
-
842
- try:
843
- with open(ENV_FILE, 'w') as file:
844
- for key, value in env_vars.items():
845
- if key.startswith('#'):
846
- # Write comments as is
847
- file.write(f"{key}\n")
848
- elif not key:
849
- # Write empty lines
850
- file.write("\n")
851
- else:
852
- # Write regular variables
853
- file.write(f"{key}={value}\n")
854
-
855
- console.print("[green]Settings saved successfully.[/]")
856
- except Exception as e:
857
- console.print(f"[red]Error saving .env file: {str(e)}[/]")