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
@@ -0,0 +1,1133 @@
1
+ """
2
+ CRCA-SD TUI: Comprehensive Interactive Terminal User Interface
3
+
4
+ Provides a rich, fully interactive terminal interface for monitoring and controlling
5
+ CRCA-SD systems in real-time.
6
+
7
+ Features:
8
+ - Live updating dashboard
9
+ - Interactive state visualization
10
+ - Policy creation and modification
11
+ - Vision progress tracking
12
+ - Board management
13
+ - Alert monitoring
14
+ - Execution control
15
+ - Full keyboard navigation and interaction
16
+ """
17
+
18
+ from typing import Dict, List, Optional, Any, Callable
19
+ from datetime import datetime
20
+ from enum import Enum
21
+ import time
22
+ import sys
23
+ import select
24
+ import os
25
+ import threading
26
+ import queue
27
+ import termios
28
+ import tty
29
+ from dataclasses import dataclass, field
30
+
31
+ try:
32
+ from rich.console import Console
33
+ from rich.layout import Layout
34
+ from rich.panel import Panel
35
+ from rich.table import Table
36
+ from rich.text import Text
37
+ from rich.live import Live
38
+ from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn
39
+ from rich.columns import Columns
40
+ from rich.align import Align
41
+ from rich import box
42
+ from rich.markdown import Markdown
43
+ from rich.prompt import Prompt, Confirm
44
+ RICH_AVAILABLE = True
45
+ except ImportError:
46
+ RICH_AVAILABLE = False
47
+ Console = None
48
+ Layout = None
49
+ Panel = None
50
+ Table = None
51
+ Text = None
52
+ Live = None
53
+ Progress = None
54
+ Columns = None
55
+ Align = None
56
+ box = None
57
+ Markdown = None
58
+ Prompt = None
59
+ Confirm = None
60
+
61
+ from loguru import logger
62
+
63
+ from crca_sd.crca_sd_core import StateVector, ControlVector
64
+
65
+ # Import formatter from utils
66
+ try:
67
+ from utils.formatter import Formatter
68
+ FORMATTER_AVAILABLE = True
69
+ except ImportError:
70
+ Formatter = None
71
+ FORMATTER_AVAILABLE = False
72
+
73
+
74
+ class ViewMode(str, Enum):
75
+ """TUI view modes."""
76
+ DASHBOARD = "dashboard"
77
+ STATE = "state"
78
+ POLICY = "policy"
79
+ VISION = "vision"
80
+ BOARDS = "boards"
81
+ EXECUTIONS = "executions"
82
+ ALERTS = "alerts"
83
+ APPROVALS = "approvals"
84
+
85
+
86
+ class InteractionMode(str, Enum):
87
+ """Interaction modes for the TUI."""
88
+ VIEW = "view"
89
+ SELECT = "select"
90
+ CREATE = "create"
91
+ EDIT = "edit"
92
+ COMMAND = "command"
93
+
94
+
95
+ @dataclass
96
+ class TUIState:
97
+ """State for TUI display."""
98
+ current_state: Optional[StateVector] = None
99
+ vision_progress: Optional[Dict[str, float]] = None
100
+ vision_target: Optional[StateVector] = None
101
+ system_status: Optional[Dict[str, Any]] = None
102
+ execution_history: List[Dict[str, Any]] = field(default_factory=list)
103
+ pending_approvals: List[Dict[str, Any]] = field(default_factory=list)
104
+ alerts: List[Dict[str, Any]] = field(default_factory=list)
105
+ policy: Optional[ControlVector] = None
106
+ boards: List[Any] = field(default_factory=list)
107
+ governance_system: Optional[Any] = None
108
+ view_mode: ViewMode = ViewMode.DASHBOARD
109
+ interaction_mode: InteractionMode = InteractionMode.VIEW
110
+ selected_index: int = 0
111
+ selected_execution_id: Optional[str] = None
112
+ selected_approval_id: Optional[str] = None
113
+ selected_board_id: Optional[str] = None
114
+ auto_refresh: bool = True
115
+ refresh_rate: float = 1.0
116
+ last_update: float = field(default_factory=time.time)
117
+ current_command: str = ""
118
+ message: Optional[str] = None
119
+ message_style: str = "white"
120
+
121
+ def __post_init__(self):
122
+ """Initialize default values."""
123
+ if self.execution_history is None:
124
+ self.execution_history = []
125
+ if self.pending_approvals is None:
126
+ self.pending_approvals = []
127
+ if self.alerts is None:
128
+ self.alerts = []
129
+ if self.boards is None:
130
+ self.boards = []
131
+
132
+
133
+ class CRCA_SD_TUI:
134
+ """
135
+ Comprehensive Interactive Terminal User Interface for CRCA-SD systems.
136
+
137
+ Provides fully interactive interface with:
138
+ - Current state visualization
139
+ - Vision progress tracking
140
+ - Policy creation and modification
141
+ - Board management
142
+ - Policy execution status
143
+ - Alert monitoring
144
+ - System health
145
+ - Full keyboard navigation
146
+ """
147
+
148
+ def __init__(self, title: str = "CRCA-SD Control System", use_formatter: bool = True):
149
+ """
150
+ Initialize TUI.
151
+
152
+ Args:
153
+ title: Title for the TUI
154
+ use_formatter: Whether to use Formatter from utils (default: True)
155
+ """
156
+ if not RICH_AVAILABLE:
157
+ raise ImportError("rich is required for TUI. Install with: pip install rich")
158
+
159
+ self.console = Console()
160
+ self.title = title
161
+ self.state = TUIState()
162
+ self.is_running = False
163
+ self.start_time = time.time()
164
+ self._should_quit = False
165
+ self._key_handlers: Dict[str, Callable] = {}
166
+ self._key_queue = []
167
+ self._keyboard_thread = None
168
+ self._old_terminal_settings = None
169
+
170
+ # Use Formatter from utils if available
171
+ if use_formatter and FORMATTER_AVAILABLE and Formatter is not None:
172
+ self.formatter = Formatter(md=True)
173
+ logger.debug("Using Formatter from utils for enhanced formatting")
174
+ else:
175
+ self.formatter = None
176
+
177
+ self._setup_key_handlers()
178
+
179
+ def _setup_key_handlers(self) -> None:
180
+ """Setup keyboard handlers."""
181
+ self._key_handlers = {
182
+ 'q': self._quit,
183
+ 'Q': self._quit,
184
+ 'r': self._refresh,
185
+ 'R': self._refresh,
186
+ '1': lambda: self._set_view(ViewMode.DASHBOARD),
187
+ '2': lambda: self._set_view(ViewMode.STATE),
188
+ '3': lambda: self._set_view(ViewMode.POLICY),
189
+ '4': lambda: self._set_view(ViewMode.VISION),
190
+ '5': lambda: self._set_view(ViewMode.BOARDS),
191
+ '6': lambda: self._set_view(ViewMode.EXECUTIONS),
192
+ '7': lambda: self._set_view(ViewMode.ALERTS),
193
+ '8': lambda: self._set_view(ViewMode.APPROVALS),
194
+ 'a': self._toggle_auto_refresh,
195
+ 'A': self._toggle_auto_refresh,
196
+ 'c': self._enter_command_mode,
197
+ 'C': self._enter_command_mode,
198
+ 'n': self._create_new_item,
199
+ 'N': self._create_new_item,
200
+ 's': self._select_item,
201
+ 'S': self._select_item,
202
+ 'enter': self._activate_selected,
203
+ '\r': self._activate_selected,
204
+ '\n': self._activate_selected,
205
+ 'up': self._navigate_up,
206
+ 'down': self._navigate_down,
207
+ 'k': self._navigate_up,
208
+ 'j': self._navigate_down,
209
+ 'h': self._navigate_left,
210
+ 'l': self._navigate_right,
211
+ 'escape': self._exit_interaction,
212
+ '\x1b': self._exit_interaction,
213
+ '?': self._show_help,
214
+ }
215
+
216
+ def _quit(self) -> None:
217
+ """Quit the TUI."""
218
+ self._should_quit = True
219
+
220
+ def _refresh(self) -> None:
221
+ """Manually refresh the display."""
222
+ self.state.message = "Status refreshed"
223
+ self.state.message_style = "green"
224
+ self.state.last_update = time.time()
225
+
226
+ def _set_view(self, mode: ViewMode) -> None:
227
+ """Set the current view mode."""
228
+ self.state.view_mode = mode
229
+ self.state.selected_index = 0
230
+ self.state.interaction_mode = InteractionMode.VIEW
231
+ self.state.message = None
232
+
233
+ def _toggle_auto_refresh(self) -> None:
234
+ """Toggle auto-refresh mode."""
235
+ self.state.auto_refresh = not self.state.auto_refresh
236
+ status = "enabled" if self.state.auto_refresh else "disabled"
237
+ self.state.message = f"Auto-refresh {status}"
238
+ self.state.message_style = "green"
239
+
240
+ def _enter_command_mode(self) -> None:
241
+ """Enter command input mode."""
242
+ self.state.interaction_mode = InteractionMode.COMMAND
243
+ self.state.current_command = ""
244
+
245
+ def _create_new_item(self) -> None:
246
+ """Create a new item based on current view."""
247
+ if self.state.view_mode == ViewMode.POLICY:
248
+ self._create_policy_interactive()
249
+ else:
250
+ self.state.message = "Cannot create items in this view"
251
+ self.state.message_style = "yellow"
252
+
253
+ def _select_item(self) -> None:
254
+ """Enter selection mode."""
255
+ if self._get_list_items():
256
+ self.state.interaction_mode = InteractionMode.SELECT
257
+ self.state.message = "Use arrow keys to navigate, Enter to select"
258
+ self.state.message_style = "cyan"
259
+ else:
260
+ self.state.message = "No items to select"
261
+ self.state.message_style = "yellow"
262
+
263
+ def _activate_selected(self) -> None:
264
+ """Activate the selected item."""
265
+ if self.state.interaction_mode == InteractionMode.SELECT:
266
+ self._show_item_details()
267
+ elif self.state.interaction_mode == InteractionMode.COMMAND:
268
+ self._execute_command()
269
+
270
+ def _navigate_up(self) -> None:
271
+ """Navigate up in list."""
272
+ items = self._get_list_items()
273
+ if items and self.state.selected_index > 0:
274
+ self.state.selected_index -= 1
275
+
276
+ def _navigate_down(self) -> None:
277
+ """Navigate down in list."""
278
+ items = self._get_list_items()
279
+ if items and self.state.selected_index < len(items) - 1:
280
+ self.state.selected_index += 1
281
+
282
+ def _navigate_left(self) -> None:
283
+ """Navigate left (back)."""
284
+ self.state.interaction_mode = InteractionMode.VIEW
285
+ self.state.message = None
286
+
287
+ def _navigate_right(self) -> None:
288
+ """Navigate right (forward)."""
289
+ if self._get_list_items():
290
+ self._select_item()
291
+
292
+ def _exit_interaction(self) -> None:
293
+ """Exit current interaction mode."""
294
+ self.state.interaction_mode = InteractionMode.VIEW
295
+ self.state.current_command = ""
296
+ self.state.message = None
297
+
298
+ def _show_help(self) -> None:
299
+ """Show help information."""
300
+ self.state.message = (
301
+ "Help: [1-8] Views | [N]ew Policy | [S]elect | [C]ommand | "
302
+ "[R]efresh | [A]uto-refresh | [Q]uit | [?] Help"
303
+ )
304
+ self.state.message_style = "cyan"
305
+
306
+ def _get_list_items(self) -> List[Any]:
307
+ """Get list items for current view."""
308
+ if self.state.view_mode == ViewMode.EXECUTIONS:
309
+ return self.state.execution_history
310
+ elif self.state.view_mode == ViewMode.APPROVALS:
311
+ return self.state.pending_approvals
312
+ elif self.state.view_mode == ViewMode.BOARDS:
313
+ return self.state.boards
314
+ elif self.state.view_mode == ViewMode.ALERTS:
315
+ return self.state.alerts
316
+ return []
317
+
318
+ def _show_item_details(self) -> None:
319
+ """Show details for selected item."""
320
+ items = self._get_list_items()
321
+ if not items or self.state.selected_index >= len(items):
322
+ return
323
+
324
+ selected = items[self.state.selected_index]
325
+
326
+ if self.state.view_mode == ViewMode.EXECUTIONS:
327
+ self.state.selected_execution_id = selected.get("execution_id")
328
+ self.state.interaction_mode = InteractionMode.VIEW
329
+ elif self.state.view_mode == ViewMode.APPROVALS:
330
+ self.state.selected_approval_id = selected.get("approval_id")
331
+ self.state.interaction_mode = InteractionMode.VIEW
332
+ elif self.state.view_mode == ViewMode.BOARDS:
333
+ if hasattr(selected, 'board_id'):
334
+ self.state.selected_board_id = selected.board_id
335
+ self.state.interaction_mode = InteractionMode.VIEW
336
+
337
+ def _execute_command(self) -> None:
338
+ """Execute a command."""
339
+ if not self.state.current_command:
340
+ self.state.interaction_mode = InteractionMode.VIEW
341
+ return
342
+
343
+ cmd = self.state.current_command.strip().lower()
344
+ parts = cmd.split()
345
+
346
+ if not parts:
347
+ self.state.interaction_mode = InteractionMode.VIEW
348
+ return
349
+
350
+ command = parts[0]
351
+ args = parts[1:] if len(parts) > 1 else []
352
+
353
+ try:
354
+ if command == "policy" or command == "create":
355
+ self._create_policy_interactive()
356
+ elif command == "approve" and args:
357
+ self._approve_interactive(args[0])
358
+ elif command == "reject" and args:
359
+ self._reject_interactive(args[0])
360
+ elif command == "status":
361
+ self._show_full_status()
362
+ elif command == "help":
363
+ self._show_help()
364
+ else:
365
+ self.state.message = f"Unknown command: {command}. Type 'help' for commands"
366
+ self.state.message_style = "yellow"
367
+ except Exception as e:
368
+ self.state.message = f"Command error: {str(e)}"
369
+ self.state.message_style = "red"
370
+ finally:
371
+ self.state.current_command = ""
372
+ self.state.interaction_mode = InteractionMode.VIEW
373
+
374
+ def _create_policy_interactive(self) -> None:
375
+ """Interactively create a policy."""
376
+ try:
377
+ self.console.clear()
378
+ self.console.print(Panel("Create New Policy", border_style="cyan", box=box.ROUNDED))
379
+
380
+ # Default budget categories
381
+ categories = [
382
+ "education", "infrastructure", "healthcare",
383
+ "social_welfare", "defense", "other"
384
+ ]
385
+
386
+ budget_shares = {}
387
+ total = 0.0
388
+
389
+ self.console.print("\nEnter budget shares (must sum to 1.0):")
390
+ for category in categories:
391
+ share_str = Prompt.ask(f"{category.replace('_', ' ').title()} share", default="0.0")
392
+ try:
393
+ share = float(share_str)
394
+ budget_shares[category] = share
395
+ total += share
396
+ except ValueError:
397
+ budget_shares[category] = 0.0
398
+
399
+ # Normalize if needed
400
+ if total > 0 and abs(total - 1.0) > 0.01:
401
+ if Confirm.ask(f"Total is {total:.2%}, normalize to 1.0?"):
402
+ for category in budget_shares:
403
+ budget_shares[category] /= total
404
+
405
+ # Create ControlVector
406
+ policy = ControlVector(budget_shares=budget_shares)
407
+ self.state.policy = policy
408
+
409
+ self.state.message = "Policy created successfully"
410
+ self.state.message_style = "green"
411
+
412
+ except KeyboardInterrupt:
413
+ self.state.message = "Policy creation cancelled"
414
+ self.state.message_style = "yellow"
415
+ except Exception as e:
416
+ self.state.message = f"Error creating policy: {str(e)}"
417
+ self.state.message_style = "red"
418
+
419
+ def _approve_interactive(self, approval_id: str) -> None:
420
+ """Interactively approve an item."""
421
+ self.state.message = f"Approval {approval_id} approved (simulated)"
422
+ self.state.message_style = "green"
423
+
424
+ def _reject_interactive(self, approval_id: str) -> None:
425
+ """Interactively reject an item."""
426
+ self.state.message = f"Approval {approval_id} rejected (simulated)"
427
+ self.state.message_style = "red"
428
+
429
+ def _show_full_status(self) -> None:
430
+ """Show full system status."""
431
+ self.state.view_mode = ViewMode.DASHBOARD
432
+ self.state.message = "Full status displayed"
433
+ self.state.message_style = "green"
434
+
435
+ def create_layout(self) -> Layout:
436
+ """Create the main layout structure."""
437
+ layout = Layout()
438
+
439
+ layout.split_column(
440
+ Layout(name="header", size=3),
441
+ Layout(name="main", ratio=1),
442
+ Layout(name="footer", size=4)
443
+ )
444
+
445
+ layout["main"].split_row(
446
+ Layout(name="left", ratio=1),
447
+ Layout(name="right", ratio=1)
448
+ )
449
+
450
+ return layout
451
+
452
+ def create_header(self) -> Panel:
453
+ """Create header panel."""
454
+ uptime = time.time() - self.start_time
455
+ uptime_str = f"{int(uptime // 3600)}h {int((uptime % 3600) // 60)}m {int(uptime % 60)}s"
456
+
457
+ last_update_str = datetime.fromtimestamp(self.state.last_update).strftime("%H:%M:%S") if self.state.last_update else "N/A"
458
+
459
+ header_text = Text()
460
+ header_text.append(self.title, style="bold bright_white")
461
+ header_text.append(" | ", style="dim")
462
+ header_text.append(f"Uptime: {uptime_str}", style="cyan")
463
+ header_text.append(" | ", style="dim")
464
+ header_text.append(f"Last Update: {last_update_str}", style="green")
465
+ header_text.append(" | ", style="dim")
466
+
467
+ if self.state.auto_refresh:
468
+ header_text.append("Auto-Refresh ON", style="green")
469
+ else:
470
+ header_text.append("Auto-Refresh OFF", style="yellow")
471
+
472
+ header_text.append(" | ", style="dim")
473
+ header_text.append(f"View: {self.state.view_mode.value.upper()}", style="magenta")
474
+
475
+ if self.state.interaction_mode != InteractionMode.VIEW:
476
+ header_text.append(" | ", style="dim")
477
+ header_text.append(f"Mode: {self.state.interaction_mode.value.upper()}", style="cyan")
478
+
479
+ return Panel(Align.center(header_text), style="bold blue", box=box.ROUNDED)
480
+
481
+ def create_footer(self) -> Layout:
482
+ """Create footer with controls and messages."""
483
+ footer_layout = Layout()
484
+ footer_layout.split_column(
485
+ Layout(name="controls", size=2),
486
+ Layout(name="message", size=2)
487
+ )
488
+
489
+ # Controls
490
+ controls = Text()
491
+ controls.append("Controls: ", style="bold")
492
+ controls.append("[Q]uit ", style="red")
493
+ controls.append("[R]efresh ", style="yellow")
494
+ controls.append("[1-8] Views ", style="cyan")
495
+ controls.append("[N]ew Policy ", style="green")
496
+ controls.append("[S]elect ", style="blue")
497
+ controls.append("[C]ommand ", style="magenta")
498
+ controls.append("[A]uto-refresh ", style="green")
499
+ controls.append("[?] Help", style="dim")
500
+
501
+ footer_layout["controls"].update(
502
+ Panel(Align.center(controls), border_style="blue", box=box.ROUNDED)
503
+ )
504
+
505
+ # Message/Command line
506
+ if self.state.interaction_mode == InteractionMode.COMMAND:
507
+ cmd_text = Text()
508
+ cmd_text.append("Command: ", style="bold cyan")
509
+ cmd_text.append(self.state.current_command, style="white")
510
+ cmd_text.append("_", style="dim") # Cursor
511
+ footer_layout["message"].update(
512
+ Panel(cmd_text, border_style="cyan", box=box.ROUNDED)
513
+ )
514
+ elif self.state.message:
515
+ msg_text = Text(self.state.message, style=self.state.message_style)
516
+ footer_layout["message"].update(
517
+ Panel(Align.center(msg_text), border_style=self.state.message_style, box=box.ROUNDED)
518
+ )
519
+ else:
520
+ footer_layout["message"].update(
521
+ Panel("", border_style="dim", box=box.ROUNDED)
522
+ )
523
+
524
+ return footer_layout
525
+
526
+ def create_state_panel(self) -> Panel:
527
+ """Create state visualization panel."""
528
+ if self.state.current_state is None:
529
+ return Panel("No state data available", title="Current State", border_style="yellow", box=box.ROUNDED)
530
+
531
+ x = self.state.current_state
532
+
533
+ table = Table.grid(padding=(0, 2))
534
+ table.add_column(style="cyan", justify="right")
535
+ table.add_column(style="white")
536
+
537
+ # Key metrics
538
+ table.add_row("Population", f"{x.P:,.0f}")
539
+ table.add_row("GDP", f"${x.Y/1e9:.2f}B")
540
+ table.add_row("Unemployment", f"{x.U:.1%}", style="red" if x.U > 0.10 else "green")
541
+ table.add_row("Stability", f"{x.S:.1%}", style="green" if x.S > 0.70 else "yellow" if x.S > 0.50 else "red")
542
+ table.add_row("Literacy", f"{x.literacy:.1%}")
543
+ table.add_row("Infrastructure", f"{x.I:.1%}")
544
+ table.add_row("Capital", f"${x.K/1e9:.2f}B")
545
+ table.add_row("Wage", f"${x.W:.2f}")
546
+
547
+ return Panel(table, title="Current State", border_style="cyan", box=box.ROUNDED)
548
+
549
+ def create_vision_panel(self) -> Panel:
550
+ """Create vision progress panel."""
551
+ if self.state.vision_progress is None:
552
+ return Panel("No vision data available", title="Vision Progress", border_style="yellow", box=box.ROUNDED)
553
+
554
+ progress = self.state.vision_progress
555
+
556
+ # Overall progress bar
557
+ overall = progress.get("overall", 0.0)
558
+ progress_text = Text()
559
+ progress_text.append("Overall: ", style="dim")
560
+ progress_text.append(f"{overall:.1%}", style="bold bright_green" if overall > 0.7 else "bold yellow" if overall > 0.4 else "bold red")
561
+
562
+ # Individual metrics
563
+ table = Table.grid(padding=(0, 1))
564
+ table.add_column(style="cyan", justify="right")
565
+ table.add_column(style="white")
566
+
567
+ metrics = [
568
+ ("Unemployment", progress.get("unemployment", 0.0), 0.8),
569
+ ("GDP", progress.get("gdp", 0.0), 0.7),
570
+ ("Stability", progress.get("stability", 0.0), 0.76),
571
+ ("Infrastructure", progress.get("infrastructure", 0.0), 0.76),
572
+ ("Literacy", progress.get("literacy", 0.0), 0.99),
573
+ ]
574
+
575
+ for name, value, threshold in metrics:
576
+ style = "green" if value >= threshold else "yellow" if value >= threshold * 0.7 else "red"
577
+ table.add_row(name, f"{value:.1%}", style=style)
578
+
579
+ content = Columns([progress_text, table], equal=True)
580
+
581
+ return Panel(content, title="Vision Progress", border_style="bright_green", box=box.ROUNDED)
582
+
583
+ def create_policy_panel(self) -> Panel:
584
+ """Create current policy panel."""
585
+ if self.state.policy is None:
586
+ return Panel("No active policy. Use [N] or command 'policy' to create one.", title="Current Policy", border_style="yellow", box=box.ROUNDED)
587
+
588
+ policy = self.state.policy
589
+
590
+ table = Table.grid(padding=(0, 1))
591
+ table.add_column(style="cyan", justify="right")
592
+ table.add_column(style="white")
593
+
594
+ # Sort by budget share
595
+ sorted_shares = sorted(policy.budget_shares.items(), key=lambda x: x[1], reverse=True)
596
+
597
+ for category, share in sorted_shares[:7]: # Top 7
598
+ bar_length = int(share * 20) # Scale to 20 chars
599
+ bar = "█" * bar_length + "░" * (20 - bar_length)
600
+ style = "green" if share > 0.15 else "yellow" if share > 0.10 else "dim"
601
+ table.add_row(category.capitalize(), f"{bar} {share:.1%}", style=style)
602
+
603
+ return Panel(table, title="Current Policy", border_style="magenta", box=box.ROUNDED)
604
+
605
+ def create_status_panel(self) -> Panel:
606
+ """Create system status panel."""
607
+ if self.state.system_status is None:
608
+ return Panel("No status data available", title="System Status", border_style="yellow", box=box.ROUNDED)
609
+
610
+ status = self.state.system_status
611
+
612
+ table = Table.grid(padding=(0, 1))
613
+ table.add_column(style="cyan", justify="right")
614
+ table.add_column(style="white")
615
+
616
+ is_running = status.get("is_running", False)
617
+ status_text = "Running" if is_running else "Stopped"
618
+ table.add_row("Status", status_text, style="green" if is_running else "red")
619
+
620
+ table.add_row("Executions", str(status.get("n_executions", 0)))
621
+ table.add_row("Pending Approvals", str(status.get("n_pending_approvals", 0)),
622
+ style="yellow" if status.get("n_pending_approvals", 0) > 0 else "dim")
623
+
624
+ confidence = status.get("state_confidence", 0.0)
625
+ conf_style = "green" if confidence > 0.9 else "yellow" if confidence > 0.7 else "red"
626
+ table.add_row("State Confidence", f"{confidence:.1%}", style=conf_style)
627
+
628
+ health = status.get("system_health", {})
629
+ health_status = health.get("status", "unknown")
630
+ health_style = "green" if health_status == "healthy" else "yellow" if health_status == "degraded" else "red"
631
+ table.add_row("System Health", health_status.capitalize(), style=health_style)
632
+
633
+ return Panel(table, title="System Status", border_style="blue", box=box.ROUNDED)
634
+
635
+ def create_alerts_panel(self) -> Panel:
636
+ """Create alerts panel."""
637
+ if not self.state.alerts:
638
+ return Panel("No active alerts", title="Alerts", border_style="green", box=box.ROUNDED)
639
+
640
+ # Show last 5 alerts
641
+ recent_alerts = self.state.alerts[-5:]
642
+
643
+ table = Table.grid(padding=(0, 1))
644
+ table.add_column(style="white", width=12)
645
+ table.add_column(style="white")
646
+
647
+ for idx, alert in enumerate(reversed(recent_alerts)):
648
+ level = alert.get("level", "info").upper()
649
+ message = alert.get("message", "No message")[:50]
650
+
651
+ if level == "CRITICAL":
652
+ style = "bold red"
653
+ level_text = f"CRITICAL"
654
+ elif level == "WARNING":
655
+ style = "bold yellow"
656
+ level_text = f"WARNING"
657
+ else:
658
+ style = "dim"
659
+ level_text = f"INFO"
660
+
661
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
662
+ level_text = f"> {level_text}"
663
+ style = style + " bold"
664
+
665
+ table.add_row(level_text, message, style=style)
666
+
667
+ return Panel(table, title="Alerts", border_style="red", box=box.ROUNDED)
668
+
669
+ def create_history_panel(self) -> Panel:
670
+ """Create execution history panel."""
671
+ if not self.state.execution_history:
672
+ return Panel("No execution history", title="Recent Executions", border_style="dim", box=box.ROUNDED)
673
+
674
+ # Show last 5 executions
675
+ recent = self.state.execution_history[-5:]
676
+
677
+ table = Table.grid(padding=(0, 1))
678
+ table.add_column(style="dim", width=15)
679
+ table.add_column(style="white")
680
+
681
+ for idx, exec_item in enumerate(reversed(recent)):
682
+ exec_id = exec_item.get("execution_id", "unknown")[:8]
683
+ status = exec_item.get("status", "unknown")
684
+ automated = exec_item.get("automated", False)
685
+
686
+ status_style = "green" if status == "executed" else "yellow"
687
+ auto_text = "AUTO" if automated else "MANUAL"
688
+
689
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
690
+ exec_id = f"> {exec_id}"
691
+ status_style = status_style + " bold"
692
+
693
+ table.add_row(f"{auto_text} {exec_id}", status, style=status_style)
694
+
695
+ return Panel(table, title="Recent Executions", border_style="cyan", box=box.ROUNDED)
696
+
697
+ def render_executions_view(self) -> Panel:
698
+ """Render detailed executions view."""
699
+ if not self.state.execution_history:
700
+ return Panel("No execution history available", border_style="yellow", box=box.ROUNDED)
701
+
702
+ executions_table = Table(show_header=True, header_style="bold cyan", box=box.ROUNDED)
703
+ executions_table.add_column("", width=2)
704
+ executions_table.add_column("Execution ID", style="cyan", width=12)
705
+ executions_table.add_column("Status", style="white", width=12)
706
+ executions_table.add_column("Type", style="yellow", width=10)
707
+ executions_table.add_column("Timestamp", style="dim", width=15)
708
+
709
+ for idx, exec_item in enumerate(self.state.execution_history[-20:]):
710
+ exec_id = exec_item.get("execution_id", "unknown")[:10]
711
+ status = exec_item.get("status", "unknown")
712
+ automated = exec_item.get("automated", False)
713
+ timestamp = exec_item.get("timestamp", 0)
714
+
715
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
716
+ selector = ">"
717
+ row_style = "bold"
718
+ else:
719
+ selector = " "
720
+ row_style = None
721
+
722
+ status_style = "green" if status == "executed" else "yellow" if status == "pending" else "red"
723
+ auto_text = "AUTO" if automated else "MANUAL"
724
+
725
+ time_str = datetime.fromtimestamp(timestamp).strftime("%H:%M:%S") if timestamp else "N/A"
726
+
727
+ executions_table.add_row(
728
+ selector,
729
+ Text(exec_id, style=row_style) if row_style else exec_id,
730
+ f"[{status_style}]{status.upper()}[/{status_style}]",
731
+ auto_text,
732
+ time_str
733
+ )
734
+
735
+ return Panel(
736
+ executions_table,
737
+ title="Execution History",
738
+ border_style="cyan",
739
+ box=box.ROUNDED
740
+ )
741
+
742
+ def render_approvals_view(self) -> Panel:
743
+ """Render approvals view."""
744
+ if not self.state.pending_approvals:
745
+ return Panel("No pending approvals", border_style="green", box=box.ROUNDED)
746
+
747
+ approvals_table = Table(show_header=True, header_style="bold yellow", box=box.ROUNDED)
748
+ approvals_table.add_column("", width=2)
749
+ approvals_table.add_column("Approval ID", style="cyan", width=12)
750
+ approvals_table.add_column("Type", style="yellow", width=15)
751
+ approvals_table.add_column("Status", style="white", width=12)
752
+ approvals_table.add_column("Timestamp", style="dim", width=15)
753
+
754
+ for idx, approval in enumerate(self.state.pending_approvals):
755
+ approval_id = approval.get("approval_id", "unknown")[:10]
756
+ approval_type = approval.get("type", "unknown")
757
+ status = approval.get("status", "pending")
758
+ timestamp = approval.get("timestamp", 0)
759
+
760
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
761
+ selector = ">"
762
+ row_style = "bold"
763
+ else:
764
+ selector = " "
765
+ row_style = None
766
+
767
+ status_style = "yellow" if status == "pending" else "green" if status == "approved" else "red"
768
+ time_str = datetime.fromtimestamp(timestamp).strftime("%H:%M:%S") if timestamp else "N/A"
769
+
770
+ approvals_table.add_row(
771
+ selector,
772
+ Text(approval_id, style=row_style) if row_style else approval_id,
773
+ approval_type,
774
+ f"[{status_style}]{status.upper()}[/{status_style}]",
775
+ time_str
776
+ )
777
+
778
+ return Panel(
779
+ approvals_table,
780
+ title="Pending Approvals",
781
+ border_style="yellow",
782
+ box=box.ROUNDED
783
+ )
784
+
785
+ def render_boards_view(self) -> Panel:
786
+ """Render boards view."""
787
+ if not self.state.boards:
788
+ return Panel("No boards available", border_style="yellow", box=box.ROUNDED)
789
+
790
+ boards_table = Table(show_header=True, header_style="bold blue", box=box.ROUNDED)
791
+ boards_table.add_column("", width=2)
792
+ boards_table.add_column("Board ID", style="cyan", width=15)
793
+ boards_table.add_column("Type", style="yellow", width=15)
794
+ boards_table.add_column("Members", style="white", justify="right", width=10)
795
+
796
+ for idx, board in enumerate(self.state.boards):
797
+ board_id = getattr(board, 'board_id', 'unknown')[:12]
798
+ board_type = getattr(board, 'board_type', None)
799
+ members = getattr(board, 'members', [])
800
+
801
+ if self.state.interaction_mode == InteractionMode.SELECT and idx == self.state.selected_index:
802
+ selector = ">"
803
+ row_style = "bold"
804
+ else:
805
+ selector = " "
806
+ row_style = None
807
+
808
+ type_str = str(board_type).split('.')[-1] if board_type else "Unknown"
809
+
810
+ boards_table.add_row(
811
+ selector,
812
+ Text(board_id, style=row_style) if row_style else board_id,
813
+ type_str,
814
+ str(len(members))
815
+ )
816
+
817
+ return Panel(
818
+ boards_table,
819
+ title="Boards",
820
+ border_style="blue",
821
+ box=box.ROUNDED
822
+ )
823
+
824
+ def render_dashboard(self) -> Layout:
825
+ """Render the main dashboard view."""
826
+ layout = Layout()
827
+ layout.split_column(
828
+ Layout(name="state", ratio=2),
829
+ Layout(name="vision", ratio=1),
830
+ Layout(name="policy", ratio=1)
831
+ )
832
+
833
+ layout["state"].update(self.create_state_panel())
834
+ layout["vision"].update(self.create_vision_panel())
835
+ layout["policy"].update(self.create_policy_panel())
836
+
837
+ return layout
838
+
839
+ def render(self) -> Layout:
840
+ """Render the complete TUI layout."""
841
+ layout = self.create_layout()
842
+
843
+ layout["header"].update(self.create_header())
844
+ layout["footer"].update(self.create_footer())
845
+
846
+ # Render main content based on view mode
847
+ if self.state.view_mode == ViewMode.DASHBOARD:
848
+ main_content = self.render_dashboard()
849
+ layout["left"].update(main_content["state"])
850
+ layout["right"].split_column(
851
+ Layout(main_content["vision"]),
852
+ Layout(main_content["policy"]),
853
+ Layout(self.create_status_panel()),
854
+ Layout(self.create_alerts_panel()),
855
+ Layout(self.create_history_panel())
856
+ )
857
+ elif self.state.view_mode == ViewMode.STATE:
858
+ layout["left"].update(self.create_state_panel())
859
+ layout["right"].update(
860
+ Panel(
861
+ "State Details\n\nView current economic state metrics",
862
+ border_style="dim",
863
+ box=box.ROUNDED
864
+ )
865
+ )
866
+ elif self.state.view_mode == ViewMode.POLICY:
867
+ layout["left"].update(self.create_policy_panel())
868
+ layout["right"].update(
869
+ Panel(
870
+ "Policy Management\n\nPress [N] to create new policy\nPress [C] for command mode",
871
+ border_style="dim",
872
+ box=box.ROUNDED
873
+ )
874
+ )
875
+ elif self.state.view_mode == ViewMode.VISION:
876
+ layout["left"].update(self.create_vision_panel())
877
+ layout["right"].update(
878
+ Panel(
879
+ "Vision Progress\n\nTrack progress towards vision goals",
880
+ border_style="dim",
881
+ box=box.ROUNDED
882
+ )
883
+ )
884
+ elif self.state.view_mode == ViewMode.BOARDS:
885
+ layout["left"].update(self.render_boards_view())
886
+ layout["right"].update(
887
+ Panel(
888
+ "Board Details\n\nPress [S] to select a board\nPress [Enter] to view details",
889
+ border_style="dim",
890
+ box=box.ROUNDED
891
+ )
892
+ )
893
+ elif self.state.view_mode == ViewMode.EXECUTIONS:
894
+ layout["left"].update(self.render_executions_view())
895
+ layout["right"].update(
896
+ Panel(
897
+ "Execution Details\n\nPress [S] to select an execution\nPress [Enter] to view details",
898
+ border_style="dim",
899
+ box=box.ROUNDED
900
+ )
901
+ )
902
+ elif self.state.view_mode == ViewMode.ALERTS:
903
+ layout["left"].update(self.create_alerts_panel())
904
+ layout["right"].update(
905
+ Panel(
906
+ "Alert Details\n\nView and manage system alerts",
907
+ border_style="dim",
908
+ box=box.ROUNDED
909
+ )
910
+ )
911
+ elif self.state.view_mode == ViewMode.APPROVALS:
912
+ layout["left"].update(self.render_approvals_view())
913
+ layout["right"].update(
914
+ Panel(
915
+ "Approval Management\n\nPress [S] to select\nUse commands: approve <id> or reject <id>",
916
+ border_style="dim",
917
+ box=box.ROUNDED
918
+ )
919
+ )
920
+
921
+ return layout
922
+
923
+ def update_state(
924
+ self,
925
+ current_state: Optional[StateVector] = None,
926
+ vision_progress: Optional[Dict[str, float]] = None,
927
+ vision_target: Optional[StateVector] = None,
928
+ system_status: Optional[Dict[str, Any]] = None,
929
+ execution_history: Optional[List[Dict[str, Any]]] = None,
930
+ pending_approvals: Optional[List[Dict[str, Any]]] = None,
931
+ alerts: Optional[List[Dict[str, Any]]] = None,
932
+ policy: Optional[ControlVector] = None,
933
+ boards: Optional[List[Any]] = None,
934
+ governance_system: Optional[Any] = None
935
+ ) -> None:
936
+ """
937
+ Update TUI state.
938
+
939
+ Args:
940
+ current_state: Current state vector
941
+ vision_progress: Progress towards vision
942
+ vision_target: Target vision state
943
+ system_status: System status dict
944
+ execution_history: Execution history
945
+ pending_approvals: Pending approvals
946
+ alerts: Active alerts
947
+ policy: Current policy
948
+ boards: List of boards
949
+ governance_system: Governance system instance
950
+ """
951
+ if current_state is not None:
952
+ self.state.current_state = current_state
953
+ if vision_progress is not None:
954
+ self.state.vision_progress = vision_progress
955
+ if vision_target is not None:
956
+ self.state.vision_target = vision_target
957
+ if system_status is not None:
958
+ self.state.system_status = system_status
959
+ if execution_history is not None:
960
+ self.state.execution_history = execution_history
961
+ if pending_approvals is not None:
962
+ self.state.pending_approvals = pending_approvals
963
+ if alerts is not None:
964
+ self.state.alerts = alerts
965
+ if policy is not None:
966
+ self.state.policy = policy
967
+ if boards is not None:
968
+ self.state.boards = boards
969
+ if governance_system is not None:
970
+ self.state.governance_system = governance_system
971
+
972
+ self.state.last_update = time.time()
973
+
974
+ def register_key_handler(self, key: str, handler: Callable) -> None:
975
+ """
976
+ Register a key handler.
977
+
978
+ Args:
979
+ key: Key to handle (e.g., 'q', 'Q')
980
+ handler: Callback function to call when key is pressed
981
+ """
982
+ self._key_handlers[key.lower()] = handler
983
+
984
+ def _setup_keyboard_listener(self) -> None:
985
+ """Setup keyboard listener thread."""
986
+ if sys.platform != "win32":
987
+ try:
988
+ # Save terminal settings
989
+ self._old_terminal_settings = termios.tcgetattr(sys.stdin.fileno())
990
+ tty.setcbreak(sys.stdin.fileno())
991
+ except Exception:
992
+ self._old_terminal_settings = None
993
+
994
+ self._key_queue = []
995
+ self._keyboard_thread = threading.Thread(target=self._keyboard_listener, daemon=True)
996
+ self._keyboard_thread.start()
997
+
998
+ def _keyboard_listener(self) -> None:
999
+ """Keyboard listener thread."""
1000
+ try:
1001
+ while self.is_running and not self._should_quit:
1002
+ key = self._get_key()
1003
+ if key:
1004
+ # Handle escape sequences for arrow keys
1005
+ if key == '\x1b':
1006
+ try:
1007
+ if sys.platform != "win32":
1008
+ if select.select([sys.stdin], [], [], 0.1) == ([sys.stdin], [], []):
1009
+ seq = sys.stdin.read(2)
1010
+ if seq == '[A':
1011
+ key = 'up'
1012
+ elif seq == '[B':
1013
+ key = 'down'
1014
+ elif seq == '[C':
1015
+ key = 'right'
1016
+ elif seq == '[D':
1017
+ key = 'left'
1018
+ else:
1019
+ key = 'escape'
1020
+ else:
1021
+ key = 'escape'
1022
+ else:
1023
+ key = 'escape'
1024
+ except Exception:
1025
+ key = 'escape'
1026
+
1027
+ self._key_queue.append(key)
1028
+ time.sleep(0.05)
1029
+ except Exception as e:
1030
+ logger.debug(f"Keyboard listener error: {e}")
1031
+
1032
+ def _get_key(self) -> Optional[str]:
1033
+ """Get a key press from stdin (non-blocking)."""
1034
+ if sys.platform == "win32":
1035
+ try:
1036
+ import msvcrt
1037
+ if msvcrt.kbhit():
1038
+ key = msvcrt.getch()
1039
+ if isinstance(key, bytes):
1040
+ key = key.decode('utf-8', errors='ignore')
1041
+ return key
1042
+ except Exception:
1043
+ pass
1044
+ else:
1045
+ try:
1046
+ if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
1047
+ key = sys.stdin.read(1)
1048
+ return key
1049
+ except Exception:
1050
+ pass
1051
+ return None
1052
+
1053
+ def _process_keys(self) -> None:
1054
+ """Process queued key presses."""
1055
+ if not self._key_queue:
1056
+ return
1057
+
1058
+ while self._key_queue:
1059
+ key = self._key_queue.pop(0)
1060
+
1061
+ # Handle command mode
1062
+ if self.state.interaction_mode == InteractionMode.COMMAND:
1063
+ if key == '\r' or key == '\n':
1064
+ self._activate_selected()
1065
+ elif key == '\x1b' or key == 'escape':
1066
+ self._exit_interaction()
1067
+ elif key == '\x7f' or key == '\b': # Backspace
1068
+ if self.state.current_command:
1069
+ self.state.current_command = self.state.current_command[:-1]
1070
+ elif len(key) == 1 and key.isprintable() and ord(key) >= 32:
1071
+ self.state.current_command += key
1072
+ continue
1073
+
1074
+ # Handle normal key presses
1075
+ handler = self._key_handlers.get(key)
1076
+ if handler:
1077
+ try:
1078
+ handler()
1079
+ except Exception as e:
1080
+ logger.error(f"Error handling key {key}: {e}")
1081
+
1082
+ def run_live(self, update_callback: Optional[Callable] = None, refresh_rate: float = 1.0) -> None:
1083
+ """
1084
+ Run TUI with live updates and keyboard input handling.
1085
+
1086
+ Args:
1087
+ update_callback: Callback function that updates state (called each refresh)
1088
+ refresh_rate: Refresh rate in seconds
1089
+ """
1090
+ self.is_running = True
1091
+ self._should_quit = False
1092
+ self.state.refresh_rate = refresh_rate
1093
+
1094
+ # Setup keyboard listener
1095
+ self._setup_keyboard_listener()
1096
+
1097
+ try:
1098
+ with Live(
1099
+ self.render(),
1100
+ refresh_per_second=1.0 / refresh_rate,
1101
+ screen=True
1102
+ ) as live:
1103
+ while not self._should_quit:
1104
+ # Process keyboard input
1105
+ self._process_keys()
1106
+
1107
+ # Update state via callback
1108
+ if update_callback:
1109
+ try:
1110
+ update_callback(self)
1111
+ except Exception as e:
1112
+ logger.debug(f"Error in update callback: {e}")
1113
+
1114
+ # Clear message after a delay
1115
+ if self.state.message and time.time() - self.state.last_update > 3:
1116
+ self.state.message = None
1117
+
1118
+ # Render updated layout
1119
+ live.update(self.render())
1120
+
1121
+ # Sleep briefly to avoid CPU spinning
1122
+ time.sleep(min(refresh_rate, 0.1))
1123
+ except KeyboardInterrupt:
1124
+ logger.info("Interrupted by user (Ctrl+C)")
1125
+ self._should_quit = True
1126
+ finally:
1127
+ self.is_running = False
1128
+ if sys.platform != "win32" and self._old_terminal_settings:
1129
+ try:
1130
+ termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, self._old_terminal_settings)
1131
+ except:
1132
+ pass
1133
+ self.console.clear()