iCode-TUI 0.29.1__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.
- chrys/__init__.py +16 -0
- chrys/app/__init__.py +3 -0
- chrys/app/acp/__init__.py +3 -0
- chrys/app/acp/bridge.py +664 -0
- chrys/app/acp/content.py +132 -0
- chrys/app/acp/doc/frontend-api.md +425 -0
- chrys/app/acp/history.py +585 -0
- chrys/app/acp/server.py +1796 -0
- chrys/app/acp/session_manager.py +1815 -0
- chrys/app/acp/tool_status.py +45 -0
- chrys/app/cli/__init__.py +3 -0
- chrys/app/cli/acp.py +178 -0
- chrys/app/cli/app.py +165 -0
- chrys/app/cli/approvals.py +101 -0
- chrys/app/cli/headless.py +223 -0
- chrys/app/cli/launch_cwd.py +42 -0
- chrys/app/cli/profiles.py +298 -0
- chrys/app/cli/progress.py +857 -0
- chrys/app/cli/run.py +425 -0
- chrys/app/cli/serve.py +1593 -0
- chrys/app/cli/tool_summary.py +225 -0
- chrys/app/cli/trajectory.py +201 -0
- chrys/app/cli/workflow.py +601 -0
- chrys/app/features/__init__.py +3 -0
- chrys/app/features/buddy/__init__.py +3 -0
- chrys/app/features/buddy/actions.py +68 -0
- chrys/app/features/buddy/animation.py +76 -0
- chrys/app/features/buddy/commands.py +196 -0
- chrys/app/features/buddy/docs/design.md +187 -0
- chrys/app/features/buddy/hatchery.py +80 -0
- chrys/app/features/buddy/lifecycle.py +41 -0
- chrys/app/features/buddy/model.py +265 -0
- chrys/app/features/buddy/pixel_renderer.py +113 -0
- chrys/app/features/buddy/pixel_sprites.py +279 -0
- chrys/app/features/buddy/portrait.py +76 -0
- chrys/app/features/buddy/progression.py +58 -0
- chrys/app/features/buddy/replies.py +191 -0
- chrys/app/features/buddy/sprites/alien.toml +70 -0
- chrys/app/features/buddy/sprites/axolotl.toml +71 -0
- chrys/app/features/buddy/sprites/bat.toml +69 -0
- chrys/app/features/buddy/sprites/bee.toml +69 -0
- chrys/app/features/buddy/sprites/cactus.toml +73 -0
- chrys/app/features/buddy/sprites/capybara.toml +70 -0
- chrys/app/features/buddy/sprites/cat.toml +69 -0
- chrys/app/features/buddy/sprites/crab.toml +70 -0
- chrys/app/features/buddy/sprites/dragon.toml +71 -0
- chrys/app/features/buddy/sprites/duck.toml +69 -0
- chrys/app/features/buddy/sprites/fox.toml +69 -0
- chrys/app/features/buddy/sprites/frog.toml +70 -0
- chrys/app/features/buddy/sprites/ghost.toml +70 -0
- chrys/app/features/buddy/sprites/goose.toml +69 -0
- chrys/app/features/buddy/sprites/jelly.toml +70 -0
- chrys/app/features/buddy/sprites/llama.toml +70 -0
- chrys/app/features/buddy/sprites/mushroom.toml +69 -0
- chrys/app/features/buddy/sprites/octopus.toml +70 -0
- chrys/app/features/buddy/sprites/owl.toml +70 -0
- chrys/app/features/buddy/sprites/panda.toml +71 -0
- chrys/app/features/buddy/sprites/penguin.toml +69 -0
- chrys/app/features/buddy/sprites/rabbit.toml +70 -0
- chrys/app/features/buddy/sprites/robot.toml +72 -0
- chrys/app/features/buddy/sprites/shark.toml +70 -0
- chrys/app/features/buddy/sprites/snail.toml +69 -0
- chrys/app/features/buddy/sprites/snake.toml +69 -0
- chrys/app/features/buddy/sprites/tabby.toml +69 -0
- chrys/app/features/buddy/sprites/turtle.toml +69 -0
- chrys/app/features/buddy/store.py +143 -0
- chrys/app/features/session_title/__init__.py +7 -0
- chrys/app/features/session_title/updater.py +582 -0
- chrys/app/installer.py +651 -0
- chrys/app/parsing.py +17 -0
- chrys/app/tui/__init__.py +3 -0
- chrys/app/tui/app.py +1287 -0
- chrys/app/tui/behaviors/__init__.py +3 -0
- chrys/app/tui/behaviors/click_outside_dismiss.py +90 -0
- chrys/app/tui/behaviors/insert_clipboard.py +73 -0
- chrys/app/tui/behaviors/right_click_copy.py +146 -0
- chrys/app/tui/binding_display.py +139 -0
- chrys/app/tui/buddy_messages.py +17 -0
- chrys/app/tui/buddy_reply.py +86 -0
- chrys/app/tui/chrys.tcss +549 -0
- chrys/app/tui/clipboard.py +109 -0
- chrys/app/tui/copy_messages.py +10 -0
- chrys/app/tui/i18n.py +230 -0
- chrys/app/tui/language.py +58 -0
- chrys/app/tui/notifications/__init__.py +12 -0
- chrys/app/tui/notifications/drivers.py +180 -0
- chrys/app/tui/notifications/service.py +126 -0
- chrys/app/tui/notifications/settings.py +141 -0
- chrys/app/tui/screens/__init__.py +3 -0
- chrys/app/tui/screens/agents/__init__.py +8 -0
- chrys/app/tui/screens/agents/agent_draft_store.py +937 -0
- chrys/app/tui/screens/agents/config.py +2142 -0
- chrys/app/tui/screens/agents/config.tcss +169 -0
- chrys/app/tui/screens/agents/panels/__init__.py +3 -0
- chrys/app/tui/screens/agents/panels/acp.py +1176 -0
- chrys/app/tui/screens/agents/panels/basic.py +497 -0
- chrys/app/tui/screens/agents/panels/compaction.py +231 -0
- chrys/app/tui/screens/agents/panels/config_card.py +218 -0
- chrys/app/tui/screens/agents/panels/instructions.py +91 -0
- chrys/app/tui/screens/agents/panels/markdown_report.py +76 -0
- chrys/app/tui/screens/agents/panels/mcp.py +2262 -0
- chrys/app/tui/screens/agents/panels/memory.py +684 -0
- chrys/app/tui/screens/agents/panels/path_entry.py +227 -0
- chrys/app/tui/screens/agents/panels/skills.py +806 -0
- chrys/app/tui/screens/agents/panels/subagents.py +652 -0
- chrys/app/tui/screens/agents/panels/tools.py +205 -0
- chrys/app/tui/screens/agents/picker.py +103 -0
- chrys/app/tui/screens/agents/skill_paths.py +38 -0
- chrys/app/tui/screens/agents/validation_messages.py +452 -0
- chrys/app/tui/screens/dialogs/__init__.py +35 -0
- chrys/app/tui/screens/dialogs/agent_load.py +834 -0
- chrys/app/tui/screens/dialogs/agent_load.tcss +78 -0
- chrys/app/tui/screens/dialogs/app_mode.py +55 -0
- chrys/app/tui/screens/dialogs/approval/__init__.py +15 -0
- chrys/app/tui/screens/dialogs/approval/approval.tcss +311 -0
- chrys/app/tui/screens/dialogs/approval/bodies/__init__.py +3 -0
- chrys/app/tui/screens/dialogs/approval/bodies/file_edit.py +210 -0
- chrys/app/tui/screens/dialogs/approval/bodies/sub_agent.py +82 -0
- chrys/app/tui/screens/dialogs/approval/body.py +110 -0
- chrys/app/tui/screens/dialogs/approval/dialog.py +565 -0
- chrys/app/tui/screens/dialogs/approval/mode.py +105 -0
- chrys/app/tui/screens/dialogs/ask_user.py +148 -0
- chrys/app/tui/screens/dialogs/ask_user.tcss +62 -0
- chrys/app/tui/screens/dialogs/base.py +84 -0
- chrys/app/tui/screens/dialogs/confirm.py +184 -0
- chrys/app/tui/screens/dialogs/confirm.tcss +46 -0
- chrys/app/tui/screens/dialogs/connection_test.py +183 -0
- chrys/app/tui/screens/dialogs/connection_test.tcss +92 -0
- chrys/app/tui/screens/dialogs/diagram.py +102 -0
- chrys/app/tui/screens/dialogs/diagram.tcss +24 -0
- chrys/app/tui/screens/dialogs/editor.py +378 -0
- chrys/app/tui/screens/dialogs/editor.tcss +132 -0
- chrys/app/tui/screens/dialogs/file_picker.py +582 -0
- chrys/app/tui/screens/dialogs/file_picker.tcss +78 -0
- chrys/app/tui/screens/dialogs/fork_session.py +219 -0
- chrys/app/tui/screens/dialogs/fork_session.tcss +75 -0
- chrys/app/tui/screens/dialogs/image_compression.py +102 -0
- chrys/app/tui/screens/dialogs/image_compression.tcss +28 -0
- chrys/app/tui/screens/dialogs/man_page.py +172 -0
- chrys/app/tui/screens/dialogs/man_page.tcss +39 -0
- chrys/app/tui/screens/dialogs/new_folder.py +277 -0
- chrys/app/tui/screens/dialogs/new_folder.tcss +51 -0
- chrys/app/tui/screens/dialogs/notice.tcss +14 -0
- chrys/app/tui/screens/dialogs/prompt_cache.py +144 -0
- chrys/app/tui/screens/dialogs/prompt_cache.tcss +38 -0
- chrys/app/tui/screens/dialogs/runtime_details.py +371 -0
- chrys/app/tui/screens/dialogs/runtime_details.tcss +49 -0
- chrys/app/tui/screens/dialogs/session_title.py +110 -0
- chrys/app/tui/screens/dialogs/session_title.tcss +43 -0
- chrys/app/tui/screens/dialogs/tool_view.py +207 -0
- chrys/app/tui/screens/dialogs/tool_view.tcss +43 -0
- chrys/app/tui/screens/dialogs/vision_unsupported.py +122 -0
- chrys/app/tui/screens/dialogs/vision_unsupported.tcss +35 -0
- chrys/app/tui/screens/dialogs/workflow_confirm.py +91 -0
- chrys/app/tui/screens/dialogs/workflow_confirm.tcss +17 -0
- chrys/app/tui/screens/dialogs/workflow_input.py +258 -0
- chrys/app/tui/screens/dialogs/workflow_input.tcss +73 -0
- chrys/app/tui/screens/dialogs/workflow_node.py +462 -0
- chrys/app/tui/screens/dialogs/workflow_node.tcss +41 -0
- chrys/app/tui/screens/dialogs/workflow_picker.py +46 -0
- chrys/app/tui/screens/dialogs/workflow_result.py +136 -0
- chrys/app/tui/screens/dialogs/workflow_result.tcss +14 -0
- chrys/app/tui/screens/diff/__init__.py +22 -0
- chrys/app/tui/screens/diff/rollback_modal.py +1381 -0
- chrys/app/tui/screens/diff/rollback_modal.tcss +248 -0
- chrys/app/tui/screens/diff/screen.py +1532 -0
- chrys/app/tui/screens/diff/screen.tcss +104 -0
- chrys/app/tui/screens/guides/__init__.py +7 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/agents.md +178 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/approval.md +117 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/chat-options.md +276 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/compaction.md +42 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/memory.md +48 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/models.md +158 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/settings.md +210 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/themes.md +61 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/tools.md +60 -0
- chrys/app/tui/screens/guides/_docs/en/guides/configuration/web-tools.md +286 -0
- chrys/app/tui/screens/guides/_docs/en/guides/daily-use/sessions.md +77 -0
- chrys/app/tui/screens/guides/_docs/en/guides/daily-use/workspaces.md +51 -0
- chrys/app/tui/screens/guides/_docs/en/guides/extensions/external-acp-agents.md +126 -0
- chrys/app/tui/screens/guides/_docs/en/guides/extensions/hooks.md +167 -0
- chrys/app/tui/screens/guides/_docs/en/guides/extensions/mcp.md +95 -0
- chrys/app/tui/screens/guides/_docs/en/guides/extensions/skills.md +175 -0
- chrys/app/tui/screens/guides/_docs/en/guides/running/icode-acp.md +61 -0
- chrys/app/tui/screens/guides/_docs/en/guides/running/icode-run.md +190 -0
- chrys/app/tui/screens/guides/_docs/en/guides/running/icode-serve.md +239 -0
- chrys/app/tui/screens/guides/_docs/en/guides/running/workflows.md +664 -0
- chrys/app/tui/screens/guides/_docs/en/reference/agent-profile.md +548 -0
- chrys/app/tui/screens/guides/_docs/en/reference/hooks.md +602 -0
- chrys/app/tui/screens/guides/_docs/en/reference/opentelemetry.md +177 -0
- chrys/app/tui/screens/guides/_docs/en/reference/settings.md +245 -0
- chrys/app/tui/screens/guides/_docs/en/reference/themes.md +149 -0
- chrys/app/tui/screens/guides/_docs/en/reference/tool-kinds-and-names.md +58 -0
- chrys/app/tui/screens/guides/_docs/en/reference/tui-slash-commands.md +76 -0
- chrys/app/tui/screens/guides/_docs/en/reference/workflows.md +1006 -0
- chrys/app/tui/screens/guides/_docs/en/start/getting-started.md +170 -0
- chrys/app/tui/screens/guides/_docs/en/start/what-is-icode.md +34 -0
- chrys/app/tui/screens/guides/_docs/index.yaml +100 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/agents.md +178 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/approval.md +117 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/chat-options.md +276 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/compaction.md +42 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/memory.md +48 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/models.md +158 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/settings.md +210 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/themes.md +61 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/tools.md +60 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/configuration/web-tools.md +286 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/daily-use/sessions.md +77 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/daily-use/workspaces.md +51 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/external-acp-agents.md +126 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/hooks.md +167 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/mcp.md +95 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/extensions/skills.md +175 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-acp.md +61 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-run.md +190 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/icode-serve.md +239 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/guides/running/workflows.md +664 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/agent-profile.md +548 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/hooks.md +602 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/opentelemetry.md +177 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/settings.md +245 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/themes.md +149 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/tool-kinds-and-names.md +58 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/tui-slash-commands.md +76 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/reference/workflows.md +1005 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/start/getting-started.md +170 -0
- chrys/app/tui/screens/guides/_docs/zh-Hans/start/what-is-icode.md +34 -0
- chrys/app/tui/screens/guides/index.py +215 -0
- chrys/app/tui/screens/guides/reader.py +173 -0
- chrys/app/tui/screens/guides/screen.py +442 -0
- chrys/app/tui/screens/guides/screen.tcss +52 -0
- chrys/app/tui/screens/logs/__init__.py +7 -0
- chrys/app/tui/screens/logs/screen.py +504 -0
- chrys/app/tui/screens/logs/screen.tcss +45 -0
- chrys/app/tui/screens/main/__init__.py +7 -0
- chrys/app/tui/screens/main/action_availability.py +30 -0
- chrys/app/tui/screens/main/buddy_command.py +143 -0
- chrys/app/tui/screens/main/commands.py +1073 -0
- chrys/app/tui/screens/main/config_actions.py +464 -0
- chrys/app/tui/screens/main/copy_actions.py +117 -0
- chrys/app/tui/screens/main/dialog_controllers.py +826 -0
- chrys/app/tui/screens/main/dialog_gateway.py +166 -0
- chrys/app/tui/screens/main/diff_controller.py +478 -0
- chrys/app/tui/screens/main/engine_read_model.py +184 -0
- chrys/app/tui/screens/main/event_handlers.py +2014 -0
- chrys/app/tui/screens/main/input_flow.py +241 -0
- chrys/app/tui/screens/main/live_diff.py +244 -0
- chrys/app/tui/screens/main/main_screen_presenter.py +295 -0
- chrys/app/tui/screens/main/model_indicator.py +217 -0
- chrys/app/tui/screens/main/navigation.py +343 -0
- chrys/app/tui/screens/main/ports.py +571 -0
- chrys/app/tui/screens/main/recent_dirs.py +123 -0
- chrys/app/tui/screens/main/rollback_controller.py +586 -0
- chrys/app/tui/screens/main/runtime_info.py +71 -0
- chrys/app/tui/screens/main/screen.py +2265 -0
- chrys/app/tui/screens/main/screen.tcss +21 -0
- chrys/app/tui/screens/main/session_handlers.py +1127 -0
- chrys/app/tui/screens/main/session_title.py +239 -0
- chrys/app/tui/screens/main/settings_coordinator.py +365 -0
- chrys/app/tui/screens/main/settings_persistence.py +184 -0
- chrys/app/tui/screens/main/shell_mode.py +112 -0
- chrys/app/tui/screens/main/state.py +289 -0
- chrys/app/tui/screens/main/submit_state.py +11 -0
- chrys/app/tui/screens/main/subscriptions.py +177 -0
- chrys/app/tui/screens/main/suggestions.py +982 -0
- chrys/app/tui/screens/main/tool_action_bridge.py +75 -0
- chrys/app/tui/screens/main/view_adapter.py +1567 -0
- chrys/app/tui/screens/main/workflow_browser.py +747 -0
- chrys/app/tui/screens/main/workflow_content.py +248 -0
- chrys/app/tui/screens/main/workflow_controller.py +240 -0
- chrys/app/tui/screens/main/workflow_feedback.py +137 -0
- chrys/app/tui/screens/main/workflow_flow.py +49 -0
- chrys/app/tui/screens/main/workflow_run_control.py +456 -0
- chrys/app/tui/screens/main/workflow_session_view.py +316 -0
- chrys/app/tui/screens/main/workspace_actions.py +272 -0
- chrys/app/tui/screens/main/workspace_branch.py +194 -0
- chrys/app/tui/screens/menus/__init__.py +8 -0
- chrys/app/tui/screens/menus/languages.py +114 -0
- chrys/app/tui/screens/models/__init__.py +7 -0
- chrys/app/tui/screens/models/picker.py +147 -0
- chrys/app/tui/screens/models/screen.py +2043 -0
- chrys/app/tui/screens/models/screen.tcss +255 -0
- chrys/app/tui/screens/sessions/__init__.py +8 -0
- chrys/app/tui/screens/sessions/presenter.py +586 -0
- chrys/app/tui/screens/sessions/screen.py +779 -0
- chrys/app/tui/screens/sessions/screen.tcss +127 -0
- chrys/app/tui/screens/settings/__init__.py +29 -0
- chrys/app/tui/screens/settings/danger.py +26 -0
- chrys/app/tui/screens/settings/dialog.py +281 -0
- chrys/app/tui/screens/settings/layout.py +519 -0
- chrys/app/tui/screens/settings/migrate_dialog.py +253 -0
- chrys/app/tui/screens/settings/panes/__init__.py +3 -0
- chrys/app/tui/screens/settings/panes/notifications.py +248 -0
- chrys/app/tui/screens/settings/panes/sessions.py +148 -0
- chrys/app/tui/screens/settings/ports.py +55 -0
- chrys/app/tui/screens/settings/provenance.py +102 -0
- chrys/app/tui/screens/settings/rows.py +546 -0
- chrys/app/tui/screens/settings/settings.tcss +406 -0
- chrys/app/tui/screens/themes/__init__.py +8 -0
- chrys/app/tui/screens/themes/dialogs.py +330 -0
- chrys/app/tui/screens/themes/editor.py +632 -0
- chrys/app/tui/screens/themes/editor.tcss +268 -0
- chrys/app/tui/screens/themes/messages.py +95 -0
- chrys/app/tui/screens/themes/palette.py +694 -0
- chrys/app/tui/screens/themes/panel.py +113 -0
- chrys/app/tui/screens/themes/picker.py +203 -0
- chrys/app/tui/screens/themes/save.py +191 -0
- chrys/app/tui/support/__init__.py +3 -0
- chrys/app/tui/support/file_manager.py +64 -0
- chrys/app/tui/support/gc_freeze.py +1114 -0
- chrys/app/tui/support/path_shortcuts.py +50 -0
- chrys/app/tui/support/prompt_history.py +298 -0
- chrys/app/tui/support/workspace_mru.py +476 -0
- chrys/app/tui/terminal/__init__.py +6 -0
- chrys/app/tui/terminal/_pty_backend.py +114 -0
- chrys/app/tui/terminal/emulator/__init__.py +24 -0
- chrys/app/tui/terminal/emulator/buffer.py +456 -0
- chrys/app/tui/terminal/emulator/charsets.py +113 -0
- chrys/app/tui/terminal/emulator/core.py +963 -0
- chrys/app/tui/terminal/emulator/input.py +342 -0
- chrys/app/tui/terminal/emulator/parser.py +227 -0
- chrys/app/tui/terminal/emulator/pen.py +158 -0
- chrys/app/tui/terminal/launcher.py +455 -0
- chrys/app/tui/terminal/leaked_reports.py +44 -0
- chrys/app/tui/terminal/panel.py +323 -0
- chrys/app/tui/terminal/pty_process.py +405 -0
- chrys/app/tui/terminal/rendering.py +151 -0
- chrys/app/tui/terminal/shell.py +273 -0
- chrys/app/tui/terminal/shell_integration.py +199 -0
- chrys/app/tui/terminal/title.py +224 -0
- chrys/app/tui/terminal/widget.py +654 -0
- chrys/app/tui/theme.py +422 -0
- chrys/app/tui/theme_loader.py +201 -0
- chrys/app/tui/theme_stylesheet.py +49 -0
- chrys/app/tui/themes/__init__.py +3 -0
- chrys/app/tui/themes/document.py +120 -0
- chrys/app/tui/themes/preview.py +170 -0
- chrys/app/tui/themes/store.py +176 -0
- chrys/app/tui/toasts.py +69 -0
- chrys/app/tui/util/__init__.py +3 -0
- chrys/app/tui/util/context_pressure.py +146 -0
- chrys/app/tui/util/debug_log.py +292 -0
- chrys/app/tui/util/diff_entries.py +64 -0
- chrys/app/tui/util/formatting.py +53 -0
- chrys/app/tui/util/git_branch.py +326 -0
- chrys/app/tui/util/invocation_progress.py +57 -0
- chrys/app/tui/util/logo.py +32 -0
- chrys/app/tui/util/message_gate.py +35 -0
- chrys/app/tui/util/mutation_sources.py +14 -0
- chrys/app/tui/util/picker_text.py +27 -0
- chrys/app/tui/util/removal.py +47 -0
- chrys/app/tui/util/rich_style.py +36 -0
- chrys/app/tui/util/source_text.py +12 -0
- chrys/app/tui/util/static_update.py +88 -0
- chrys/app/tui/util/todo_format.py +51 -0
- chrys/app/tui/util/visibility.py +214 -0
- chrys/app/tui/widgets/__init__.py +60 -0
- chrys/app/tui/widgets/ask_user_controls.py +652 -0
- chrys/app/tui/widgets/ask_user_markdown.py +17 -0
- chrys/app/tui/widgets/ask_user_prompt.py +606 -0
- chrys/app/tui/widgets/buttons.py +52 -0
- chrys/app/tui/widgets/chat/__init__.py +3 -0
- chrys/app/tui/widgets/chat/agent_transcript_surface.py +818 -0
- chrys/app/tui/widgets/chat/chrome.py +296 -0
- chrys/app/tui/widgets/chat/compaction_card.py +353 -0
- chrys/app/tui/widgets/chat/context_fold.py +77 -0
- chrys/app/tui/widgets/chat/file_snapshot.py +91 -0
- chrys/app/tui/widgets/chat/image_preview.py +214 -0
- chrys/app/tui/widgets/chat/live_renderer.py +383 -0
- chrys/app/tui/widgets/chat/messages.py +1039 -0
- chrys/app/tui/widgets/chat/panel.py +1769 -0
- chrys/app/tui/widgets/chat/ports.py +245 -0
- chrys/app/tui/widgets/chat/renderers/__init__.py +7 -0
- chrys/app/tui/widgets/chat/renderers/ask_user.py +747 -0
- chrys/app/tui/widgets/chat/renderers/execute.py +431 -0
- chrys/app/tui/widgets/chat/renderers/file_edit.py +925 -0
- chrys/app/tui/widgets/chat/renderers/hosted_code.py +83 -0
- chrys/app/tui/widgets/chat/renderers/hosted_generic.py +330 -0
- chrys/app/tui/widgets/chat/renderers/hosted_image.py +107 -0
- chrys/app/tui/widgets/chat/renderers/hosted_mcp.py +43 -0
- chrys/app/tui/widgets/chat/renderers/hosted_search.py +167 -0
- chrys/app/tui/widgets/chat/renderers/hosted_shell.py +132 -0
- chrys/app/tui/widgets/chat/renderers/read_file.py +399 -0
- chrys/app/tui/widgets/chat/renderers/search.py +348 -0
- chrys/app/tui/widgets/chat/renderers/skill.py +564 -0
- chrys/app/tui/widgets/chat/renderers/sleep.py +287 -0
- chrys/app/tui/widgets/chat/renderers/sub_agent.py +1385 -0
- chrys/app/tui/widgets/chat/renderers/todo.py +114 -0
- chrys/app/tui/widgets/chat/renderers/web.py +69 -0
- chrys/app/tui/widgets/chat/replay.py +1605 -0
- chrys/app/tui/widgets/chat/replay_mount.py +322 -0
- chrys/app/tui/widgets/chat/scroll_controller.py +579 -0
- chrys/app/tui/widgets/chat/selection_controller.py +435 -0
- chrys/app/tui/widgets/chat/session_json.py +508 -0
- chrys/app/tui/widgets/chat/toc_model.py +156 -0
- chrys/app/tui/widgets/chat/tool_call.py +2478 -0
- chrys/app/tui/widgets/chat/tool_registry.py +753 -0
- chrys/app/tui/widgets/chat/tool_renderers.py +247 -0
- chrys/app/tui/widgets/chat/tool_view_builders.py +260 -0
- chrys/app/tui/widgets/chat/transcript_reader.py +57 -0
- chrys/app/tui/widgets/checkbox.py +24 -0
- chrys/app/tui/widgets/chrome/__init__.py +3 -0
- chrys/app/tui/widgets/chrome/app_header.py +283 -0
- chrys/app/tui/widgets/chrome/commands.py +95 -0
- chrys/app/tui/widgets/chrome/file_index.py +68 -0
- chrys/app/tui/widgets/chrome/file_scanner.py +670 -0
- chrys/app/tui/widgets/chrome/footer.py +284 -0
- chrys/app/tui/widgets/chrome/image_paste.py +351 -0
- chrys/app/tui/widgets/chrome/input_bar.py +1299 -0
- chrys/app/tui/widgets/chrome/status_bar.py +911 -0
- chrys/app/tui/widgets/chrome/suggestion_list.py +652 -0
- chrys/app/tui/widgets/click_affordance.py +24 -0
- chrys/app/tui/widgets/color_picker/__init__.py +254 -0
- chrys/app/tui/widgets/color_picker/controls.py +171 -0
- chrys/app/tui/widgets/color_picker/model.py +89 -0
- chrys/app/tui/widgets/dialog_buttons.py +58 -0
- chrys/app/tui/widgets/dialog_scroll.py +24 -0
- chrys/app/tui/widgets/diff_view/__init__.py +20 -0
- chrys/app/tui/widgets/diff_view/cells.py +59 -0
- chrys/app/tui/widgets/diff_view/code.py +280 -0
- chrys/app/tui/widgets/diff_view/compute.py +286 -0
- chrys/app/tui/widgets/diff_view/gutter.py +161 -0
- chrys/app/tui/widgets/diff_view/inline.py +77 -0
- chrys/app/tui/widgets/diff_view/palette.py +87 -0
- chrys/app/tui/widgets/diff_view/protocols.py +24 -0
- chrys/app/tui/widgets/diff_view/rows.py +138 -0
- chrys/app/tui/widgets/diff_view/unified.py +267 -0
- chrys/app/tui/widgets/diff_view/widget.py +209 -0
- chrys/app/tui/widgets/editor/__init__.py +79 -0
- chrys/app/tui/widgets/editor/coordinates.py +30 -0
- chrys/app/tui/widgets/editor/highlighter.py +139 -0
- chrys/app/tui/widgets/editor/keymaps.py +357 -0
- chrys/app/tui/widgets/editor/types.py +216 -0
- chrys/app/tui/widgets/editor/vim.py +1195 -0
- chrys/app/tui/widgets/editor/widget.py +401 -0
- chrys/app/tui/widgets/file_preview.py +58 -0
- chrys/app/tui/widgets/hatch.py +138 -0
- chrys/app/tui/widgets/input.py +66 -0
- chrys/app/tui/widgets/loading.py +125 -0
- chrys/app/tui/widgets/markdown/__init__.py +25 -0
- chrys/app/tui/widgets/markdown/_utils.py +21 -0
- chrys/app/tui/widgets/markdown/anchors.py +71 -0
- chrys/app/tui/widgets/markdown/blocks.py +115 -0
- chrys/app/tui/widgets/markdown/copyable.py +163 -0
- chrys/app/tui/widgets/markdown/diagram/__init__.py +35 -0
- chrys/app/tui/widgets/markdown/diagram/canvas.py +409 -0
- chrys/app/tui/widgets/markdown/diagram/charts.py +52 -0
- chrys/app/tui/widgets/markdown/diagram/diagnostics.py +101 -0
- chrys/app/tui/widgets/markdown/diagram/geometry.py +46 -0
- chrys/app/tui/widgets/markdown/diagram/layout.py +494 -0
- chrys/app/tui/widgets/markdown/diagram/messages.py +18 -0
- chrys/app/tui/widgets/markdown/diagram/model.py +275 -0
- chrys/app/tui/widgets/markdown/diagram/parser.py +173 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/__init__.py +3 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/charts.py +349 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/common.py +403 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/graphs.py +1072 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/planning.py +317 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/schedule.py +298 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/schemas.py +241 -0
- chrys/app/tui/widgets/markdown/diagram/parsers/structure.py +221 -0
- chrys/app/tui/widgets/markdown/diagram/presentation.py +32 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/__init__.py +3 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/charts.py +275 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/common.py +73 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/planning.py +157 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/schedule.py +202 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/structure.py +77 -0
- chrys/app/tui/widgets/markdown/diagram/renderers/xy.py +385 -0
- chrys/app/tui/widgets/markdown/diagram/router.py +651 -0
- chrys/app/tui/widgets/markdown/diagram/specs/__init__.py +3 -0
- chrys/app/tui/widgets/markdown/diagram/specs/charts.py +94 -0
- chrys/app/tui/widgets/markdown/diagram/specs/planning.py +68 -0
- chrys/app/tui/widgets/markdown/diagram/specs/schedule.py +65 -0
- chrys/app/tui/widgets/markdown/diagram/specs/structure.py +23 -0
- chrys/app/tui/widgets/markdown/diagram/viewer.py +92 -0
- chrys/app/tui/widgets/markdown/links.py +47 -0
- chrys/app/tui/widgets/markdown/math/__init__.py +36 -0
- chrys/app/tui/widgets/markdown/math/layout.py +739 -0
- chrys/app/tui/widgets/markdown/math/markdown.py +291 -0
- chrys/app/tui/widgets/markdown/math/parser.py +325 -0
- chrys/app/tui/widgets/markdown/math/symbols.py +325 -0
- chrys/app/tui/widgets/markdown/navigator.py +80 -0
- chrys/app/tui/widgets/markdown/parser.py +1057 -0
- chrys/app/tui/widgets/markdown/stream.py +73 -0
- chrys/app/tui/widgets/markdown/toc.py +98 -0
- chrys/app/tui/widgets/markdown/viewer.py +146 -0
- chrys/app/tui/widgets/markdown/widget.py +2046 -0
- chrys/app/tui/widgets/marquee.py +101 -0
- chrys/app/tui/widgets/option_menu.py +82 -0
- chrys/app/tui/widgets/page_navigator.py +118 -0
- chrys/app/tui/widgets/select.py +196 -0
- chrys/app/tui/widgets/selection.py +59 -0
- chrys/app/tui/widgets/sidebar/__init__.py +3 -0
- chrys/app/tui/widgets/sidebar/buddy.py +367 -0
- chrys/app/tui/widgets/sidebar/context.py +482 -0
- chrys/app/tui/widgets/sidebar/debug.py +195 -0
- chrys/app/tui/widgets/sidebar/empty_state.py +11 -0
- chrys/app/tui/widgets/sidebar/panel.py +198 -0
- chrys/app/tui/widgets/sidebar/tasks.py +198 -0
- chrys/app/tui/widgets/sidebar/toc.py +166 -0
- chrys/app/tui/widgets/sidebar/toc_types.py +30 -0
- chrys/app/tui/widgets/syntax_theme.py +85 -0
- chrys/app/tui/widgets/text_area.py +258 -0
- chrys/app/tui/widgets/trajectory/__init__.py +8 -0
- chrys/app/tui/widgets/trajectory/chartkit.py +264 -0
- chrys/app/tui/widgets/trajectory/insights.py +1266 -0
- chrys/app/tui/widgets/trajectory/overview.py +1101 -0
- chrys/app/tui/widgets/trajectory/panel.py +983 -0
- chrys/app/tui/widgets/trajectory/presentation.py +311 -0
- chrys/app/tui/widgets/trajectory/session_info.py +124 -0
- chrys/app/tui/widgets/trajectory/text_view.py +124 -0
- chrys/app/tui/widgets/trajectory/timeline.py +380 -0
- chrys/app/tui/widgets/welcome.py +126 -0
- chrys/app/tui/widgets/workflow/__init__.py +5 -0
- chrys/app/tui/widgets/workflow/edges.py +89 -0
- chrys/app/tui/widgets/workflow/graph.py +869 -0
- chrys/app/tui/widgets/workflow/info.py +310 -0
- chrys/app/tui/widgets/workflow/node_view.py +27 -0
- chrys/app/tui/widgets/workflow/output.py +225 -0
- chrys/app/tui/widgets/workflow/panel.py +658 -0
- chrys/app/tui/widgets/workflow/projector.py +324 -0
- chrys/app/tui/widgets/workflow/records.py +69 -0
- chrys/app/tui/widgets/workflow/scrollbar.py +82 -0
- chrys/app/tui/widgets/workflow/selection.py +151 -0
- chrys/app/tui/widgets/workflow/source.py +65 -0
- chrys/app/tui/widgets/workflow/text.py +257 -0
- chrys/app/tui/widgets/workflow/values.py +317 -0
- chrys/foundation/__init__.py +0 -0
- chrys/foundation/branding.py +15 -0
- chrys/foundation/config/__init__.py +7 -0
- chrys/foundation/config/coercion.py +374 -0
- chrys/foundation/config/context.py +34 -0
- chrys/foundation/config/env_file.py +141 -0
- chrys/foundation/config/env_layers.py +370 -0
- chrys/foundation/config/migrations.py +521 -0
- chrys/foundation/config/notification_events.py +22 -0
- chrys/foundation/config/process_settings.py +332 -0
- chrys/foundation/config/runtime_pointer.py +133 -0
- chrys/foundation/config/settings.py +1952 -0
- chrys/foundation/config/settings_store.py +996 -0
- chrys/foundation/config/spec.py +396 -0
- chrys/foundation/config/user_settings.py +140 -0
- chrys/foundation/config/warnings.py +262 -0
- chrys/foundation/config/web_values.py +135 -0
- chrys/foundation/config/yaml_store.py +487 -0
- chrys/foundation/errors/__init__.py +68 -0
- chrys/foundation/errors/_legacy.py +117 -0
- chrys/foundation/errors/_text.py +13 -0
- chrys/foundation/errors/_walk.py +85 -0
- chrys/foundation/errors/classify.py +278 -0
- chrys/foundation/errors/display.py +274 -0
- chrys/foundation/errors/formatting.py +283 -0
- chrys/foundation/errors/kinds.py +67 -0
- chrys/foundation/errors/network.py +497 -0
- chrys/foundation/errors/provider.py +445 -0
- chrys/foundation/errors/route.py +85 -0
- chrys/foundation/events/__init__.py +8 -0
- chrys/foundation/events/bus.py +143 -0
- chrys/foundation/events/types.py +1629 -0
- chrys/foundation/events/workflow.py +38 -0
- chrys/foundation/hosted_tools.py +142 -0
- chrys/foundation/i18n/__init__.py +32 -0
- chrys/foundation/i18n/_catalogs/zh-Hans/LC_MESSAGES/chrys.mo +0 -0
- chrys/foundation/i18n/catalogs.py +42 -0
- chrys/foundation/i18n/formatting.py +202 -0
- chrys/foundation/i18n/locale.py +92 -0
- chrys/foundation/i18n/localizer.py +187 -0
- chrys/foundation/i18n/messages.py +268 -0
- chrys/foundation/io/__init__.py +3 -0
- chrys/foundation/io/result_content.py +237 -0
- chrys/foundation/models/__init__.py +3 -0
- chrys/foundation/models/approval_reuse.py +23 -0
- chrys/foundation/models/ask_user.py +468 -0
- chrys/foundation/models/execution.py +18 -0
- chrys/foundation/models/history_markers.py +115 -0
- chrys/foundation/models/invocations.py +63 -0
- chrys/foundation/models/mutation_scope.py +28 -0
- chrys/foundation/models/session_env.py +87 -0
- chrys/foundation/models/session_surface.py +29 -0
- chrys/foundation/models/todos.py +74 -0
- chrys/foundation/models/turns.py +125 -0
- chrys/foundation/models/workflow_session.py +89 -0
- chrys/foundation/models/workspace.py +59 -0
- chrys/foundation/net/__init__.py +3 -0
- chrys/foundation/net/address_class.py +57 -0
- chrys/foundation/net/route_probe.py +94 -0
- chrys/foundation/net/url.py +107 -0
- chrys/foundation/observability/__init__.py +3 -0
- chrys/foundation/observability/exporters.py +174 -0
- chrys/foundation/observability/gate.py +31 -0
- chrys/foundation/observability/setup.py +497 -0
- chrys/foundation/observability/sink.py +228 -0
- chrys/foundation/patches/__init__.py +19 -0
- chrys/foundation/patches/mdurl_cache.py +59 -0
- chrys/foundation/patches/patcher.py +287 -0
- chrys/foundation/patches/staged_members.py +205 -0
- chrys/foundation/patches/textual_block_border.py +105 -0
- chrys/foundation/patches/textual_button_ansi.py +65 -0
- chrys/foundation/patches/textual_button_ansi_old.txt +68 -0
- chrys/foundation/patches/textual_callback_cache.py +248 -0
- chrys/foundation/patches/textual_callback_dispatch.py +109 -0
- chrys/foundation/patches/textual_compositor_cjk.py +566 -0
- chrys/foundation/patches/textual_dispatch_cache.py +150 -0
- chrys/foundation/patches/textual_ime_cursor_anchor.py +92 -0
- chrys/foundation/patches/textual_kitty_keyboard.py +268 -0
- chrys/foundation/patches/textual_lru_acyclic.py +241 -0
- chrys/foundation/patches/textual_message_pump.py +136 -0
- chrys/foundation/patches/textual_node_diet.py +875 -0
- chrys/foundation/patches/textual_one_shot_timer.py +48 -0
- chrys/foundation/patches/textual_option_list.py +90 -0
- chrys/foundation/patches/textual_precompose.py +89 -0
- chrys/foundation/patches/textual_pruned_tabs.py +69 -0
- chrys/foundation/patches/textual_reflow_reuse.py +1753 -0
- chrys/foundation/patches/textual_removed_node_caches.py +86 -0
- chrys/foundation/patches/textual_removed_screen_callbacks.py +55 -0
- chrys/foundation/patches/textual_selection_extract.py +48 -0
- chrys/foundation/patches/textual_strip_cycles.py +119 -0
- chrys/foundation/patches/textual_tab_selection.py +1611 -0
- chrys/foundation/patches/textual_timer_skip.py +70 -0
- chrys/foundation/patches/textual_utf8_decoder.py +106 -0
- chrys/foundation/patches/textual_win_sleep.py +167 -0
- chrys/foundation/patches/watchdog_fsevents.py +70 -0
- chrys/foundation/patches/watchdog_windows.py +52 -0
- chrys/foundation/platform/__init__.py +556 -0
- chrys/foundation/platform/c_api.py +32 -0
- chrys/foundation/platform/child_reap.py +107 -0
- chrys/foundation/platform/command_line.py +95 -0
- chrys/foundation/platform/files.py +1470 -0
- chrys/foundation/platform/output_capture.py +113 -0
- chrys/foundation/platform/paths.py +193 -0
- chrys/foundation/platform/process.py +1468 -0
- chrys/foundation/platform/pty_output.py +19 -0
- chrys/foundation/platform/runtime_paths.py +281 -0
- chrys/foundation/platform/win_console.py +129 -0
- chrys/foundation/reasoning_origin.py +67 -0
- chrys/foundation/recovery.py +16 -0
- chrys/foundation/retry.py +278 -0
- chrys/foundation/text/__init__.py +3 -0
- chrys/foundation/text/encoding.py +603 -0
- chrys/foundation/text/images.py +304 -0
- chrys/foundation/text/lines.py +24 -0
- chrys/foundation/text/mentions.py +90 -0
- chrys/foundation/text/model_json.py +25 -0
- chrys/foundation/text/reading_order.py +20 -0
- chrys/foundation/text/tokenizer.py +25 -0
- chrys/foundation/text/tool_output.py +287 -0
- chrys/foundation/text/yaml_io.py +62 -0
- chrys/foundation/tool_call_context.py +202 -0
- chrys/foundation/tool_execution_stamp.py +184 -0
- chrys/foundation/tool_invocation_order.py +48 -0
- chrys/foundation/tool_kinds.py +102 -0
- chrys/foundation/tool_result_metadata.py +287 -0
- chrys/foundation/trajectory/__init__.py +10 -0
- chrys/foundation/trajectory/context.py +481 -0
- chrys/foundation/trajectory/envelope.py +571 -0
- chrys/foundation/trajectory/event_types.py +294 -0
- chrys/foundation/trajectory/finalizers.py +46 -0
- chrys/foundation/trajectory/fingerprint.py +62 -0
- chrys/foundation/trajectory/ids.py +155 -0
- chrys/foundation/trajectory/keys.py +99 -0
- chrys/foundation/trajectory/lease.py +173 -0
- chrys/foundation/trajectory/metadata.py +72 -0
- chrys/foundation/trajectory/reader.py +271 -0
- chrys/foundation/trajectory/recovery.py +225 -0
- chrys/foundation/trajectory/revisions.py +152 -0
- chrys/foundation/trajectory/segments.py +225 -0
- chrys/foundation/trajectory/tools.py +117 -0
- chrys/foundation/trajectory/usage.py +151 -0
- chrys/foundation/trajectory/writer.py +972 -0
- chrys/foundation/trajectory_timing.py +97 -0
- chrys/foundation/util/__init__.py +3 -0
- chrys/foundation/util/async_tasks.py +29 -0
- chrys/foundation/util/chrys_headers.py +23 -0
- chrys/foundation/util/env_templates.py +104 -0
- chrys/foundation/util/filenames.py +96 -0
- chrys/foundation/util/header_charset.py +138 -0
- chrys/foundation/util/httpx_helpers.py +12 -0
- chrys/foundation/util/lock.py +236 -0
- chrys/foundation/util/once_close.py +46 -0
- chrys/foundation/util/session_ids.py +29 -0
- chrys/foundation/util/shell_tokens.py +88 -0
- chrys/foundation/util/sub_agent_context.py +38 -0
- chrys/foundation/util/time.py +35 -0
- chrys/foundation/util/unicode_scalars.py +36 -0
- chrys/foundation/vendor/__init__.py +43 -0
- chrys/foundation/vendor/ripgrep/rg-aarch64-apple-darwin +0 -0
- chrys/foundation/vendor/ripgrep/rg-aarch64-pc-windows-msvc.exe +0 -0
- chrys/foundation/vendor/ripgrep/rg-aarch64-unknown-linux-gnu +0 -0
- chrys/foundation/vendor/ripgrep/rg-x86_64-apple-darwin +0 -0
- chrys/foundation/vendor/ripgrep/rg-x86_64-pc-windows-msvc.exe +0 -0
- chrys/foundation/vendor/ripgrep/rg-x86_64-unknown-linux-musl +0 -0
- chrys/kernel/__init__.py +256 -0
- chrys/kernel/_content.py +1866 -0
- chrys/kernel/_loop_recorder.py +631 -0
- chrys/kernel/_null_overlay.py +1026 -0
- chrys/kernel/_result_ceiling.py +216 -0
- chrys/kernel/_serialization.py +431 -0
- chrys/kernel/_tool_arg_errors.py +1629 -0
- chrys/kernel/_tool_execution.py +1172 -0
- chrys/kernel/_tool_expansion.py +26 -0
- chrys/kernel/_types.py +2598 -0
- chrys/kernel/agent.py +994 -0
- chrys/kernel/client.py +1084 -0
- chrys/kernel/compaction.py +1315 -0
- chrys/kernel/exceptions.py +211 -0
- chrys/kernel/exchanges.py +683 -0
- chrys/kernel/identity.py +95 -0
- chrys/kernel/images.py +36 -0
- chrys/kernel/instrumentation.py +1618 -0
- chrys/kernel/loop.py +2308 -0
- chrys/kernel/middleware.py +616 -0
- chrys/kernel/sessions.py +604 -0
- chrys/kernel/tools.py +1061 -0
- chrys/kernel/types.py +126 -0
- chrys/orchestration/__init__.py +3 -0
- chrys/orchestration/engine/__init__.py +3 -0
- chrys/orchestration/engine/assembly.py +236 -0
- chrys/orchestration/engine/build/__init__.py +3 -0
- chrys/orchestration/engine/build/builder.py +1061 -0
- chrys/orchestration/engine/build/construction.py +408 -0
- chrys/orchestration/engine/build/loaded.py +139 -0
- chrys/orchestration/engine/engine.py +789 -0
- chrys/orchestration/engine/execution.py +771 -0
- chrys/orchestration/engine/loader.py +865 -0
- chrys/orchestration/engine/rollback.py +918 -0
- chrys/orchestration/engine/run/__init__.py +3 -0
- chrys/orchestration/engine/run/active_injection.py +419 -0
- chrys/orchestration/engine/run/attachments.py +519 -0
- chrys/orchestration/engine/run/bindings.py +1095 -0
- chrys/orchestration/engine/run/coordinator.py +1062 -0
- chrys/orchestration/engine/run/finalizer.py +417 -0
- chrys/orchestration/engine/run/input_refs.py +60 -0
- chrys/orchestration/engine/run/prompt_content.py +457 -0
- chrys/orchestration/engine/run/resume.py +299 -0
- chrys/orchestration/engine/run/retry.py +948 -0
- chrys/orchestration/engine/run/runner.py +625 -0
- chrys/orchestration/engine/run/runtime_skills.py +146 -0
- chrys/orchestration/engine/run/sub_agent_coordination.py +126 -0
- chrys/orchestration/engine/run/turn_hooks.py +258 -0
- chrys/orchestration/engine/run/turn_state.py +149 -0
- chrys/orchestration/engine/run/working_dir.py +50 -0
- chrys/orchestration/engine/session_lifecycle.py +2013 -0
- chrys/orchestration/engine/state/__init__.py +3 -0
- chrys/orchestration/engine/state/active_session.py +183 -0
- chrys/orchestration/engine/state/controls.py +639 -0
- chrys/orchestration/engine/state/current_agent.py +26 -0
- chrys/orchestration/engine/state/lifecycle_permits.py +395 -0
- chrys/orchestration/engine/state/machine.py +193 -0
- chrys/orchestration/engine/state/session_writer.py +434 -0
- chrys/orchestration/engine/trajectory.py +714 -0
- chrys/orchestration/engine/usage.py +118 -0
- chrys/orchestration/invoker/__init__.py +3 -0
- chrys/orchestration/invoker/acp.py +727 -0
- chrys/orchestration/invoker/acp_protocol.py +1115 -0
- chrys/orchestration/invoker/acp_spec.py +79 -0
- chrys/orchestration/invoker/attempts.py +994 -0
- chrys/orchestration/invoker/child_compaction.py +131 -0
- chrys/orchestration/invoker/child_history.py +99 -0
- chrys/orchestration/invoker/contracts.py +253 -0
- chrys/orchestration/invoker/evidence.py +94 -0
- chrys/orchestration/invoker/kernel.py +343 -0
- chrys/orchestration/invoker/origin.py +79 -0
- chrys/orchestration/invoker/resources.py +343 -0
- chrys/orchestration/invoker/runtime.py +299 -0
- chrys/orchestration/invoker/usage.py +80 -0
- chrys/orchestration/session_hooks.py +117 -0
- chrys/orchestration/session_host.py +1023 -0
- chrys/orchestration/session_resources.py +95 -0
- chrys/orchestration/session_usage.py +219 -0
- chrys/orchestration/startup.py +255 -0
- chrys/orchestration/sub_agents/__init__.py +3 -0
- chrys/orchestration/sub_agents/acp_policy.py +269 -0
- chrys/orchestration/sub_agents/kernel_policy.py +848 -0
- chrys/orchestration/sub_agents/registration.py +44 -0
- chrys/orchestration/sub_agents/shell.py +337 -0
- chrys/orchestration/sub_agents/tools.py +2228 -0
- chrys/orchestration/workflows/__init__.py +3 -0
- chrys/orchestration/workflows/agent_archive.py +156 -0
- chrys/orchestration/workflows/agent_node.py +894 -0
- chrys/orchestration/workflows/agent_node_build.py +687 -0
- chrys/orchestration/workflows/catalog.py +332 -0
- chrys/orchestration/workflows/coordinator.py +771 -0
- chrys/orchestration/workflows/hooks.py +176 -0
- chrys/orchestration/workflows/preview.py +322 -0
- chrys/orchestration/workflows/rollback.py +151 -0
- chrys/orchestration/workflows/runner.py +986 -0
- chrys/orchestration/workflows/session.py +390 -0
- chrys/orchestration/workflows/settings.py +97 -0
- chrys/orchestration/workflows/validation.py +674 -0
- chrys/orchestration/workflows/worker_client.py +1002 -0
- chrys/service/__init__.py +3 -0
- chrys/service/acp_client/__init__.py +65 -0
- chrys/service/acp_client/_transport.py +922 -0
- chrys/service/acp_client/client.py +1311 -0
- chrys/service/acp_client/errors.py +224 -0
- chrys/service/acp_client/protocol.py +220 -0
- chrys/service/acp_client/spawn.py +239 -0
- chrys/service/acp_client/spec.py +100 -0
- chrys/service/agent_middleware/__init__.py +60 -0
- chrys/service/agent_middleware/_metadata_keys.py +52 -0
- chrys/service/agent_middleware/control/__init__.py +3 -0
- chrys/service/agent_middleware/control/approval.py +769 -0
- chrys/service/agent_middleware/control/approval_hooks.py +62 -0
- chrys/service/agent_middleware/control/ask_user.py +207 -0
- chrys/service/agent_middleware/control/interrupt.py +50 -0
- chrys/service/agent_middleware/control/sleep.py +118 -0
- chrys/service/agent_middleware/control/todo.py +117 -0
- chrys/service/agent_middleware/events/__init__.py +3 -0
- chrys/service/agent_middleware/events/hook_dispatch.py +250 -0
- chrys/service/agent_middleware/events/hosted_tools.py +1762 -0
- chrys/service/agent_middleware/events/intermediate_text.py +128 -0
- chrys/service/agent_middleware/events/rejection_metadata.py +50 -0
- chrys/service/agent_middleware/events/result_persistence.py +98 -0
- chrys/service/agent_middleware/events/sub_agent_events.py +951 -0
- chrys/service/agent_middleware/events/tool_error_text.py +22 -0
- chrys/service/agent_middleware/events/tool_events.py +779 -0
- chrys/service/agent_middleware/injection.py +510 -0
- chrys/service/agent_middleware/reminders/__init__.py +91 -0
- chrys/service/agent_middleware/reminders/archive_pointer.py +154 -0
- chrys/service/agent_middleware/reminders/base.py +25 -0
- chrys/service/agent_middleware/reminders/context_usage.py +74 -0
- chrys/service/agent_middleware/reminders/file_change.py +63 -0
- chrys/service/agent_middleware/reminders/mcp.py +39 -0
- chrys/service/agent_middleware/reminders/profile_switch.py +106 -0
- chrys/service/agent_middleware/reminders/runtime_env.py +190 -0
- chrys/service/agent_middleware/reminders/skills.py +44 -0
- chrys/service/agent_middleware/reminders/sub_agents.py +35 -0
- chrys/service/agent_middleware/reminders/todo.py +35 -0
- chrys/service/agent_middleware/reminders/turn_line.py +48 -0
- chrys/service/agent_middleware/response_validation.py +1380 -0
- chrys/service/agent_middleware/system_reminder.py +1107 -0
- chrys/service/agent_middleware/validators.py +396 -0
- chrys/service/analytics/__init__.py +124 -0
- chrys/service/analytics/_actions.py +896 -0
- chrys/service/analytics/_context_evidence.py +357 -0
- chrys/service/analytics/_critical_path.py +179 -0
- chrys/service/analytics/_facts.py +919 -0
- chrys/service/analytics/_insights.py +769 -0
- chrys/service/analytics/_metric_ops.py +83 -0
- chrys/service/analytics/_session_projection.py +460 -0
- chrys/service/analytics/_timeline.py +434 -0
- chrys/service/analytics/_turn_graph.py +1237 -0
- chrys/service/analytics/_turns.py +1377 -0
- chrys/service/analytics/_workflows.py +171 -0
- chrys/service/analytics/aggregation.py +1474 -0
- chrys/service/analytics/classification.py +128 -0
- chrys/service/analytics/export.py +803 -0
- chrys/service/analytics/findings.py +282 -0
- chrys/service/analytics/math.py +79 -0
- chrys/service/analytics/model.py +886 -0
- chrys/service/analytics/reader.py +321 -0
- chrys/service/approval/__init__.py +3 -0
- chrys/service/approval/arbitration.py +102 -0
- chrys/service/approval/command_identity.py +109 -0
- chrys/service/approval/correlation.py +57 -0
- chrys/service/approval/grant_store.py +108 -0
- chrys/service/approval/judge.py +589 -0
- chrys/service/approval/level.py +15 -0
- chrys/service/approval/policy.py +209 -0
- chrys/service/approval/reuse.py +223 -0
- chrys/service/approval/reuse_binding.py +133 -0
- chrys/service/approval/safety_classifier.py +536 -0
- chrys/service/approval/turn_context.py +49 -0
- chrys/service/context/__init__.py +3 -0
- chrys/service/context/compaction/__init__.py +38 -0
- chrys/service/context/compaction/breaker.py +156 -0
- chrys/service/context/compaction/budgets.py +93 -0
- chrys/service/context/compaction/calibration.py +77 -0
- chrys/service/context/compaction/compression.py +690 -0
- chrys/service/context/compaction/current_turn_drop.py +458 -0
- chrys/service/context/compaction/events.py +201 -0
- chrys/service/context/compaction/exclusions.py +261 -0
- chrys/service/context/compaction/groups.py +361 -0
- chrys/service/context/compaction/last_words.py +1996 -0
- chrys/service/context/compaction/last_words_state.py +752 -0
- chrys/service/context/compaction/scoped.py +472 -0
- chrys/service/context/compaction/spill.py +1947 -0
- chrys/service/context/compaction/strategy.py +1116 -0
- chrys/service/context/compaction/summaries.py +319 -0
- chrys/service/context/compaction/turns.py +375 -0
- chrys/service/context/manager.py +174 -0
- chrys/service/context/memory_loader.py +792 -0
- chrys/service/context/middleware/__init__.py +3 -0
- chrys/service/context/middleware/usage.py +332 -0
- chrys/service/context/providers/__init__.py +3 -0
- chrys/service/context/providers/context_management.py +432 -0
- chrys/service/context/providers/history.py +647 -0
- chrys/service/context/providers/memory.py +50 -0
- chrys/service/context/tool_content.py +22 -0
- chrys/service/hooks/__init__.py +37 -0
- chrys/service/hooks/detached_worker.py +118 -0
- chrys/service/hooks/docs/README.md +14 -0
- chrys/service/hooks/docs/authoring.md +684 -0
- chrys/service/hooks/docs/configuration.md +499 -0
- chrys/service/hooks/docs/design.md +359 -0
- chrys/service/hooks/docs/project-hooks.md +348 -0
- chrys/service/hooks/events.py +157 -0
- chrys/service/hooks/loader.py +665 -0
- chrys/service/hooks/manager.py +807 -0
- chrys/service/hooks/matcher.py +111 -0
- chrys/service/hooks/outbox.py +294 -0
- chrys/service/hooks/runner.py +572 -0
- chrys/service/hooks/schema.py +407 -0
- chrys/service/llm/__init__.py +7 -0
- chrys/service/llm/_structured_outputs.py +192 -0
- chrys/service/llm/anthropic_messages/__init__.py +9 -0
- chrys/service/llm/anthropic_messages/client.py +254 -0
- chrys/service/llm/anthropic_messages/decode.py +331 -0
- chrys/service/llm/anthropic_messages/history.py +279 -0
- chrys/service/llm/anthropic_messages/request.py +323 -0
- chrys/service/llm/anthropic_messages/server_tools.py +319 -0
- chrys/service/llm/anthropic_messages/stream.py +297 -0
- chrys/service/llm/anthropic_messages/thinking_binding.py +156 -0
- chrys/service/llm/chat_completions/__init__.py +9 -0
- chrys/service/llm/chat_completions/client.py +369 -0
- chrys/service/llm/chat_completions/decode.py +338 -0
- chrys/service/llm/chat_completions/history.py +657 -0
- chrys/service/llm/chat_completions/reasoning.py +244 -0
- chrys/service/llm/chat_completions/request.py +192 -0
- chrys/service/llm/chat_completions/stream.py +546 -0
- chrys/service/llm/chat_completions/validation.py +308 -0
- chrys/service/llm/clients.py +613 -0
- chrys/service/llm/images.py +65 -0
- chrys/service/llm/mock.py +413 -0
- chrys/service/llm/observer.py +446 -0
- chrys/service/llm/one_shot.py +106 -0
- chrys/service/llm/openai_exceptions.py +93 -0
- chrys/service/llm/openai_responses/__init__.py +10 -0
- chrys/service/llm/openai_responses/client.py +323 -0
- chrys/service/llm/openai_responses/decode.py +432 -0
- chrys/service/llm/openai_responses/history.py +519 -0
- chrys/service/llm/openai_responses/hosted.py +625 -0
- chrys/service/llm/openai_responses/replay.py +629 -0
- chrys/service/llm/openai_responses/request.py +342 -0
- chrys/service/llm/openai_responses/stream.py +847 -0
- chrys/service/llm/openai_timestamps.py +57 -0
- chrys/service/llm/providers.py +107 -0
- chrys/service/llm/proxy_route.py +54 -0
- chrys/service/llm/raw_http_log.py +309 -0
- chrys/service/llm/route_facts.py +63 -0
- chrys/service/llm/route_sessions.py +49 -0
- chrys/service/llm/sdk_anthropic.py +18 -0
- chrys/service/llm/sdk_headers.py +47 -0
- chrys/service/llm/sdk_openai.py +18 -0
- chrys/service/llm/sdk_retry.py +59 -0
- chrys/service/llm/wire_client.py +246 -0
- chrys/service/mcp/__init__.py +3 -0
- chrys/service/mcp/_connection.py +235 -0
- chrys/service/mcp/_http_transport.py +350 -0
- chrys/service/mcp/_progressive.py +459 -0
- chrys/service/mcp/_stdio_transport.py +614 -0
- chrys/service/mcp/_tool_mixins.py +96 -0
- chrys/service/mcp/adapter.py +1031 -0
- chrys/service/mcp/cache.py +476 -0
- chrys/service/mcp/content.py +32 -0
- chrys/service/mcp/errors.py +169 -0
- chrys/service/mcp/owned.py +1330 -0
- chrys/service/mcp/result_limits.py +168 -0
- chrys/service/mcp/thinking_warning.py +95 -0
- chrys/service/mcp/validation.py +74 -0
- chrys/service/mutations/__init__.py +84 -0
- chrys/service/mutations/coordination.py +894 -0
- chrys/service/mutations/detector.py +458 -0
- chrys/service/mutations/git_calibrator.py +397 -0
- chrys/service/mutations/git_state.py +647 -0
- chrys/service/mutations/pipeline.py +779 -0
- chrys/service/mutations/scanner.py +466 -0
- chrys/service/mutations/snapshot_files.py +233 -0
- chrys/service/mutations/store.py +625 -0
- chrys/service/mutations/tool_names.py +15 -0
- chrys/service/mutations/trace.py +246 -0
- chrys/service/mutations/tracker.py +1289 -0
- chrys/service/mutations/types.py +559 -0
- chrys/service/mutations/workspace_changes.py +1583 -0
- chrys/service/profiles/__init__.py +2 -0
- chrys/service/profiles/agents/__init__.py +3 -0
- chrys/service/profiles/agents/builtins/Code.yaml +199 -0
- chrys/service/profiles/agents/builtins/Explore.yaml +62 -0
- chrys/service/profiles/agents/builtins/General.yaml +114 -0
- chrys/service/profiles/agents/builtins/QA.yaml +128 -0
- chrys/service/profiles/agents/loader.py +808 -0
- chrys/service/profiles/agents/registry.py +727 -0
- chrys/service/profiles/agents/schema.py +371 -0
- chrys/service/profiles/agents/serializer.py +196 -0
- chrys/service/profiles/coercion.py +22 -0
- chrys/service/profiles/models/__init__.py +3 -0
- chrys/service/profiles/models/env_bridge.py +157 -0
- chrys/service/profiles/models/loader.py +282 -0
- chrys/service/profiles/models/options.py +438 -0
- chrys/service/profiles/models/registry.py +104 -0
- chrys/service/profiles/models/resolver.py +286 -0
- chrys/service/profiles/models/schema.py +91 -0
- chrys/service/profiles/models/serializer.py +76 -0
- chrys/service/session/__init__.py +3 -0
- chrys/service/session/checkpoint.py +156 -0
- chrys/service/session/history.py +1616 -0
- chrys/service/session/message_metadata.py +151 -0
- chrys/service/session/persistence.py +435 -0
- chrys/service/session/runtime_metadata.py +210 -0
- chrys/service/session/sub_agent_logs.py +1069 -0
- chrys/service/session/sub_agent_transcript.py +654 -0
- chrys/service/skills/__init__.py +3 -0
- chrys/service/skills/adapter.py +408 -0
- chrys/service/skills/constants.py +8 -0
- chrys/service/skills/loader.py +575 -0
- chrys/service/skills/model.py +130 -0
- chrys/service/skills/provider.py +841 -0
- chrys/service/skills/runner.py +390 -0
- chrys/service/state/__init__.py +3 -0
- chrys/service/state/_fork.py +710 -0
- chrys/service/state/_session_files.py +175 -0
- chrys/service/state/_session_meta.py +552 -0
- chrys/service/state/locks.py +154 -0
- chrys/service/state/serializers.py +156 -0
- chrys/service/state/session_catalog.py +361 -0
- chrys/service/state/session_listing.py +84 -0
- chrys/service/state/session_migration.py +446 -0
- chrys/service/state/session_mru.py +315 -0
- chrys/service/state/store.py +2132 -0
- chrys/service/state/workflow.py +158 -0
- chrys/service/text_blocks.py +47 -0
- chrys/service/todos/__init__.py +3 -0
- chrys/service/todos/reminder.py +31 -0
- chrys/service/todos/tracker.py +58 -0
- chrys/service/tools/__init__.py +3 -0
- chrys/service/tools/approval_targets.py +92 -0
- chrys/service/tools/builtins/__init__.py +3 -0
- chrys/service/tools/builtins/ask_user.py +326 -0
- chrys/service/tools/builtins/doc_converter/__init__.py +494 -0
- chrys/service/tools/builtins/doc_converter/artifacts.py +392 -0
- chrys/service/tools/builtins/doc_converter/parsers/__init__.py +3 -0
- chrys/service/tools/builtins/doc_converter/parsers/_table.py +34 -0
- chrys/service/tools/builtins/doc_converter/parsers/base.py +101 -0
- chrys/service/tools/builtins/doc_converter/parsers/docx.py +88 -0
- chrys/service/tools/builtins/doc_converter/parsers/pdf.py +144 -0
- chrys/service/tools/builtins/doc_converter/parsers/pptx.py +103 -0
- chrys/service/tools/builtins/doc_converter/parsers/xls.py +32 -0
- chrys/service/tools/builtins/doc_converter/parsers/xlsx.py +51 -0
- chrys/service/tools/builtins/doc_converter/registry.py +55 -0
- chrys/service/tools/builtins/filesystem.py +1071 -0
- chrys/service/tools/builtins/search.py +1265 -0
- chrys/service/tools/builtins/shell.py +967 -0
- chrys/service/tools/builtins/shell_command_filtering/__init__.py +5 -0
- chrys/service/tools/builtins/shell_command_filtering/policy.py +60 -0
- chrys/service/tools/builtins/shell_command_filtering/presets.py +152 -0
- chrys/service/tools/builtins/shell_command_filtering/readonly/__init__.py +358 -0
- chrys/service/tools/builtins/shell_command_filtering/readonly/commands.py +416 -0
- chrys/service/tools/builtins/shell_command_filtering/readonly/git.py +408 -0
- chrys/service/tools/builtins/shell_command_filtering/readonly/syntax.py +87 -0
- chrys/service/tools/builtins/shell_command_filtering/tokenizer.py +214 -0
- chrys/service/tools/builtins/shell_filter.py +24 -0
- chrys/service/tools/builtins/sleep.py +91 -0
- chrys/service/tools/builtins/todo.py +64 -0
- chrys/service/tools/builtins/web/__init__.py +6 -0
- chrys/service/tools/builtins/web/build.py +268 -0
- chrys/service/tools/builtins/web/config.py +338 -0
- chrys/service/tools/builtins/web/credentials.py +37 -0
- chrys/service/tools/builtins/web/fetch/__init__.py +3 -0
- chrys/service/tools/builtins/web/fetch/cache.py +68 -0
- chrys/service/tools/builtins/web/fetch/convert.py +56 -0
- chrys/service/tools/builtins/web/fetch/tool.py +223 -0
- chrys/service/tools/builtins/web/hosted.py +61 -0
- chrys/service/tools/builtins/web/http.py +330 -0
- chrys/service/tools/builtins/web/progress.py +18 -0
- chrys/service/tools/builtins/web/search/__init__.py +3 -0
- chrys/service/tools/builtins/web/search/exa_mcp.py +146 -0
- chrys/service/tools/builtins/web/search/html.py +152 -0
- chrys/service/tools/builtins/web/search/json_api.py +227 -0
- chrys/service/tools/builtins/web/search/providers.py +77 -0
- chrys/service/tools/builtins/web/search/tool.py +218 -0
- chrys/service/tools/builtins/web/search/types.py +28 -0
- chrys/service/tools/builtins/web/tls_identity.py +66 -0
- chrys/service/tools/kinds.py +115 -0
- chrys/service/tools/names.py +47 -0
- chrys/service/tools/registry.py +242 -0
- chrys/service/tools/result_metadata.py +103 -0
- chrys/service/tools/session_artifacts.py +196 -0
- chrys/service/tools/spill.py +218 -0
- chrys/service/tools/workspace_paths.py +81 -0
- chrys/service/trajectory/__init__.py +11 -0
- chrys/service/trajectory/approvals.py +201 -0
- chrys/service/trajectory/compaction.py +420 -0
- chrys/service/trajectory/fork.py +75 -0
- chrys/service/trajectory/hooks.py +217 -0
- chrys/service/trajectory/items.py +41 -0
- chrys/service/trajectory/preparation.py +374 -0
- chrys/service/trajectory/retries.py +95 -0
- chrys/service/trajectory/revisions.py +129 -0
- chrys/service/trajectory/segmented.py +163 -0
- chrys/service/trajectory/session.py +762 -0
- chrys/service/trajectory/state.py +83 -0
- chrys/service/trajectory/sub_agents.py +169 -0
- chrys/service/trajectory/tombstone.py +262 -0
- chrys/service/trajectory/tools.py +323 -0
- chrys/service/trajectory/validation.py +130 -0
- chrys/service/trajectory/waits.py +161 -0
- chrys/service/trajectory/workflow.py +148 -0
- chrys/service/vision.py +128 -0
- chrys/service/workflows/__init__.py +3 -0
- chrys/service/workflows/admission.py +151 -0
- chrys/service/workflows/artifacts.py +109 -0
- chrys/service/workflows/asks.py +130 -0
- chrys/service/workflows/builtins/__init__.py +12 -0
- chrys/service/workflows/builtins/demo-workflow.manifest.json +635 -0
- chrys/service/workflows/builtins/demo-workflow.py +756 -0
- chrys/service/workflows/discovery.py +554 -0
- chrys/service/workflows/environment.py +284 -0
- chrys/service/workflows/graph.py +430 -0
- chrys/service/workflows/history.py +82 -0
- chrys/service/workflows/interpreter.py +107 -0
- chrys/service/workflows/journal.py +334 -0
- chrys/service/workflows/layout.py +56 -0
- chrys/service/workflows/ledger.py +149 -0
- chrys/service/workflows/model_selection.py +18 -0
- chrys/service/workflows/orphans.py +209 -0
- chrys/service/workflows/outcomes.py +46 -0
- chrys/service/workflows/protocol.py +210 -0
- chrys/service/workflows/records.py +142 -0
- chrys/service/workflows/scheduler.py +770 -0
- chrys/service/workflows/sdk/__init__.py +51 -0
- chrys/service/workflows/sdk/_ask.py +167 -0
- chrys/service/workflows/sdk/_builder.py +781 -0
- chrys/service/workflows/sdk/_values.py +92 -0
- chrys/service/workflows/sdk_artifact.py +74 -0
- chrys/service/workflows/store.py +494 -0
- chrys/service/workflows/transcript.py +102 -0
- chrys/service/workflows/values.py +73 -0
- chrys/service/workflows/worker_host.py +1820 -0
- chrys/workflows.py +38 -0
- icode_tui-0.29.1.dist-info/METADATA +104 -0
- icode_tui-0.29.1.dist-info/RECORD +1138 -0
- icode_tui-0.29.1.dist-info/WHEEL +4 -0
- icode_tui-0.29.1.dist-info/entry_points.txt +2 -0
- icode_tui-0.29.1.dist-info/licenses/LICENSE +202 -0
- icode_tui-0.29.1.dist-info/licenses/NOTICE +1955 -0
chrys/app/tui/theme.py
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Chrys TUI theme definitions."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from functools import lru_cache
|
|
8
|
+
from typing import TYPE_CHECKING, Any, TypedDict
|
|
9
|
+
|
|
10
|
+
from textual.color import Color, ColorParseError
|
|
11
|
+
from textual.design import DEFAULT_DARK_BACKGROUND, DEFAULT_LIGHT_BACKGROUND
|
|
12
|
+
from textual.theme import Theme
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from textual.app import App
|
|
16
|
+
|
|
17
|
+
_TuiVariableDefaultsBase = App[Any]
|
|
18
|
+
else:
|
|
19
|
+
_TuiVariableDefaultsBase = object
|
|
20
|
+
|
|
21
|
+
# Built-in inventory only; these names never select rendering rules.
|
|
22
|
+
CHRYS_THEMES = {"chrys", "chrys-legacy", "chrys-ansi"}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Shared Dracula-inspired palette used by every chrys theme.
|
|
26
|
+
class _ChrysColors(TypedDict):
|
|
27
|
+
"""Keyword-compatible color subset accepted by ``Theme``."""
|
|
28
|
+
|
|
29
|
+
primary: str
|
|
30
|
+
secondary: str
|
|
31
|
+
warning: str
|
|
32
|
+
error: str
|
|
33
|
+
success: str
|
|
34
|
+
accent: str
|
|
35
|
+
foreground: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
_CHRYS_COLORS: _ChrysColors = {
|
|
39
|
+
"primary": "#AF87FF",
|
|
40
|
+
"secondary": "#5F5FAF",
|
|
41
|
+
"warning": "#FFAF5F",
|
|
42
|
+
"error": "#FF5F5F",
|
|
43
|
+
"success": "#5FFF87",
|
|
44
|
+
"accent": "#FF87D7",
|
|
45
|
+
"foreground": "#EEEEEE",
|
|
46
|
+
}
|
|
47
|
+
CHRYS_COLOR_NAMES = tuple(_CHRYS_COLORS)
|
|
48
|
+
|
|
49
|
+
# Shared control slots. These RGB defaults are the Chrys palette; the resolver
|
|
50
|
+
# derives other themes' defaults from their own surfaces and foregrounds.
|
|
51
|
+
CONTROL_VARIABLE_DEFAULTS: dict[str, str] = {
|
|
52
|
+
"control-background": "#303030",
|
|
53
|
+
"control-background-muted": "#262626",
|
|
54
|
+
"control-foreground-muted": "#585858",
|
|
55
|
+
"overlay-background": "#3A3A3A",
|
|
56
|
+
"markdown-block-background": "#303030",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# CSS variables that must remain resolvable with every Textual theme.
|
|
60
|
+
TUI_VARIABLE_DEFAULTS: dict[str, str] = {
|
|
61
|
+
**CONTROL_VARIABLE_DEFAULTS,
|
|
62
|
+
"border-opacity": "80%",
|
|
63
|
+
"control-disabled-background": "transparent",
|
|
64
|
+
"hatch-color": "#808080 15%",
|
|
65
|
+
"ansi-background": "ansi_default",
|
|
66
|
+
"ansi-foreground": "ansi_default",
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# The editor exposes only common controls. Semantic fills already follow the
|
|
70
|
+
# main palette. Existing per-variant YAML overrides remain compatible.
|
|
71
|
+
BUTTON_COLOR_VARIABLES = (
|
|
72
|
+
"button-flat-foreground",
|
|
73
|
+
"button-hover-foreground",
|
|
74
|
+
"button-hover-background",
|
|
75
|
+
"button-disabled-foreground",
|
|
76
|
+
"button-disabled-background",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@lru_cache(maxsize=1024)
|
|
81
|
+
def concrete_theme_color(value: str, background: str, dark: bool) -> str:
|
|
82
|
+
"""Flatten legacy color/percentage expressions into theme-derived colors.
|
|
83
|
+
|
|
84
|
+
ANSI ink stays terminal-owned: Textual ignores its alpha, so removing the
|
|
85
|
+
percentage preserves the actual rendering. RGB/auto ink is blended over
|
|
86
|
+
the background; terminal backgrounds use an RGB approximation for that.
|
|
87
|
+
Plain color tokens and non-color CSS values keep their original meaning.
|
|
88
|
+
"""
|
|
89
|
+
parts = value.rsplit(maxsplit=1)
|
|
90
|
+
if len(parts) != 2 or not parts[1].endswith("%"):
|
|
91
|
+
return value
|
|
92
|
+
color_text, percentage = parts
|
|
93
|
+
try:
|
|
94
|
+
alpha = float(percentage[:-1]) / 100
|
|
95
|
+
if not 0 <= alpha <= 1:
|
|
96
|
+
return value
|
|
97
|
+
if color_text != "auto" and Color.parse(color_text).ansi is not None:
|
|
98
|
+
return color_text
|
|
99
|
+
|
|
100
|
+
def rgb(text: str, *, is_background: bool) -> Color:
|
|
101
|
+
color = Color.parse(text)
|
|
102
|
+
if color.ansi == -1:
|
|
103
|
+
return Color(0, 0, 0) if dark == is_background else Color(255, 255, 255)
|
|
104
|
+
if color.ansi is not None:
|
|
105
|
+
return Color(*color.rich_color.get_truecolor())
|
|
106
|
+
return color
|
|
107
|
+
|
|
108
|
+
base = rgb(background, is_background=True)
|
|
109
|
+
ink = base.get_contrast_text(1) if color_text == "auto" else rgb(color_text, is_background=False)
|
|
110
|
+
return base.blend(ink, ink.a * alpha, 1).hex
|
|
111
|
+
except ColorParseError, ValueError:
|
|
112
|
+
return value
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _readable_button_text(background: str, foreground: str) -> str:
|
|
116
|
+
"""Keep semantic ink unless its opaque RGB fill makes it hard to read.
|
|
117
|
+
|
|
118
|
+
ANSI slots and explicit button overrides retain their own policies;
|
|
119
|
+
this only repairs generated flat-button fallbacks.
|
|
120
|
+
"""
|
|
121
|
+
try:
|
|
122
|
+
fill = Color.parse(background)
|
|
123
|
+
if foreground.startswith("auto ") and foreground.endswith("%"):
|
|
124
|
+
alpha = float(foreground.removeprefix("auto ").removesuffix("%")) / 100
|
|
125
|
+
ink = fill + fill.get_contrast_text(alpha)
|
|
126
|
+
else:
|
|
127
|
+
ink = Color.parse(foreground)
|
|
128
|
+
except ColorParseError, ValueError:
|
|
129
|
+
return foreground
|
|
130
|
+
if fill.ansi is not None or ink.ansi is not None or fill.a != 1 or ink.a != 1:
|
|
131
|
+
return foreground
|
|
132
|
+
|
|
133
|
+
def luminance(color: Color) -> float:
|
|
134
|
+
channels = (value / 255 for value in (color.r, color.g, color.b))
|
|
135
|
+
linear = (value / 12.92 if value <= 0.04045 else ((value + 0.055) / 1.055) ** 2.4 for value in channels)
|
|
136
|
+
return sum(value * weight for value, weight in zip(linear, (0.2126, 0.7152, 0.0722), strict=True))
|
|
137
|
+
|
|
138
|
+
fill_luma, ink_luma = luminance(fill), luminance(ink)
|
|
139
|
+
low, high = sorted((fill_luma, ink_luma))
|
|
140
|
+
if (high + 0.05) / (low + 0.05) >= 3:
|
|
141
|
+
return foreground
|
|
142
|
+
return "#000000" if fill_luma > 0.179 else "#FFFFFF"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _with_button_css_variables(theme: Theme, variables: dict[str, str]) -> dict[str, str]:
|
|
146
|
+
"""Resolve button overrides identically for live themes and editor drafts.
|
|
147
|
+
|
|
148
|
+
The common foreground overrides semantic label defaults; a per-variant
|
|
149
|
+
foreground takes precedence. Unset hover/disabled fills retain each
|
|
150
|
+
variant's palette. Internal aliases let those fallbacks remain distinct
|
|
151
|
+
without requiring users to configure every variant/state combination.
|
|
152
|
+
"""
|
|
153
|
+
resolved = dict(variables)
|
|
154
|
+
overrides = dict(theme.variables)
|
|
155
|
+
# A shared user color must match its swatch on every button variant.
|
|
156
|
+
# Only generated contrast defaults adapt separately to each fill.
|
|
157
|
+
for name in (*BUTTON_COLOR_VARIABLES, "button-color-foreground"):
|
|
158
|
+
if name in overrides:
|
|
159
|
+
background = concrete_theme_color(
|
|
160
|
+
variables.get(name.removesuffix("-foreground") + "-background", variables["background"]),
|
|
161
|
+
variables["background"],
|
|
162
|
+
theme.dark,
|
|
163
|
+
)
|
|
164
|
+
overrides[name] = concrete_theme_color(overrides[name], background, theme.dark)
|
|
165
|
+
resolved[name] = overrides[name]
|
|
166
|
+
if not theme.ansi and "button-color-foreground" not in overrides:
|
|
167
|
+
resolved["button-color-foreground"] = "auto 100%"
|
|
168
|
+
if "button-flat-foreground" in overrides:
|
|
169
|
+
resolved["button-color-foreground"] = overrides["button-flat-foreground"]
|
|
170
|
+
# Textual's button-color-foreground belongs to solid/raised fills. Many
|
|
171
|
+
# bundled themes set dark ink there, which is unreadable on muted flat
|
|
172
|
+
# fills. Keep a separate flat override, copied as ordinary theme data.
|
|
173
|
+
ink = overrides.get("button-flat-foreground", resolved["button-color-foreground"] if theme.ansi else None)
|
|
174
|
+
for variant in ("default", "primary", "success", "warning", "error"):
|
|
175
|
+
default = variant == "default"
|
|
176
|
+
prefix = "button" if default else f"button-{variant}"
|
|
177
|
+
background = overrides.get(f"{prefix}-background", resolved["surface" if default else f"{variant}-muted"])
|
|
178
|
+
foreground = overrides.get(
|
|
179
|
+
f"{prefix}-foreground", ink or ("auto 90%" if default else resolved[f"text-{variant}"])
|
|
180
|
+
)
|
|
181
|
+
if ink is None and f"{prefix}-foreground" not in overrides and (default or f"text-{variant}" not in overrides):
|
|
182
|
+
foreground = _readable_button_text(background, foreground)
|
|
183
|
+
alias = f"tui-button-{variant}"
|
|
184
|
+
resolved[f"{alias}-background"] = background
|
|
185
|
+
resolved[f"{alias}-foreground"] = foreground
|
|
186
|
+
resolved[f"{alias}-hover-background"] = overrides.get(
|
|
187
|
+
"button-hover-background", resolved["primary" if default else variant]
|
|
188
|
+
)
|
|
189
|
+
resolved[f"{alias}-hover-foreground"] = overrides.get(
|
|
190
|
+
"button-hover-foreground", ink or ("auto 90%" if default else resolved["text"])
|
|
191
|
+
)
|
|
192
|
+
if ink is None and "button-hover-foreground" not in overrides and "text" not in overrides:
|
|
193
|
+
resolved[f"{alias}-hover-foreground"] = _readable_button_text(
|
|
194
|
+
resolved[f"{alias}-hover-background"], resolved[f"{alias}-hover-foreground"]
|
|
195
|
+
)
|
|
196
|
+
resolved[f"{alias}-disabled-background"] = overrides.get("button-disabled-background", background)
|
|
197
|
+
resolved[f"{alias}-disabled-foreground"] = overrides.get(
|
|
198
|
+
"button-disabled-foreground", "auto 50%" if default else foreground
|
|
199
|
+
)
|
|
200
|
+
# Flat borders complete the colored fill; they must follow the button
|
|
201
|
+
# palette, including on themes with neutral container outlines.
|
|
202
|
+
for state in ("", "-hover", "-disabled"):
|
|
203
|
+
resolved[f"tui-border-button-{variant}{state}"] = resolved[f"{alias}{state}-background"]
|
|
204
|
+
resolved["button-active-tint"] = overrides.get("button-active-tint", f"{resolved['background']} 30%")
|
|
205
|
+
return resolved
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
_BORDER_COLOR_VARIABLE_SOURCES: dict[str, str] = {
|
|
209
|
+
"tui-border-accent": "accent",
|
|
210
|
+
"tui-border-block-hover-background": "block-hover-background",
|
|
211
|
+
"tui-border-control-background": "control-background",
|
|
212
|
+
"tui-border-error": "error",
|
|
213
|
+
"tui-border-foreground": "foreground",
|
|
214
|
+
"tui-border-primary": "primary",
|
|
215
|
+
"tui-border-primary-darken-2": "primary-darken-2",
|
|
216
|
+
"tui-border-primary-darken-3": "primary-darken-3",
|
|
217
|
+
"tui-border-secondary": "secondary",
|
|
218
|
+
"tui-border-success": "success",
|
|
219
|
+
"tui-border-warning": "warning",
|
|
220
|
+
"tui-border-warning-darken-1": "warning-darken-1",
|
|
221
|
+
}
|
|
222
|
+
_BORDER_COLOR_LITERAL_DEFAULTS: dict[str, str] = {
|
|
223
|
+
"tui-border-neutral-100": "rgb(100, 100, 100)",
|
|
224
|
+
"tui-border-neutral-128": "#808080",
|
|
225
|
+
"tui-border-neutral-160": "rgb(160, 160, 160)",
|
|
226
|
+
"tui-border-neutral-gray": "gray",
|
|
227
|
+
}
|
|
228
|
+
_SEMANTIC_BORDER_COLOR_VARIABLE_SOURCES: dict[str, str] = {
|
|
229
|
+
"tui-border-agent-message": "success",
|
|
230
|
+
"tui-border-selected-turn": "primary",
|
|
231
|
+
"tui-border-status-error": "error",
|
|
232
|
+
"tui-border-status-warning": "warning",
|
|
233
|
+
"tui-border-user-message": "accent",
|
|
234
|
+
}
|
|
235
|
+
_BORDER_TITLE_COLOR_VARIABLE_SOURCES: dict[str, str] = {
|
|
236
|
+
"tui-border-title-accent": "accent",
|
|
237
|
+
"tui-border-title-primary": "primary",
|
|
238
|
+
"tui-border-title-warning": "warning",
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def with_tui_css_variables(theme: Theme, variables: dict[str, str]) -> dict[str, str]:
|
|
243
|
+
"""Resolve chrome and button colors for live, preview and recovery paths."""
|
|
244
|
+
resolved = dict(variables)
|
|
245
|
+
# Resolve the roots before building dependent colors; otherwise a legacy
|
|
246
|
+
# foreground like "red 40%" would become the invalid "red 40% 15%" hatch.
|
|
247
|
+
background = theme.background or (
|
|
248
|
+
"ansi_default" if theme.ansi else DEFAULT_DARK_BACKGROUND if theme.dark else DEFAULT_LIGHT_BACKGROUND
|
|
249
|
+
)
|
|
250
|
+
resolved["background"] = concrete_theme_color(resolved["background"], background, theme.dark)
|
|
251
|
+
resolved["foreground"] = concrete_theme_color(resolved["foreground"], resolved["background"], theme.dark)
|
|
252
|
+
# One common track color covers hover and drag too. Explicit advanced
|
|
253
|
+
# per-state YAML overrides remain supported, including in ANSI mode.
|
|
254
|
+
for state in ("hover", "active"):
|
|
255
|
+
key = f"scrollbar-background-{state}"
|
|
256
|
+
resolved[key] = theme.variables.get(key, resolved["scrollbar-background"])
|
|
257
|
+
for name, source in (
|
|
258
|
+
("control-background", "surface"),
|
|
259
|
+
("control-background-muted", "surface"),
|
|
260
|
+
("control-disabled-background", "background"),
|
|
261
|
+
("control-foreground-muted", "text-disabled"),
|
|
262
|
+
("overlay-background", "panel"),
|
|
263
|
+
("markdown-block-background", "surface"),
|
|
264
|
+
):
|
|
265
|
+
resolved[name] = theme.variables.get(name, resolved[source])
|
|
266
|
+
resolved["hatch-color"] = theme.variables.get("hatch-color", f"{resolved['foreground']} 15%")
|
|
267
|
+
# Native ANSI colors ignore alpha; opaque neutral fills keep turn text readable.
|
|
268
|
+
resolved["tui-ansi-turn-background"] = "#303030" if theme.dark else "#DADADA"
|
|
269
|
+
resolved["tui-ansi-turn-focus-background"] = "#444444" if theme.dark else "#C6C6C6"
|
|
270
|
+
border_override = theme.variables.get("border-color")
|
|
271
|
+
for alias, source in _BORDER_COLOR_VARIABLE_SOURCES.items():
|
|
272
|
+
resolved[alias] = border_override or resolved[source]
|
|
273
|
+
for alias, color in _BORDER_COLOR_LITERAL_DEFAULTS.items():
|
|
274
|
+
resolved[alias] = border_override or color
|
|
275
|
+
# Transcript chrome remains semantic when a theme uses uniform outlines.
|
|
276
|
+
for alias, source in _SEMANTIC_BORDER_COLOR_VARIABLE_SOURCES.items():
|
|
277
|
+
resolved[alias] = resolved[source]
|
|
278
|
+
for alias, source in _BORDER_TITLE_COLOR_VARIABLE_SOURCES.items():
|
|
279
|
+
resolved[alias] = resolved[source]
|
|
280
|
+
resolved["tui-tool-group-title"] = theme.variables.get("tool-group-title-color", resolved["warning"])
|
|
281
|
+
resolved = _with_button_css_variables(theme, resolved)
|
|
282
|
+
# The editable palette uses concrete colors. Internal contrast roles are
|
|
283
|
+
# shared across different fills (e.g. warning badges and primary buttons);
|
|
284
|
+
# CSS must resolve those against the consuming control, not the app surface.
|
|
285
|
+
# Active tint is a blend effect, not an editable foreground/background.
|
|
286
|
+
# Making it opaque would paint over the pressed button and its label.
|
|
287
|
+
contrast_roles = {"button-color-foreground", "text", *(f"text-{color}" for color in CHRYS_COLOR_NAMES)}
|
|
288
|
+
return {
|
|
289
|
+
name: value
|
|
290
|
+
if name == "button-active-tint" or (name in contrast_roles and value.startswith("auto "))
|
|
291
|
+
else concrete_theme_color(
|
|
292
|
+
value,
|
|
293
|
+
concrete_theme_color(
|
|
294
|
+
resolved.get(name.removesuffix("-foreground") + "-background", resolved["background"]),
|
|
295
|
+
resolved["background"],
|
|
296
|
+
theme.dark,
|
|
297
|
+
)
|
|
298
|
+
if name.endswith("-foreground")
|
|
299
|
+
else resolved["background"],
|
|
300
|
+
theme.dark,
|
|
301
|
+
)
|
|
302
|
+
for name, value in resolved.items()
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class TuiVariableDefaultsMixin(_TuiVariableDefaultsBase):
|
|
307
|
+
"""Supply Chrys-specific CSS variables to lightweight Textual hosts.
|
|
308
|
+
|
|
309
|
+
Border alpha applies to RGB-backed themes. Textual deliberately preserves
|
|
310
|
+
native ANSI palette tokens as opaque, so ``ansi-dark`` and ``ansi-light``
|
|
311
|
+
ignore the percentage while ``chrys-ansi`` (RGB palette, ANSI output mode)
|
|
312
|
+
honors it.
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
def get_theme_variable_defaults(self) -> dict[str, str]:
|
|
316
|
+
return TUI_VARIABLE_DEFAULTS
|
|
317
|
+
|
|
318
|
+
def get_css_variables(self) -> dict[str, str]:
|
|
319
|
+
variables = with_tui_css_variables(self.current_theme, super().get_css_variables())
|
|
320
|
+
self.theme_variables = variables
|
|
321
|
+
return variables
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
# Chrys palettes override the same semantic and control slots as user themes.
|
|
325
|
+
# The legacy theme draws its chrome in the accent colors; ANSI keeps that look.
|
|
326
|
+
_CHRYS_LEGACY_VARIABLES = {
|
|
327
|
+
# RGB keeps bold button labels black even when the terminal brightens
|
|
328
|
+
# ANSI black to gray (or defines its black palette entry as gray).
|
|
329
|
+
"button-color-foreground": "#000000",
|
|
330
|
+
"button-flat-foreground": "#000000",
|
|
331
|
+
"button-disabled-background": "#303030",
|
|
332
|
+
"button-disabled-foreground": "#5F5FAF",
|
|
333
|
+
"button-active-tint": "transparent",
|
|
334
|
+
"border": "#AF87FF",
|
|
335
|
+
"border-blurred": "#5F5FAF",
|
|
336
|
+
"scrollbar": "#5F5FAF",
|
|
337
|
+
"scrollbar-hover": "#AF87FF",
|
|
338
|
+
"scrollbar-active": "#FF87D7",
|
|
339
|
+
"scrollbar-background": "#1C1C1C",
|
|
340
|
+
"primary-muted": "#875FAF",
|
|
341
|
+
"error-muted": "#D75F5F",
|
|
342
|
+
"warning-muted": "#D7875F",
|
|
343
|
+
"success-muted": "#5FD75F",
|
|
344
|
+
"block-cursor-foreground": "#303030",
|
|
345
|
+
"block-cursor-background": "#8787D7",
|
|
346
|
+
"block-cursor-blurred-background": "#8787D7",
|
|
347
|
+
"block-hover-background": "#4E4E4E",
|
|
348
|
+
"footer-background": "#262626",
|
|
349
|
+
"footer-foreground": "#EEEEEE",
|
|
350
|
+
"footer-key-foreground": "#AF87FF",
|
|
351
|
+
"footer-key-background": "transparent",
|
|
352
|
+
"footer-description-foreground": "#D0D0D0",
|
|
353
|
+
"footer-description-background": "transparent",
|
|
354
|
+
"footer-item-background": "transparent",
|
|
355
|
+
**CONTROL_VARIABLE_DEFAULTS,
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
# The default theme quiets that chrome down to grays.
|
|
359
|
+
_CHRYS_VARIABLES = {
|
|
360
|
+
**_CHRYS_LEGACY_VARIABLES,
|
|
361
|
+
"border-color": "#5F5F5F",
|
|
362
|
+
"tool-group-title-color": "#949494",
|
|
363
|
+
"scrollbar": "#585858",
|
|
364
|
+
"scrollbar-hover": "#767676",
|
|
365
|
+
"scrollbar-active": "#808080",
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
_CHRYS_ANSI_VARIABLES = {
|
|
369
|
+
**_CHRYS_LEGACY_VARIABLES,
|
|
370
|
+
"ansi-background": "ansi_black",
|
|
371
|
+
"ansi-foreground": "ansi_white",
|
|
372
|
+
"foreground-muted": "ansi_bright_black",
|
|
373
|
+
"text-muted": "ansi_white 40%",
|
|
374
|
+
"text-disabled": "ansi_bright_black",
|
|
375
|
+
"markdown-h1-color": _CHRYS_COLORS["primary"],
|
|
376
|
+
"markdown-h2-color": _CHRYS_COLORS["primary"],
|
|
377
|
+
"markdown-h3-color": _CHRYS_COLORS["primary"],
|
|
378
|
+
"markdown-h4-color": _CHRYS_COLORS["foreground"],
|
|
379
|
+
"markdown-h5-color": _CHRYS_COLORS["foreground"],
|
|
380
|
+
# Nearest 256-color approximations of Chrys alpha colors over _DARK_GRAY.
|
|
381
|
+
# Keep these covered by tests/app/tui/behaviors/test_chrys_themes.py so chrys-ansi remains close
|
|
382
|
+
# to chrys without forcing the truecolor theme onto flat approximations.
|
|
383
|
+
"markdown-h6-color": "#9E9E9E",
|
|
384
|
+
"input-selection-background": "#5F5F87",
|
|
385
|
+
"screen-selection-background": "#5F5F87",
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
_DARK_GRAY = "#1C1C1C"
|
|
389
|
+
|
|
390
|
+
CHRYS_THEME = Theme(
|
|
391
|
+
name="chrys",
|
|
392
|
+
**_CHRYS_COLORS,
|
|
393
|
+
background=_DARK_GRAY,
|
|
394
|
+
surface=_DARK_GRAY,
|
|
395
|
+
panel=_DARK_GRAY,
|
|
396
|
+
boost=_DARK_GRAY,
|
|
397
|
+
dark=True,
|
|
398
|
+
variables=_CHRYS_VARIABLES,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
CHRYS_LEGACY_THEME = Theme(
|
|
402
|
+
name="chrys-legacy",
|
|
403
|
+
**_CHRYS_COLORS,
|
|
404
|
+
background=_DARK_GRAY,
|
|
405
|
+
surface=_DARK_GRAY,
|
|
406
|
+
panel=_DARK_GRAY,
|
|
407
|
+
boost=_DARK_GRAY,
|
|
408
|
+
dark=True,
|
|
409
|
+
variables=_CHRYS_LEGACY_VARIABLES,
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
CHRYS_ANSI_THEME = Theme(
|
|
413
|
+
name="chrys-ansi",
|
|
414
|
+
ansi=True,
|
|
415
|
+
**_CHRYS_COLORS,
|
|
416
|
+
background="ansi_default",
|
|
417
|
+
surface="ansi_default",
|
|
418
|
+
panel="ansi_default",
|
|
419
|
+
boost="ansi_default",
|
|
420
|
+
dark=True,
|
|
421
|
+
variables=_CHRYS_ANSI_VARIABLES,
|
|
422
|
+
)
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Loader for user-registered TUI themes (``<config_dir>/themes/*.yaml``).
|
|
4
|
+
|
|
5
|
+
Each ``<name>.yaml`` becomes a Textual ``Theme`` registered alongside the
|
|
6
|
+
built-ins, so every surface that lists ``App.available_themes`` (theme picker,
|
|
7
|
+
``/theme``, Settings panel) picks it up without further wiring. A user theme
|
|
8
|
+
cannot shadow a built-in, and a malformed file costs one warning, not startup.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
import math
|
|
15
|
+
import re
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
import yaml
|
|
20
|
+
from textual.color import Color, ColorParseError
|
|
21
|
+
from textual.css.tokenize import tokenize_values
|
|
22
|
+
from textual.theme import BUILTIN_THEMES, Theme
|
|
23
|
+
|
|
24
|
+
from chrys.app.tui.theme import CHRYS_THEMES
|
|
25
|
+
from chrys.foundation.config.settings import RENAMED_THEMES
|
|
26
|
+
from chrys.foundation.events.types import Warning
|
|
27
|
+
from chrys.foundation.i18n import msg
|
|
28
|
+
from chrys.foundation.platform import get_platform
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
_USER_THEME_SKIPPED = msg(
|
|
33
|
+
"tui.theme_loader.skipped",
|
|
34
|
+
fallback="Skipped user theme {path}: {reason}",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Theme names that always resolve without a user file; user files never displace them.
|
|
38
|
+
# A retired name resolves too — to the theme that has it now — and a user theme
|
|
39
|
+
# taking one could never be selected: the setting would be renamed on the way in.
|
|
40
|
+
_RESERVED_THEME_NAMES = frozenset(BUILTIN_THEMES) | frozenset(CHRYS_THEMES) | frozenset(RENAMED_THEMES)
|
|
41
|
+
_RESERVED_THEME_NAMES_CASEFOLDED = frozenset(name.casefold() for name in _RESERVED_THEME_NAMES)
|
|
42
|
+
|
|
43
|
+
# The name doubles as the ``<name>.yaml`` stem it came from, so separators,
|
|
44
|
+
# drives, and traversal are all out by construction. UserThemeStore.validate_name
|
|
45
|
+
# additionally rejects Windows device names before creating a file.
|
|
46
|
+
_THEME_NAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$")
|
|
47
|
+
|
|
48
|
+
_COLOR_KEYS = (
|
|
49
|
+
"primary",
|
|
50
|
+
"secondary",
|
|
51
|
+
"warning",
|
|
52
|
+
"error",
|
|
53
|
+
"success",
|
|
54
|
+
"accent",
|
|
55
|
+
"foreground",
|
|
56
|
+
"background",
|
|
57
|
+
"surface",
|
|
58
|
+
"panel",
|
|
59
|
+
"boost",
|
|
60
|
+
)
|
|
61
|
+
_BOOL_KEYS = ("dark", "ansi")
|
|
62
|
+
_FLOAT_KEYS = ("luminosity_spread", "text_alpha")
|
|
63
|
+
_KNOWN_KEYS = frozenset(_COLOR_KEYS + _BOOL_KEYS + _FLOAT_KEYS + ("variables",))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class UserThemeLoadError(Exception):
|
|
67
|
+
"""Raised for a single theme file that cannot become a usable Theme."""
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def default_theme_directory() -> Path:
|
|
71
|
+
"""``<config_dir>/themes`` — the single root user themes are scanned from."""
|
|
72
|
+
return get_platform().config_dir / "themes"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def theme_name_is_valid(name: str) -> bool:
|
|
76
|
+
"""Return True when ``name`` can serve as a ``<name>.yaml`` stem."""
|
|
77
|
+
if not name or name.strip() != name or name in {".", ".."} or name.startswith("."):
|
|
78
|
+
return False
|
|
79
|
+
if not _THEME_NAME_RE.match(name):
|
|
80
|
+
return False
|
|
81
|
+
return not name.lower().endswith((".yaml", ".yml"))
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def theme_is_read_only(name: str) -> bool:
|
|
85
|
+
"""Built-in names are protected on case-sensitive and insensitive filesystems."""
|
|
86
|
+
return name.casefold() in _RESERVED_THEME_NAMES_CASEFOLDED
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _load_theme_data(path: Path) -> dict[str, Any]:
|
|
90
|
+
try:
|
|
91
|
+
text = path.read_text(encoding="utf-8")
|
|
92
|
+
except (OSError, UnicodeError) as e:
|
|
93
|
+
raise UserThemeLoadError(f"Cannot read theme file {path}: {e}") from e
|
|
94
|
+
try:
|
|
95
|
+
data = yaml.safe_load(text)
|
|
96
|
+
except Exception as e:
|
|
97
|
+
# PyYAML's scalar constructors also raise errors outside YAMLError
|
|
98
|
+
# (e.g. ValueError for an impossible date, AttributeError for an
|
|
99
|
+
# invalid explicit timestamp). Keep those inside the per-file boundary.
|
|
100
|
+
raise UserThemeLoadError(f"Invalid YAML in {path}: {e}") from e
|
|
101
|
+
if not isinstance(data, dict):
|
|
102
|
+
raise UserThemeLoadError(f"Theme file {path} must contain a mapping at the top level")
|
|
103
|
+
return data
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _theme_from_data(name: str, data: dict[str, Any], path: Path) -> Theme:
|
|
107
|
+
unknown = {key for key in data if not isinstance(key, str) or key not in _KNOWN_KEYS}
|
|
108
|
+
if unknown:
|
|
109
|
+
listed = ", ".join(sorted(repr(key) for key in unknown))
|
|
110
|
+
raise UserThemeLoadError(f"Unknown keys in theme {path}: {listed}")
|
|
111
|
+
for key in _COLOR_KEYS:
|
|
112
|
+
value = data.get(key)
|
|
113
|
+
if value is not None and not isinstance(value, str):
|
|
114
|
+
raise UserThemeLoadError(f"Theme {path}: '{key}' must be a color string")
|
|
115
|
+
for key in _BOOL_KEYS:
|
|
116
|
+
if key in data and not isinstance(data[key], bool):
|
|
117
|
+
raise UserThemeLoadError(f"Theme {path}: '{key}' must be a boolean")
|
|
118
|
+
for key in _FLOAT_KEYS:
|
|
119
|
+
if key not in data:
|
|
120
|
+
continue
|
|
121
|
+
value = data[key]
|
|
122
|
+
try:
|
|
123
|
+
finite = isinstance(value, int | float) and not isinstance(value, bool) and math.isfinite(value)
|
|
124
|
+
except OverflowError:
|
|
125
|
+
finite = False
|
|
126
|
+
if not finite:
|
|
127
|
+
raise UserThemeLoadError(f"Theme {path}: '{key}' must be a finite number")
|
|
128
|
+
variables = data.get("variables", {})
|
|
129
|
+
if not isinstance(variables, dict) or not all(
|
|
130
|
+
isinstance(key, str) and isinstance(value, str) for key, value in variables.items()
|
|
131
|
+
):
|
|
132
|
+
raise UserThemeLoadError(f"Theme {path}: 'variables' must be a mapping of strings to strings")
|
|
133
|
+
# Theme() stores colors as strings and only parses them when the theme is
|
|
134
|
+
# applied — a bad value would crash the picker preview instead of load.
|
|
135
|
+
# Validate with Textual's own parser so what registers is what renders.
|
|
136
|
+
# Color.parse raises AttributeError (not ColorParseError) for non-str
|
|
137
|
+
# input like ``primary:`` (None), so catch both.
|
|
138
|
+
for key in _COLOR_KEYS:
|
|
139
|
+
if key in data:
|
|
140
|
+
try:
|
|
141
|
+
Color.parse(data[key])
|
|
142
|
+
except (ColorParseError, AttributeError, TypeError) as e:
|
|
143
|
+
raise UserThemeLoadError(f"Theme {path}: invalid color for '{key}': {data[key]!r}") from e
|
|
144
|
+
# Variables are tokenized as CSS value tokens when the theme is applied;
|
|
145
|
+
# an untokenizable value would crash the stylesheet refresh (TokenError
|
|
146
|
+
# terminates the app). Pre-validate with the same tokenizer Textual uses,
|
|
147
|
+
# so legal non-color spellings like ``ansi_white 40%`` or ``none`` pass.
|
|
148
|
+
for var_key, var_value in variables.items():
|
|
149
|
+
try:
|
|
150
|
+
tokenize_values({var_key: var_value})
|
|
151
|
+
except Exception as e:
|
|
152
|
+
raise UserThemeLoadError(f"Theme {path}: invalid CSS value for variable '{var_key}': {var_value!r}") from e
|
|
153
|
+
kwargs = {key: data[key] for key in _COLOR_KEYS + _BOOL_KEYS + _FLOAT_KEYS if key in data}
|
|
154
|
+
try:
|
|
155
|
+
theme = Theme(name=name, variables=variables, **kwargs)
|
|
156
|
+
# Construction alone does not exercise derived shade arithmetic or
|
|
157
|
+
# ColorSystem's parsing of variable overrides used by other colors.
|
|
158
|
+
theme.to_color_system().generate()
|
|
159
|
+
except Exception as e:
|
|
160
|
+
raise UserThemeLoadError(f"Invalid theme {path}: {e}") from e
|
|
161
|
+
return theme
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def user_theme_warning(path: Path | str, reason: str) -> Warning:
|
|
165
|
+
"""Build the shared warning for a rejected file or an unusable live theme."""
|
|
166
|
+
display = _USER_THEME_SKIPPED.bind(path=str(path), reason=reason)
|
|
167
|
+
return Warning(code="user_theme_skipped", message=reason, display_message=display)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def load_user_themes(directory: Path | None = None) -> tuple[list[Theme], list[Warning]]:
|
|
171
|
+
"""Discover and parse every user theme under *directory*.
|
|
172
|
+
|
|
173
|
+
Returns ``(themes, warnings)``; per-file failures become warning events
|
|
174
|
+
(publishable on the bus) and the file is skipped, mirroring how an
|
|
175
|
+
invalid agent profile behaves.
|
|
176
|
+
"""
|
|
177
|
+
root = directory if directory is not None else default_theme_directory()
|
|
178
|
+
themes: list[Theme] = []
|
|
179
|
+
warnings: list[Warning] = []
|
|
180
|
+
if not root.is_dir():
|
|
181
|
+
return themes, warnings
|
|
182
|
+
seen: set[str] = set()
|
|
183
|
+
paths = sorted(root.glob("*.yaml")) + sorted(root.glob("*.yml"))
|
|
184
|
+
for path in paths:
|
|
185
|
+
name = path.name[: -len(path.suffix)]
|
|
186
|
+
try:
|
|
187
|
+
if not theme_name_is_valid(name):
|
|
188
|
+
raise UserThemeLoadError(f"Invalid theme name {name!r} (from {path.name})")
|
|
189
|
+
if theme_is_read_only(name):
|
|
190
|
+
raise UserThemeLoadError(f"Theme {name!r} is reserved and cannot be overridden")
|
|
191
|
+
if name in seen:
|
|
192
|
+
# Same stem with .yaml and .yml: first (sorted) file wins.
|
|
193
|
+
continue
|
|
194
|
+
theme = _theme_from_data(name, _load_theme_data(path), path)
|
|
195
|
+
except UserThemeLoadError as e:
|
|
196
|
+
warnings.append(user_theme_warning(path, str(e)))
|
|
197
|
+
logger.warning("Skipping user theme file %s: %s", path, e)
|
|
198
|
+
continue
|
|
199
|
+
seen.add(name)
|
|
200
|
+
themes.append(theme)
|
|
201
|
+
return themes, warnings
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Recover user-theme failures at Textual's actual CSS parsing boundary, and keep its rule cache warm."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
|
|
9
|
+
from textual.cache import LRUCache
|
|
10
|
+
from textual.css.stylesheet import Stylesheet, StylesheetError
|
|
11
|
+
from textual.css.tokenizer import TokenError
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ThemeStylesheet(Stylesheet):
|
|
15
|
+
"""Cover initial parsing, theme refreshes, and lazily mounted widget CSS."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, *, variables: dict[str, str], recover: Callable[[Stylesheet, Exception], bool]) -> None:
|
|
18
|
+
super().__init__(variables=variables)
|
|
19
|
+
self._recover = recover
|
|
20
|
+
|
|
21
|
+
def copy(self) -> ThemeStylesheet:
|
|
22
|
+
# Textual replaces the live stylesheet with a copy after CSS hot reload.
|
|
23
|
+
stylesheet = ThemeStylesheet(variables=self._variables.copy(), recover=self._recover)
|
|
24
|
+
stylesheet.source = self.source.copy()
|
|
25
|
+
return stylesheet
|
|
26
|
+
|
|
27
|
+
def parse(self) -> None:
|
|
28
|
+
# Every parse walks all sources in order through a 64-entry LRU of parsed rules. Past
|
|
29
|
+
# 64 sources, the walk evicts each entry before its next use, so each newly mounted
|
|
30
|
+
# widget type re-tokenizes the whole app's CSS. Upstream's cache, once it has evicted,
|
|
31
|
+
# evicts on every insert even after grow(); the LRU patch lifts that, but a skipped patch
|
|
32
|
+
# keeps it, so replace the cache, doubled to amortize later growth.
|
|
33
|
+
if len(self.source) > self._parse_cache.maxsize:
|
|
34
|
+
self._parse_cache = LRUCache(2 * len(self.source))
|
|
35
|
+
try:
|
|
36
|
+
super().parse()
|
|
37
|
+
except (StylesheetError, TokenError) as error:
|
|
38
|
+
if not self._recover(self, error):
|
|
39
|
+
raise
|
|
40
|
+
super().parse()
|
|
41
|
+
|
|
42
|
+
def reparse(self) -> None:
|
|
43
|
+
# Textual's reparse uses a plain temporary Stylesheet internally.
|
|
44
|
+
try:
|
|
45
|
+
super().reparse()
|
|
46
|
+
except (StylesheetError, TokenError) as error:
|
|
47
|
+
if not self._recover(self, error):
|
|
48
|
+
raise
|
|
49
|
+
super().reparse()
|