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
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Deduplicated Footer with display-only binding localization."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from textual.binding import Binding
|
|
11
|
+
from textual.content import Content
|
|
12
|
+
from textual.screen import Screen
|
|
13
|
+
from textual.widgets import Footer
|
|
14
|
+
from textual.widgets._footer import FooterKey, FooterLabel
|
|
15
|
+
|
|
16
|
+
from chrys.app.tui.binding_display import resolve_binding_display
|
|
17
|
+
from chrys.app.tui.i18n import LocaleController, render_str
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from textual.app import ComposeResult
|
|
21
|
+
|
|
22
|
+
from chrys.foundation.i18n import Localizer
|
|
23
|
+
|
|
24
|
+
type _BindingEntry = tuple[str, Binding, bool, str]
|
|
25
|
+
type _BindingSignature = tuple[tuple[_BindingEntry, ...], _BindingEntry | None]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True, slots=True)
|
|
29
|
+
class _FooterKeyDisplay:
|
|
30
|
+
binding: Binding
|
|
31
|
+
description_literal: str
|
|
32
|
+
tooltip_literal: str
|
|
33
|
+
description_visible: bool
|
|
34
|
+
tooltip_uses_description: bool
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ChrysFooter(Footer):
|
|
38
|
+
"""Avoid recomposing the Footer when only hidden bindings changed.
|
|
39
|
+
|
|
40
|
+
Textual publishes a bindings update after every focus transition. Its
|
|
41
|
+
stock Footer always recomposes in response, and those mount/removal layout
|
|
42
|
+
messages make a large transcript reflow even when the visible footer is
|
|
43
|
+
byte-for-byte unchanged.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, *, locale_controller: LocaleController | None = None) -> None:
|
|
47
|
+
self._locale_controller = locale_controller
|
|
48
|
+
self._visible_binding_signature: _BindingSignature | None = None
|
|
49
|
+
self._binding_recompose_generation = 0
|
|
50
|
+
self._binding_recompose_in_progress = False
|
|
51
|
+
self._binding_recompose_dirty = False
|
|
52
|
+
self._localization_dirty = False
|
|
53
|
+
self._rendered_locale_revision: int | None = None
|
|
54
|
+
self._rendered_key_displays: dict[FooterKey, _FooterKeyDisplay] = {}
|
|
55
|
+
super().__init__()
|
|
56
|
+
# Render the screen-level shortcuts in the initial composition. Textual
|
|
57
|
+
# normally composes an empty Footer and waits for a bindings signal, but
|
|
58
|
+
# Chrys may push the startup loading dialog before that signal's deferred
|
|
59
|
+
# recompose runs. The active-screen guard then intentionally strands the
|
|
60
|
+
# callback until MainScreen resumes, leaving the footer blank throughout
|
|
61
|
+
# startup. Later binding changes still flow through the signature-based
|
|
62
|
+
# recompose path below.
|
|
63
|
+
self._bindings_ready = True
|
|
64
|
+
|
|
65
|
+
def on_mount(self) -> None:
|
|
66
|
+
"""Subscribe to bindings and join the bounded locale refresh registry."""
|
|
67
|
+
super().on_mount()
|
|
68
|
+
if self._locale_controller is not None:
|
|
69
|
+
self._locale_controller.register_footer(self)
|
|
70
|
+
if self._rendered_locale_revision != self._locale_controller.revision:
|
|
71
|
+
self.invalidate_localization()
|
|
72
|
+
|
|
73
|
+
def on_unmount(self) -> None:
|
|
74
|
+
"""Leave the locale registry before Textual releases the Footer."""
|
|
75
|
+
if self._locale_controller is not None:
|
|
76
|
+
self._locale_controller.unregister_footer(self)
|
|
77
|
+
super().on_unmount()
|
|
78
|
+
|
|
79
|
+
def invalidate_localization(self) -> None:
|
|
80
|
+
"""Retranslate mounted key children in place, never by recomposition."""
|
|
81
|
+
if self._locale_controller is None or not self.is_attached:
|
|
82
|
+
return
|
|
83
|
+
if self._binding_recompose_in_progress:
|
|
84
|
+
self._localization_dirty = True
|
|
85
|
+
return
|
|
86
|
+
if not self._rendered_key_displays:
|
|
87
|
+
return
|
|
88
|
+
self._update_localization_in_place()
|
|
89
|
+
|
|
90
|
+
def compose(self) -> ComposeResult:
|
|
91
|
+
"""Localize stock compose nodes while retaining their source Bindings.
|
|
92
|
+
|
|
93
|
+
Only display text is rewritten; widths stay ``auto`` so every locale
|
|
94
|
+
gets its natural key geometry, at startup and after a hot switch.
|
|
95
|
+
"""
|
|
96
|
+
controller = self._locale_controller
|
|
97
|
+
if controller is None:
|
|
98
|
+
yield from super().compose()
|
|
99
|
+
return
|
|
100
|
+
|
|
101
|
+
active_bindings = self.screen.active_bindings
|
|
102
|
+
visible_by_action: dict[str, tuple[Binding, str]] = {}
|
|
103
|
+
for _namespace, binding, _enabled, tooltip in active_bindings.values():
|
|
104
|
+
if binding.show:
|
|
105
|
+
visible_by_action.setdefault(binding.action, (binding, tooltip))
|
|
106
|
+
|
|
107
|
+
palette_entry: tuple[Binding, str] | None = None
|
|
108
|
+
if self.show_command_palette and self.app.ENABLE_COMMAND_PALETTE:
|
|
109
|
+
palette_key = self.app.COMMAND_PALETTE_BINDING
|
|
110
|
+
if active := active_bindings.get(palette_key):
|
|
111
|
+
_namespace, binding, _enabled, tooltip = active
|
|
112
|
+
palette_entry = binding, tooltip
|
|
113
|
+
|
|
114
|
+
localizer = controller.localizer
|
|
115
|
+
compose_revision = controller.revision
|
|
116
|
+
self._rendered_key_displays = {}
|
|
117
|
+
for child in super().compose():
|
|
118
|
+
if isinstance(child, FooterKey):
|
|
119
|
+
is_palette = child.has_class("-command-palette")
|
|
120
|
+
entry = palette_entry if is_palette else visible_by_action.get(child.action)
|
|
121
|
+
if entry is not None:
|
|
122
|
+
binding, active_tooltip = entry
|
|
123
|
+
grouped = child.has_class("-grouped")
|
|
124
|
+
tooltip = child.tooltip
|
|
125
|
+
display = _FooterKeyDisplay(
|
|
126
|
+
binding=binding,
|
|
127
|
+
description_literal=child.description,
|
|
128
|
+
tooltip_literal=tooltip if isinstance(tooltip, str) else "",
|
|
129
|
+
description_visible=bool(child.description),
|
|
130
|
+
tooltip_uses_description=(grouped and not active_tooltip)
|
|
131
|
+
or (is_palette and not binding.tooltip),
|
|
132
|
+
)
|
|
133
|
+
self._rendered_key_displays[child] = display
|
|
134
|
+
description, tooltip_text = self._resolve_display(display, localizer)
|
|
135
|
+
child.description = description
|
|
136
|
+
child.tooltip = tooltip_text or None
|
|
137
|
+
elif isinstance(child, FooterLabel):
|
|
138
|
+
content = child.content
|
|
139
|
+
literal = content if isinstance(content, str) else str(content)
|
|
140
|
+
child.update(Content.from_text(literal, markup=False), layout=False)
|
|
141
|
+
yield child
|
|
142
|
+
self._rendered_locale_revision = compose_revision
|
|
143
|
+
|
|
144
|
+
def _resolve_display(self, display: _FooterKeyDisplay, localizer: Localizer) -> tuple[str, str]:
|
|
145
|
+
spec = resolve_binding_display(display.binding)
|
|
146
|
+
if spec is None:
|
|
147
|
+
return display.description_literal, display.tooltip_literal
|
|
148
|
+
|
|
149
|
+
description_text = render_str(localizer, spec.description.bind())
|
|
150
|
+
description = description_text if display.description_visible else display.description_literal
|
|
151
|
+
if spec.tooltip is not None:
|
|
152
|
+
tooltip = render_str(localizer, spec.tooltip.bind())
|
|
153
|
+
elif display.tooltip_uses_description:
|
|
154
|
+
tooltip = description_text
|
|
155
|
+
else:
|
|
156
|
+
tooltip = display.tooltip_literal
|
|
157
|
+
return description, tooltip
|
|
158
|
+
|
|
159
|
+
def _update_localization_in_place(self) -> None:
|
|
160
|
+
controller = self._locale_controller
|
|
161
|
+
if controller is None:
|
|
162
|
+
return
|
|
163
|
+
localizer = controller.localizer
|
|
164
|
+
for key, display in self._rendered_key_displays.items():
|
|
165
|
+
if not key.is_attached:
|
|
166
|
+
continue
|
|
167
|
+
description, tooltip = self._resolve_display(display, localizer)
|
|
168
|
+
tooltip_value = tooltip or None
|
|
169
|
+
if key.description != description:
|
|
170
|
+
key.description = description
|
|
171
|
+
key.tooltip = tooltip_value
|
|
172
|
+
# ``width: auto`` only re-measures the new text on a layout
|
|
173
|
+
# pass; a repaint alone would keep the old locale's width.
|
|
174
|
+
key.refresh(layout=True)
|
|
175
|
+
elif key.tooltip != tooltip_value:
|
|
176
|
+
key.tooltip = tooltip_value
|
|
177
|
+
self._rendered_locale_revision = controller.revision
|
|
178
|
+
self._localization_dirty = False
|
|
179
|
+
|
|
180
|
+
def _finish_localization_after_recompose(self) -> None:
|
|
181
|
+
controller = self._locale_controller
|
|
182
|
+
if controller is None:
|
|
183
|
+
return
|
|
184
|
+
if self._rendered_locale_revision != controller.revision:
|
|
185
|
+
self._update_localization_in_place()
|
|
186
|
+
else:
|
|
187
|
+
self._localization_dirty = False
|
|
188
|
+
|
|
189
|
+
def bindings_changed(self, screen: Screen) -> None:
|
|
190
|
+
"""Recompose only when the rendered binding set actually changed."""
|
|
191
|
+
self._bindings_ready = True
|
|
192
|
+
# Invalidate every queued callback before deduplication. In particular,
|
|
193
|
+
# an A -> B -> A bounce must make the pending B callback stale even
|
|
194
|
+
# though A already matches the last successfully rendered signature.
|
|
195
|
+
self._binding_recompose_generation += 1
|
|
196
|
+
generation = self._binding_recompose_generation
|
|
197
|
+
if self._binding_recompose_in_progress:
|
|
198
|
+
# The in-flight compose may already have read the prior binding
|
|
199
|
+
# state. Its rendered result is now uncertain, even when this
|
|
200
|
+
# signal happens to equal the last committed signature.
|
|
201
|
+
self._binding_recompose_dirty = True
|
|
202
|
+
return
|
|
203
|
+
signature = self._binding_signature(screen)
|
|
204
|
+
if signature == self._visible_binding_signature and not self._binding_recompose_dirty:
|
|
205
|
+
return
|
|
206
|
+
if not screen.app.app_focus:
|
|
207
|
+
# Preserve the last rendered signature. App focus will call
|
|
208
|
+
# ``sync_bindings`` so a real background change is not lost.
|
|
209
|
+
return
|
|
210
|
+
self._schedule_recompose(screen, generation)
|
|
211
|
+
|
|
212
|
+
def _schedule_recompose(self, screen: Screen, generation: int) -> None:
|
|
213
|
+
"""Queue one generation, retaining uncertainty if delivery is lost."""
|
|
214
|
+
if not self.call_after_refresh(self._recompose_bindings, screen, generation):
|
|
215
|
+
# A later signal or MainScreen resume must force a retry even when
|
|
216
|
+
# live bindings equal the last committed signature.
|
|
217
|
+
self._binding_recompose_dirty = True
|
|
218
|
+
self._binding_recompose_generation += 1
|
|
219
|
+
|
|
220
|
+
async def _recompose_bindings(
|
|
221
|
+
self,
|
|
222
|
+
screen: Screen,
|
|
223
|
+
generation: int,
|
|
224
|
+
) -> None:
|
|
225
|
+
"""Commit the dedup signature only after its recompose completes."""
|
|
226
|
+
if generation != self._binding_recompose_generation:
|
|
227
|
+
return
|
|
228
|
+
if (
|
|
229
|
+
not self.is_attached
|
|
230
|
+
or screen is not self.screen
|
|
231
|
+
or screen is not screen.app.screen
|
|
232
|
+
or not screen.app.app_focus
|
|
233
|
+
):
|
|
234
|
+
return
|
|
235
|
+
# Binding signals may originate from App/Screen handlers, and
|
|
236
|
+
# ``call_after_refresh`` preserves that sender context. Footer.compose
|
|
237
|
+
# binds Footer.compact, so recomposition must run with this Footer as
|
|
238
|
+
# the active message pump rather than ChrysApp.
|
|
239
|
+
self._binding_recompose_in_progress = True
|
|
240
|
+
self._binding_recompose_dirty = False
|
|
241
|
+
try:
|
|
242
|
+
with self._context():
|
|
243
|
+
await self.recompose()
|
|
244
|
+
except BaseException:
|
|
245
|
+
self._binding_recompose_dirty = True
|
|
246
|
+
raise
|
|
247
|
+
finally:
|
|
248
|
+
self._binding_recompose_in_progress = False
|
|
249
|
+
self._finish_localization_after_recompose()
|
|
250
|
+
if generation == self._binding_recompose_generation and not self._binding_recompose_dirty:
|
|
251
|
+
# Recompose reads live bindings, so record the same live state
|
|
252
|
+
# rather than the potentially stale schedule-time signature.
|
|
253
|
+
self._visible_binding_signature = self._binding_signature(screen)
|
|
254
|
+
return
|
|
255
|
+
|
|
256
|
+
# A synchronous cross-pump publish landed while ``recompose`` was
|
|
257
|
+
# awaiting. Force one more pass: deduplicating against the last
|
|
258
|
+
# committed signature is unsafe because the just-rendered state may
|
|
259
|
+
# differ from it.
|
|
260
|
+
self._binding_recompose_dirty = True
|
|
261
|
+
if self.is_attached and screen is self.screen and screen is screen.app.screen and screen.app.app_focus:
|
|
262
|
+
self._schedule_recompose(screen, self._binding_recompose_generation)
|
|
263
|
+
|
|
264
|
+
def sync_bindings(self) -> None:
|
|
265
|
+
"""Apply a binding change that may have occurred while unfocused."""
|
|
266
|
+
self.bindings_changed(self.screen)
|
|
267
|
+
|
|
268
|
+
def _binding_signature(self, screen: Screen) -> _BindingSignature:
|
|
269
|
+
active = screen.active_bindings
|
|
270
|
+
visible = tuple(
|
|
271
|
+
(key, binding, enabled, tooltip)
|
|
272
|
+
for key, (_namespace, binding, enabled, tooltip) in active.items()
|
|
273
|
+
if binding.show
|
|
274
|
+
)
|
|
275
|
+
command_palette: _BindingEntry | None = None
|
|
276
|
+
if self.show_command_palette and screen.app.ENABLE_COMMAND_PALETTE:
|
|
277
|
+
palette_key = screen.app.COMMAND_PALETTE_BINDING
|
|
278
|
+
if palette := active.get(palette_key):
|
|
279
|
+
_namespace, binding, enabled, tooltip = palette
|
|
280
|
+
command_palette = (palette_key, binding, enabled, tooltip)
|
|
281
|
+
return visible, command_palette
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
__all__ = ["ChrysFooter"]
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Convert pasted or dropped image paths into chat ``@file`` mentions."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import shlex
|
|
9
|
+
import subprocess
|
|
10
|
+
import time
|
|
11
|
+
import uuid
|
|
12
|
+
from binascii import Error as BinasciiError
|
|
13
|
+
from binascii import unhexlify
|
|
14
|
+
from collections.abc import Sequence
|
|
15
|
+
from contextlib import suppress
|
|
16
|
+
from io import BytesIO
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
from urllib.error import URLError
|
|
20
|
+
from urllib.parse import urlparse
|
|
21
|
+
from urllib.request import url2pathname
|
|
22
|
+
|
|
23
|
+
from chrys.app.tui.terminal.title import running_under_textual_web_driver
|
|
24
|
+
from chrys.foundation.platform import get_platform, safe_getcwd
|
|
25
|
+
from chrys.foundation.text.images import IMAGE_MIME_BY_EXTENSION
|
|
26
|
+
from chrys.foundation.text.mentions import format_file_mention
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from PIL import Image
|
|
30
|
+
|
|
31
|
+
from chrys.service.state.store import StateStore
|
|
32
|
+
|
|
33
|
+
CLIPBOARD_IMAGE_SESSION_SUBDIR = Path("attachments") / "clipboard"
|
|
34
|
+
_CLIPBOARD_IMAGE_KEEP_COUNT = 100
|
|
35
|
+
_CLIPBOARD_IMAGE_KEEP_BYTES = 512 * 1024 * 1024
|
|
36
|
+
_WINDOWS_CLIPBOARD_GRAB_ATTEMPTS = 5
|
|
37
|
+
_WINDOWS_CLIPBOARD_GRAB_DELAY_SECONDS = 0.02
|
|
38
|
+
_MACOS_CLIPBOARD_IMAGE_CLASSES = ("PNGf", "TIFF", "JPEG", "GIFf")
|
|
39
|
+
# The formats those classes carry; Pillow decodes no other from the clipboard.
|
|
40
|
+
_MACOS_CLIPBOARD_IMAGE_FORMATS = ("PNG", "TIFF", "JPEG", "GIF")
|
|
41
|
+
_MACOS_CLASS_OPEN = chr(0x00AB)
|
|
42
|
+
_MACOS_CLASS_CLOSE = chr(0x00BB)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def convert_pasted_image_paths_to_mentions(text: str, cwd: Path) -> str:
|
|
46
|
+
"""Return ``@`` mentions when *text* is a paste/drop payload of image paths.
|
|
47
|
+
|
|
48
|
+
Terminal drag-and-drop generally arrives as bracketed paste text. File
|
|
49
|
+
copy/paste can arrive the same way depending on the terminal and platform.
|
|
50
|
+
Only path-only payloads are rewritten; normal prose is left untouched.
|
|
51
|
+
"""
|
|
52
|
+
normalized = text.replace("\r\n", "\n").replace("\r", "\n")
|
|
53
|
+
paths = _parse_image_path_payload(normalized, cwd=cwd)
|
|
54
|
+
if not paths:
|
|
55
|
+
return text
|
|
56
|
+
return " ".join(format_file_mention(path) for path in paths) + " "
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def clipboard_image_dir_for_session(state_store: StateStore | None, session_id: str | None) -> Path | None:
|
|
60
|
+
"""Return the session attachment directory for saved clipboard images."""
|
|
61
|
+
if state_store is None or not session_id:
|
|
62
|
+
return None
|
|
63
|
+
return state_store.session_dir(session_id) / CLIPBOARD_IMAGE_SESSION_SUBDIR
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def save_clipboard_image_to_file(directory: Path | None) -> Path | None:
|
|
67
|
+
"""Save a platform clipboard image into *directory* and return its path.
|
|
68
|
+
|
|
69
|
+
Screenshot and image-copy workflows on macOS and Windows can put bitmap
|
|
70
|
+
data on the clipboard instead of a file path. Textual's terminal paste
|
|
71
|
+
events only carry text, so the chat input uses this helper from its
|
|
72
|
+
explicit paste action to bridge bitmap clipboard contents back into
|
|
73
|
+
Chrys' existing ``@file`` image attachment flow. Browser-host sessions
|
|
74
|
+
must not read the server machine's clipboard because it is unrelated to
|
|
75
|
+
the browser client's clipboard and may belong to a different user.
|
|
76
|
+
"""
|
|
77
|
+
if directory is None or running_under_textual_web_driver():
|
|
78
|
+
return None
|
|
79
|
+
info = get_platform()
|
|
80
|
+
if not (info.is_macos or info.is_windows):
|
|
81
|
+
return None
|
|
82
|
+
try:
|
|
83
|
+
clipboard_payload = _grab_clipboard()
|
|
84
|
+
return _path_from_clipboard_payload(clipboard_payload, directory=directory)
|
|
85
|
+
except OSError, RuntimeError, ValueError:
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _grab_clipboard() -> object:
|
|
90
|
+
if get_platform().is_macos:
|
|
91
|
+
return _grab_macos_clipboard_image()
|
|
92
|
+
return _grab_windows_clipboard()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _grab_windows_clipboard() -> object:
|
|
96
|
+
"""Read the Windows clipboard with retries for transient clipboard-owner races."""
|
|
97
|
+
from PIL import ImageGrab
|
|
98
|
+
|
|
99
|
+
for attempt in range(_WINDOWS_CLIPBOARD_GRAB_ATTEMPTS):
|
|
100
|
+
try:
|
|
101
|
+
return ImageGrab.grabclipboard()
|
|
102
|
+
except OSError:
|
|
103
|
+
if attempt == _WINDOWS_CLIPBOARD_GRAB_ATTEMPTS - 1:
|
|
104
|
+
raise
|
|
105
|
+
time.sleep(_WINDOWS_CLIPBOARD_GRAB_DELAY_SECONDS)
|
|
106
|
+
|
|
107
|
+
return None
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _grab_macos_clipboard_image() -> object | None:
|
|
111
|
+
from PIL import Image, UnidentifiedImageError
|
|
112
|
+
|
|
113
|
+
for class_code in _MACOS_CLIPBOARD_IMAGE_CLASSES:
|
|
114
|
+
data = _read_macos_clipboard_class(class_code)
|
|
115
|
+
if data is None:
|
|
116
|
+
continue
|
|
117
|
+
try:
|
|
118
|
+
with Image.open(BytesIO(data), formats=_MACOS_CLIPBOARD_IMAGE_FORMATS) as image:
|
|
119
|
+
image.load()
|
|
120
|
+
return image.copy()
|
|
121
|
+
except UnidentifiedImageError, OSError, ValueError:
|
|
122
|
+
continue
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _read_macos_clipboard_class(class_code: str) -> bytes | None:
|
|
127
|
+
try:
|
|
128
|
+
result = subprocess.run( # noqa: S603 - fixed osascript path and fixed AppleScript class codes.
|
|
129
|
+
[
|
|
130
|
+
"/usr/bin/osascript",
|
|
131
|
+
"-e",
|
|
132
|
+
f"get the clipboard as {_MACOS_CLASS_OPEN}class {class_code}{_MACOS_CLASS_CLOSE}",
|
|
133
|
+
],
|
|
134
|
+
stdin=subprocess.DEVNULL,
|
|
135
|
+
capture_output=True,
|
|
136
|
+
check=False,
|
|
137
|
+
timeout=2,
|
|
138
|
+
)
|
|
139
|
+
except subprocess.SubprocessError, FileNotFoundError, OSError:
|
|
140
|
+
return None
|
|
141
|
+
if result.returncode != 0:
|
|
142
|
+
return None
|
|
143
|
+
return _decode_macos_clipboard_data(result.stdout)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _decode_macos_clipboard_data(stdout: bytes) -> bytes | None:
|
|
147
|
+
prefix = b"\xc2\xabdata "
|
|
148
|
+
suffix = b"\xc2\xbb"
|
|
149
|
+
start = stdout.find(prefix)
|
|
150
|
+
if start < 0:
|
|
151
|
+
return None
|
|
152
|
+
hex_start = start + len(prefix) + 4
|
|
153
|
+
end = stdout.find(suffix, hex_start)
|
|
154
|
+
if end < 0:
|
|
155
|
+
return None
|
|
156
|
+
try:
|
|
157
|
+
return unhexlify(stdout[hex_start:end].strip())
|
|
158
|
+
except BinasciiError:
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _path_from_clipboard_payload(payload: object, *, directory: Path) -> Path | None:
|
|
163
|
+
from PIL import Image
|
|
164
|
+
|
|
165
|
+
if isinstance(payload, Image.Image):
|
|
166
|
+
return _save_clipboard_image(payload, directory=directory)
|
|
167
|
+
if isinstance(payload, list):
|
|
168
|
+
return _first_supported_clipboard_file_path(payload)
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _save_clipboard_image(image: Image.Image, *, directory: Path) -> Path | None:
|
|
173
|
+
try:
|
|
174
|
+
directory.mkdir(parents=True, exist_ok=True)
|
|
175
|
+
except OSError:
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
path = directory / f"clipboard-image-{uuid.uuid4().hex}.png"
|
|
179
|
+
converted: Image.Image | None = None
|
|
180
|
+
try:
|
|
181
|
+
image_to_save = image
|
|
182
|
+
if image.mode not in {"1", "L", "LA", "P", "RGB", "RGBA"}:
|
|
183
|
+
converted = image.convert("RGBA")
|
|
184
|
+
image_to_save = converted
|
|
185
|
+
image_to_save.save(path, format="PNG")
|
|
186
|
+
saved = path.resolve(strict=True)
|
|
187
|
+
_prune_clipboard_image_dir(directory, keep=saved)
|
|
188
|
+
return saved
|
|
189
|
+
except OSError, RuntimeError, ValueError:
|
|
190
|
+
return None
|
|
191
|
+
finally:
|
|
192
|
+
if converted is not None:
|
|
193
|
+
converted.close()
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _prune_clipboard_image_dir(directory: Path, *, keep: Path) -> None:
|
|
197
|
+
"""Bound session/temp clipboard-image buildup while keeping recent pasted files available."""
|
|
198
|
+
entries: list[tuple[int, int, Path]] = []
|
|
199
|
+
try:
|
|
200
|
+
candidates = list(directory.glob("clipboard-image-*.png"))
|
|
201
|
+
except OSError:
|
|
202
|
+
return
|
|
203
|
+
for path in candidates:
|
|
204
|
+
try:
|
|
205
|
+
stat = path.stat()
|
|
206
|
+
except OSError:
|
|
207
|
+
continue
|
|
208
|
+
entries.append((stat.st_mtime_ns, stat.st_size, path))
|
|
209
|
+
entries.sort(key=lambda entry: entry[0], reverse=True)
|
|
210
|
+
|
|
211
|
+
total_size = 0
|
|
212
|
+
for index, (_mtime_ns, size, path) in enumerate(entries):
|
|
213
|
+
total_size += size
|
|
214
|
+
if path == keep or (index < _CLIPBOARD_IMAGE_KEEP_COUNT and total_size <= _CLIPBOARD_IMAGE_KEEP_BYTES):
|
|
215
|
+
continue
|
|
216
|
+
with suppress(OSError):
|
|
217
|
+
path.unlink()
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _first_supported_clipboard_file_path(paths: Sequence[object]) -> Path | None:
|
|
221
|
+
cwd = Path(safe_getcwd())
|
|
222
|
+
for candidate in paths:
|
|
223
|
+
if not isinstance(candidate, str):
|
|
224
|
+
continue
|
|
225
|
+
path = _resolve_supported_image_path(candidate, cwd=cwd)
|
|
226
|
+
if path is not None:
|
|
227
|
+
return path
|
|
228
|
+
return None
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _parse_image_path_payload(text: str, *, cwd: Path) -> list[Path]:
|
|
232
|
+
stripped = text.strip()
|
|
233
|
+
if not stripped:
|
|
234
|
+
return []
|
|
235
|
+
|
|
236
|
+
for candidates in _candidate_path_groups(stripped):
|
|
237
|
+
paths = _resolve_supported_image_group(candidates, cwd=cwd)
|
|
238
|
+
if paths:
|
|
239
|
+
return paths
|
|
240
|
+
return []
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _candidate_path_groups(text: str) -> list[list[str]]:
|
|
244
|
+
groups: list[list[str]] = [[text]]
|
|
245
|
+
|
|
246
|
+
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
|
247
|
+
if len(lines) > 1:
|
|
248
|
+
groups.append(lines)
|
|
249
|
+
|
|
250
|
+
split_tokens = text.split()
|
|
251
|
+
if len(split_tokens) > 1:
|
|
252
|
+
groups.append(split_tokens)
|
|
253
|
+
|
|
254
|
+
if os.name != "nt":
|
|
255
|
+
shlex_tokens = _shlex_split(text)
|
|
256
|
+
if shlex_tokens and shlex_tokens not in groups:
|
|
257
|
+
groups.append(shlex_tokens)
|
|
258
|
+
|
|
259
|
+
return groups
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _shlex_split(text: str) -> list[str]:
|
|
263
|
+
try:
|
|
264
|
+
return shlex.split(text)
|
|
265
|
+
except ValueError:
|
|
266
|
+
return []
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _resolve_supported_image_group(candidates: list[str], *, cwd: Path) -> list[Path]:
|
|
270
|
+
paths: list[Path] = []
|
|
271
|
+
for candidate in candidates:
|
|
272
|
+
path = _resolve_supported_image_path(candidate, cwd=cwd)
|
|
273
|
+
if path is None:
|
|
274
|
+
return []
|
|
275
|
+
paths.append(path)
|
|
276
|
+
return paths
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _resolve_supported_image_path(candidate: str, *, cwd: Path) -> Path | None:
|
|
280
|
+
quoted = _candidate_is_quoted(candidate)
|
|
281
|
+
path_text = _path_text_from_candidate(candidate)
|
|
282
|
+
if not _path_text_has_supported_image_suffix(path_text) or not _path_text_looks_like_single_path(
|
|
283
|
+
path_text,
|
|
284
|
+
quoted=quoted,
|
|
285
|
+
):
|
|
286
|
+
return None
|
|
287
|
+
try:
|
|
288
|
+
path = Path(path_text).expanduser()
|
|
289
|
+
except RuntimeError:
|
|
290
|
+
return None
|
|
291
|
+
if path.suffix.lower() not in IMAGE_MIME_BY_EXTENSION:
|
|
292
|
+
return None
|
|
293
|
+
if not path.is_absolute():
|
|
294
|
+
path = cwd / path
|
|
295
|
+
try:
|
|
296
|
+
resolved = path.resolve(strict=True)
|
|
297
|
+
except OSError, ValueError:
|
|
298
|
+
return None
|
|
299
|
+
if not resolved.is_file():
|
|
300
|
+
return None
|
|
301
|
+
return resolved
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def _path_text_has_supported_image_suffix(path_text: str) -> bool:
|
|
305
|
+
if not path_text:
|
|
306
|
+
return False
|
|
307
|
+
try:
|
|
308
|
+
suffix = Path(path_text).suffix.lower()
|
|
309
|
+
except ValueError:
|
|
310
|
+
return False
|
|
311
|
+
return suffix in IMAGE_MIME_BY_EXTENSION
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _path_text_looks_like_single_path(path_text: str, *, quoted: bool) -> bool:
|
|
315
|
+
if not any(char.isspace() for char in path_text):
|
|
316
|
+
return True
|
|
317
|
+
try:
|
|
318
|
+
expanded_path = Path(path_text).expanduser()
|
|
319
|
+
except RuntimeError, ValueError:
|
|
320
|
+
return False
|
|
321
|
+
return (
|
|
322
|
+
quoted or expanded_path.is_absolute() or path_text.startswith("~") or _path_text_is_windows_absolute(path_text)
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _path_text_is_windows_absolute(path_text: str) -> bool:
|
|
327
|
+
return (len(path_text) >= 3 and path_text[1:3] in (":\\", ":/")) or path_text.startswith(("\\\\", "//"))
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _candidate_is_quoted(candidate: str) -> bool:
|
|
331
|
+
text = candidate.strip()
|
|
332
|
+
return len(text) >= 2 and text[0] == text[-1] and text[0] in ("'", '"')
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
def _path_text_from_candidate(candidate: str) -> str:
|
|
336
|
+
text = candidate.strip()
|
|
337
|
+
if len(text) >= 2 and text[0] == text[-1] and text[0] in ("'", '"'):
|
|
338
|
+
text = text[1:-1]
|
|
339
|
+
try:
|
|
340
|
+
parsed = urlparse(text)
|
|
341
|
+
except ValueError:
|
|
342
|
+
return text
|
|
343
|
+
if parsed.scheme == "file":
|
|
344
|
+
path = parsed.path
|
|
345
|
+
if parsed.netloc and parsed.netloc != "localhost":
|
|
346
|
+
path = f"//{parsed.netloc}{path}"
|
|
347
|
+
try:
|
|
348
|
+
return url2pathname(path)
|
|
349
|
+
except URLError, ValueError:
|
|
350
|
+
return ""
|
|
351
|
+
return text
|