crca 1.4.0__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.
Files changed (501) hide show
  1. .github/ISSUE_TEMPLATE/bug_report.md +65 -0
  2. .github/ISSUE_TEMPLATE/feature_request.md +41 -0
  3. .github/PULL_REQUEST_TEMPLATE.md +20 -0
  4. .github/workflows/publish-manual.yml +61 -0
  5. .github/workflows/publish.yml +64 -0
  6. .gitignore +214 -0
  7. CRCA.py +4156 -0
  8. LICENSE +201 -0
  9. MANIFEST.in +43 -0
  10. PKG-INFO +5035 -0
  11. README.md +4959 -0
  12. __init__.py +17 -0
  13. branches/CRCA-Q.py +2728 -0
  14. branches/crca_cg/corposwarm.py +9065 -0
  15. branches/crca_cg/fix_rancher_docker_creds.ps1 +155 -0
  16. branches/crca_cg/package.json +5 -0
  17. branches/crca_cg/test_bolt_integration.py +446 -0
  18. branches/crca_cg/test_corposwarm_comprehensive.py +773 -0
  19. branches/crca_cg/test_new_features.py +163 -0
  20. branches/crca_sd/__init__.py +149 -0
  21. branches/crca_sd/crca_sd_core.py +770 -0
  22. branches/crca_sd/crca_sd_governance.py +1325 -0
  23. branches/crca_sd/crca_sd_mpc.py +1130 -0
  24. branches/crca_sd/crca_sd_realtime.py +1844 -0
  25. branches/crca_sd/crca_sd_tui.py +1133 -0
  26. crca-1.4.0.dist-info/METADATA +5035 -0
  27. crca-1.4.0.dist-info/RECORD +501 -0
  28. crca-1.4.0.dist-info/WHEEL +4 -0
  29. crca-1.4.0.dist-info/licenses/LICENSE +201 -0
  30. docs/CRCA-Q.md +2333 -0
  31. examples/config.yaml.example +25 -0
  32. examples/crca_sd_example.py +513 -0
  33. examples/data_broker_example.py +294 -0
  34. examples/logistics_corporation.py +861 -0
  35. examples/palantir_example.py +299 -0
  36. examples/policy_bench.py +934 -0
  37. examples/pridnestrovia-sd.py +705 -0
  38. examples/pridnestrovia_realtime.py +1902 -0
  39. prompts/__init__.py +10 -0
  40. prompts/default_crca.py +101 -0
  41. pyproject.toml +151 -0
  42. requirements.txt +76 -0
  43. schemas/__init__.py +43 -0
  44. schemas/mcpSchemas.py +51 -0
  45. schemas/policy.py +458 -0
  46. templates/__init__.py +38 -0
  47. templates/base_specialized_agent.py +195 -0
  48. templates/drift_detection.py +325 -0
  49. templates/examples/causal_agent_template.py +309 -0
  50. templates/examples/drag_drop_example.py +213 -0
  51. templates/examples/logistics_agent_template.py +207 -0
  52. templates/examples/trading_agent_template.py +206 -0
  53. templates/feature_mixins.py +253 -0
  54. templates/graph_management.py +442 -0
  55. templates/llm_integration.py +194 -0
  56. templates/module_registry.py +276 -0
  57. templates/mpc_planner.py +280 -0
  58. templates/policy_loop.py +1168 -0
  59. templates/prediction_framework.py +448 -0
  60. templates/statistical_methods.py +778 -0
  61. tests/sanity.yml +31 -0
  62. tests/sanity_check +406 -0
  63. tests/test_core.py +47 -0
  64. tests/test_crca_excel.py +166 -0
  65. tests/test_crca_sd.py +780 -0
  66. tests/test_data_broker.py +424 -0
  67. tests/test_palantir.py +349 -0
  68. tools/__init__.py +38 -0
  69. tools/actuators.py +437 -0
  70. tools/bolt.diy/Dockerfile +103 -0
  71. tools/bolt.diy/app/components/@settings/core/AvatarDropdown.tsx +175 -0
  72. tools/bolt.diy/app/components/@settings/core/ControlPanel.tsx +345 -0
  73. tools/bolt.diy/app/components/@settings/core/constants.tsx +108 -0
  74. tools/bolt.diy/app/components/@settings/core/types.ts +114 -0
  75. tools/bolt.diy/app/components/@settings/index.ts +12 -0
  76. tools/bolt.diy/app/components/@settings/shared/components/TabTile.tsx +151 -0
  77. tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionForm.tsx +193 -0
  78. tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionTestIndicator.tsx +60 -0
  79. tools/bolt.diy/app/components/@settings/shared/service-integration/ErrorState.tsx +102 -0
  80. tools/bolt.diy/app/components/@settings/shared/service-integration/LoadingState.tsx +94 -0
  81. tools/bolt.diy/app/components/@settings/shared/service-integration/ServiceHeader.tsx +72 -0
  82. tools/bolt.diy/app/components/@settings/shared/service-integration/index.ts +6 -0
  83. tools/bolt.diy/app/components/@settings/tabs/data/DataTab.tsx +721 -0
  84. tools/bolt.diy/app/components/@settings/tabs/data/DataVisualization.tsx +384 -0
  85. tools/bolt.diy/app/components/@settings/tabs/event-logs/EventLogsTab.tsx +1013 -0
  86. tools/bolt.diy/app/components/@settings/tabs/features/FeaturesTab.tsx +295 -0
  87. tools/bolt.diy/app/components/@settings/tabs/github/GitHubTab.tsx +281 -0
  88. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubAuthDialog.tsx +173 -0
  89. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubCacheManager.tsx +367 -0
  90. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubConnection.tsx +233 -0
  91. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubErrorBoundary.tsx +105 -0
  92. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubProgressiveLoader.tsx +266 -0
  93. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositoryCard.tsx +121 -0
  94. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositorySelector.tsx +312 -0
  95. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubStats.tsx +291 -0
  96. tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubUserProfile.tsx +46 -0
  97. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/GitHubStateIndicators.tsx +264 -0
  98. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/RepositoryCard.tsx +361 -0
  99. tools/bolt.diy/app/components/@settings/tabs/github/components/shared/index.ts +11 -0
  100. tools/bolt.diy/app/components/@settings/tabs/gitlab/GitLabTab.tsx +305 -0
  101. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabAuthDialog.tsx +186 -0
  102. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabConnection.tsx +253 -0
  103. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabRepositorySelector.tsx +358 -0
  104. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryCard.tsx +79 -0
  105. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryList.tsx +142 -0
  106. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/StatsDisplay.tsx +91 -0
  107. tools/bolt.diy/app/components/@settings/tabs/gitlab/components/index.ts +4 -0
  108. tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerList.tsx +99 -0
  109. tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerListItem.tsx +70 -0
  110. tools/bolt.diy/app/components/@settings/tabs/mcp/McpStatusBadge.tsx +37 -0
  111. tools/bolt.diy/app/components/@settings/tabs/mcp/McpTab.tsx +239 -0
  112. tools/bolt.diy/app/components/@settings/tabs/netlify/NetlifyTab.tsx +1393 -0
  113. tools/bolt.diy/app/components/@settings/tabs/netlify/components/NetlifyConnection.tsx +990 -0
  114. tools/bolt.diy/app/components/@settings/tabs/netlify/components/index.ts +1 -0
  115. tools/bolt.diy/app/components/@settings/tabs/notifications/NotificationsTab.tsx +300 -0
  116. tools/bolt.diy/app/components/@settings/tabs/profile/ProfileTab.tsx +181 -0
  117. tools/bolt.diy/app/components/@settings/tabs/providers/cloud/CloudProvidersTab.tsx +308 -0
  118. tools/bolt.diy/app/components/@settings/tabs/providers/local/ErrorBoundary.tsx +68 -0
  119. tools/bolt.diy/app/components/@settings/tabs/providers/local/HealthStatusBadge.tsx +64 -0
  120. tools/bolt.diy/app/components/@settings/tabs/providers/local/LoadingSkeleton.tsx +107 -0
  121. tools/bolt.diy/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx +556 -0
  122. tools/bolt.diy/app/components/@settings/tabs/providers/local/ModelCard.tsx +106 -0
  123. tools/bolt.diy/app/components/@settings/tabs/providers/local/ProviderCard.tsx +120 -0
  124. tools/bolt.diy/app/components/@settings/tabs/providers/local/SetupGuide.tsx +671 -0
  125. tools/bolt.diy/app/components/@settings/tabs/providers/local/StatusDashboard.tsx +91 -0
  126. tools/bolt.diy/app/components/@settings/tabs/providers/local/types.ts +44 -0
  127. tools/bolt.diy/app/components/@settings/tabs/settings/SettingsTab.tsx +215 -0
  128. tools/bolt.diy/app/components/@settings/tabs/supabase/SupabaseTab.tsx +1089 -0
  129. tools/bolt.diy/app/components/@settings/tabs/vercel/VercelTab.tsx +909 -0
  130. tools/bolt.diy/app/components/@settings/tabs/vercel/components/VercelConnection.tsx +368 -0
  131. tools/bolt.diy/app/components/@settings/tabs/vercel/components/index.ts +1 -0
  132. tools/bolt.diy/app/components/@settings/utils/tab-helpers.ts +54 -0
  133. tools/bolt.diy/app/components/chat/APIKeyManager.tsx +169 -0
  134. tools/bolt.diy/app/components/chat/Artifact.tsx +296 -0
  135. tools/bolt.diy/app/components/chat/AssistantMessage.tsx +192 -0
  136. tools/bolt.diy/app/components/chat/BaseChat.module.scss +47 -0
  137. tools/bolt.diy/app/components/chat/BaseChat.tsx +522 -0
  138. tools/bolt.diy/app/components/chat/Chat.client.tsx +670 -0
  139. tools/bolt.diy/app/components/chat/ChatAlert.tsx +108 -0
  140. tools/bolt.diy/app/components/chat/ChatBox.tsx +334 -0
  141. tools/bolt.diy/app/components/chat/CodeBlock.module.scss +10 -0
  142. tools/bolt.diy/app/components/chat/CodeBlock.tsx +85 -0
  143. tools/bolt.diy/app/components/chat/DicussMode.tsx +17 -0
  144. tools/bolt.diy/app/components/chat/ExamplePrompts.tsx +37 -0
  145. tools/bolt.diy/app/components/chat/FilePreview.tsx +38 -0
  146. tools/bolt.diy/app/components/chat/GitCloneButton.tsx +327 -0
  147. tools/bolt.diy/app/components/chat/ImportFolderButton.tsx +141 -0
  148. tools/bolt.diy/app/components/chat/LLMApiAlert.tsx +109 -0
  149. tools/bolt.diy/app/components/chat/MCPTools.tsx +129 -0
  150. tools/bolt.diy/app/components/chat/Markdown.module.scss +171 -0
  151. tools/bolt.diy/app/components/chat/Markdown.spec.ts +48 -0
  152. tools/bolt.diy/app/components/chat/Markdown.tsx +252 -0
  153. tools/bolt.diy/app/components/chat/Messages.client.tsx +102 -0
  154. tools/bolt.diy/app/components/chat/ModelSelector.tsx +797 -0
  155. tools/bolt.diy/app/components/chat/NetlifyDeploymentLink.client.tsx +51 -0
  156. tools/bolt.diy/app/components/chat/ProgressCompilation.tsx +110 -0
  157. tools/bolt.diy/app/components/chat/ScreenshotStateManager.tsx +33 -0
  158. tools/bolt.diy/app/components/chat/SendButton.client.tsx +39 -0
  159. tools/bolt.diy/app/components/chat/SpeechRecognition.tsx +28 -0
  160. tools/bolt.diy/app/components/chat/StarterTemplates.tsx +38 -0
  161. tools/bolt.diy/app/components/chat/SupabaseAlert.tsx +199 -0
  162. tools/bolt.diy/app/components/chat/SupabaseConnection.tsx +339 -0
  163. tools/bolt.diy/app/components/chat/ThoughtBox.tsx +43 -0
  164. tools/bolt.diy/app/components/chat/ToolInvocations.tsx +409 -0
  165. tools/bolt.diy/app/components/chat/UserMessage.tsx +101 -0
  166. tools/bolt.diy/app/components/chat/VercelDeploymentLink.client.tsx +158 -0
  167. tools/bolt.diy/app/components/chat/chatExportAndImport/ExportChatButton.tsx +49 -0
  168. tools/bolt.diy/app/components/chat/chatExportAndImport/ImportButtons.tsx +96 -0
  169. tools/bolt.diy/app/components/deploy/DeployAlert.tsx +197 -0
  170. tools/bolt.diy/app/components/deploy/DeployButton.tsx +277 -0
  171. tools/bolt.diy/app/components/deploy/GitHubDeploy.client.tsx +171 -0
  172. tools/bolt.diy/app/components/deploy/GitHubDeploymentDialog.tsx +1041 -0
  173. tools/bolt.diy/app/components/deploy/GitLabDeploy.client.tsx +171 -0
  174. tools/bolt.diy/app/components/deploy/GitLabDeploymentDialog.tsx +764 -0
  175. tools/bolt.diy/app/components/deploy/NetlifyDeploy.client.tsx +246 -0
  176. tools/bolt.diy/app/components/deploy/VercelDeploy.client.tsx +235 -0
  177. tools/bolt.diy/app/components/editor/codemirror/BinaryContent.tsx +7 -0
  178. tools/bolt.diy/app/components/editor/codemirror/CodeMirrorEditor.tsx +555 -0
  179. tools/bolt.diy/app/components/editor/codemirror/EnvMasking.ts +80 -0
  180. tools/bolt.diy/app/components/editor/codemirror/cm-theme.ts +192 -0
  181. tools/bolt.diy/app/components/editor/codemirror/indent.ts +68 -0
  182. tools/bolt.diy/app/components/editor/codemirror/languages.ts +112 -0
  183. tools/bolt.diy/app/components/git/GitUrlImport.client.tsx +147 -0
  184. tools/bolt.diy/app/components/header/Header.tsx +42 -0
  185. tools/bolt.diy/app/components/header/HeaderActionButtons.client.tsx +54 -0
  186. tools/bolt.diy/app/components/mandate/MandateSubmission.tsx +167 -0
  187. tools/bolt.diy/app/components/observability/DeploymentStatus.tsx +168 -0
  188. tools/bolt.diy/app/components/observability/EventTimeline.tsx +119 -0
  189. tools/bolt.diy/app/components/observability/FileDiffViewer.tsx +121 -0
  190. tools/bolt.diy/app/components/observability/GovernanceStatus.tsx +197 -0
  191. tools/bolt.diy/app/components/observability/GovernorMetrics.tsx +246 -0
  192. tools/bolt.diy/app/components/observability/LogStream.tsx +244 -0
  193. tools/bolt.diy/app/components/observability/MandateDetails.tsx +201 -0
  194. tools/bolt.diy/app/components/observability/ObservabilityDashboard.tsx +200 -0
  195. tools/bolt.diy/app/components/sidebar/HistoryItem.tsx +187 -0
  196. tools/bolt.diy/app/components/sidebar/Menu.client.tsx +536 -0
  197. tools/bolt.diy/app/components/sidebar/date-binning.ts +59 -0
  198. tools/bolt.diy/app/components/txt +1 -0
  199. tools/bolt.diy/app/components/ui/BackgroundRays/index.tsx +18 -0
  200. tools/bolt.diy/app/components/ui/BackgroundRays/styles.module.scss +246 -0
  201. tools/bolt.diy/app/components/ui/Badge.tsx +53 -0
  202. tools/bolt.diy/app/components/ui/BranchSelector.tsx +270 -0
  203. tools/bolt.diy/app/components/ui/Breadcrumbs.tsx +101 -0
  204. tools/bolt.diy/app/components/ui/Button.tsx +46 -0
  205. tools/bolt.diy/app/components/ui/Card.tsx +55 -0
  206. tools/bolt.diy/app/components/ui/Checkbox.tsx +32 -0
  207. tools/bolt.diy/app/components/ui/CloseButton.tsx +49 -0
  208. tools/bolt.diy/app/components/ui/CodeBlock.tsx +103 -0
  209. tools/bolt.diy/app/components/ui/Collapsible.tsx +9 -0
  210. tools/bolt.diy/app/components/ui/ColorSchemeDialog.tsx +378 -0
  211. tools/bolt.diy/app/components/ui/Dialog.tsx +449 -0
  212. tools/bolt.diy/app/components/ui/Dropdown.tsx +63 -0
  213. tools/bolt.diy/app/components/ui/EmptyState.tsx +154 -0
  214. tools/bolt.diy/app/components/ui/FileIcon.tsx +346 -0
  215. tools/bolt.diy/app/components/ui/FilterChip.tsx +92 -0
  216. tools/bolt.diy/app/components/ui/GlowingEffect.tsx +192 -0
  217. tools/bolt.diy/app/components/ui/GradientCard.tsx +100 -0
  218. tools/bolt.diy/app/components/ui/IconButton.tsx +84 -0
  219. tools/bolt.diy/app/components/ui/Input.tsx +22 -0
  220. tools/bolt.diy/app/components/ui/Label.tsx +20 -0
  221. tools/bolt.diy/app/components/ui/LoadingDots.tsx +27 -0
  222. tools/bolt.diy/app/components/ui/LoadingOverlay.tsx +32 -0
  223. tools/bolt.diy/app/components/ui/PanelHeader.tsx +20 -0
  224. tools/bolt.diy/app/components/ui/PanelHeaderButton.tsx +36 -0
  225. tools/bolt.diy/app/components/ui/Popover.tsx +29 -0
  226. tools/bolt.diy/app/components/ui/Progress.tsx +22 -0
  227. tools/bolt.diy/app/components/ui/RepositoryStats.tsx +87 -0
  228. tools/bolt.diy/app/components/ui/ScrollArea.tsx +41 -0
  229. tools/bolt.diy/app/components/ui/SearchInput.tsx +80 -0
  230. tools/bolt.diy/app/components/ui/SearchResultItem.tsx +134 -0
  231. tools/bolt.diy/app/components/ui/Separator.tsx +22 -0
  232. tools/bolt.diy/app/components/ui/SettingsButton.tsx +35 -0
  233. tools/bolt.diy/app/components/ui/Slider.tsx +73 -0
  234. tools/bolt.diy/app/components/ui/StatusIndicator.tsx +90 -0
  235. tools/bolt.diy/app/components/ui/Switch.tsx +37 -0
  236. tools/bolt.diy/app/components/ui/Tabs.tsx +52 -0
  237. tools/bolt.diy/app/components/ui/TabsWithSlider.tsx +112 -0
  238. tools/bolt.diy/app/components/ui/ThemeSwitch.tsx +29 -0
  239. tools/bolt.diy/app/components/ui/Tooltip.tsx +122 -0
  240. tools/bolt.diy/app/components/ui/index.ts +38 -0
  241. tools/bolt.diy/app/components/ui/use-toast.ts +66 -0
  242. tools/bolt.diy/app/components/workbench/DiffView.tsx +796 -0
  243. tools/bolt.diy/app/components/workbench/EditorPanel.tsx +174 -0
  244. tools/bolt.diy/app/components/workbench/ExpoQrModal.tsx +55 -0
  245. tools/bolt.diy/app/components/workbench/FileBreadcrumb.tsx +150 -0
  246. tools/bolt.diy/app/components/workbench/FileTree.tsx +565 -0
  247. tools/bolt.diy/app/components/workbench/Inspector.tsx +126 -0
  248. tools/bolt.diy/app/components/workbench/InspectorPanel.tsx +146 -0
  249. tools/bolt.diy/app/components/workbench/LockManager.tsx +262 -0
  250. tools/bolt.diy/app/components/workbench/PortDropdown.tsx +91 -0
  251. tools/bolt.diy/app/components/workbench/Preview.tsx +1049 -0
  252. tools/bolt.diy/app/components/workbench/ScreenshotSelector.tsx +293 -0
  253. tools/bolt.diy/app/components/workbench/Search.tsx +257 -0
  254. tools/bolt.diy/app/components/workbench/Workbench.client.tsx +506 -0
  255. tools/bolt.diy/app/components/workbench/terminal/Terminal.tsx +131 -0
  256. tools/bolt.diy/app/components/workbench/terminal/TerminalManager.tsx +68 -0
  257. tools/bolt.diy/app/components/workbench/terminal/TerminalTabs.tsx +277 -0
  258. tools/bolt.diy/app/components/workbench/terminal/theme.ts +36 -0
  259. tools/bolt.diy/app/components/workflow/WorkflowPhase.tsx +109 -0
  260. tools/bolt.diy/app/components/workflow/WorkflowStatus.tsx +60 -0
  261. tools/bolt.diy/app/components/workflow/WorkflowTimeline.tsx +150 -0
  262. tools/bolt.diy/app/entry.client.tsx +7 -0
  263. tools/bolt.diy/app/entry.server.tsx +80 -0
  264. tools/bolt.diy/app/root.tsx +156 -0
  265. tools/bolt.diy/app/routes/_index.tsx +175 -0
  266. tools/bolt.diy/app/routes/api.bug-report.ts +254 -0
  267. tools/bolt.diy/app/routes/api.chat.ts +463 -0
  268. tools/bolt.diy/app/routes/api.check-env-key.ts +41 -0
  269. tools/bolt.diy/app/routes/api.configured-providers.ts +110 -0
  270. tools/bolt.diy/app/routes/api.corporate-swarm-status.ts +55 -0
  271. tools/bolt.diy/app/routes/api.enhancer.ts +137 -0
  272. tools/bolt.diy/app/routes/api.export-api-keys.ts +44 -0
  273. tools/bolt.diy/app/routes/api.git-info.ts +69 -0
  274. tools/bolt.diy/app/routes/api.git-proxy.$.ts +178 -0
  275. tools/bolt.diy/app/routes/api.github-branches.ts +166 -0
  276. tools/bolt.diy/app/routes/api.github-deploy.ts +67 -0
  277. tools/bolt.diy/app/routes/api.github-stats.ts +198 -0
  278. tools/bolt.diy/app/routes/api.github-template.ts +242 -0
  279. tools/bolt.diy/app/routes/api.github-user.ts +287 -0
  280. tools/bolt.diy/app/routes/api.gitlab-branches.ts +143 -0
  281. tools/bolt.diy/app/routes/api.gitlab-deploy.ts +67 -0
  282. tools/bolt.diy/app/routes/api.gitlab-projects.ts +105 -0
  283. tools/bolt.diy/app/routes/api.health.ts +8 -0
  284. tools/bolt.diy/app/routes/api.llmcall.ts +298 -0
  285. tools/bolt.diy/app/routes/api.mandate.ts +351 -0
  286. tools/bolt.diy/app/routes/api.mcp-check.ts +16 -0
  287. tools/bolt.diy/app/routes/api.mcp-update-config.ts +23 -0
  288. tools/bolt.diy/app/routes/api.models.$provider.ts +2 -0
  289. tools/bolt.diy/app/routes/api.models.ts +90 -0
  290. tools/bolt.diy/app/routes/api.netlify-deploy.ts +240 -0
  291. tools/bolt.diy/app/routes/api.netlify-user.ts +142 -0
  292. tools/bolt.diy/app/routes/api.supabase-user.ts +199 -0
  293. tools/bolt.diy/app/routes/api.supabase.query.ts +92 -0
  294. tools/bolt.diy/app/routes/api.supabase.ts +56 -0
  295. tools/bolt.diy/app/routes/api.supabase.variables.ts +32 -0
  296. tools/bolt.diy/app/routes/api.system.diagnostics.ts +142 -0
  297. tools/bolt.diy/app/routes/api.system.disk-info.ts +311 -0
  298. tools/bolt.diy/app/routes/api.system.git-info.ts +332 -0
  299. tools/bolt.diy/app/routes/api.update.ts +21 -0
  300. tools/bolt.diy/app/routes/api.vercel-deploy.ts +497 -0
  301. tools/bolt.diy/app/routes/api.vercel-user.ts +161 -0
  302. tools/bolt.diy/app/routes/api.workflow-status.$proposalId.ts +309 -0
  303. tools/bolt.diy/app/routes/chat.$id.tsx +8 -0
  304. tools/bolt.diy/app/routes/execute.$mandateId.tsx +432 -0
  305. tools/bolt.diy/app/routes/git.tsx +25 -0
  306. tools/bolt.diy/app/routes/observability.$mandateId.tsx +50 -0
  307. tools/bolt.diy/app/routes/webcontainer.connect.$id.tsx +32 -0
  308. tools/bolt.diy/app/routes/webcontainer.preview.$id.tsx +97 -0
  309. tools/bolt.diy/app/routes/workflow.$proposalId.tsx +170 -0
  310. tools/bolt.diy/app/styles/animations.scss +49 -0
  311. tools/bolt.diy/app/styles/components/code.scss +9 -0
  312. tools/bolt.diy/app/styles/components/editor.scss +135 -0
  313. tools/bolt.diy/app/styles/components/resize-handle.scss +30 -0
  314. tools/bolt.diy/app/styles/components/terminal.scss +3 -0
  315. tools/bolt.diy/app/styles/components/toast.scss +23 -0
  316. tools/bolt.diy/app/styles/diff-view.css +72 -0
  317. tools/bolt.diy/app/styles/index.scss +73 -0
  318. tools/bolt.diy/app/styles/variables.scss +255 -0
  319. tools/bolt.diy/app/styles/z-index.scss +37 -0
  320. tools/bolt.diy/app/types/GitHub.ts +182 -0
  321. tools/bolt.diy/app/types/GitLab.ts +103 -0
  322. tools/bolt.diy/app/types/actions.ts +85 -0
  323. tools/bolt.diy/app/types/artifact.ts +5 -0
  324. tools/bolt.diy/app/types/context.ts +26 -0
  325. tools/bolt.diy/app/types/design-scheme.ts +93 -0
  326. tools/bolt.diy/app/types/global.d.ts +13 -0
  327. tools/bolt.diy/app/types/mandate.ts +333 -0
  328. tools/bolt.diy/app/types/model.ts +25 -0
  329. tools/bolt.diy/app/types/netlify.ts +94 -0
  330. tools/bolt.diy/app/types/supabase.ts +54 -0
  331. tools/bolt.diy/app/types/template.ts +8 -0
  332. tools/bolt.diy/app/types/terminal.ts +9 -0
  333. tools/bolt.diy/app/types/theme.ts +1 -0
  334. tools/bolt.diy/app/types/vercel.ts +67 -0
  335. tools/bolt.diy/app/utils/buffer.ts +29 -0
  336. tools/bolt.diy/app/utils/classNames.ts +65 -0
  337. tools/bolt.diy/app/utils/constants.ts +147 -0
  338. tools/bolt.diy/app/utils/debounce.ts +13 -0
  339. tools/bolt.diy/app/utils/debugLogger.ts +1284 -0
  340. tools/bolt.diy/app/utils/diff.spec.ts +11 -0
  341. tools/bolt.diy/app/utils/diff.ts +117 -0
  342. tools/bolt.diy/app/utils/easings.ts +3 -0
  343. tools/bolt.diy/app/utils/fileLocks.ts +96 -0
  344. tools/bolt.diy/app/utils/fileUtils.ts +121 -0
  345. tools/bolt.diy/app/utils/folderImport.ts +73 -0
  346. tools/bolt.diy/app/utils/formatSize.ts +12 -0
  347. tools/bolt.diy/app/utils/getLanguageFromExtension.ts +24 -0
  348. tools/bolt.diy/app/utils/githubStats.ts +9 -0
  349. tools/bolt.diy/app/utils/gitlabStats.ts +54 -0
  350. tools/bolt.diy/app/utils/logger.ts +162 -0
  351. tools/bolt.diy/app/utils/markdown.ts +155 -0
  352. tools/bolt.diy/app/utils/mobile.ts +4 -0
  353. tools/bolt.diy/app/utils/os.ts +4 -0
  354. tools/bolt.diy/app/utils/path.ts +19 -0
  355. tools/bolt.diy/app/utils/projectCommands.ts +197 -0
  356. tools/bolt.diy/app/utils/promises.ts +19 -0
  357. tools/bolt.diy/app/utils/react.ts +6 -0
  358. tools/bolt.diy/app/utils/sampler.ts +49 -0
  359. tools/bolt.diy/app/utils/selectStarterTemplate.ts +255 -0
  360. tools/bolt.diy/app/utils/shell.ts +384 -0
  361. tools/bolt.diy/app/utils/stacktrace.ts +27 -0
  362. tools/bolt.diy/app/utils/stripIndent.ts +23 -0
  363. tools/bolt.diy/app/utils/terminal.ts +11 -0
  364. tools/bolt.diy/app/utils/unreachable.ts +3 -0
  365. tools/bolt.diy/app/vite-env.d.ts +2 -0
  366. tools/bolt.diy/assets/entitlements.mac.plist +25 -0
  367. tools/bolt.diy/assets/icons/icon.icns +0 -0
  368. tools/bolt.diy/assets/icons/icon.ico +0 -0
  369. tools/bolt.diy/assets/icons/icon.png +0 -0
  370. tools/bolt.diy/bindings.js +78 -0
  371. tools/bolt.diy/bindings.sh +33 -0
  372. tools/bolt.diy/docker-compose.yaml +145 -0
  373. tools/bolt.diy/electron/main/index.ts +201 -0
  374. tools/bolt.diy/electron/main/tsconfig.json +30 -0
  375. tools/bolt.diy/electron/main/ui/menu.ts +29 -0
  376. tools/bolt.diy/electron/main/ui/window.ts +54 -0
  377. tools/bolt.diy/electron/main/utils/auto-update.ts +110 -0
  378. tools/bolt.diy/electron/main/utils/constants.ts +4 -0
  379. tools/bolt.diy/electron/main/utils/cookie.ts +40 -0
  380. tools/bolt.diy/electron/main/utils/reload.ts +35 -0
  381. tools/bolt.diy/electron/main/utils/serve.ts +71 -0
  382. tools/bolt.diy/electron/main/utils/store.ts +3 -0
  383. tools/bolt.diy/electron/main/utils/vite-server.ts +44 -0
  384. tools/bolt.diy/electron/main/vite.config.ts +44 -0
  385. tools/bolt.diy/electron/preload/index.ts +22 -0
  386. tools/bolt.diy/electron/preload/tsconfig.json +7 -0
  387. tools/bolt.diy/electron/preload/vite.config.ts +31 -0
  388. tools/bolt.diy/electron-builder.yml +64 -0
  389. tools/bolt.diy/electron-update.yml +4 -0
  390. tools/bolt.diy/eslint.config.mjs +57 -0
  391. tools/bolt.diy/functions/[[path]].ts +12 -0
  392. tools/bolt.diy/icons/angular.svg +1 -0
  393. tools/bolt.diy/icons/astro.svg +8 -0
  394. tools/bolt.diy/icons/chat.svg +1 -0
  395. tools/bolt.diy/icons/expo-brand.svg +1 -0
  396. tools/bolt.diy/icons/expo.svg +4 -0
  397. tools/bolt.diy/icons/logo-text.svg +1 -0
  398. tools/bolt.diy/icons/logo.svg +4 -0
  399. tools/bolt.diy/icons/mcp.svg +1 -0
  400. tools/bolt.diy/icons/nativescript.svg +1 -0
  401. tools/bolt.diy/icons/netlify.svg +10 -0
  402. tools/bolt.diy/icons/nextjs.svg +1 -0
  403. tools/bolt.diy/icons/nuxt.svg +1 -0
  404. tools/bolt.diy/icons/qwik.svg +1 -0
  405. tools/bolt.diy/icons/react.svg +1 -0
  406. tools/bolt.diy/icons/remix.svg +24 -0
  407. tools/bolt.diy/icons/remotion.svg +1 -0
  408. tools/bolt.diy/icons/shadcn.svg +21 -0
  409. tools/bolt.diy/icons/slidev.svg +60 -0
  410. tools/bolt.diy/icons/solidjs.svg +1 -0
  411. tools/bolt.diy/icons/stars.svg +1 -0
  412. tools/bolt.diy/icons/svelte.svg +1 -0
  413. tools/bolt.diy/icons/typescript.svg +1 -0
  414. tools/bolt.diy/icons/vite.svg +1 -0
  415. tools/bolt.diy/icons/vue.svg +1 -0
  416. tools/bolt.diy/load-context.ts +9 -0
  417. tools/bolt.diy/notarize.cjs +31 -0
  418. tools/bolt.diy/package.json +218 -0
  419. tools/bolt.diy/playwright.config.preview.ts +35 -0
  420. tools/bolt.diy/pre-start.cjs +26 -0
  421. tools/bolt.diy/public/apple-touch-icon-precomposed.png +0 -0
  422. tools/bolt.diy/public/apple-touch-icon.png +0 -0
  423. tools/bolt.diy/public/favicon.ico +0 -0
  424. tools/bolt.diy/public/favicon.svg +4 -0
  425. tools/bolt.diy/public/icons/AmazonBedrock.svg +1 -0
  426. tools/bolt.diy/public/icons/Anthropic.svg +4 -0
  427. tools/bolt.diy/public/icons/Cohere.svg +4 -0
  428. tools/bolt.diy/public/icons/Deepseek.svg +5 -0
  429. tools/bolt.diy/public/icons/Default.svg +4 -0
  430. tools/bolt.diy/public/icons/Google.svg +4 -0
  431. tools/bolt.diy/public/icons/Groq.svg +4 -0
  432. tools/bolt.diy/public/icons/HuggingFace.svg +4 -0
  433. tools/bolt.diy/public/icons/Hyperbolic.svg +3 -0
  434. tools/bolt.diy/public/icons/LMStudio.svg +5 -0
  435. tools/bolt.diy/public/icons/Mistral.svg +4 -0
  436. tools/bolt.diy/public/icons/Ollama.svg +4 -0
  437. tools/bolt.diy/public/icons/OpenAI.svg +4 -0
  438. tools/bolt.diy/public/icons/OpenAILike.svg +4 -0
  439. tools/bolt.diy/public/icons/OpenRouter.svg +4 -0
  440. tools/bolt.diy/public/icons/Perplexity.svg +4 -0
  441. tools/bolt.diy/public/icons/Together.svg +4 -0
  442. tools/bolt.diy/public/icons/xAI.svg +5 -0
  443. tools/bolt.diy/public/inspector-script.js +292 -0
  444. tools/bolt.diy/public/logo-dark-styled.png +0 -0
  445. tools/bolt.diy/public/logo-dark.png +0 -0
  446. tools/bolt.diy/public/logo-light-styled.png +0 -0
  447. tools/bolt.diy/public/logo-light.png +0 -0
  448. tools/bolt.diy/public/logo.svg +15 -0
  449. tools/bolt.diy/public/social_preview_index.jpg +0 -0
  450. tools/bolt.diy/scripts/clean.js +45 -0
  451. tools/bolt.diy/scripts/electron-dev.mjs +181 -0
  452. tools/bolt.diy/scripts/setup-env.sh +41 -0
  453. tools/bolt.diy/scripts/update-imports.sh +7 -0
  454. tools/bolt.diy/scripts/update.sh +52 -0
  455. tools/bolt.diy/services/execution-governor/Dockerfile +41 -0
  456. tools/bolt.diy/services/execution-governor/config.ts +42 -0
  457. tools/bolt.diy/services/execution-governor/index.ts +683 -0
  458. tools/bolt.diy/services/execution-governor/metrics.ts +141 -0
  459. tools/bolt.diy/services/execution-governor/package.json +31 -0
  460. tools/bolt.diy/services/execution-governor/priority-queue.ts +139 -0
  461. tools/bolt.diy/services/execution-governor/tsconfig.json +21 -0
  462. tools/bolt.diy/services/execution-governor/types.ts +145 -0
  463. tools/bolt.diy/services/headless-executor/Dockerfile +43 -0
  464. tools/bolt.diy/services/headless-executor/executor.ts +210 -0
  465. tools/bolt.diy/services/headless-executor/index.ts +323 -0
  466. tools/bolt.diy/services/headless-executor/package.json +27 -0
  467. tools/bolt.diy/services/headless-executor/tsconfig.json +21 -0
  468. tools/bolt.diy/services/headless-executor/types.ts +38 -0
  469. tools/bolt.diy/test-workflows.sh +240 -0
  470. tools/bolt.diy/tests/integration/corporate-swarm.test.ts +208 -0
  471. tools/bolt.diy/tests/mandates/budget-limited.json +34 -0
  472. tools/bolt.diy/tests/mandates/complex.json +53 -0
  473. tools/bolt.diy/tests/mandates/constraint-enforced.json +36 -0
  474. tools/bolt.diy/tests/mandates/simple.json +35 -0
  475. tools/bolt.diy/tsconfig.json +37 -0
  476. tools/bolt.diy/types/istextorbinary.d.ts +15 -0
  477. tools/bolt.diy/uno.config.ts +279 -0
  478. tools/bolt.diy/vite-electron.config.ts +76 -0
  479. tools/bolt.diy/vite.config.ts +112 -0
  480. tools/bolt.diy/worker-configuration.d.ts +22 -0
  481. tools/bolt.diy/wrangler.toml +6 -0
  482. tools/code_generator.py +461 -0
  483. tools/file_operations.py +465 -0
  484. tools/mandate_generator.py +337 -0
  485. tools/mcpClientUtils.py +1216 -0
  486. tools/sensors.py +285 -0
  487. utils/Agent_types.py +15 -0
  488. utils/AnyToStr.py +0 -0
  489. utils/HHCS.py +277 -0
  490. utils/__init__.py +30 -0
  491. utils/agent.py +3627 -0
  492. utils/aop.py +2948 -0
  493. utils/canonical.py +143 -0
  494. utils/conversation.py +1195 -0
  495. utils/doctrine_versioning +230 -0
  496. utils/formatter.py +474 -0
  497. utils/ledger.py +311 -0
  498. utils/out_types.py +16 -0
  499. utils/rollback.py +339 -0
  500. utils/router.py +929 -0
  501. utils/tui.py +1908 -0
utils/tui.py ADDED
@@ -0,0 +1,1908 @@
1
+ """
2
+ CorporateSwarm TUI - Comprehensive Interactive Terminal User Interface
3
+
4
+ A rich, fully interactive terminal interface for monitoring and controlling
5
+ CorporateSwarm governance systems in real-time.
6
+
7
+ Features:
8
+ - Live updating dashboard
9
+ - Interactive member management
10
+ - Proposal creation and voting
11
+ - Board meeting scheduling
12
+ - ESG score visualization
13
+ - Risk assessment management
14
+ - AOP integration control
15
+ - Real-time metrics
16
+ - Full keyboard navigation and interaction
17
+ """
18
+
19
+ import time
20
+ import threading
21
+ import sys
22
+ import select
23
+ import termios
24
+ import tty
25
+ from typing import Any, Dict, List, Optional, Callable, Tuple
26
+ from dataclasses import dataclass, field
27
+ from datetime import datetime
28
+ from enum import Enum
29
+
30
+ try:
31
+ from rich.console import Console, Group
32
+ from rich.layout import Layout
33
+ from rich.panel import Panel
34
+ from rich.table import Table
35
+ from rich.text import Text
36
+ from rich.live import Live
37
+ from rich.progress import (
38
+ Progress, SpinnerColumn, TextColumn, BarColumn,
39
+ TimeElapsedColumn, ProgressColumn
40
+ )
41
+ from rich.columns import Columns
42
+ from rich.align import Align
43
+ from rich import box
44
+ from rich.markdown import Markdown
45
+ from rich.tree import Tree
46
+ from rich.rule import Rule
47
+ from rich.spinner import Spinner
48
+ from rich.status import Status
49
+ from rich.prompt import Prompt, Confirm
50
+ from rich.console import Group as RichGroup
51
+ RICH_AVAILABLE = True
52
+ except ImportError:
53
+ RICH_AVAILABLE = False
54
+ Console = None
55
+ Layout = None
56
+ Panel = None
57
+ Table = None
58
+ Text = None
59
+ Live = None
60
+ Progress = None
61
+ Columns = None
62
+ Align = None
63
+ box = None
64
+ Markdown = None
65
+ Tree = None
66
+ Rule = None
67
+ Spinner = None
68
+ Status = None
69
+ Prompt = None
70
+ Confirm = None
71
+ RichGroup = None
72
+
73
+ from loguru import logger
74
+
75
+
76
+ class ViewMode(str, Enum):
77
+ """TUI view modes."""
78
+ DASHBOARD = "dashboard"
79
+ MEMBERS = "members"
80
+ PROPOSALS = "proposals"
81
+ VOTES = "votes"
82
+ MEETINGS = "meetings"
83
+ ESG = "esg"
84
+ RISK = "risk"
85
+ AOP = "aop"
86
+ COMMITTEES = "committees"
87
+ DEPARTMENTS = "departments"
88
+ COMMAND = "command"
89
+
90
+
91
+ class InteractionMode(str, Enum):
92
+ """Interaction modes for the TUI."""
93
+ VIEW = "view"
94
+ SELECT = "select"
95
+ CREATE = "create"
96
+ EDIT = "edit"
97
+ DELETE = "delete"
98
+ COMMAND = "command"
99
+
100
+
101
+ @dataclass
102
+ class TUIState:
103
+ """State for CorporateSwarm TUI display."""
104
+ corporate_swarm: Optional[Any] = None
105
+ view_mode: ViewMode = ViewMode.DASHBOARD
106
+ interaction_mode: InteractionMode = InteractionMode.VIEW
107
+ selected_member_id: Optional[str] = None
108
+ selected_proposal_id: Optional[str] = None
109
+ selected_committee_id: Optional[str] = None
110
+ selected_vote_id: Optional[str] = None
111
+ selected_meeting_id: Optional[str] = None
112
+ selected_index: int = 0
113
+ list_items: List[Any] = field(default_factory=list)
114
+ auto_refresh: bool = True
115
+ refresh_rate: float = 1.0
116
+ last_update: float = field(default_factory=time.time)
117
+ status_data: Optional[Dict[str, Any]] = None
118
+ alerts: List[Dict[str, Any]] = field(default_factory=list)
119
+ command_history: List[str] = field(default_factory=list)
120
+ current_command: str = ""
121
+ message: Optional[str] = None
122
+ message_style: str = "white"
123
+
124
+ def __post_init__(self):
125
+ """Initialize default values."""
126
+ if self.status_data is None:
127
+ self.status_data = {}
128
+ if self.alerts is None:
129
+ self.alerts = []
130
+ if self.list_items is None:
131
+ self.list_items = []
132
+
133
+
134
+ class CorporateSwarmTUI:
135
+ """
136
+ Comprehensive Interactive Terminal User Interface for CorporateSwarm.
137
+
138
+ Provides fully interactive interface with:
139
+ - Corporate overview and metrics
140
+ - Interactive member management
141
+ - Proposal creation and voting
142
+ - Board meeting scheduling
143
+ - ESG score visualization
144
+ - Risk assessment management
145
+ - AOP integration control
146
+ - Real-time alerts and notifications
147
+ - Keyboard navigation and commands
148
+ """
149
+
150
+ def __init__(
151
+ self,
152
+ corporate_swarm: Any,
153
+ title: str = "CorporateSwarm Governance System",
154
+ refresh_rate: float = 1.0
155
+ ):
156
+ """
157
+ Initialize CorporateSwarm TUI.
158
+
159
+ Args:
160
+ corporate_swarm: CorporateSwarm instance to monitor
161
+ title: Title for the TUI
162
+ refresh_rate: Refresh rate in seconds
163
+ """
164
+ if not RICH_AVAILABLE:
165
+ raise ImportError("rich is required for TUI. Install with: pip install rich")
166
+
167
+ self.corporate_swarm = corporate_swarm
168
+ self.console = Console()
169
+ self.title = title
170
+ self.state = TUIState(
171
+ corporate_swarm=corporate_swarm,
172
+ refresh_rate=refresh_rate
173
+ )
174
+ self.is_running = False
175
+ self.start_time = time.time()
176
+ self._should_quit = False
177
+ self._key_queue = None
178
+ self._keyboard_thread = None
179
+ self._setup_key_handlers()
180
+
181
+ def _setup_key_handlers(self) -> None:
182
+ """Setup keyboard handlers."""
183
+ self._key_handlers: Dict[str, Callable] = {
184
+ 'q': self._quit,
185
+ 'Q': self._quit,
186
+ 'r': self._refresh,
187
+ 'R': self._refresh,
188
+ '1': lambda: self._set_view(ViewMode.DASHBOARD),
189
+ '2': lambda: self._set_view(ViewMode.MEMBERS),
190
+ '3': lambda: self._set_view(ViewMode.PROPOSALS),
191
+ '4': lambda: self._set_view(ViewMode.VOTES),
192
+ '5': lambda: self._set_view(ViewMode.MEETINGS),
193
+ '6': lambda: self._set_view(ViewMode.ESG),
194
+ '7': lambda: self._set_view(ViewMode.RISK),
195
+ '8': lambda: self._set_view(ViewMode.AOP),
196
+ '9': lambda: self._set_view(ViewMode.COMMITTEES),
197
+ '0': lambda: self._set_view(ViewMode.DEPARTMENTS),
198
+ 'a': self._toggle_auto_refresh,
199
+ 'A': self._toggle_auto_refresh,
200
+ 'c': self._enter_command_mode,
201
+ 'C': self._enter_command_mode,
202
+ 'n': self._create_new_item,
203
+ 'N': self._create_new_item,
204
+ 's': self._select_item,
205
+ 'S': self._select_item,
206
+ 'enter': self._activate_selected,
207
+ '\r': self._activate_selected,
208
+ '\n': self._activate_selected,
209
+ 'up': self._navigate_up,
210
+ 'down': self._navigate_down,
211
+ 'k': self._navigate_up,
212
+ 'j': self._navigate_down,
213
+ 'h': self._navigate_left,
214
+ 'l': self._navigate_right,
215
+ 'escape': self._exit_interaction,
216
+ '\x1b': self._exit_interaction,
217
+ '?': self._show_help,
218
+ }
219
+
220
+ def _quit(self) -> None:
221
+ """Quit the TUI."""
222
+ self._should_quit = True
223
+
224
+ def _refresh(self) -> None:
225
+ """Manually refresh the display."""
226
+ self._update_status()
227
+ self.state.message = "Status refreshed"
228
+ self.state.message_style = "green"
229
+
230
+ def _set_view(self, mode: ViewMode) -> None:
231
+ """Set the current view mode."""
232
+ self.state.view_mode = mode
233
+ self.state.selected_index = 0
234
+ self.state.interaction_mode = InteractionMode.VIEW
235
+ self._update_list_items()
236
+
237
+ def _toggle_auto_refresh(self) -> None:
238
+ """Toggle auto-refresh mode."""
239
+ self.state.auto_refresh = not self.state.auto_refresh
240
+ status = "enabled" if self.state.auto_refresh else "disabled"
241
+ self.state.message = f"Auto-refresh {status}"
242
+ self.state.message_style = "green"
243
+
244
+ def _enter_command_mode(self) -> None:
245
+ """Enter command input mode."""
246
+ self.state.interaction_mode = InteractionMode.COMMAND
247
+ self.state.current_command = ""
248
+
249
+ def _create_new_item(self) -> None:
250
+ """Create a new item based on current view."""
251
+ if self.state.view_mode == ViewMode.PROPOSALS:
252
+ self._create_proposal_interactive()
253
+ elif self.state.view_mode == ViewMode.MEMBERS:
254
+ self._create_member_interactive()
255
+ elif self.state.view_mode == ViewMode.MEETINGS:
256
+ self._schedule_meeting_interactive()
257
+ else:
258
+ self.state.message = "Cannot create items in this view"
259
+ self.state.message_style = "yellow"
260
+
261
+ def _select_item(self) -> None:
262
+ """Enter selection mode."""
263
+ if self.state.list_items:
264
+ self.state.interaction_mode = InteractionMode.SELECT
265
+ self.state.message = "Use arrow keys to navigate, Enter to select"
266
+ self.state.message_style = "cyan"
267
+ else:
268
+ self.state.message = "No items to select"
269
+ self.state.message_style = "yellow"
270
+
271
+ def _activate_selected(self) -> None:
272
+ """Activate the selected item."""
273
+ if self.state.interaction_mode == InteractionMode.SELECT:
274
+ self._show_item_details()
275
+ elif self.state.interaction_mode == InteractionMode.COMMAND:
276
+ self._execute_command()
277
+
278
+ def _navigate_up(self) -> None:
279
+ """Navigate up in list."""
280
+ if self.state.list_items and self.state.selected_index > 0:
281
+ self.state.selected_index -= 1
282
+
283
+ def _navigate_down(self) -> None:
284
+ """Navigate down in list."""
285
+ if self.state.list_items and self.state.selected_index < len(self.state.list_items) - 1:
286
+ self.state.selected_index += 1
287
+
288
+ def _navigate_left(self) -> None:
289
+ """Navigate left (back)."""
290
+ self.state.interaction_mode = InteractionMode.VIEW
291
+ self.state.message = None
292
+
293
+ def _navigate_right(self) -> None:
294
+ """Navigate right (forward)."""
295
+ if self.state.list_items:
296
+ self._select_item()
297
+
298
+ def _exit_interaction(self) -> None:
299
+ """Exit current interaction mode."""
300
+ self.state.interaction_mode = InteractionMode.VIEW
301
+ self.state.current_command = ""
302
+ self.state.message = None
303
+
304
+ def _show_help(self) -> None:
305
+ """Show help information."""
306
+ self.state.message = (
307
+ "Help: [1-0] Views | [N]ew | [S]elect | [C]ommand | [R]efresh | "
308
+ "[A]uto-refresh | [Q]uit | [?] Help"
309
+ )
310
+ self.state.message_style = "cyan"
311
+
312
+ def _update_list_items(self) -> None:
313
+ """Update list items based on current view."""
314
+ if not self.corporate_swarm:
315
+ self.state.list_items = []
316
+ return
317
+
318
+ if self.state.view_mode == ViewMode.MEMBERS:
319
+ self.state.list_items = list(self.corporate_swarm.members.values())
320
+ elif self.state.view_mode == ViewMode.PROPOSALS:
321
+ self.state.list_items = self.corporate_swarm.proposals
322
+ elif self.state.view_mode == ViewMode.VOTES:
323
+ self.state.list_items = self.corporate_swarm.votes
324
+ elif self.state.view_mode == ViewMode.MEETINGS:
325
+ self.state.list_items = self.corporate_swarm.board_meetings
326
+ elif self.state.view_mode == ViewMode.COMMITTEES:
327
+ self.state.list_items = list(self.corporate_swarm.board_committees.values())
328
+ elif self.state.view_mode == ViewMode.DEPARTMENTS:
329
+ self.state.list_items = list(self.corporate_swarm.departments.values())
330
+ else:
331
+ self.state.list_items = []
332
+
333
+ # Reset selection index
334
+ if self.state.selected_index >= len(self.state.list_items):
335
+ self.state.selected_index = max(0, len(self.state.list_items) - 1)
336
+
337
+ def _show_item_details(self) -> None:
338
+ """Show details for selected item."""
339
+ if not self.state.list_items or self.state.selected_index >= len(self.state.list_items):
340
+ return
341
+
342
+ selected = self.state.list_items[self.state.selected_index]
343
+
344
+ if self.state.view_mode == ViewMode.MEMBERS:
345
+ self.state.selected_member_id = selected.member_id
346
+ self.state.interaction_mode = InteractionMode.VIEW
347
+ elif self.state.view_mode == ViewMode.PROPOSALS:
348
+ self.state.selected_proposal_id = selected.proposal_id
349
+ self.state.interaction_mode = InteractionMode.VIEW
350
+ elif self.state.view_mode == ViewMode.VOTES:
351
+ self.state.selected_vote_id = selected.vote_id
352
+ self.state.interaction_mode = InteractionMode.VIEW
353
+ elif self.state.view_mode == ViewMode.MEETINGS:
354
+ self.state.selected_meeting_id = selected.meeting_id
355
+ self.state.interaction_mode = InteractionMode.VIEW
356
+ elif self.state.view_mode == ViewMode.COMMITTEES:
357
+ self.state.selected_committee_id = selected.committee_id
358
+ self.state.interaction_mode = InteractionMode.VIEW
359
+
360
+ def _execute_command(self) -> None:
361
+ """Execute a command."""
362
+ if not self.state.current_command:
363
+ self.state.interaction_mode = InteractionMode.VIEW
364
+ return
365
+
366
+ cmd = self.state.current_command.strip().lower()
367
+ parts = cmd.split()
368
+
369
+ if not parts:
370
+ self.state.interaction_mode = InteractionMode.VIEW
371
+ return
372
+
373
+ command = parts[0]
374
+ args = parts[1:] if len(parts) > 1 else []
375
+
376
+ try:
377
+ if command == "vote" and args:
378
+ # Vote on a proposal
379
+ proposal_id = args[0]
380
+ self._conduct_vote_interactive(proposal_id)
381
+ elif command == "proposal" or command == "create":
382
+ self._create_proposal_interactive()
383
+ elif command == "member" or command == "add":
384
+ self._create_member_interactive()
385
+ elif command == "meeting" or command == "schedule":
386
+ self._schedule_meeting_interactive()
387
+ elif command == "risk":
388
+ self._conduct_risk_assessment()
389
+ elif command == "esg":
390
+ self._calculate_esg()
391
+ elif command == "status":
392
+ self._show_full_status()
393
+ else:
394
+ self.state.message = f"Unknown command: {command}. Type 'help' for commands"
395
+ self.state.message_style = "yellow"
396
+ except Exception as e:
397
+ self.state.message = f"Command error: {str(e)}"
398
+ self.state.message_style = "red"
399
+ finally:
400
+ self.state.current_command = ""
401
+ self.state.interaction_mode = InteractionMode.VIEW
402
+
403
+ def _create_proposal_interactive(self) -> None:
404
+ """Interactively create a proposal."""
405
+ if not self.corporate_swarm:
406
+ self.state.message = "No CorporateSwarm instance"
407
+ self.state.message_style = "red"
408
+ return
409
+
410
+ try:
411
+ self.console.clear()
412
+ self.console.print(Panel("Create New Proposal", border_style="cyan", box=box.ROUNDED))
413
+
414
+ title = Prompt.ask("Proposal Title")
415
+ description = Prompt.ask("Description")
416
+
417
+ # Show proposal types
418
+ proposal_types = [
419
+ "strategic_initiative", "budget_allocation", "hiring_decision",
420
+ "product_launch", "partnership", "merger_acquisition",
421
+ "policy_change", "investment", "operational_change"
422
+ ]
423
+
424
+ self.console.print("\nProposal Types:")
425
+ for i, ptype in enumerate(proposal_types, 1):
426
+ self.console.print(f" {i}. {ptype.replace('_', ' ').title()}")
427
+
428
+ type_choice = Prompt.ask("Select proposal type (number or name)", default="1")
429
+
430
+ # Parse type choice
431
+ try:
432
+ type_index = int(type_choice) - 1
433
+ if 0 <= type_index < len(proposal_types):
434
+ proposal_type_str = proposal_types[type_index]
435
+ else:
436
+ proposal_type_str = type_choice.lower().replace(" ", "_")
437
+ except ValueError:
438
+ proposal_type_str = type_choice.lower().replace(" ", "_")
439
+
440
+ # Get department
441
+ dept_choice = Prompt.ask(
442
+ "Department (finance/operations/marketing/technology/legal/hr)",
443
+ default="operations"
444
+ )
445
+
446
+ # Get budget
447
+ budget_str = Prompt.ask("Budget Impact ($)", default="0")
448
+ try:
449
+ budget = float(budget_str)
450
+ except ValueError:
451
+ budget = 0.0
452
+
453
+ # Get sponsor (use first executive or board member)
454
+ sponsor_id = None
455
+ if self.corporate_swarm.executive_team:
456
+ sponsor_id = self.corporate_swarm.executive_team[0]
457
+ elif self.corporate_swarm.board_members:
458
+ sponsor_id = self.corporate_swarm.board_members[0]
459
+
460
+ if not sponsor_id:
461
+ self.state.message = "No sponsor available"
462
+ self.state.message_style = "red"
463
+ return
464
+
465
+ # Import ProposalType
466
+ from crca_cg.corposwarm import ProposalType, DepartmentType
467
+
468
+ # Map strings to enums
469
+ proposal_type_map = {
470
+ "strategic_initiative": ProposalType.STRATEGIC_INITIATIVE,
471
+ "budget_allocation": ProposalType.BUDGET_ALLOCATION,
472
+ "hiring_decision": ProposalType.HIRING_DECISION,
473
+ "product_launch": ProposalType.PRODUCT_LAUNCH,
474
+ "partnership": ProposalType.PARTNERSHIP,
475
+ "merger_acquisition": ProposalType.MERGER_ACQUISITION,
476
+ "policy_change": ProposalType.POLICY_CHANGE,
477
+ "investment": ProposalType.INVESTMENT,
478
+ "operational_change": ProposalType.OPERATIONAL_CHANGE,
479
+ }
480
+
481
+ dept_map = {
482
+ "finance": DepartmentType.FINANCE,
483
+ "operations": DepartmentType.OPERATIONS,
484
+ "marketing": DepartmentType.MARKETING,
485
+ "technology": DepartmentType.TECHNOLOGY,
486
+ "legal": DepartmentType.LEGAL,
487
+ "hr": DepartmentType.HUMAN_RESOURCES,
488
+ "human_resources": DepartmentType.HUMAN_RESOURCES,
489
+ }
490
+
491
+ proposal_type = proposal_type_map.get(proposal_type_str, ProposalType.STRATEGIC_INITIATIVE)
492
+ department = dept_map.get(dept_choice.lower(), DepartmentType.OPERATIONS)
493
+
494
+ # Create proposal
495
+ proposal_id = self.corporate_swarm.create_proposal(
496
+ title=title,
497
+ description=description,
498
+ proposal_type=proposal_type,
499
+ sponsor_id=sponsor_id,
500
+ department=department,
501
+ budget_impact=budget
502
+ )
503
+
504
+ self.state.message = f"Proposal created: {proposal_id}"
505
+ self.state.message_style = "green"
506
+ self._update_list_items()
507
+
508
+ except KeyboardInterrupt:
509
+ self.state.message = "Proposal creation cancelled"
510
+ self.state.message_style = "yellow"
511
+ except Exception as e:
512
+ self.state.message = f"Error creating proposal: {str(e)}"
513
+ self.state.message_style = "red"
514
+
515
+ def _create_member_interactive(self) -> None:
516
+ """Interactively create a member."""
517
+ if not self.corporate_swarm:
518
+ self.state.message = "No CorporateSwarm instance"
519
+ self.state.message_style = "red"
520
+ return
521
+
522
+ try:
523
+ self.console.clear()
524
+ self.console.print(Panel("Add New Member", border_style="cyan", box=box.ROUNDED))
525
+
526
+ name = Prompt.ask("Member Name")
527
+
528
+ # Show roles
529
+ from crca_cg.corposwarm import CorporateRole, DepartmentType
530
+
531
+ roles = [
532
+ "ceo", "cfo", "cto", "coo",
533
+ "board_chair", "board_member", "independent_director",
534
+ "department_head", "manager", "employee"
535
+ ]
536
+
537
+ self.console.print("\nRoles:")
538
+ for i, role in enumerate(roles, 1):
539
+ self.console.print(f" {i}. {role.replace('_', ' ').title()}")
540
+
541
+ role_choice = Prompt.ask("Select role (number or name)", default="employee")
542
+
543
+ # Parse role
544
+ try:
545
+ role_index = int(role_choice) - 1
546
+ if 0 <= role_index < len(roles):
547
+ role_str = roles[role_index]
548
+ else:
549
+ role_str = role_choice.lower().replace(" ", "_")
550
+ except ValueError:
551
+ role_str = role_choice.lower().replace(" ", "_")
552
+
553
+ # Get department
554
+ dept_choice = Prompt.ask(
555
+ "Department (finance/operations/marketing/technology/legal/hr)",
556
+ default="operations"
557
+ )
558
+
559
+ # Get expertise
560
+ expertise_str = Prompt.ask("Expertise areas (comma-separated)", default="")
561
+ expertise = [e.strip() for e in expertise_str.split(",") if e.strip()]
562
+
563
+ # Get voting weight
564
+ weight_str = Prompt.ask("Voting Weight", default="1.0")
565
+ try:
566
+ weight = float(weight_str)
567
+ except ValueError:
568
+ weight = 1.0
569
+
570
+ # Map to enums
571
+ role_map = {
572
+ "ceo": CorporateRole.CEO,
573
+ "cfo": CorporateRole.CFO,
574
+ "cto": CorporateRole.CTO,
575
+ "coo": CorporateRole.COO,
576
+ "board_chair": CorporateRole.BOARD_CHAIR,
577
+ "board_member": CorporateRole.BOARD_MEMBER,
578
+ "independent_director": CorporateRole.INDEPENDENT_DIRECTOR,
579
+ "department_head": CorporateRole.DEPARTMENT_HEAD,
580
+ "manager": CorporateRole.MANAGER,
581
+ "employee": CorporateRole.EMPLOYEE,
582
+ }
583
+
584
+ dept_map = {
585
+ "finance": DepartmentType.FINANCE,
586
+ "operations": DepartmentType.OPERATIONS,
587
+ "marketing": DepartmentType.MARKETING,
588
+ "technology": DepartmentType.TECHNOLOGY,
589
+ "legal": DepartmentType.LEGAL,
590
+ "hr": DepartmentType.HUMAN_RESOURCES,
591
+ "human_resources": DepartmentType.HUMAN_RESOURCES,
592
+ }
593
+
594
+ role = role_map.get(role_str, CorporateRole.EMPLOYEE)
595
+ department = dept_map.get(dept_choice.lower(), DepartmentType.OPERATIONS)
596
+
597
+ # Create member
598
+ member_id = self.corporate_swarm.add_member(
599
+ name=name,
600
+ role=role,
601
+ department=department,
602
+ expertise_areas=expertise,
603
+ voting_weight=weight
604
+ )
605
+
606
+ self.state.message = f"Member added: {name} ({member_id})"
607
+ self.state.message_style = "green"
608
+ self._update_list_items()
609
+
610
+ except KeyboardInterrupt:
611
+ self.state.message = "Member creation cancelled"
612
+ self.state.message_style = "yellow"
613
+ except Exception as e:
614
+ self.state.message = f"Error adding member: {str(e)}"
615
+ self.state.message_style = "red"
616
+
617
+ def _schedule_meeting_interactive(self) -> None:
618
+ """Interactively schedule a meeting."""
619
+ if not self.corporate_swarm:
620
+ self.state.message = "No CorporateSwarm instance"
621
+ self.state.message_style = "red"
622
+ return
623
+
624
+ try:
625
+ self.console.clear()
626
+ self.console.print(Panel("Schedule Board Meeting", border_style="cyan", box=box.ROUNDED))
627
+
628
+ from crca_cg.corposwarm import MeetingType
629
+
630
+ meeting_types = [
631
+ "regular_board", "special_board", "annual_general",
632
+ "committee_meeting", "executive_session", "emergency_meeting"
633
+ ]
634
+
635
+ self.console.print("\nMeeting Types:")
636
+ for i, mtype in enumerate(meeting_types, 1):
637
+ self.console.print(f" {i}. {mtype.replace('_', ' ').title()}")
638
+
639
+ type_choice = Prompt.ask("Select meeting type (number or name)", default="1")
640
+
641
+ try:
642
+ type_index = int(type_choice) - 1
643
+ if 0 <= type_index < len(meeting_types):
644
+ meeting_type_str = meeting_types[type_index]
645
+ else:
646
+ meeting_type_str = type_choice.lower().replace(" ", "_")
647
+ except ValueError:
648
+ meeting_type_str = type_choice.lower().replace(" ", "_")
649
+
650
+ meeting_type_map = {
651
+ "regular_board": MeetingType.REGULAR_BOARD,
652
+ "special_board": MeetingType.SPECIAL_BOARD,
653
+ "annual_general": MeetingType.ANNUAL_GENERAL,
654
+ "committee_meeting": MeetingType.COMMITTEE_MEETING,
655
+ "executive_session": MeetingType.EXECUTIVE_SESSION,
656
+ "emergency_meeting": MeetingType.EMERGENCY_MEETING,
657
+ }
658
+
659
+ meeting_type = meeting_type_map.get(meeting_type_str, MeetingType.REGULAR_BOARD)
660
+
661
+ # Get agenda items
662
+ agenda_str = Prompt.ask("Agenda items (comma-separated)", default="")
663
+ agenda = [a.strip() for a in agenda_str.split(",") if a.strip()]
664
+
665
+ # Schedule meeting
666
+ meeting_id = self.corporate_swarm.schedule_board_meeting(
667
+ meeting_type=meeting_type,
668
+ agenda=agenda if agenda else None
669
+ )
670
+
671
+ self.state.message = f"Meeting scheduled: {meeting_id}"
672
+ self.state.message_style = "green"
673
+ self._update_list_items()
674
+
675
+ except KeyboardInterrupt:
676
+ self.state.message = "Meeting scheduling cancelled"
677
+ self.state.message_style = "yellow"
678
+ except Exception as e:
679
+ self.state.message = f"Error scheduling meeting: {str(e)}"
680
+ self.state.message_style = "red"
681
+
682
+ def _conduct_vote_interactive(self, proposal_id: Optional[str] = None) -> None:
683
+ """Interactively conduct a vote."""
684
+ if not self.corporate_swarm:
685
+ self.state.message = "No CorporateSwarm instance"
686
+ self.state.message_style = "red"
687
+ return
688
+
689
+ try:
690
+ if not proposal_id:
691
+ # Show proposals
692
+ if not self.corporate_swarm.proposals:
693
+ self.state.message = "No proposals available"
694
+ self.state.message_style = "yellow"
695
+ return
696
+
697
+ self.console.clear()
698
+ self.console.print(Panel("Select Proposal to Vote", border_style="cyan", box=box.ROUNDED))
699
+
700
+ for i, proposal in enumerate(self.corporate_swarm.proposals[-10:], 1):
701
+ self.console.print(f" {i}. {proposal.title} ({proposal.proposal_id[:8]})")
702
+
703
+ choice = Prompt.ask("Select proposal (number or ID)", default="1")
704
+
705
+ try:
706
+ index = int(choice) - 1
707
+ if 0 <= index < len(self.corporate_swarm.proposals[-10:]):
708
+ proposal_id = self.corporate_swarm.proposals[-10:][index].proposal_id
709
+ else:
710
+ proposal_id = choice
711
+ except ValueError:
712
+ proposal_id = choice
713
+
714
+ # Conduct vote
715
+ vote = self.corporate_swarm.conduct_corporate_vote(proposal_id)
716
+
717
+ self.state.message = f"Vote completed: {vote.result.value.upper()}"
718
+ self.state.message_style = "green"
719
+ self._update_list_items()
720
+
721
+ except Exception as e:
722
+ self.state.message = f"Error conducting vote: {str(e)}"
723
+ self.state.message_style = "red"
724
+
725
+ def _conduct_risk_assessment(self) -> None:
726
+ """Conduct risk assessment."""
727
+ if not self.corporate_swarm:
728
+ return
729
+
730
+ try:
731
+ category = Prompt.ask("Risk category (or 'comprehensive')", default="comprehensive")
732
+ assessments = self.corporate_swarm.conduct_risk_assessment(category)
733
+ self.state.message = f"Risk assessment completed: {len(assessments)} categories"
734
+ self.state.message_style = "green"
735
+ self._update_status()
736
+ except Exception as e:
737
+ self.state.message = f"Error: {str(e)}"
738
+ self.state.message_style = "red"
739
+
740
+ def _calculate_esg(self) -> None:
741
+ """Calculate ESG score."""
742
+ if not self.corporate_swarm:
743
+ return
744
+
745
+ try:
746
+ esg_score = self.corporate_swarm.calculate_esg_score()
747
+ self.state.message = f"ESG Score: {esg_score.overall_score:.1f}%"
748
+ self.state.message_style = "green"
749
+ self._update_status()
750
+ except Exception as e:
751
+ self.state.message = f"Error: {str(e)}"
752
+ self.state.message_style = "red"
753
+
754
+ def _show_full_status(self) -> None:
755
+ """Show full corporate status."""
756
+ self._update_status()
757
+ self.state.view_mode = ViewMode.DASHBOARD
758
+ self.state.message = "Full status displayed"
759
+ self.state.message_style = "green"
760
+
761
+ def _update_status(self) -> None:
762
+ """Update status data from CorporateSwarm."""
763
+ try:
764
+ if self.corporate_swarm:
765
+ self.state.status_data = self.corporate_swarm.get_corporate_status()
766
+ self.state.last_update = time.time()
767
+ except Exception as e:
768
+ logger.error(f"Error updating status: {e}")
769
+
770
+ def create_layout(self) -> Layout:
771
+ """Create the main layout structure."""
772
+ layout = Layout()
773
+
774
+ layout.split_column(
775
+ Layout(name="header", size=3),
776
+ Layout(name="main", ratio=1),
777
+ Layout(name="footer", size=4)
778
+ )
779
+
780
+ layout["main"].split_row(
781
+ Layout(name="left", ratio=1),
782
+ Layout(name="right", ratio=1)
783
+ )
784
+
785
+ return layout
786
+
787
+ def render_header(self) -> Panel:
788
+ """Render the header panel."""
789
+ uptime = time.time() - self.start_time
790
+ uptime_str = f"{int(uptime // 3600)}h {int((uptime % 3600) // 60)}m {int(uptime % 60)}s"
791
+
792
+ last_update_str = datetime.fromtimestamp(self.state.last_update).strftime("%H:%M:%S")
793
+
794
+ header_text = Text()
795
+ header_text.append(self.title, style="bold cyan")
796
+ header_text.append(" | ", style="dim")
797
+ header_text.append(f"Uptime: {uptime_str}", style="green")
798
+ header_text.append(" | ", style="dim")
799
+ header_text.append(f"Last Update: {last_update_str}", style="yellow")
800
+ header_text.append(" | ", style="dim")
801
+
802
+ if self.state.auto_refresh:
803
+ header_text.append("Auto-Refresh ON", style="green")
804
+ else:
805
+ header_text.append("Auto-Refresh OFF", style="yellow")
806
+
807
+ header_text.append(" | ", style="dim")
808
+ header_text.append(f"View: {self.state.view_mode.value.upper()}", style="magenta")
809
+
810
+ if self.state.interaction_mode != InteractionMode.VIEW:
811
+ header_text.append(" | ", style="dim")
812
+ header_text.append(f"Mode: {self.state.interaction_mode.value.upper()}", style="cyan")
813
+
814
+ return Panel(
815
+ Align.center(header_text),
816
+ border_style="cyan",
817
+ box=box.ROUNDED
818
+ )
819
+
820
+ def render_footer(self) -> Layout:
821
+ """Render the footer with controls and messages."""
822
+ footer_layout = Layout()
823
+ footer_layout.split_column(
824
+ Layout(name="controls", size=2),
825
+ Layout(name="message", size=2)
826
+ )
827
+
828
+ # Controls
829
+ controls = Text()
830
+ controls.append("Controls: ", style="bold")
831
+ controls.append("[Q]uit ", style="red")
832
+ controls.append("[R]efresh ", style="yellow")
833
+ controls.append("[1-0] Views ", style="cyan")
834
+ controls.append("[N]ew ", style="green")
835
+ controls.append("[S]elect ", style="blue")
836
+ controls.append("[C]ommand ", style="magenta")
837
+ controls.append("[A]uto-refresh ", style="green")
838
+ controls.append("[?] Help", style="dim")
839
+
840
+ footer_layout["controls"].update(
841
+ Panel(Align.center(controls), border_style="blue", box=box.ROUNDED)
842
+ )
843
+
844
+ # Message/Command line
845
+ if self.state.interaction_mode == InteractionMode.COMMAND:
846
+ cmd_text = Text()
847
+ cmd_text.append("Command: ", style="bold cyan")
848
+ cmd_text.append(self.state.current_command, style="white")
849
+ cmd_text.append("_", style="dim") # Cursor
850
+ footer_layout["message"].update(
851
+ Panel(cmd_text, border_style="cyan", box=box.ROUNDED)
852
+ )
853
+ elif self.state.message:
854
+ msg_text = Text(self.state.message, style=self.state.message_style)
855
+ footer_layout["message"].update(
856
+ Panel(Align.center(msg_text), border_style=self.state.message_style, box=box.ROUNDED)
857
+ )
858
+ else:
859
+ footer_layout["message"].update(
860
+ Panel("", border_style="dim", box=box.ROUNDED)
861
+ )
862
+
863
+ return footer_layout
864
+
865
+ def render_dashboard(self) -> Layout:
866
+ """Render the main dashboard view."""
867
+ layout = Layout()
868
+ layout.split_column(
869
+ Layout(name="overview", size=8),
870
+ Layout(name="metrics", ratio=1),
871
+ Layout(name="recent", ratio=1)
872
+ )
873
+
874
+ layout["overview"].update(self._render_overview_panel())
875
+ layout["metrics"].update(self._render_metrics_panel())
876
+ layout["recent"].update(self._render_recent_activity_panel())
877
+
878
+ return layout
879
+
880
+ def _render_overview_panel(self) -> Panel:
881
+ """Render corporate overview panel."""
882
+ status = self.state.status_data or {}
883
+
884
+ overview_table = Table.grid(padding=(0, 2))
885
+ overview_table.add_column(style="cyan", justify="right")
886
+ overview_table.add_column(style="white")
887
+
888
+ overview_table.add_row("Corporation:", status.get("name", "N/A"))
889
+ overview_table.add_row("Members:", str(status.get("total_members", 0)))
890
+ overview_table.add_row("Board Members:", str(status.get("board_members", 0)))
891
+ overview_table.add_row("Executive Team:", str(status.get("executive_team", 0)))
892
+ overview_table.add_row("Departments:", str(status.get("departments", 0)))
893
+ overview_table.add_row("Committees:", str(status.get("board_committees", 0)))
894
+ overview_table.add_row("Active Proposals:", str(status.get("active_proposals", 0)))
895
+ overview_table.add_row("Total Votes:", str(status.get("total_votes", 0)))
896
+
897
+ return Panel(
898
+ overview_table,
899
+ title="Corporate Overview",
900
+ border_style="cyan",
901
+ box=box.ROUNDED
902
+ )
903
+
904
+ def _render_metrics_panel(self) -> Panel:
905
+ """Render key metrics panel."""
906
+ status = self.state.status_data or {}
907
+ esg = status.get("esg_governance", {})
908
+ risk = status.get("risk_management", {})
909
+
910
+ metrics_table = Table.grid(padding=(0, 2))
911
+ metrics_table.add_column(style="yellow", justify="right")
912
+ metrics_table.add_column(style="white")
913
+
914
+ # ESG Scores
915
+ esg_score = esg.get("overall_score", 0)
916
+ metrics_table.add_row(
917
+ "ESG Score:",
918
+ self._colorize_score(esg_score, 70, 85)
919
+ )
920
+
921
+ metrics_table.add_row(
922
+ "Environmental:",
923
+ self._colorize_score(esg.get("environmental_score", 0), 70, 85)
924
+ )
925
+
926
+ metrics_table.add_row(
927
+ "Social:",
928
+ self._colorize_score(esg.get("social_score", 0), 70, 85)
929
+ )
930
+
931
+ metrics_table.add_row(
932
+ "Governance:",
933
+ self._colorize_score(esg.get("governance_score", 0), 70, 85)
934
+ )
935
+
936
+ metrics_table.add_row("", "") # Spacer
937
+
938
+ # Risk Metrics
939
+ total_risks = risk.get("total_risks", 0)
940
+ high_risks = risk.get("high_risks", 0)
941
+ medium_risks = risk.get("medium_risks", 0)
942
+
943
+ metrics_table.add_row(
944
+ "Total Risks:",
945
+ str(total_risks)
946
+ )
947
+
948
+ metrics_table.add_row(
949
+ "High Risks:",
950
+ f"[red]{high_risks}[/red]"
951
+ )
952
+
953
+ metrics_table.add_row(
954
+ "Medium Risks:",
955
+ f"[yellow]{medium_risks}[/yellow]"
956
+ )
957
+
958
+ return Panel(
959
+ metrics_table,
960
+ title="Key Metrics",
961
+ border_style="yellow",
962
+ box=box.ROUNDED
963
+ )
964
+
965
+ def _render_recent_activity_panel(self) -> Panel:
966
+ """Render recent activity panel."""
967
+ status = self.state.status_data or {}
968
+ recent_decisions = status.get("recent_decisions", [])
969
+
970
+ if not recent_decisions:
971
+ content = Text("No recent decisions", style="dim")
972
+ else:
973
+ content = Table.grid(padding=(0, 1))
974
+ content.add_column(style="cyan")
975
+ content.add_column(style="white")
976
+ content.add_column(style="dim")
977
+
978
+ for decision in recent_decisions[-5:]:
979
+ proposal = decision.get("proposal", "Unknown")
980
+ result = decision.get("result", "unknown")
981
+ timestamp = decision.get("timestamp", 0)
982
+
983
+ time_str = datetime.fromtimestamp(timestamp).strftime("%H:%M:%S") if timestamp else "N/A"
984
+
985
+ result_style = "green" if result == "approved" else "red" if result == "rejected" else "yellow"
986
+
987
+ content.add_row(
988
+ proposal[:30] + ("..." if len(proposal) > 30 else ""),
989
+ f"[{result_style}]{result.upper()}[/{result_style}]",
990
+ time_str
991
+ )
992
+
993
+ return Panel(
994
+ content,
995
+ title="Recent Decisions",
996
+ border_style="green",
997
+ box=box.ROUNDED
998
+ )
999
+
1000
+ def render_members_view(self) -> Panel:
1001
+ """Render members view with selection."""
1002
+ if not self.corporate_swarm:
1003
+ return Panel("No CorporateSwarm instance", border_style="red")
1004
+
1005
+ members_table = Table(show_header=True, header_style="bold cyan", box=box.ROUNDED)
1006
+ members_table.add_column("", width=2) # Selection indicator
1007
+ members_table.add_column("Name", style="cyan", width=20)
1008
+ members_table.add_column("Role", style="yellow", width=15)
1009
+ members_table.add_column("Department", style="green", width=15)
1010
+ members_table.add_column("Expertise", style="white", width=25)
1011
+ members_table.add_column("Voting Weight", style="magenta", justify="right", width=12)
1012
+
1013
+ for idx, (member_id, member) in enumerate(self.corporate_swarm.members.items()):
1014
+ expertise_str = ", ".join(member.expertise_areas[:2])
1015
+ if len(member.expertise_areas) > 2:
1016
+ expertise_str += "..."
1017
+
1018
+ # Highlight selected row
1019
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
1020
+ selector = ">"
1021
+ row_style = "bold"
1022
+ else:
1023
+ selector = " "
1024
+ row_style = None
1025
+
1026
+ members_table.add_row(
1027
+ selector,
1028
+ Text(member.name, style=row_style) if row_style else member.name,
1029
+ member.role.value.title(),
1030
+ member.department.value.title(),
1031
+ expertise_str,
1032
+ f"{member.voting_weight:.1f}"
1033
+ )
1034
+
1035
+ return Panel(
1036
+ members_table,
1037
+ title="Corporate Members",
1038
+ border_style="cyan",
1039
+ box=box.ROUNDED
1040
+ )
1041
+
1042
+ def render_member_details(self, member_id: str) -> Panel:
1043
+ """Render detailed member information."""
1044
+ if not self.corporate_swarm or member_id not in self.corporate_swarm.members:
1045
+ return Panel("Member not found", border_style="red")
1046
+
1047
+ member = self.corporate_swarm.members[member_id]
1048
+
1049
+ details_table = Table.grid(padding=(0, 2))
1050
+ details_table.add_column(style="cyan", justify="right", width=20)
1051
+ details_table.add_column(style="white")
1052
+
1053
+ details_table.add_row("Name:", member.name)
1054
+ details_table.add_row("Member ID:", member.member_id)
1055
+ details_table.add_row("Role:", member.role.value.title())
1056
+ details_table.add_row("Department:", member.department.value.title())
1057
+ details_table.add_row("Voting Weight:", f"{member.voting_weight:.1f}")
1058
+ details_table.add_row("Independence:", "Yes" if member.independence_status else "No")
1059
+ details_table.add_row("", "")
1060
+ details_table.add_row("Expertise Areas:", ", ".join(member.expertise_areas) if member.expertise_areas else "None")
1061
+ details_table.add_row("Committees:", str(len(member.board_committees)))
1062
+
1063
+ if member.agent:
1064
+ details_table.add_row("", "")
1065
+ details_table.add_row("Agent Status:", "Active")
1066
+ if hasattr(member.agent, 'agent_name'):
1067
+ details_table.add_row("Agent Name:", member.agent.agent_name)
1068
+
1069
+ return Panel(
1070
+ details_table,
1071
+ title=f"Member Details: {member.name}",
1072
+ border_style="cyan",
1073
+ box=box.ROUNDED
1074
+ )
1075
+
1076
+ def render_proposals_view(self) -> Panel:
1077
+ """Render proposals view with selection."""
1078
+ if not self.corporate_swarm:
1079
+ return Panel("No CorporateSwarm instance", border_style="red")
1080
+
1081
+ proposals_table = Table(show_header=True, header_style="bold yellow", box=box.ROUNDED)
1082
+ proposals_table.add_column("", width=2)
1083
+ proposals_table.add_column("Title", style="cyan", width=30)
1084
+ proposals_table.add_column("Type", style="yellow", width=15)
1085
+ proposals_table.add_column("Department", style="green", width=15)
1086
+ proposals_table.add_column("Budget Impact", style="magenta", justify="right", width=15)
1087
+ proposals_table.add_column("Status", style="white", width=12)
1088
+
1089
+ for idx, proposal in enumerate(self.corporate_swarm.proposals):
1090
+ status_style = "green" if proposal.status == "approved" else "red" if proposal.status == "rejected" else "yellow"
1091
+
1092
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
1093
+ selector = ">"
1094
+ row_style = "bold"
1095
+ else:
1096
+ selector = " "
1097
+ row_style = None
1098
+
1099
+ proposals_table.add_row(
1100
+ selector,
1101
+ Text(proposal.title[:28] + ("..." if len(proposal.title) > 28 else ""), style=row_style) if row_style else proposal.title[:28] + ("..." if len(proposal.title) > 28 else ""),
1102
+ proposal.proposal_type.value.replace("_", " ").title(),
1103
+ proposal.department.value.title(),
1104
+ f"${proposal.budget_impact:,.2f}",
1105
+ f"[{status_style}]{proposal.status.upper()}[/{status_style}]"
1106
+ )
1107
+
1108
+ return Panel(
1109
+ proposals_table,
1110
+ title="Proposals",
1111
+ border_style="yellow",
1112
+ box=box.ROUNDED
1113
+ )
1114
+
1115
+ def render_proposal_details(self, proposal_id: str) -> Panel:
1116
+ """Render detailed proposal information."""
1117
+ if not self.corporate_swarm:
1118
+ return Panel("No CorporateSwarm instance", border_style="red")
1119
+
1120
+ proposal = None
1121
+ for p in self.corporate_swarm.proposals:
1122
+ if p.proposal_id == proposal_id:
1123
+ proposal = p
1124
+ break
1125
+
1126
+ if not proposal:
1127
+ return Panel("Proposal not found", border_style="red")
1128
+
1129
+ details_table = Table.grid(padding=(0, 2))
1130
+ details_table.add_column(style="cyan", justify="right", width=20)
1131
+ details_table.add_column(style="white")
1132
+
1133
+ details_table.add_row("Title:", proposal.title)
1134
+ details_table.add_row("Proposal ID:", proposal.proposal_id)
1135
+ details_table.add_row("Type:", proposal.proposal_type.value.replace("_", " ").title())
1136
+ details_table.add_row("Department:", proposal.department.value.title())
1137
+ details_table.add_row("Budget Impact:", f"${proposal.budget_impact:,.2f}")
1138
+ details_table.add_row("Status:", proposal.status.upper())
1139
+ details_table.add_row("Timeline:", proposal.timeline or "Not specified")
1140
+ details_table.add_row("", "")
1141
+ details_table.add_row("Description:", proposal.description[:200] + ("..." if len(proposal.description) > 200 else ""))
1142
+
1143
+ if proposal.causal_analysis:
1144
+ details_table.add_row("", "")
1145
+ details_table.add_row("Causal Analysis:", "Available")
1146
+
1147
+ if proposal.quant_analysis:
1148
+ details_table.add_row("Quantitative Analysis:", "Available")
1149
+
1150
+ if proposal.board_evaluations:
1151
+ details_table.add_row("Board Evaluations:", "Available")
1152
+
1153
+ return Panel(
1154
+ details_table,
1155
+ title=f"Proposal Details: {proposal.title}",
1156
+ border_style="yellow",
1157
+ box=box.ROUNDED
1158
+ )
1159
+
1160
+ def render_votes_view(self) -> Panel:
1161
+ """Render votes view with selection."""
1162
+ if not self.corporate_swarm:
1163
+ return Panel("No CorporateSwarm instance", border_style="red")
1164
+
1165
+ votes_table = Table(show_header=True, header_style="bold green", box=box.ROUNDED)
1166
+ votes_table.add_column("", width=2)
1167
+ votes_table.add_column("Proposal", style="cyan", width=30)
1168
+ votes_table.add_column("Participants", style="yellow", justify="right", width=12)
1169
+ votes_table.add_column("Result", style="white", width=15)
1170
+ votes_table.add_column("Consensus", style="magenta", justify="right", width=12)
1171
+ votes_table.add_column("Time", style="dim", width=10)
1172
+
1173
+ for idx, vote in enumerate(self.corporate_swarm.votes[-10:]):
1174
+ result_style = "green" if vote.result.value == "approved" else "red" if vote.result.value == "rejected" else "yellow"
1175
+ consensus = vote.governance_consensus * 100
1176
+
1177
+ time_str = datetime.fromtimestamp(vote.timestamp).strftime("%H:%M:%S") if vote.timestamp else "N/A"
1178
+
1179
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
1180
+ selector = ">"
1181
+ row_style = "bold"
1182
+ else:
1183
+ selector = " "
1184
+ row_style = None
1185
+
1186
+ votes_table.add_row(
1187
+ selector,
1188
+ Text(vote.proposal.title[:28] + ("..." if len(vote.proposal.title) > 28 else ""), style=row_style) if row_style else vote.proposal.title[:28] + ("..." if len(vote.proposal.title) > 28 else ""),
1189
+ str(len(vote.participants)),
1190
+ f"[{result_style}]{vote.result.value.upper()}[/{result_style}]",
1191
+ f"{consensus:.1f}%",
1192
+ time_str
1193
+ )
1194
+
1195
+ return Panel(
1196
+ votes_table,
1197
+ title="Voting History",
1198
+ border_style="green",
1199
+ box=box.ROUNDED
1200
+ )
1201
+
1202
+ def render_vote_details(self, vote_id: str) -> Panel:
1203
+ """Render detailed vote information."""
1204
+ if not self.corporate_swarm:
1205
+ return Panel("No CorporateSwarm instance", border_style="red")
1206
+
1207
+ vote = None
1208
+ for v in self.corporate_swarm.votes:
1209
+ if v.vote_id == vote_id:
1210
+ vote = v
1211
+ break
1212
+
1213
+ if not vote:
1214
+ return Panel("Vote not found", border_style="red")
1215
+
1216
+ details_table = Table.grid(padding=(0, 2))
1217
+ details_table.add_column(style="cyan", justify="right", width=20)
1218
+ details_table.add_column(style="white")
1219
+
1220
+ details_table.add_row("Proposal:", vote.proposal.title)
1221
+ details_table.add_row("Vote ID:", vote.vote_id)
1222
+ details_table.add_row("Result:", vote.result.value.upper())
1223
+ details_table.add_row("Participants:", str(len(vote.participants)))
1224
+ details_table.add_row("Consensus:", f"{vote.governance_consensus * 100:.1f}%")
1225
+ details_table.add_row("Timestamp:", datetime.fromtimestamp(vote.timestamp).strftime("%Y-%m-%d %H:%M:%S") if vote.timestamp else "N/A")
1226
+
1227
+ if vote.causal_reasoning_summary:
1228
+ details_table.add_row("", "")
1229
+ details_table.add_row("Causal Reasoning:", vote.causal_reasoning_summary[:100] + ("..." if len(vote.causal_reasoning_summary) > 100 else ""))
1230
+
1231
+ if vote.quant_signals:
1232
+ details_table.add_row("Quant Signals:", f"{len(vote.quant_signals)} signals")
1233
+
1234
+ # Individual votes summary
1235
+ if vote.individual_votes:
1236
+ details_table.add_row("", "")
1237
+ details_table.add_row("Individual Votes:", "")
1238
+ approve_count = sum(1 for v in vote.individual_votes.values() if v.get("vote") == "APPROVE")
1239
+ reject_count = sum(1 for v in vote.individual_votes.values() if v.get("vote") == "REJECT")
1240
+ abstain_count = sum(1 for v in vote.individual_votes.values() if v.get("vote") == "ABSTAIN")
1241
+
1242
+ details_table.add_row(" Approve:", f"[green]{approve_count}[/green]")
1243
+ details_table.add_row(" Reject:", f"[red]{reject_count}[/red]")
1244
+ details_table.add_row(" Abstain:", f"[yellow]{abstain_count}[/yellow]")
1245
+
1246
+ return Panel(
1247
+ details_table,
1248
+ title=f"Vote Details: {vote.proposal.title}",
1249
+ border_style="green",
1250
+ box=box.ROUNDED
1251
+ )
1252
+
1253
+ def render_meetings_view(self) -> Panel:
1254
+ """Render board meetings view with selection."""
1255
+ if not self.corporate_swarm:
1256
+ return Panel("No CorporateSwarm instance", border_style="red")
1257
+
1258
+ meetings_table = Table(show_header=True, header_style="bold blue", box=box.ROUNDED)
1259
+ meetings_table.add_column("", width=2)
1260
+ meetings_table.add_column("Type", style="cyan", width=20)
1261
+ meetings_table.add_column("Date", style="yellow", width=15)
1262
+ meetings_table.add_column("Attendees", style="green", justify="right", width=12)
1263
+ meetings_table.add_column("Quorum", style="white", width=10)
1264
+ meetings_table.add_column("Resolutions", style="magenta", justify="right", width=12)
1265
+
1266
+ for idx, meeting in enumerate(self.corporate_swarm.board_meetings[-10:]):
1267
+ date_str = datetime.fromtimestamp(meeting.date).strftime("%Y-%m-%d %H:%M") if meeting.date else "N/A"
1268
+ quorum_style = "green" if meeting.quorum_met else "red"
1269
+ quorum_symbol = "YES" if meeting.quorum_met else "NO"
1270
+
1271
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
1272
+ selector = ">"
1273
+ row_style = "bold"
1274
+ else:
1275
+ selector = " "
1276
+ row_style = None
1277
+
1278
+ meetings_table.add_row(
1279
+ selector,
1280
+ Text(meeting.meeting_type.value.replace("_", " ").title(), style=row_style) if row_style else meeting.meeting_type.value.replace("_", " ").title(),
1281
+ date_str,
1282
+ str(len(meeting.attendees)),
1283
+ f"[{quorum_style}]{quorum_symbol}[/{quorum_style}]",
1284
+ str(len(meeting.resolutions))
1285
+ )
1286
+
1287
+ return Panel(
1288
+ meetings_table,
1289
+ title="Board Meetings",
1290
+ border_style="blue",
1291
+ box=box.ROUNDED
1292
+ )
1293
+
1294
+ def render_meeting_details(self, meeting_id: str) -> Panel:
1295
+ """Render detailed meeting information."""
1296
+ if not self.corporate_swarm:
1297
+ return Panel("No CorporateSwarm instance", border_style="red")
1298
+
1299
+ meeting = None
1300
+ for m in self.corporate_swarm.board_meetings:
1301
+ if m.meeting_id == meeting_id:
1302
+ meeting = m
1303
+ break
1304
+
1305
+ if not meeting:
1306
+ return Panel("Meeting not found", border_style="red")
1307
+
1308
+ details_table = Table.grid(padding=(0, 2))
1309
+ details_table.add_column(style="cyan", justify="right", width=20)
1310
+ details_table.add_column(style="white")
1311
+
1312
+ details_table.add_row("Meeting ID:", meeting.meeting_id)
1313
+ details_table.add_row("Type:", meeting.meeting_type.value.replace("_", " ").title())
1314
+ details_table.add_row("Date:", datetime.fromtimestamp(meeting.date).strftime("%Y-%m-%d %H:%M:%S") if meeting.date else "N/A")
1315
+ details_table.add_row("Location:", meeting.location or "Virtual")
1316
+ details_table.add_row("Attendees:", str(len(meeting.attendees)))
1317
+ details_table.add_row("Quorum Met:", "Yes" if meeting.quorum_met else "No")
1318
+ details_table.add_row("Resolutions:", str(len(meeting.resolutions)))
1319
+
1320
+ if meeting.agenda:
1321
+ details_table.add_row("", "")
1322
+ details_table.add_row("Agenda:", "")
1323
+ for item in meeting.agenda[:5]:
1324
+ details_table.add_row("", f" • {item}")
1325
+
1326
+ if meeting.resolutions:
1327
+ details_table.add_row("", "")
1328
+ details_table.add_row("Resolutions:", "")
1329
+ for resolution in meeting.resolutions[:5]:
1330
+ details_table.add_row("", f" • {resolution[:60]}")
1331
+
1332
+ if meeting.minutes:
1333
+ details_table.add_row("", "")
1334
+ details_table.add_row("Minutes:", meeting.minutes[:200] + ("..." if len(meeting.minutes) > 200 else ""))
1335
+
1336
+ return Panel(
1337
+ details_table,
1338
+ title=f"Meeting Details: {meeting.meeting_type.value.replace('_', ' ').title()}",
1339
+ border_style="blue",
1340
+ box=box.ROUNDED
1341
+ )
1342
+
1343
+ def render_esg_view(self) -> Panel:
1344
+ """Render ESG dashboard view."""
1345
+ status = self.state.status_data or {}
1346
+ esg = status.get("esg_governance", {})
1347
+
1348
+ esg_layout = Layout()
1349
+ esg_layout.split_column(
1350
+ Layout(name="scores", size=12),
1351
+ Layout(name="details", ratio=1)
1352
+ )
1353
+
1354
+ # Scores with progress bars
1355
+ scores_table = Table.grid(padding=(0, 2))
1356
+ scores_table.add_column(style="cyan", width=20)
1357
+ scores_table.add_column(style="white", width=50)
1358
+ scores_table.add_column(style="yellow", width=10)
1359
+
1360
+ overall = esg.get("overall_score", 0)
1361
+ env = esg.get("environmental_score", 0)
1362
+ social = esg.get("social_score", 0)
1363
+ gov = esg.get("governance_score", 0)
1364
+
1365
+ scores_table.add_row(
1366
+ "Overall ESG:",
1367
+ self._create_progress_bar(overall, 100),
1368
+ f"{overall:.1f}%"
1369
+ )
1370
+
1371
+ scores_table.add_row(
1372
+ "Environmental:",
1373
+ self._create_progress_bar(env, 100),
1374
+ f"{env:.1f}%"
1375
+ )
1376
+
1377
+ scores_table.add_row(
1378
+ "Social:",
1379
+ self._create_progress_bar(social, 100),
1380
+ f"{social:.1f}%"
1381
+ )
1382
+
1383
+ scores_table.add_row(
1384
+ "Governance:",
1385
+ self._create_progress_bar(gov, 100),
1386
+ f"{gov:.1f}%"
1387
+ )
1388
+
1389
+ esg_layout["scores"].update(
1390
+ Panel(scores_table, title="ESG Scores", border_style="green", box=box.ROUNDED)
1391
+ )
1392
+
1393
+ # Details
1394
+ details_table = Table.grid(padding=(0, 2))
1395
+ details_table.add_column(style="cyan", justify="right")
1396
+ details_table.add_column(style="white")
1397
+
1398
+ details_table.add_row("Carbon Footprint:", f"{esg.get('carbon_footprint', 0):.2f} tons CO2")
1399
+ details_table.add_row("Diversity Index:", f"{esg.get('diversity_index', 0):.2%}")
1400
+ details_table.add_row("Stakeholder Satisfaction:", f"{esg.get('stakeholder_satisfaction', 0):.1f}%")
1401
+
1402
+ goals = esg.get("sustainability_goals", [])
1403
+ if goals:
1404
+ details_table.add_row("", "")
1405
+ details_table.add_row("Sustainability Goals:", "")
1406
+ for goal in goals[:3]:
1407
+ details_table.add_row("", f" • {goal}")
1408
+
1409
+ esg_layout["details"].update(
1410
+ Panel(details_table, title="Details", border_style="green", box=box.ROUNDED)
1411
+ )
1412
+
1413
+ return Panel(
1414
+ esg_layout,
1415
+ title="ESG Dashboard",
1416
+ border_style="green",
1417
+ box=box.ROUNDED
1418
+ )
1419
+
1420
+ def render_risk_view(self) -> Panel:
1421
+ """Render risk assessment view."""
1422
+ status = self.state.status_data or {}
1423
+ risk = status.get("risk_management", {})
1424
+
1425
+ if not self.corporate_swarm or not self.corporate_swarm.risk_assessments:
1426
+ return Panel("No risk assessments available. Use command 'risk' to conduct assessment.", border_style="yellow")
1427
+
1428
+ risk_table = Table(show_header=True, header_style="bold red", box=box.ROUNDED)
1429
+ risk_table.add_column("Category", style="cyan", width=20)
1430
+ risk_table.add_column("Level", style="white", width=12)
1431
+ risk_table.add_column("Probability", style="yellow", justify="right", width=12)
1432
+ risk_table.add_column("Impact", style="magenta", justify="right", width=12)
1433
+ risk_table.add_column("Score", style="red", justify="right", width=12)
1434
+ risk_table.add_column("Owner", style="green", width=15)
1435
+
1436
+ for risk_id, assessment in list(self.corporate_swarm.risk_assessments.items())[:15]:
1437
+ level_style = "red" if assessment.risk_level == "high" else "yellow" if assessment.risk_level == "medium" else "green"
1438
+
1439
+ risk_table.add_row(
1440
+ assessment.risk_category.title(),
1441
+ f"[{level_style}]{assessment.risk_level.upper()}[/{level_style}]",
1442
+ f"{assessment.probability:.2%}",
1443
+ f"{assessment.impact:.2%}",
1444
+ f"{assessment.risk_score:.2%}",
1445
+ assessment.owner
1446
+ )
1447
+
1448
+ return Panel(
1449
+ risk_table,
1450
+ title="Risk Assessment",
1451
+ border_style="red",
1452
+ box=box.ROUNDED
1453
+ )
1454
+
1455
+ def render_aop_view(self) -> Panel:
1456
+ """Render AOP integration view."""
1457
+ status = self.state.status_data or {}
1458
+ aop = status.get("aop_integration", {})
1459
+
1460
+ aop_layout = Layout()
1461
+ aop_layout.split_column(
1462
+ Layout(name="status", size=10),
1463
+ Layout(name="queues", ratio=1)
1464
+ )
1465
+
1466
+ # Status
1467
+ status_table = Table.grid(padding=(0, 2))
1468
+ status_table.add_column(style="cyan", justify="right", width=25)
1469
+ status_table.add_column(style="white")
1470
+
1471
+ status_table.add_row(
1472
+ "AOP Enabled:",
1473
+ "Yes" if aop.get("enabled", False) else "No"
1474
+ )
1475
+
1476
+ status_table.add_row(
1477
+ "Queue Execution:",
1478
+ "Yes" if aop.get("queue_execution_enabled", False) else "No"
1479
+ )
1480
+
1481
+ status_table.add_row(
1482
+ "AOP Server Active:",
1483
+ "Yes" if aop.get("aop_server_active", False) else "No"
1484
+ )
1485
+
1486
+ status_table.add_row(
1487
+ "Member Queues:",
1488
+ str(aop.get("total_member_queues", 0))
1489
+ )
1490
+
1491
+ server_info = aop.get("aop_server", {})
1492
+ if server_info:
1493
+ status_table.add_row("", "")
1494
+ status_table.add_row("Server Port:", str(server_info.get("port", "N/A")))
1495
+ status_table.add_row("Total Agents:", str(server_info.get("total_agents", 0)))
1496
+
1497
+ aop_layout["status"].update(
1498
+ Panel(status_table, title="AOP Status", border_style="magenta", box=box.ROUNDED)
1499
+ )
1500
+
1501
+ # Queue Stats
1502
+ queue_stats = aop.get("member_queue_stats", {})
1503
+ if queue_stats:
1504
+ queues_table = Table(show_header=True, header_style="bold magenta", box=box.ROUNDED)
1505
+ queues_table.add_column("Member", style="cyan", width=20)
1506
+ queues_table.add_column("Total Tasks", style="yellow", justify="right", width=12)
1507
+ queues_table.add_column("Completed", style="green", justify="right", width=12)
1508
+ queues_table.add_column("Pending", style="yellow", justify="right", width=12)
1509
+ queues_table.add_column("Status", style="white", width=12)
1510
+
1511
+ for member_name, stats in list(queue_stats.items())[:10]:
1512
+ queues_table.add_row(
1513
+ member_name[:18] + ("..." if len(member_name) > 18 else ""),
1514
+ str(stats.get("total_tasks", 0)),
1515
+ str(stats.get("completed_tasks", 0)),
1516
+ str(stats.get("pending_tasks", 0)),
1517
+ stats.get("queue_status", "unknown")
1518
+ )
1519
+
1520
+ aop_layout["queues"].update(
1521
+ Panel(queues_table, title="Queue Statistics", border_style="magenta", box=box.ROUNDED)
1522
+ )
1523
+ else:
1524
+ aop_layout["queues"].update(
1525
+ Panel("No queue statistics available", border_style="dim", box=box.ROUNDED)
1526
+ )
1527
+
1528
+ return Panel(
1529
+ aop_layout,
1530
+ title="AOP Integration",
1531
+ border_style="magenta",
1532
+ box=box.ROUNDED
1533
+ )
1534
+
1535
+ def render_committees_view(self) -> Panel:
1536
+ """Render board committees view."""
1537
+ if not self.corporate_swarm:
1538
+ return Panel("No CorporateSwarm instance", border_style="red")
1539
+
1540
+ committees_table = Table(show_header=True, header_style="bold blue", box=box.ROUNDED)
1541
+ committees_table.add_column("Name", style="cyan", width=25)
1542
+ committees_table.add_column("Type", style="yellow", width=20)
1543
+ committees_table.add_column("Chair", style="green", width=20)
1544
+ committees_table.add_column("Members", style="white", justify="right", width=10)
1545
+
1546
+ for committee_id, committee in self.corporate_swarm.board_committees.items():
1547
+ chair_name = "Unknown"
1548
+ if committee.chair and committee.chair in self.corporate_swarm.members:
1549
+ chair_name = self.corporate_swarm.members[committee.chair].name
1550
+
1551
+ committees_table.add_row(
1552
+ committee.name,
1553
+ committee.committee_type.value.replace("_", " ").title(),
1554
+ chair_name[:18] + ("..." if len(chair_name) > 18 else ""),
1555
+ str(len(committee.members))
1556
+ )
1557
+
1558
+ return Panel(
1559
+ committees_table,
1560
+ title="Board Committees",
1561
+ border_style="blue",
1562
+ box=box.ROUNDED
1563
+ )
1564
+
1565
+ def render_departments_view(self) -> Panel:
1566
+ """Render departments view."""
1567
+ if not self.corporate_swarm:
1568
+ return Panel("No CorporateSwarm instance", border_style="red")
1569
+
1570
+ dept_table = Table(show_header=True, header_style="bold green", box=box.ROUNDED)
1571
+ dept_table.add_column("Name", style="cyan", width=25)
1572
+ dept_table.add_column("Type", style="yellow", width=20)
1573
+ dept_table.add_column("Head", style="green", width=20)
1574
+ dept_table.add_column("Budget", style="magenta", justify="right", width=15)
1575
+ dept_table.add_column("Members", style="white", justify="right", width=10)
1576
+
1577
+ for dept_id, dept in self.corporate_swarm.departments.items():
1578
+ head_name = "Vacant"
1579
+ if dept.head and dept.head in self.corporate_swarm.members:
1580
+ head_name = self.corporate_swarm.members[dept.head].name
1581
+
1582
+ dept_table.add_row(
1583
+ dept.name,
1584
+ dept.department_type.value.replace("_", " ").title(),
1585
+ head_name[:18] + ("..." if len(head_name) > 18 else ""),
1586
+ f"${dept.budget:,.2f}",
1587
+ str(len(dept.members))
1588
+ )
1589
+
1590
+ return Panel(
1591
+ dept_table,
1592
+ title="Departments",
1593
+ border_style="green",
1594
+ box=box.ROUNDED
1595
+ )
1596
+
1597
+ def render(self) -> Layout:
1598
+ """Render the complete TUI layout."""
1599
+ layout = self.create_layout()
1600
+
1601
+ layout["header"].update(self.render_header())
1602
+ layout["footer"].update(self.render_footer())
1603
+
1604
+ # Render main content based on view mode
1605
+ if self.state.view_mode == ViewMode.DASHBOARD:
1606
+ main_content = self.render_dashboard()
1607
+ layout["left"].update(main_content["overview"])
1608
+ layout["right"].split_column(
1609
+ Layout(main_content["metrics"]),
1610
+ Layout(main_content["recent"])
1611
+ )
1612
+ elif self.state.view_mode == ViewMode.MEMBERS:
1613
+ layout["left"].update(self.render_members_view())
1614
+ if self.state.selected_member_id:
1615
+ layout["right"].update(self.render_member_details(self.state.selected_member_id))
1616
+ else:
1617
+ layout["right"].update(
1618
+ Panel(
1619
+ "Select a member to view details\n\nPress [S] to enter selection mode\nPress [Enter] to view details",
1620
+ border_style="dim",
1621
+ box=box.ROUNDED
1622
+ )
1623
+ )
1624
+ elif self.state.view_mode == ViewMode.PROPOSALS:
1625
+ layout["left"].update(self.render_proposals_view())
1626
+ if self.state.selected_proposal_id:
1627
+ layout["right"].update(self.render_proposal_details(self.state.selected_proposal_id))
1628
+ else:
1629
+ layout["right"].update(
1630
+ Panel(
1631
+ "Select a proposal to view details\n\nPress [S] to enter selection mode\nPress [N] to create new proposal\nPress [Enter] to view details",
1632
+ border_style="dim",
1633
+ box=box.ROUNDED
1634
+ )
1635
+ )
1636
+ elif self.state.view_mode == ViewMode.VOTES:
1637
+ layout["left"].update(self.render_votes_view())
1638
+ if self.state.selected_vote_id:
1639
+ layout["right"].update(self.render_vote_details(self.state.selected_vote_id))
1640
+ else:
1641
+ layout["right"].update(
1642
+ Panel(
1643
+ "Select a vote to view details\n\nPress [S] to enter selection mode\nPress [Enter] to view details",
1644
+ border_style="dim",
1645
+ box=box.ROUNDED
1646
+ )
1647
+ )
1648
+ elif self.state.view_mode == ViewMode.MEETINGS:
1649
+ layout["left"].update(self.render_meetings_view())
1650
+ if self.state.selected_meeting_id:
1651
+ layout["right"].update(self.render_meeting_details(self.state.selected_meeting_id))
1652
+ else:
1653
+ layout["right"].update(
1654
+ Panel(
1655
+ "Select a meeting to view details\n\nPress [S] to enter selection mode\nPress [N] to schedule new meeting\nPress [Enter] to view details",
1656
+ border_style="dim",
1657
+ box=box.ROUNDED
1658
+ )
1659
+ )
1660
+ elif self.state.view_mode == ViewMode.ESG:
1661
+ layout["left"].update(self.render_esg_view())
1662
+ layout["right"].update(
1663
+ Panel(
1664
+ "ESG Dashboard\n\nUse command 'esg' to recalculate scores",
1665
+ border_style="dim",
1666
+ box=box.ROUNDED
1667
+ )
1668
+ )
1669
+ elif self.state.view_mode == ViewMode.RISK:
1670
+ layout["left"].update(self.render_risk_view())
1671
+ layout["right"].update(
1672
+ Panel(
1673
+ "Risk Assessment\n\nUse command 'risk' to conduct new assessment",
1674
+ border_style="dim",
1675
+ box=box.ROUNDED
1676
+ )
1677
+ )
1678
+ elif self.state.view_mode == ViewMode.AOP:
1679
+ layout["left"].update(self.render_aop_view())
1680
+ layout["right"].update(
1681
+ Panel(
1682
+ "AOP Integration Status\n\nMonitor queue statistics and server status",
1683
+ border_style="dim",
1684
+ box=box.ROUNDED
1685
+ )
1686
+ )
1687
+ elif self.state.view_mode == ViewMode.COMMITTEES:
1688
+ layout["left"].update(self.render_committees_view())
1689
+ layout["right"].update(
1690
+ Panel(
1691
+ "Board Committees\n\nView committee structure and membership",
1692
+ border_style="dim",
1693
+ box=box.ROUNDED
1694
+ )
1695
+ )
1696
+ elif self.state.view_mode == ViewMode.DEPARTMENTS:
1697
+ layout["left"].update(self.render_departments_view())
1698
+ layout["right"].update(
1699
+ Panel(
1700
+ "Departments\n\nView department structure and budgets",
1701
+ border_style="dim",
1702
+ box=box.ROUNDED
1703
+ )
1704
+ )
1705
+
1706
+ return layout
1707
+
1708
+ def _colorize_score(self, score: float, low_threshold: float = 70, high_threshold: float = 85) -> Text:
1709
+ """Colorize a score based on thresholds."""
1710
+ if score >= high_threshold:
1711
+ style = "green"
1712
+ elif score >= low_threshold:
1713
+ style = "yellow"
1714
+ else:
1715
+ style = "red"
1716
+
1717
+ return Text(f"{score:.1f}%", style=style)
1718
+
1719
+ def _create_progress_bar(self, value: float, max_value: float = 100) -> Text:
1720
+ """Create a text-based progress bar."""
1721
+ if max_value == 0:
1722
+ return Text("N/A", style="dim")
1723
+
1724
+ percentage = min(100, max(0, (value / max_value) * 100))
1725
+ bar_width = 40
1726
+ filled = int((percentage / 100) * bar_width)
1727
+ empty = bar_width - filled
1728
+
1729
+ if percentage >= 85:
1730
+ color = "green"
1731
+ elif percentage >= 70:
1732
+ color = "yellow"
1733
+ else:
1734
+ color = "red"
1735
+
1736
+ bar = "█" * filled + "░" * empty
1737
+ return Text(bar, style=color)
1738
+
1739
+ def _setup_keyboard_listener(self) -> None:
1740
+ """Setup keyboard listener thread."""
1741
+ if sys.platform != "win32":
1742
+ try:
1743
+ # Save terminal settings
1744
+ self._old_terminal_settings = termios.tcgetattr(sys.stdin.fileno())
1745
+ tty.setcbreak(sys.stdin.fileno())
1746
+ except Exception:
1747
+ self._old_terminal_settings = None
1748
+
1749
+ self._key_queue = []
1750
+ self._keyboard_thread = threading.Thread(target=self._keyboard_listener, daemon=True)
1751
+ self._keyboard_thread.start()
1752
+
1753
+ def _keyboard_listener(self) -> None:
1754
+ """Keyboard listener thread."""
1755
+ try:
1756
+ while self.is_running and not self._should_quit:
1757
+ key = self._get_key()
1758
+ if key:
1759
+ # Handle escape sequences for arrow keys
1760
+ if key == '\x1b':
1761
+ try:
1762
+ if sys.platform != "win32":
1763
+ if select.select([sys.stdin], [], [], 0.1) == ([sys.stdin], [], []):
1764
+ seq = sys.stdin.read(2)
1765
+ if seq == '[A':
1766
+ key = 'up'
1767
+ elif seq == '[B':
1768
+ key = 'down'
1769
+ elif seq == '[C':
1770
+ key = 'right'
1771
+ elif seq == '[D':
1772
+ key = 'left'
1773
+ else:
1774
+ key = 'escape'
1775
+ else:
1776
+ key = 'escape'
1777
+ else:
1778
+ key = 'escape'
1779
+ except Exception:
1780
+ key = 'escape'
1781
+
1782
+ self._key_queue.append(key)
1783
+ time.sleep(0.05)
1784
+ except Exception as e:
1785
+ logger.debug(f"Keyboard listener error: {e}")
1786
+
1787
+ def _get_key(self) -> Optional[str]:
1788
+ """Get a key press from stdin (non-blocking)."""
1789
+ if sys.platform == "win32":
1790
+ try:
1791
+ import msvcrt
1792
+ if msvcrt.kbhit():
1793
+ key = msvcrt.getch()
1794
+ if isinstance(key, bytes):
1795
+ key = key.decode('utf-8', errors='ignore')
1796
+ return key
1797
+ except Exception:
1798
+ pass
1799
+ else:
1800
+ try:
1801
+ if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
1802
+ key = sys.stdin.read(1)
1803
+ return key
1804
+ except Exception:
1805
+ pass
1806
+ return None
1807
+
1808
+ def _process_keys(self) -> None:
1809
+ """Process queued key presses."""
1810
+ if not self._key_queue:
1811
+ return
1812
+
1813
+ while self._key_queue:
1814
+ key = self._key_queue.pop(0)
1815
+
1816
+ # Handle command mode
1817
+ if self.state.interaction_mode == InteractionMode.COMMAND:
1818
+ if key == '\r' or key == '\n':
1819
+ self._activate_selected()
1820
+ elif key == '\x1b' or key == 'escape':
1821
+ self._exit_interaction()
1822
+ elif key == '\x7f' or key == '\b': # Backspace
1823
+ if self.state.current_command:
1824
+ self.state.current_command = self.state.current_command[:-1]
1825
+ elif len(key) == 1 and key.isprintable() and ord(key) >= 32:
1826
+ self.state.current_command += key
1827
+ continue
1828
+
1829
+ # Handle normal key presses
1830
+ handler = self._key_handlers.get(key)
1831
+ if handler:
1832
+ try:
1833
+ handler()
1834
+ except Exception as e:
1835
+ logger.error(f"Error handling key {key}: {e}")
1836
+
1837
+ def run_live(
1838
+ self,
1839
+ update_callback: Optional[Callable] = None,
1840
+ refresh_rate: Optional[float] = None
1841
+ ) -> None:
1842
+ """
1843
+ Run the TUI with live updates and keyboard interaction.
1844
+
1845
+ Args:
1846
+ update_callback: Optional callback function to call before each update
1847
+ refresh_rate: Optional refresh rate override
1848
+ """
1849
+ if refresh_rate:
1850
+ self.state.refresh_rate = refresh_rate
1851
+
1852
+ self.is_running = True
1853
+ self._should_quit = False
1854
+
1855
+ # Setup keyboard listener
1856
+ self._setup_keyboard_listener()
1857
+
1858
+ try:
1859
+ with Live(
1860
+ self.render(),
1861
+ refresh_per_second=1.0 / self.state.refresh_rate,
1862
+ screen=True
1863
+ ) as live:
1864
+ while not self._should_quit:
1865
+ # Process keyboard input
1866
+ self._process_keys()
1867
+
1868
+ if update_callback:
1869
+ update_callback(self)
1870
+
1871
+ if self.state.auto_refresh:
1872
+ self._update_status()
1873
+
1874
+ # Clear message after a delay
1875
+ if self.state.message and time.time() - self.state.last_update > 3:
1876
+ self.state.message = None
1877
+
1878
+ live.update(self.render())
1879
+ time.sleep(self.state.refresh_rate)
1880
+ except KeyboardInterrupt:
1881
+ pass
1882
+ finally:
1883
+ self.is_running = False
1884
+ if sys.platform != "win32" and hasattr(self, '_old_terminal_settings'):
1885
+ try:
1886
+ termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, self._old_terminal_settings)
1887
+ except:
1888
+ pass
1889
+ self.console.clear()
1890
+
1891
+ def run_once(self) -> None:
1892
+ """Render the TUI once without live updates."""
1893
+ self._update_status()
1894
+ self.console.print(self.render())
1895
+
1896
+
1897
+ def create_corporate_tui(corporate_swarm: Any, **kwargs) -> CorporateSwarmTUI:
1898
+ """
1899
+ Create a CorporateSwarm TUI instance.
1900
+
1901
+ Args:
1902
+ corporate_swarm: CorporateSwarm instance
1903
+ **kwargs: Additional arguments for TUI initialization
1904
+
1905
+ Returns:
1906
+ CorporateSwarmTUI instance
1907
+ """
1908
+ return CorporateSwarmTUI(corporate_swarm, **kwargs)