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.
- .github/ISSUE_TEMPLATE/bug_report.md +65 -0
- .github/ISSUE_TEMPLATE/feature_request.md +41 -0
- .github/PULL_REQUEST_TEMPLATE.md +20 -0
- .github/workflows/publish-manual.yml +61 -0
- .github/workflows/publish.yml +64 -0
- .gitignore +214 -0
- CRCA.py +4156 -0
- LICENSE +201 -0
- MANIFEST.in +43 -0
- PKG-INFO +5035 -0
- README.md +4959 -0
- __init__.py +17 -0
- branches/CRCA-Q.py +2728 -0
- branches/crca_cg/corposwarm.py +9065 -0
- branches/crca_cg/fix_rancher_docker_creds.ps1 +155 -0
- branches/crca_cg/package.json +5 -0
- branches/crca_cg/test_bolt_integration.py +446 -0
- branches/crca_cg/test_corposwarm_comprehensive.py +773 -0
- branches/crca_cg/test_new_features.py +163 -0
- branches/crca_sd/__init__.py +149 -0
- branches/crca_sd/crca_sd_core.py +770 -0
- branches/crca_sd/crca_sd_governance.py +1325 -0
- branches/crca_sd/crca_sd_mpc.py +1130 -0
- branches/crca_sd/crca_sd_realtime.py +1844 -0
- branches/crca_sd/crca_sd_tui.py +1133 -0
- crca-1.4.0.dist-info/METADATA +5035 -0
- crca-1.4.0.dist-info/RECORD +501 -0
- crca-1.4.0.dist-info/WHEEL +4 -0
- crca-1.4.0.dist-info/licenses/LICENSE +201 -0
- docs/CRCA-Q.md +2333 -0
- examples/config.yaml.example +25 -0
- examples/crca_sd_example.py +513 -0
- examples/data_broker_example.py +294 -0
- examples/logistics_corporation.py +861 -0
- examples/palantir_example.py +299 -0
- examples/policy_bench.py +934 -0
- examples/pridnestrovia-sd.py +705 -0
- examples/pridnestrovia_realtime.py +1902 -0
- prompts/__init__.py +10 -0
- prompts/default_crca.py +101 -0
- pyproject.toml +151 -0
- requirements.txt +76 -0
- schemas/__init__.py +43 -0
- schemas/mcpSchemas.py +51 -0
- schemas/policy.py +458 -0
- templates/__init__.py +38 -0
- templates/base_specialized_agent.py +195 -0
- templates/drift_detection.py +325 -0
- templates/examples/causal_agent_template.py +309 -0
- templates/examples/drag_drop_example.py +213 -0
- templates/examples/logistics_agent_template.py +207 -0
- templates/examples/trading_agent_template.py +206 -0
- templates/feature_mixins.py +253 -0
- templates/graph_management.py +442 -0
- templates/llm_integration.py +194 -0
- templates/module_registry.py +276 -0
- templates/mpc_planner.py +280 -0
- templates/policy_loop.py +1168 -0
- templates/prediction_framework.py +448 -0
- templates/statistical_methods.py +778 -0
- tests/sanity.yml +31 -0
- tests/sanity_check +406 -0
- tests/test_core.py +47 -0
- tests/test_crca_excel.py +166 -0
- tests/test_crca_sd.py +780 -0
- tests/test_data_broker.py +424 -0
- tests/test_palantir.py +349 -0
- tools/__init__.py +38 -0
- tools/actuators.py +437 -0
- tools/bolt.diy/Dockerfile +103 -0
- tools/bolt.diy/app/components/@settings/core/AvatarDropdown.tsx +175 -0
- tools/bolt.diy/app/components/@settings/core/ControlPanel.tsx +345 -0
- tools/bolt.diy/app/components/@settings/core/constants.tsx +108 -0
- tools/bolt.diy/app/components/@settings/core/types.ts +114 -0
- tools/bolt.diy/app/components/@settings/index.ts +12 -0
- tools/bolt.diy/app/components/@settings/shared/components/TabTile.tsx +151 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionForm.tsx +193 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ConnectionTestIndicator.tsx +60 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ErrorState.tsx +102 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/LoadingState.tsx +94 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/ServiceHeader.tsx +72 -0
- tools/bolt.diy/app/components/@settings/shared/service-integration/index.ts +6 -0
- tools/bolt.diy/app/components/@settings/tabs/data/DataTab.tsx +721 -0
- tools/bolt.diy/app/components/@settings/tabs/data/DataVisualization.tsx +384 -0
- tools/bolt.diy/app/components/@settings/tabs/event-logs/EventLogsTab.tsx +1013 -0
- tools/bolt.diy/app/components/@settings/tabs/features/FeaturesTab.tsx +295 -0
- tools/bolt.diy/app/components/@settings/tabs/github/GitHubTab.tsx +281 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubAuthDialog.tsx +173 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubCacheManager.tsx +367 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubConnection.tsx +233 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubErrorBoundary.tsx +105 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubProgressiveLoader.tsx +266 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositoryCard.tsx +121 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubRepositorySelector.tsx +312 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubStats.tsx +291 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/GitHubUserProfile.tsx +46 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/GitHubStateIndicators.tsx +264 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/RepositoryCard.tsx +361 -0
- tools/bolt.diy/app/components/@settings/tabs/github/components/shared/index.ts +11 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/GitLabTab.tsx +305 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabAuthDialog.tsx +186 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabConnection.tsx +253 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/GitLabRepositorySelector.tsx +358 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryCard.tsx +79 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/RepositoryList.tsx +142 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/StatsDisplay.tsx +91 -0
- tools/bolt.diy/app/components/@settings/tabs/gitlab/components/index.ts +4 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerList.tsx +99 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpServerListItem.tsx +70 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpStatusBadge.tsx +37 -0
- tools/bolt.diy/app/components/@settings/tabs/mcp/McpTab.tsx +239 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/NetlifyTab.tsx +1393 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/components/NetlifyConnection.tsx +990 -0
- tools/bolt.diy/app/components/@settings/tabs/netlify/components/index.ts +1 -0
- tools/bolt.diy/app/components/@settings/tabs/notifications/NotificationsTab.tsx +300 -0
- tools/bolt.diy/app/components/@settings/tabs/profile/ProfileTab.tsx +181 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/cloud/CloudProvidersTab.tsx +308 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ErrorBoundary.tsx +68 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/HealthStatusBadge.tsx +64 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/LoadingSkeleton.tsx +107 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx +556 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ModelCard.tsx +106 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/ProviderCard.tsx +120 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/SetupGuide.tsx +671 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/StatusDashboard.tsx +91 -0
- tools/bolt.diy/app/components/@settings/tabs/providers/local/types.ts +44 -0
- tools/bolt.diy/app/components/@settings/tabs/settings/SettingsTab.tsx +215 -0
- tools/bolt.diy/app/components/@settings/tabs/supabase/SupabaseTab.tsx +1089 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/VercelTab.tsx +909 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/components/VercelConnection.tsx +368 -0
- tools/bolt.diy/app/components/@settings/tabs/vercel/components/index.ts +1 -0
- tools/bolt.diy/app/components/@settings/utils/tab-helpers.ts +54 -0
- tools/bolt.diy/app/components/chat/APIKeyManager.tsx +169 -0
- tools/bolt.diy/app/components/chat/Artifact.tsx +296 -0
- tools/bolt.diy/app/components/chat/AssistantMessage.tsx +192 -0
- tools/bolt.diy/app/components/chat/BaseChat.module.scss +47 -0
- tools/bolt.diy/app/components/chat/BaseChat.tsx +522 -0
- tools/bolt.diy/app/components/chat/Chat.client.tsx +670 -0
- tools/bolt.diy/app/components/chat/ChatAlert.tsx +108 -0
- tools/bolt.diy/app/components/chat/ChatBox.tsx +334 -0
- tools/bolt.diy/app/components/chat/CodeBlock.module.scss +10 -0
- tools/bolt.diy/app/components/chat/CodeBlock.tsx +85 -0
- tools/bolt.diy/app/components/chat/DicussMode.tsx +17 -0
- tools/bolt.diy/app/components/chat/ExamplePrompts.tsx +37 -0
- tools/bolt.diy/app/components/chat/FilePreview.tsx +38 -0
- tools/bolt.diy/app/components/chat/GitCloneButton.tsx +327 -0
- tools/bolt.diy/app/components/chat/ImportFolderButton.tsx +141 -0
- tools/bolt.diy/app/components/chat/LLMApiAlert.tsx +109 -0
- tools/bolt.diy/app/components/chat/MCPTools.tsx +129 -0
- tools/bolt.diy/app/components/chat/Markdown.module.scss +171 -0
- tools/bolt.diy/app/components/chat/Markdown.spec.ts +48 -0
- tools/bolt.diy/app/components/chat/Markdown.tsx +252 -0
- tools/bolt.diy/app/components/chat/Messages.client.tsx +102 -0
- tools/bolt.diy/app/components/chat/ModelSelector.tsx +797 -0
- tools/bolt.diy/app/components/chat/NetlifyDeploymentLink.client.tsx +51 -0
- tools/bolt.diy/app/components/chat/ProgressCompilation.tsx +110 -0
- tools/bolt.diy/app/components/chat/ScreenshotStateManager.tsx +33 -0
- tools/bolt.diy/app/components/chat/SendButton.client.tsx +39 -0
- tools/bolt.diy/app/components/chat/SpeechRecognition.tsx +28 -0
- tools/bolt.diy/app/components/chat/StarterTemplates.tsx +38 -0
- tools/bolt.diy/app/components/chat/SupabaseAlert.tsx +199 -0
- tools/bolt.diy/app/components/chat/SupabaseConnection.tsx +339 -0
- tools/bolt.diy/app/components/chat/ThoughtBox.tsx +43 -0
- tools/bolt.diy/app/components/chat/ToolInvocations.tsx +409 -0
- tools/bolt.diy/app/components/chat/UserMessage.tsx +101 -0
- tools/bolt.diy/app/components/chat/VercelDeploymentLink.client.tsx +158 -0
- tools/bolt.diy/app/components/chat/chatExportAndImport/ExportChatButton.tsx +49 -0
- tools/bolt.diy/app/components/chat/chatExportAndImport/ImportButtons.tsx +96 -0
- tools/bolt.diy/app/components/deploy/DeployAlert.tsx +197 -0
- tools/bolt.diy/app/components/deploy/DeployButton.tsx +277 -0
- tools/bolt.diy/app/components/deploy/GitHubDeploy.client.tsx +171 -0
- tools/bolt.diy/app/components/deploy/GitHubDeploymentDialog.tsx +1041 -0
- tools/bolt.diy/app/components/deploy/GitLabDeploy.client.tsx +171 -0
- tools/bolt.diy/app/components/deploy/GitLabDeploymentDialog.tsx +764 -0
- tools/bolt.diy/app/components/deploy/NetlifyDeploy.client.tsx +246 -0
- tools/bolt.diy/app/components/deploy/VercelDeploy.client.tsx +235 -0
- tools/bolt.diy/app/components/editor/codemirror/BinaryContent.tsx +7 -0
- tools/bolt.diy/app/components/editor/codemirror/CodeMirrorEditor.tsx +555 -0
- tools/bolt.diy/app/components/editor/codemirror/EnvMasking.ts +80 -0
- tools/bolt.diy/app/components/editor/codemirror/cm-theme.ts +192 -0
- tools/bolt.diy/app/components/editor/codemirror/indent.ts +68 -0
- tools/bolt.diy/app/components/editor/codemirror/languages.ts +112 -0
- tools/bolt.diy/app/components/git/GitUrlImport.client.tsx +147 -0
- tools/bolt.diy/app/components/header/Header.tsx +42 -0
- tools/bolt.diy/app/components/header/HeaderActionButtons.client.tsx +54 -0
- tools/bolt.diy/app/components/mandate/MandateSubmission.tsx +167 -0
- tools/bolt.diy/app/components/observability/DeploymentStatus.tsx +168 -0
- tools/bolt.diy/app/components/observability/EventTimeline.tsx +119 -0
- tools/bolt.diy/app/components/observability/FileDiffViewer.tsx +121 -0
- tools/bolt.diy/app/components/observability/GovernanceStatus.tsx +197 -0
- tools/bolt.diy/app/components/observability/GovernorMetrics.tsx +246 -0
- tools/bolt.diy/app/components/observability/LogStream.tsx +244 -0
- tools/bolt.diy/app/components/observability/MandateDetails.tsx +201 -0
- tools/bolt.diy/app/components/observability/ObservabilityDashboard.tsx +200 -0
- tools/bolt.diy/app/components/sidebar/HistoryItem.tsx +187 -0
- tools/bolt.diy/app/components/sidebar/Menu.client.tsx +536 -0
- tools/bolt.diy/app/components/sidebar/date-binning.ts +59 -0
- tools/bolt.diy/app/components/txt +1 -0
- tools/bolt.diy/app/components/ui/BackgroundRays/index.tsx +18 -0
- tools/bolt.diy/app/components/ui/BackgroundRays/styles.module.scss +246 -0
- tools/bolt.diy/app/components/ui/Badge.tsx +53 -0
- tools/bolt.diy/app/components/ui/BranchSelector.tsx +270 -0
- tools/bolt.diy/app/components/ui/Breadcrumbs.tsx +101 -0
- tools/bolt.diy/app/components/ui/Button.tsx +46 -0
- tools/bolt.diy/app/components/ui/Card.tsx +55 -0
- tools/bolt.diy/app/components/ui/Checkbox.tsx +32 -0
- tools/bolt.diy/app/components/ui/CloseButton.tsx +49 -0
- tools/bolt.diy/app/components/ui/CodeBlock.tsx +103 -0
- tools/bolt.diy/app/components/ui/Collapsible.tsx +9 -0
- tools/bolt.diy/app/components/ui/ColorSchemeDialog.tsx +378 -0
- tools/bolt.diy/app/components/ui/Dialog.tsx +449 -0
- tools/bolt.diy/app/components/ui/Dropdown.tsx +63 -0
- tools/bolt.diy/app/components/ui/EmptyState.tsx +154 -0
- tools/bolt.diy/app/components/ui/FileIcon.tsx +346 -0
- tools/bolt.diy/app/components/ui/FilterChip.tsx +92 -0
- tools/bolt.diy/app/components/ui/GlowingEffect.tsx +192 -0
- tools/bolt.diy/app/components/ui/GradientCard.tsx +100 -0
- tools/bolt.diy/app/components/ui/IconButton.tsx +84 -0
- tools/bolt.diy/app/components/ui/Input.tsx +22 -0
- tools/bolt.diy/app/components/ui/Label.tsx +20 -0
- tools/bolt.diy/app/components/ui/LoadingDots.tsx +27 -0
- tools/bolt.diy/app/components/ui/LoadingOverlay.tsx +32 -0
- tools/bolt.diy/app/components/ui/PanelHeader.tsx +20 -0
- tools/bolt.diy/app/components/ui/PanelHeaderButton.tsx +36 -0
- tools/bolt.diy/app/components/ui/Popover.tsx +29 -0
- tools/bolt.diy/app/components/ui/Progress.tsx +22 -0
- tools/bolt.diy/app/components/ui/RepositoryStats.tsx +87 -0
- tools/bolt.diy/app/components/ui/ScrollArea.tsx +41 -0
- tools/bolt.diy/app/components/ui/SearchInput.tsx +80 -0
- tools/bolt.diy/app/components/ui/SearchResultItem.tsx +134 -0
- tools/bolt.diy/app/components/ui/Separator.tsx +22 -0
- tools/bolt.diy/app/components/ui/SettingsButton.tsx +35 -0
- tools/bolt.diy/app/components/ui/Slider.tsx +73 -0
- tools/bolt.diy/app/components/ui/StatusIndicator.tsx +90 -0
- tools/bolt.diy/app/components/ui/Switch.tsx +37 -0
- tools/bolt.diy/app/components/ui/Tabs.tsx +52 -0
- tools/bolt.diy/app/components/ui/TabsWithSlider.tsx +112 -0
- tools/bolt.diy/app/components/ui/ThemeSwitch.tsx +29 -0
- tools/bolt.diy/app/components/ui/Tooltip.tsx +122 -0
- tools/bolt.diy/app/components/ui/index.ts +38 -0
- tools/bolt.diy/app/components/ui/use-toast.ts +66 -0
- tools/bolt.diy/app/components/workbench/DiffView.tsx +796 -0
- tools/bolt.diy/app/components/workbench/EditorPanel.tsx +174 -0
- tools/bolt.diy/app/components/workbench/ExpoQrModal.tsx +55 -0
- tools/bolt.diy/app/components/workbench/FileBreadcrumb.tsx +150 -0
- tools/bolt.diy/app/components/workbench/FileTree.tsx +565 -0
- tools/bolt.diy/app/components/workbench/Inspector.tsx +126 -0
- tools/bolt.diy/app/components/workbench/InspectorPanel.tsx +146 -0
- tools/bolt.diy/app/components/workbench/LockManager.tsx +262 -0
- tools/bolt.diy/app/components/workbench/PortDropdown.tsx +91 -0
- tools/bolt.diy/app/components/workbench/Preview.tsx +1049 -0
- tools/bolt.diy/app/components/workbench/ScreenshotSelector.tsx +293 -0
- tools/bolt.diy/app/components/workbench/Search.tsx +257 -0
- tools/bolt.diy/app/components/workbench/Workbench.client.tsx +506 -0
- tools/bolt.diy/app/components/workbench/terminal/Terminal.tsx +131 -0
- tools/bolt.diy/app/components/workbench/terminal/TerminalManager.tsx +68 -0
- tools/bolt.diy/app/components/workbench/terminal/TerminalTabs.tsx +277 -0
- tools/bolt.diy/app/components/workbench/terminal/theme.ts +36 -0
- tools/bolt.diy/app/components/workflow/WorkflowPhase.tsx +109 -0
- tools/bolt.diy/app/components/workflow/WorkflowStatus.tsx +60 -0
- tools/bolt.diy/app/components/workflow/WorkflowTimeline.tsx +150 -0
- tools/bolt.diy/app/entry.client.tsx +7 -0
- tools/bolt.diy/app/entry.server.tsx +80 -0
- tools/bolt.diy/app/root.tsx +156 -0
- tools/bolt.diy/app/routes/_index.tsx +175 -0
- tools/bolt.diy/app/routes/api.bug-report.ts +254 -0
- tools/bolt.diy/app/routes/api.chat.ts +463 -0
- tools/bolt.diy/app/routes/api.check-env-key.ts +41 -0
- tools/bolt.diy/app/routes/api.configured-providers.ts +110 -0
- tools/bolt.diy/app/routes/api.corporate-swarm-status.ts +55 -0
- tools/bolt.diy/app/routes/api.enhancer.ts +137 -0
- tools/bolt.diy/app/routes/api.export-api-keys.ts +44 -0
- tools/bolt.diy/app/routes/api.git-info.ts +69 -0
- tools/bolt.diy/app/routes/api.git-proxy.$.ts +178 -0
- tools/bolt.diy/app/routes/api.github-branches.ts +166 -0
- tools/bolt.diy/app/routes/api.github-deploy.ts +67 -0
- tools/bolt.diy/app/routes/api.github-stats.ts +198 -0
- tools/bolt.diy/app/routes/api.github-template.ts +242 -0
- tools/bolt.diy/app/routes/api.github-user.ts +287 -0
- tools/bolt.diy/app/routes/api.gitlab-branches.ts +143 -0
- tools/bolt.diy/app/routes/api.gitlab-deploy.ts +67 -0
- tools/bolt.diy/app/routes/api.gitlab-projects.ts +105 -0
- tools/bolt.diy/app/routes/api.health.ts +8 -0
- tools/bolt.diy/app/routes/api.llmcall.ts +298 -0
- tools/bolt.diy/app/routes/api.mandate.ts +351 -0
- tools/bolt.diy/app/routes/api.mcp-check.ts +16 -0
- tools/bolt.diy/app/routes/api.mcp-update-config.ts +23 -0
- tools/bolt.diy/app/routes/api.models.$provider.ts +2 -0
- tools/bolt.diy/app/routes/api.models.ts +90 -0
- tools/bolt.diy/app/routes/api.netlify-deploy.ts +240 -0
- tools/bolt.diy/app/routes/api.netlify-user.ts +142 -0
- tools/bolt.diy/app/routes/api.supabase-user.ts +199 -0
- tools/bolt.diy/app/routes/api.supabase.query.ts +92 -0
- tools/bolt.diy/app/routes/api.supabase.ts +56 -0
- tools/bolt.diy/app/routes/api.supabase.variables.ts +32 -0
- tools/bolt.diy/app/routes/api.system.diagnostics.ts +142 -0
- tools/bolt.diy/app/routes/api.system.disk-info.ts +311 -0
- tools/bolt.diy/app/routes/api.system.git-info.ts +332 -0
- tools/bolt.diy/app/routes/api.update.ts +21 -0
- tools/bolt.diy/app/routes/api.vercel-deploy.ts +497 -0
- tools/bolt.diy/app/routes/api.vercel-user.ts +161 -0
- tools/bolt.diy/app/routes/api.workflow-status.$proposalId.ts +309 -0
- tools/bolt.diy/app/routes/chat.$id.tsx +8 -0
- tools/bolt.diy/app/routes/execute.$mandateId.tsx +432 -0
- tools/bolt.diy/app/routes/git.tsx +25 -0
- tools/bolt.diy/app/routes/observability.$mandateId.tsx +50 -0
- tools/bolt.diy/app/routes/webcontainer.connect.$id.tsx +32 -0
- tools/bolt.diy/app/routes/webcontainer.preview.$id.tsx +97 -0
- tools/bolt.diy/app/routes/workflow.$proposalId.tsx +170 -0
- tools/bolt.diy/app/styles/animations.scss +49 -0
- tools/bolt.diy/app/styles/components/code.scss +9 -0
- tools/bolt.diy/app/styles/components/editor.scss +135 -0
- tools/bolt.diy/app/styles/components/resize-handle.scss +30 -0
- tools/bolt.diy/app/styles/components/terminal.scss +3 -0
- tools/bolt.diy/app/styles/components/toast.scss +23 -0
- tools/bolt.diy/app/styles/diff-view.css +72 -0
- tools/bolt.diy/app/styles/index.scss +73 -0
- tools/bolt.diy/app/styles/variables.scss +255 -0
- tools/bolt.diy/app/styles/z-index.scss +37 -0
- tools/bolt.diy/app/types/GitHub.ts +182 -0
- tools/bolt.diy/app/types/GitLab.ts +103 -0
- tools/bolt.diy/app/types/actions.ts +85 -0
- tools/bolt.diy/app/types/artifact.ts +5 -0
- tools/bolt.diy/app/types/context.ts +26 -0
- tools/bolt.diy/app/types/design-scheme.ts +93 -0
- tools/bolt.diy/app/types/global.d.ts +13 -0
- tools/bolt.diy/app/types/mandate.ts +333 -0
- tools/bolt.diy/app/types/model.ts +25 -0
- tools/bolt.diy/app/types/netlify.ts +94 -0
- tools/bolt.diy/app/types/supabase.ts +54 -0
- tools/bolt.diy/app/types/template.ts +8 -0
- tools/bolt.diy/app/types/terminal.ts +9 -0
- tools/bolt.diy/app/types/theme.ts +1 -0
- tools/bolt.diy/app/types/vercel.ts +67 -0
- tools/bolt.diy/app/utils/buffer.ts +29 -0
- tools/bolt.diy/app/utils/classNames.ts +65 -0
- tools/bolt.diy/app/utils/constants.ts +147 -0
- tools/bolt.diy/app/utils/debounce.ts +13 -0
- tools/bolt.diy/app/utils/debugLogger.ts +1284 -0
- tools/bolt.diy/app/utils/diff.spec.ts +11 -0
- tools/bolt.diy/app/utils/diff.ts +117 -0
- tools/bolt.diy/app/utils/easings.ts +3 -0
- tools/bolt.diy/app/utils/fileLocks.ts +96 -0
- tools/bolt.diy/app/utils/fileUtils.ts +121 -0
- tools/bolt.diy/app/utils/folderImport.ts +73 -0
- tools/bolt.diy/app/utils/formatSize.ts +12 -0
- tools/bolt.diy/app/utils/getLanguageFromExtension.ts +24 -0
- tools/bolt.diy/app/utils/githubStats.ts +9 -0
- tools/bolt.diy/app/utils/gitlabStats.ts +54 -0
- tools/bolt.diy/app/utils/logger.ts +162 -0
- tools/bolt.diy/app/utils/markdown.ts +155 -0
- tools/bolt.diy/app/utils/mobile.ts +4 -0
- tools/bolt.diy/app/utils/os.ts +4 -0
- tools/bolt.diy/app/utils/path.ts +19 -0
- tools/bolt.diy/app/utils/projectCommands.ts +197 -0
- tools/bolt.diy/app/utils/promises.ts +19 -0
- tools/bolt.diy/app/utils/react.ts +6 -0
- tools/bolt.diy/app/utils/sampler.ts +49 -0
- tools/bolt.diy/app/utils/selectStarterTemplate.ts +255 -0
- tools/bolt.diy/app/utils/shell.ts +384 -0
- tools/bolt.diy/app/utils/stacktrace.ts +27 -0
- tools/bolt.diy/app/utils/stripIndent.ts +23 -0
- tools/bolt.diy/app/utils/terminal.ts +11 -0
- tools/bolt.diy/app/utils/unreachable.ts +3 -0
- tools/bolt.diy/app/vite-env.d.ts +2 -0
- tools/bolt.diy/assets/entitlements.mac.plist +25 -0
- tools/bolt.diy/assets/icons/icon.icns +0 -0
- tools/bolt.diy/assets/icons/icon.ico +0 -0
- tools/bolt.diy/assets/icons/icon.png +0 -0
- tools/bolt.diy/bindings.js +78 -0
- tools/bolt.diy/bindings.sh +33 -0
- tools/bolt.diy/docker-compose.yaml +145 -0
- tools/bolt.diy/electron/main/index.ts +201 -0
- tools/bolt.diy/electron/main/tsconfig.json +30 -0
- tools/bolt.diy/electron/main/ui/menu.ts +29 -0
- tools/bolt.diy/electron/main/ui/window.ts +54 -0
- tools/bolt.diy/electron/main/utils/auto-update.ts +110 -0
- tools/bolt.diy/electron/main/utils/constants.ts +4 -0
- tools/bolt.diy/electron/main/utils/cookie.ts +40 -0
- tools/bolt.diy/electron/main/utils/reload.ts +35 -0
- tools/bolt.diy/electron/main/utils/serve.ts +71 -0
- tools/bolt.diy/electron/main/utils/store.ts +3 -0
- tools/bolt.diy/electron/main/utils/vite-server.ts +44 -0
- tools/bolt.diy/electron/main/vite.config.ts +44 -0
- tools/bolt.diy/electron/preload/index.ts +22 -0
- tools/bolt.diy/electron/preload/tsconfig.json +7 -0
- tools/bolt.diy/electron/preload/vite.config.ts +31 -0
- tools/bolt.diy/electron-builder.yml +64 -0
- tools/bolt.diy/electron-update.yml +4 -0
- tools/bolt.diy/eslint.config.mjs +57 -0
- tools/bolt.diy/functions/[[path]].ts +12 -0
- tools/bolt.diy/icons/angular.svg +1 -0
- tools/bolt.diy/icons/astro.svg +8 -0
- tools/bolt.diy/icons/chat.svg +1 -0
- tools/bolt.diy/icons/expo-brand.svg +1 -0
- tools/bolt.diy/icons/expo.svg +4 -0
- tools/bolt.diy/icons/logo-text.svg +1 -0
- tools/bolt.diy/icons/logo.svg +4 -0
- tools/bolt.diy/icons/mcp.svg +1 -0
- tools/bolt.diy/icons/nativescript.svg +1 -0
- tools/bolt.diy/icons/netlify.svg +10 -0
- tools/bolt.diy/icons/nextjs.svg +1 -0
- tools/bolt.diy/icons/nuxt.svg +1 -0
- tools/bolt.diy/icons/qwik.svg +1 -0
- tools/bolt.diy/icons/react.svg +1 -0
- tools/bolt.diy/icons/remix.svg +24 -0
- tools/bolt.diy/icons/remotion.svg +1 -0
- tools/bolt.diy/icons/shadcn.svg +21 -0
- tools/bolt.diy/icons/slidev.svg +60 -0
- tools/bolt.diy/icons/solidjs.svg +1 -0
- tools/bolt.diy/icons/stars.svg +1 -0
- tools/bolt.diy/icons/svelte.svg +1 -0
- tools/bolt.diy/icons/typescript.svg +1 -0
- tools/bolt.diy/icons/vite.svg +1 -0
- tools/bolt.diy/icons/vue.svg +1 -0
- tools/bolt.diy/load-context.ts +9 -0
- tools/bolt.diy/notarize.cjs +31 -0
- tools/bolt.diy/package.json +218 -0
- tools/bolt.diy/playwright.config.preview.ts +35 -0
- tools/bolt.diy/pre-start.cjs +26 -0
- tools/bolt.diy/public/apple-touch-icon-precomposed.png +0 -0
- tools/bolt.diy/public/apple-touch-icon.png +0 -0
- tools/bolt.diy/public/favicon.ico +0 -0
- tools/bolt.diy/public/favicon.svg +4 -0
- tools/bolt.diy/public/icons/AmazonBedrock.svg +1 -0
- tools/bolt.diy/public/icons/Anthropic.svg +4 -0
- tools/bolt.diy/public/icons/Cohere.svg +4 -0
- tools/bolt.diy/public/icons/Deepseek.svg +5 -0
- tools/bolt.diy/public/icons/Default.svg +4 -0
- tools/bolt.diy/public/icons/Google.svg +4 -0
- tools/bolt.diy/public/icons/Groq.svg +4 -0
- tools/bolt.diy/public/icons/HuggingFace.svg +4 -0
- tools/bolt.diy/public/icons/Hyperbolic.svg +3 -0
- tools/bolt.diy/public/icons/LMStudio.svg +5 -0
- tools/bolt.diy/public/icons/Mistral.svg +4 -0
- tools/bolt.diy/public/icons/Ollama.svg +4 -0
- tools/bolt.diy/public/icons/OpenAI.svg +4 -0
- tools/bolt.diy/public/icons/OpenAILike.svg +4 -0
- tools/bolt.diy/public/icons/OpenRouter.svg +4 -0
- tools/bolt.diy/public/icons/Perplexity.svg +4 -0
- tools/bolt.diy/public/icons/Together.svg +4 -0
- tools/bolt.diy/public/icons/xAI.svg +5 -0
- tools/bolt.diy/public/inspector-script.js +292 -0
- tools/bolt.diy/public/logo-dark-styled.png +0 -0
- tools/bolt.diy/public/logo-dark.png +0 -0
- tools/bolt.diy/public/logo-light-styled.png +0 -0
- tools/bolt.diy/public/logo-light.png +0 -0
- tools/bolt.diy/public/logo.svg +15 -0
- tools/bolt.diy/public/social_preview_index.jpg +0 -0
- tools/bolt.diy/scripts/clean.js +45 -0
- tools/bolt.diy/scripts/electron-dev.mjs +181 -0
- tools/bolt.diy/scripts/setup-env.sh +41 -0
- tools/bolt.diy/scripts/update-imports.sh +7 -0
- tools/bolt.diy/scripts/update.sh +52 -0
- tools/bolt.diy/services/execution-governor/Dockerfile +41 -0
- tools/bolt.diy/services/execution-governor/config.ts +42 -0
- tools/bolt.diy/services/execution-governor/index.ts +683 -0
- tools/bolt.diy/services/execution-governor/metrics.ts +141 -0
- tools/bolt.diy/services/execution-governor/package.json +31 -0
- tools/bolt.diy/services/execution-governor/priority-queue.ts +139 -0
- tools/bolt.diy/services/execution-governor/tsconfig.json +21 -0
- tools/bolt.diy/services/execution-governor/types.ts +145 -0
- tools/bolt.diy/services/headless-executor/Dockerfile +43 -0
- tools/bolt.diy/services/headless-executor/executor.ts +210 -0
- tools/bolt.diy/services/headless-executor/index.ts +323 -0
- tools/bolt.diy/services/headless-executor/package.json +27 -0
- tools/bolt.diy/services/headless-executor/tsconfig.json +21 -0
- tools/bolt.diy/services/headless-executor/types.ts +38 -0
- tools/bolt.diy/test-workflows.sh +240 -0
- tools/bolt.diy/tests/integration/corporate-swarm.test.ts +208 -0
- tools/bolt.diy/tests/mandates/budget-limited.json +34 -0
- tools/bolt.diy/tests/mandates/complex.json +53 -0
- tools/bolt.diy/tests/mandates/constraint-enforced.json +36 -0
- tools/bolt.diy/tests/mandates/simple.json +35 -0
- tools/bolt.diy/tsconfig.json +37 -0
- tools/bolt.diy/types/istextorbinary.d.ts +15 -0
- tools/bolt.diy/uno.config.ts +279 -0
- tools/bolt.diy/vite-electron.config.ts +76 -0
- tools/bolt.diy/vite.config.ts +112 -0
- tools/bolt.diy/worker-configuration.d.ts +22 -0
- tools/bolt.diy/wrangler.toml +6 -0
- tools/code_generator.py +461 -0
- tools/file_operations.py +465 -0
- tools/mandate_generator.py +337 -0
- tools/mcpClientUtils.py +1216 -0
- tools/sensors.py +285 -0
- utils/Agent_types.py +15 -0
- utils/AnyToStr.py +0 -0
- utils/HHCS.py +277 -0
- utils/__init__.py +30 -0
- utils/agent.py +3627 -0
- utils/aop.py +2948 -0
- utils/canonical.py +143 -0
- utils/conversation.py +1195 -0
- utils/doctrine_versioning +230 -0
- utils/formatter.py +474 -0
- utils/ledger.py +311 -0
- utils/out_types.py +16 -0
- utils/rollback.py +339 -0
- utils/router.py +929 -0
- 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()
|