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,614 @@
|
|
|
1
|
+
# Copyright (c) 2024 Anthropic, PBC
|
|
2
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
3
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
4
|
+
# Contains code adapted from the Model Context Protocol Python SDK and Microsoft Agent Framework (MIT License; see NOTICE).
|
|
5
|
+
|
|
6
|
+
"""Stdio MCP transport and diagnostics."""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import contextlib
|
|
11
|
+
import dataclasses
|
|
12
|
+
import inspect
|
|
13
|
+
import io
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
import os
|
|
17
|
+
import shutil
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
from collections.abc import AsyncIterator, Mapping
|
|
21
|
+
from contextlib import asynccontextmanager
|
|
22
|
+
from contextvars import ContextVar
|
|
23
|
+
from types import TracebackType
|
|
24
|
+
from typing import Any, TextIO, cast
|
|
25
|
+
|
|
26
|
+
from chrys.foundation.i18n.formatting import sanitize_legacy_block, sanitize_legacy_scalar
|
|
27
|
+
from chrys.foundation.platform.files import surrogate_safe_text
|
|
28
|
+
from chrys.foundation.platform.runtime_paths import reorder_path_demoting_runtime, strip_python_runtime_overrides
|
|
29
|
+
from chrys.foundation.text.tool_output import process_carriage_returns, strip_ansi
|
|
30
|
+
from chrys.service.mcp._tool_mixins import _NoPrePagePingMixin, _StructuredContentFallbackMixin
|
|
31
|
+
from chrys.service.mcp.owned import MCPStdioTool
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
# Cap how many non-JSON banner lines we keep per stdio server so a chatty
|
|
36
|
+
# logger can't unboundedly grow our diagnostic state.
|
|
37
|
+
MAX_BANNER_LINES_CAPTURED = 10
|
|
38
|
+
|
|
39
|
+
# Cap each captured banner line's length so a single very long log line
|
|
40
|
+
# (e.g. a stack trace serialized to one row) can't blow up an error
|
|
41
|
+
# message or notification.
|
|
42
|
+
MAX_BANNER_LINE_CHARS = 200
|
|
43
|
+
|
|
44
|
+
# Keep only a bounded tail of stderr from each stdio child. Capturing a tail
|
|
45
|
+
# (rather than a prefix) preserves the final exception and exit context in the
|
|
46
|
+
# common traceback case; 16 KiB is enough that launcher output such as
|
|
47
|
+
# ``uv``/``npm`` — one ``error:`` line followed by screens of hints — still
|
|
48
|
+
# keeps the ``error:`` line, while a noisy server cannot grow Chrys memory
|
|
49
|
+
# without bound.
|
|
50
|
+
MAX_STDIO_STDERR_BYTES_CAPTURED = 16 * 1024
|
|
51
|
+
|
|
52
|
+
# The full tail lives on ``MCPConnectionError.stderr_tail`` (structured
|
|
53
|
+
# consumers and tests read it there); the error *message* — which is what the
|
|
54
|
+
# warning toast, the MCP Test dialog and runtime details currently show —
|
|
55
|
+
# previews only the last few lines, each capped like banner lines.
|
|
56
|
+
MAX_STDIO_STDERR_PREVIEW_LINES = 10
|
|
57
|
+
|
|
58
|
+
# Display cap for filesystem-derived paths (executable, cwd) in error messages.
|
|
59
|
+
MAX_STDIO_PATH_DISPLAY_CHARS = 512
|
|
60
|
+
_STDIO_ENV_OVERRIDE: ContextVar[dict[str, str] | None] = ContextVar("mcp_stdio_env_override", default=None)
|
|
61
|
+
_STDIO_CWD_OVERRIDE: ContextVar[str | None] = ContextVar("mcp_stdio_cwd_override", default=None)
|
|
62
|
+
_STDIO_ENV_IS_COMPLETE: ContextVar[bool] = ContextVar("mcp_stdio_env_is_complete", default=False)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _clean_stdio_stderr(text: str) -> str:
|
|
66
|
+
"""Normalize untrusted subprocess stderr for logs and UI diagnostics."""
|
|
67
|
+
normalized = process_carriage_returns(strip_ansi(text))
|
|
68
|
+
return sanitize_legacy_block(normalized).strip()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclasses.dataclass(slots=True)
|
|
72
|
+
class _StdioProcessDiagnostics:
|
|
73
|
+
"""Bounded, mutable diagnostics populated by one stdio transport run."""
|
|
74
|
+
|
|
75
|
+
_stderr_tail: bytearray = dataclasses.field(default_factory=bytearray)
|
|
76
|
+
stderr_bytes_seen: int = 0
|
|
77
|
+
exit_code: int | None = None
|
|
78
|
+
resolved_executable: str = ""
|
|
79
|
+
effective_cwd: str = ""
|
|
80
|
+
|
|
81
|
+
def reset(self) -> None:
|
|
82
|
+
"""Reset state before a new child process is spawned."""
|
|
83
|
+
self._stderr_tail.clear()
|
|
84
|
+
self.stderr_bytes_seen = 0
|
|
85
|
+
self.exit_code = None
|
|
86
|
+
self.resolved_executable = ""
|
|
87
|
+
self.effective_cwd = ""
|
|
88
|
+
|
|
89
|
+
def record_spawn(self, *, resolved_executable: str, cwd: object) -> None:
|
|
90
|
+
"""Record what is about to be spawned and where (``None`` cwd = inherited)."""
|
|
91
|
+
self.resolved_executable = resolved_executable
|
|
92
|
+
if cwd is None or cwd == "":
|
|
93
|
+
try:
|
|
94
|
+
self.effective_cwd = os.getcwd()
|
|
95
|
+
except OSError:
|
|
96
|
+
self.effective_cwd = ""
|
|
97
|
+
else:
|
|
98
|
+
self.effective_cwd = str(cwd)
|
|
99
|
+
|
|
100
|
+
def append_stderr(self, chunk: bytes) -> None:
|
|
101
|
+
"""Append bytes while retaining only the configured tail."""
|
|
102
|
+
if not chunk:
|
|
103
|
+
return
|
|
104
|
+
self.stderr_bytes_seen += len(chunk)
|
|
105
|
+
self._stderr_tail.extend(chunk)
|
|
106
|
+
overflow = len(self._stderr_tail) - MAX_STDIO_STDERR_BYTES_CAPTURED
|
|
107
|
+
if overflow > 0:
|
|
108
|
+
del self._stderr_tail[:overflow]
|
|
109
|
+
|
|
110
|
+
def record_exit_code(self, wait_result: object, process: Any) -> None:
|
|
111
|
+
"""Record a return code from an external anyio/MCP process wrapper."""
|
|
112
|
+
exit_code = wait_result if type(wait_result) is int else getattr(process, "returncode", None)
|
|
113
|
+
if type(exit_code) is not int:
|
|
114
|
+
popen = getattr(process, "popen", None)
|
|
115
|
+
exit_code = getattr(popen, "returncode", None) if popen is not None else None
|
|
116
|
+
if type(exit_code) is int:
|
|
117
|
+
self.exit_code = exit_code
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def stderr_tail(self) -> str:
|
|
121
|
+
"""Return a display-safe decoded copy of the retained stderr tail."""
|
|
122
|
+
return _clean_stdio_stderr(bytes(self._stderr_tail).decode("utf-8", errors="replace"))
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def stderr_dropped_bytes(self) -> int:
|
|
126
|
+
"""Number of earlier stderr bytes omitted from the retained tail."""
|
|
127
|
+
return max(0, self.stderr_bytes_seen - len(self._stderr_tail))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@dataclasses.dataclass(frozen=True, slots=True)
|
|
131
|
+
class _StdioFailureDiagnostics:
|
|
132
|
+
"""Immutable snapshot attached to an MCP connection failure."""
|
|
133
|
+
|
|
134
|
+
stderr_tail: str = ""
|
|
135
|
+
stderr_dropped_bytes: int = 0
|
|
136
|
+
process_exit_code: int | None = None
|
|
137
|
+
resolved_executable: str = ""
|
|
138
|
+
effective_cwd: str = ""
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _display_path(value: str) -> str:
|
|
142
|
+
"""Make a raw filesystem path safe for a single-line message.
|
|
143
|
+
|
|
144
|
+
Paths come from ``os.fsdecode`` and config, so they may carry lone
|
|
145
|
+
surrogates (not UTF-8 encodable) or control characters (which could forge
|
|
146
|
+
extra diagnostic lines). The raw value stays on the exception attribute.
|
|
147
|
+
"""
|
|
148
|
+
text = sanitize_legacy_scalar(surrogate_safe_text(value))
|
|
149
|
+
if len(text) > MAX_STDIO_PATH_DISPLAY_CHARS:
|
|
150
|
+
text = text[: MAX_STDIO_PATH_DISPLAY_CHARS - 1] + "…"
|
|
151
|
+
return text
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _resolve_spawn_executable(command: str, env: Mapping[str, str]) -> str:
|
|
155
|
+
"""Best-effort path of what ``Popen`` will exec for *command* under *env*.
|
|
156
|
+
|
|
157
|
+
Mirrors POSIX ``subprocess``: a command with a path component is used as
|
|
158
|
+
is; otherwise the search uses the CHILD environment's ``PATH``
|
|
159
|
+
(``os.get_exec_path(env)``), which is what decides "which ``uv``" when the
|
|
160
|
+
TUI and a headless run carry different runtime paths. Falls back to the
|
|
161
|
+
unresolved command when nothing is found — the spawn itself is unchanged.
|
|
162
|
+
"""
|
|
163
|
+
if os.path.dirname(command):
|
|
164
|
+
return command
|
|
165
|
+
try:
|
|
166
|
+
found = shutil.which(command, path=os.pathsep.join(os.get_exec_path(env)))
|
|
167
|
+
except OSError, TypeError, ValueError:
|
|
168
|
+
return command
|
|
169
|
+
return found or command
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _stderr_preview(stderr_tail: str, *, dropped_bytes: int) -> str:
|
|
173
|
+
"""Render the last few stderr lines for an error message / warning toast.
|
|
174
|
+
|
|
175
|
+
The full tail stays on the exception; the message keeps at most
|
|
176
|
+
:data:`MAX_STDIO_STDERR_PREVIEW_LINES` lines, each capped like banner
|
|
177
|
+
lines, so a traceback cannot turn a toast into a wall of text.
|
|
178
|
+
"""
|
|
179
|
+
lines = stderr_tail.splitlines()
|
|
180
|
+
omitted_lines = max(0, len(lines) - MAX_STDIO_STDERR_PREVIEW_LINES)
|
|
181
|
+
shown = [
|
|
182
|
+
(line[:MAX_BANNER_LINE_CHARS] + "…") if len(line) > MAX_BANNER_LINE_CHARS else line
|
|
183
|
+
for line in lines[-MAX_STDIO_STDERR_PREVIEW_LINES:]
|
|
184
|
+
]
|
|
185
|
+
omitted: list[str] = []
|
|
186
|
+
if omitted_lines:
|
|
187
|
+
omitted.append(f"{omitted_lines} earlier lines")
|
|
188
|
+
if dropped_bytes:
|
|
189
|
+
omitted.append(f"{dropped_bytes} earlier bytes")
|
|
190
|
+
suffix = f" ({' and '.join(omitted)} omitted)" if omitted else ""
|
|
191
|
+
body = "\n ".join(shown)
|
|
192
|
+
return f"Server stderr tail{suffix}:\n {body}"
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _mirror_no_proxy_aliases(env: dict[str, str], extra_keys: set[str]) -> None:
|
|
196
|
+
"""Keep ``NO_PROXY`` and ``no_proxy`` aligned for stdio child processes.
|
|
197
|
+
|
|
198
|
+
User environments commonly set either canonical uppercase ``NO_PROXY``
|
|
199
|
+
or lowercase ``no_proxy``. Stdio MCP servers are a different boundary:
|
|
200
|
+
the child command may be implemented by a runtime that only checks the
|
|
201
|
+
lowercase proxy convention. Mirror the value into the missing casing
|
|
202
|
+
just before spawning, without mutating the parent process environment.
|
|
203
|
+
|
|
204
|
+
Per-server MCP env values should win over inherited parent values. When
|
|
205
|
+
the user supplies only one casing in the per-server env, mirror that
|
|
206
|
+
supplied value over the inherited alias too. When the user explicitly
|
|
207
|
+
supplies both casings, preserve both values unchanged.
|
|
208
|
+
|
|
209
|
+
This deliberately handles only the proxy-bypass list, not proxy URL
|
|
210
|
+
variables such as ``HTTP_PROXY`` / ``http_proxy``: those have different
|
|
211
|
+
security and precedence behavior across runtimes, including the
|
|
212
|
+
historical CGI ``HTTP_PROXY`` hazard.
|
|
213
|
+
"""
|
|
214
|
+
upper = "NO_PROXY"
|
|
215
|
+
lower = "no_proxy"
|
|
216
|
+
|
|
217
|
+
if upper in extra_keys and lower not in extra_keys:
|
|
218
|
+
env[lower] = env[upper]
|
|
219
|
+
return
|
|
220
|
+
if lower in extra_keys and upper not in extra_keys:
|
|
221
|
+
env[upper] = env[lower]
|
|
222
|
+
return
|
|
223
|
+
if upper in env and lower not in env:
|
|
224
|
+
env[lower] = env[upper]
|
|
225
|
+
return
|
|
226
|
+
if lower in env and upper not in env:
|
|
227
|
+
env[upper] = env[lower]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _inherited_stdio_environment(extra: dict[str, str] | None = None) -> dict[str, str]:
|
|
231
|
+
"""Build the env passed to a spawned stdio MCP server subprocess.
|
|
232
|
+
|
|
233
|
+
Unlike the MCP SDK's ``get_default_environment()`` — which inherits a
|
|
234
|
+
strict ~6-var allowlist (``PATH`` / ``HOME`` / ``USER`` / ...) — chrys
|
|
235
|
+
forwards nearly all of the parent ``os.environ`` so subprocesses see the
|
|
236
|
+
user's proxy settings (``HTTP_PROXY`` / ``HTTPS_PROXY`` / ``NO_PROXY``),
|
|
237
|
+
TLS bundle paths (``SSL_CERT_FILE`` / ``SSL_CERT_DIR`` /
|
|
238
|
+
``REQUESTS_CA_BUNDLE``), locale (``LANG`` / ``LC_ALL``), language
|
|
239
|
+
runtimes' caches, and other vars the user expects when running the same
|
|
240
|
+
command from their shell. Without this, a tool like ``uvx`` that reaches
|
|
241
|
+
PyPI through a corporate proxy hangs forever, because the SDK default
|
|
242
|
+
strips ``HTTPS_PROXY`` and the child never reaches the network — surfaced
|
|
243
|
+
as an ``initialize`` timeout.
|
|
244
|
+
|
|
245
|
+
Bash function exports (values starting with ``"()"``) are dropped, the
|
|
246
|
+
same Shellshock-era filter the SDK applies. Inherited ``PYTHONHOME`` and
|
|
247
|
+
``PYTHONPATH`` are also stripped so CPython-based server launchers are not
|
|
248
|
+
forced to use the parent's stdlib/search path. Optional ``extra``
|
|
249
|
+
overrides — typically ``MCPServerConfig.env`` — are merged on top so
|
|
250
|
+
per-server config wins over the sanitized inherited environment. For
|
|
251
|
+
packaged PyApp runs, Chrys runtime executable directories are moved behind
|
|
252
|
+
user/system PATH entries so commands like ``uvx`` resolve the user's
|
|
253
|
+
install first and fall back to the embedded runtime only if needed.
|
|
254
|
+
"""
|
|
255
|
+
env: dict[str, str] = {k: v for k, v in os.environ.items() if not v.startswith("()")}
|
|
256
|
+
strip_python_runtime_overrides(env)
|
|
257
|
+
extra_keys = set(extra or ())
|
|
258
|
+
if extra:
|
|
259
|
+
env.update(extra)
|
|
260
|
+
_mirror_no_proxy_aliases(env, extra_keys)
|
|
261
|
+
reorder_path_demoting_runtime(env)
|
|
262
|
+
return env
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@asynccontextmanager
|
|
266
|
+
async def tolerant_stdio_client(
|
|
267
|
+
server: Any,
|
|
268
|
+
errlog: TextIO = sys.stderr,
|
|
269
|
+
*,
|
|
270
|
+
dropped_banner_lines: list[str] | None = None,
|
|
271
|
+
process_diagnostics: _StdioProcessDiagnostics | None = None,
|
|
272
|
+
inherit_env: bool = True,
|
|
273
|
+
) -> AsyncIterator[tuple[Any, Any]]:
|
|
274
|
+
"""``mcp.client.stdio.stdio_client`` variant that ignores banner lines.
|
|
275
|
+
|
|
276
|
+
Many real-world stdio MCP servers (vendor CLI wrappers, several
|
|
277
|
+
``npx`` packages, locally-built tools) violate the spec by emitting
|
|
278
|
+
human-readable startup chatter on stdout before they begin speaking
|
|
279
|
+
JSON-RPC.
|
|
280
|
+
Upstream ``stdio_client`` treats every line as a JSON-RPC message and
|
|
281
|
+
pushes a parse exception onto the read stream when it fails — but the
|
|
282
|
+
base session quietly drops those exceptions, so the pending
|
|
283
|
+
``initialize()`` waits forever. The Test button hangs and the agent
|
|
284
|
+
build hangs.
|
|
285
|
+
|
|
286
|
+
This wrapper classifies each stdout line into three buckets:
|
|
287
|
+
|
|
288
|
+
* **Empty/whitespace-only** — skipped silently (no log, not captured).
|
|
289
|
+
* **Not JSON at all** (``json.loads`` fails) — treated as banner
|
|
290
|
+
chatter. Dropped. The first ``MAX_BANNER_LINES_CAPTURED`` banner
|
|
291
|
+
lines are appended to ``dropped_banner_lines`` (when supplied) so
|
|
292
|
+
callers can include them in error messages, and the first one is
|
|
293
|
+
logged at WARNING. This catches plaintext banners like
|
|
294
|
+
``"FooBarServer v1.0 (build 42)"`` and bracketed log lines like
|
|
295
|
+
``"[INFO] starting"``.
|
|
296
|
+
* **Valid JSON but fails JSON-RPC validation** — kept as the
|
|
297
|
+
original "push exception onto read stream" behavior. Note this
|
|
298
|
+
doesn't surface immediately: ``BaseSession._receive_loop`` routes
|
|
299
|
+
stream exceptions through ``_handle_incoming`` which the default
|
|
300
|
+
handler swallows. The pending ``initialize()`` then waits until
|
|
301
|
+
``read_timeout_seconds`` (set via ``request_timeout``) fires. Our
|
|
302
|
+
``MCPAdapter`` injects a default ``request_timeout`` floor when
|
|
303
|
+
none is configured, so this case is bounded — but it's "fails
|
|
304
|
+
eventually under the timeout floor", not "fails fast".
|
|
305
|
+
|
|
306
|
+
Process lifecycle and shutdown mirror upstream ``stdio_client``. In
|
|
307
|
+
addition to line handling and the inherited environment, stderr is piped
|
|
308
|
+
into a bounded diagnostic tail and the subprocess return code is recorded
|
|
309
|
+
during shutdown. Stderr is always drained concurrently so a verbose child
|
|
310
|
+
cannot block on a full pipe.
|
|
311
|
+
|
|
312
|
+
This reader is built on private ``mcp.client.stdio`` primitives
|
|
313
|
+
(``_create_platform_compatible_process`` / ``_get_executable_command``
|
|
314
|
+
/ ``_terminate_process_tree`` / ``PROCESS_TERMINATION_TIMEOUT``) plus the
|
|
315
|
+
SDK's ``SessionMessage`` wrapper. If a dependency update removes any of
|
|
316
|
+
them, we degrade to the stock ``stdio_client`` — losing banner tolerance
|
|
317
|
+
and bounded process diagnostics — instead of breaking every stdio MCP
|
|
318
|
+
connection. The sanitized inherited environment is still forwarded in
|
|
319
|
+
that path by copying it onto the server params.
|
|
320
|
+
"""
|
|
321
|
+
import anyio
|
|
322
|
+
import anyio.lowlevel
|
|
323
|
+
from anyio import to_thread
|
|
324
|
+
from anyio.streams.text import TextReceiveStream
|
|
325
|
+
from mcp import types
|
|
326
|
+
|
|
327
|
+
diagnostics = process_diagnostics or _StdioProcessDiagnostics()
|
|
328
|
+
diagnostics.reset()
|
|
329
|
+
|
|
330
|
+
try:
|
|
331
|
+
from mcp.client.stdio import (
|
|
332
|
+
PROCESS_TERMINATION_TIMEOUT,
|
|
333
|
+
_create_platform_compatible_process,
|
|
334
|
+
_get_executable_command,
|
|
335
|
+
_terminate_process_tree,
|
|
336
|
+
)
|
|
337
|
+
from mcp.shared.message import SessionMessage
|
|
338
|
+
except ImportError:
|
|
339
|
+
logger.warning(
|
|
340
|
+
"Tolerant stdio MCP reader is disabled because MCP SDK stdio internals changed; "
|
|
341
|
+
"falling back to the stock stdio client (stdout banner and process diagnostics lost).",
|
|
342
|
+
exc_info=True,
|
|
343
|
+
)
|
|
344
|
+
from mcp.client.stdio import stdio_client
|
|
345
|
+
|
|
346
|
+
stock_server = (
|
|
347
|
+
server.model_copy(update={"env": _inherited_stdio_environment(server.env)}) if inherit_env else server
|
|
348
|
+
)
|
|
349
|
+
async with stdio_client(stock_server, errlog=errlog) as streams:
|
|
350
|
+
yield streams
|
|
351
|
+
return
|
|
352
|
+
|
|
353
|
+
captured = dropped_banner_lines if dropped_banner_lines is not None else []
|
|
354
|
+
warned_once = False
|
|
355
|
+
|
|
356
|
+
read_stream_writer, read_stream = anyio.create_memory_object_stream(0)
|
|
357
|
+
write_stream, write_stream_reader = anyio.create_memory_object_stream(0)
|
|
358
|
+
|
|
359
|
+
try:
|
|
360
|
+
command = _get_executable_command(server.command)
|
|
361
|
+
env = _inherited_stdio_environment(server.env) if inherit_env else dict(server.env or {})
|
|
362
|
+
diagnostics.record_spawn(resolved_executable=_resolve_spawn_executable(command, env), cwd=server.cwd)
|
|
363
|
+
# The SDK types ``errlog`` as ``TextIO`` but hands it straight to
|
|
364
|
+
# ``anyio.open_process`` / ``subprocess.Popen(stderr=...)`` on every
|
|
365
|
+
# platform path, so the ``PIPE`` sentinel is accepted at runtime.
|
|
366
|
+
process = await _create_platform_compatible_process(
|
|
367
|
+
command=command,
|
|
368
|
+
args=server.args,
|
|
369
|
+
env=env,
|
|
370
|
+
errlog=cast("TextIO", subprocess.PIPE),
|
|
371
|
+
cwd=server.cwd,
|
|
372
|
+
)
|
|
373
|
+
except OSError:
|
|
374
|
+
await read_stream.aclose()
|
|
375
|
+
await write_stream.aclose()
|
|
376
|
+
await read_stream_writer.aclose()
|
|
377
|
+
await write_stream_reader.aclose()
|
|
378
|
+
raise
|
|
379
|
+
|
|
380
|
+
async def stdout_reader() -> None:
|
|
381
|
+
nonlocal warned_once
|
|
382
|
+
if not process.stdout:
|
|
383
|
+
raise RuntimeError("Opened process is missing stdout")
|
|
384
|
+
try:
|
|
385
|
+
async with read_stream_writer:
|
|
386
|
+
buffer = ""
|
|
387
|
+
async for chunk in TextReceiveStream(
|
|
388
|
+
process.stdout,
|
|
389
|
+
encoding=server.encoding,
|
|
390
|
+
errors=server.encoding_error_handler,
|
|
391
|
+
):
|
|
392
|
+
lines = (buffer + chunk).split("\n")
|
|
393
|
+
buffer = lines.pop()
|
|
394
|
+
|
|
395
|
+
for line in lines:
|
|
396
|
+
stripped = line.lstrip()
|
|
397
|
+
if not stripped:
|
|
398
|
+
# Empty/whitespace-only: silently ignore.
|
|
399
|
+
continue
|
|
400
|
+
|
|
401
|
+
try:
|
|
402
|
+
parsed = json.loads(line)
|
|
403
|
+
except json.JSONDecodeError:
|
|
404
|
+
# Not JSON at all — banner chatter. Capture a
|
|
405
|
+
# few for diagnostics, then drop.
|
|
406
|
+
if len(captured) < MAX_BANNER_LINES_CAPTURED:
|
|
407
|
+
captured.append(line.rstrip("\r"))
|
|
408
|
+
if not warned_once:
|
|
409
|
+
warned_once = True
|
|
410
|
+
logger.warning(
|
|
411
|
+
"MCP stdio server emitted non-JSON line on stdout (dropped): %r",
|
|
412
|
+
line[:200],
|
|
413
|
+
)
|
|
414
|
+
else:
|
|
415
|
+
logger.debug(
|
|
416
|
+
"MCP stdio server emitted non-JSON line on stdout (dropped): %r", line[:200]
|
|
417
|
+
)
|
|
418
|
+
continue
|
|
419
|
+
|
|
420
|
+
try:
|
|
421
|
+
message = types.JSONRPCMessage.model_validate(parsed)
|
|
422
|
+
except Exception as exc:
|
|
423
|
+
# Valid JSON but failed JSON-RPC validation.
|
|
424
|
+
# Push onto the read stream where the SDK's
|
|
425
|
+
# ``_handle_incoming`` will eventually surface
|
|
426
|
+
# it (in practice — once the pending request
|
|
427
|
+
# times out under our injected
|
|
428
|
+
# ``request_timeout`` floor).
|
|
429
|
+
logger.exception("Failed to parse JSONRPC message from server")
|
|
430
|
+
await read_stream_writer.send(exc)
|
|
431
|
+
continue
|
|
432
|
+
|
|
433
|
+
await read_stream_writer.send(SessionMessage(message))
|
|
434
|
+
except anyio.ClosedResourceError, anyio.BrokenResourceError:
|
|
435
|
+
# ClosedResourceError: our writer was closed (normal shutdown).
|
|
436
|
+
# BrokenResourceError: the SDK closed the receive end before we
|
|
437
|
+
# finished draining stdout — happens during failed-connect
|
|
438
|
+
# cleanup, where letting this escape would mask the real
|
|
439
|
+
# initialize() exception with an ExceptionGroup.
|
|
440
|
+
await anyio.lowlevel.checkpoint()
|
|
441
|
+
|
|
442
|
+
async def stdin_writer() -> None:
|
|
443
|
+
if not process.stdin:
|
|
444
|
+
raise RuntimeError("Opened process is missing stdin")
|
|
445
|
+
try:
|
|
446
|
+
async with write_stream_reader:
|
|
447
|
+
async for session_message in write_stream_reader:
|
|
448
|
+
json_text = session_message.message.model_dump_json(by_alias=True, exclude_none=True)
|
|
449
|
+
await process.stdin.send(
|
|
450
|
+
(json_text + "\n").encode(
|
|
451
|
+
encoding=server.encoding,
|
|
452
|
+
errors=server.encoding_error_handler,
|
|
453
|
+
)
|
|
454
|
+
)
|
|
455
|
+
except anyio.ClosedResourceError, anyio.BrokenResourceError:
|
|
456
|
+
await anyio.lowlevel.checkpoint()
|
|
457
|
+
|
|
458
|
+
stderr_drained = anyio.Event()
|
|
459
|
+
|
|
460
|
+
async def stderr_reader() -> None:
|
|
461
|
+
"""Drain and retain a bounded tail from anyio or Windows fallback stderr."""
|
|
462
|
+
try:
|
|
463
|
+
stderr = getattr(process, "stderr", None)
|
|
464
|
+
if stderr is None:
|
|
465
|
+
return
|
|
466
|
+
|
|
467
|
+
receive = getattr(stderr, "receive", None)
|
|
468
|
+
if receive is not None:
|
|
469
|
+
try:
|
|
470
|
+
while True:
|
|
471
|
+
chunk = await receive()
|
|
472
|
+
if chunk:
|
|
473
|
+
diagnostics.append_stderr(bytes(chunk))
|
|
474
|
+
except anyio.EndOfStream, anyio.ClosedResourceError, anyio.BrokenResourceError, OSError, ValueError:
|
|
475
|
+
return
|
|
476
|
+
|
|
477
|
+
# The SDK's Windows ``FallbackProcess`` exposes the raw Popen
|
|
478
|
+
# stderr file. Prefer ``read1`` (returns whatever is available)
|
|
479
|
+
# over ``read`` (blocks until the size is filled or EOF) so a
|
|
480
|
+
# hanging server still shows what it wrote so far.
|
|
481
|
+
read = getattr(stderr, "read1", None) or getattr(stderr, "read", None)
|
|
482
|
+
if read is None:
|
|
483
|
+
return
|
|
484
|
+
try:
|
|
485
|
+
while chunk := await to_thread.run_sync(read, 64 * 1024):
|
|
486
|
+
if inspect.isawaitable(chunk):
|
|
487
|
+
# Not a sync file after all; never loop on an awaitable.
|
|
488
|
+
# Only real coroutine objects need (and have) close().
|
|
489
|
+
if inspect.iscoroutine(chunk):
|
|
490
|
+
chunk.close()
|
|
491
|
+
return
|
|
492
|
+
diagnostics.append_stderr(chunk if isinstance(chunk, bytes) else str(chunk).encode())
|
|
493
|
+
except OSError, ValueError:
|
|
494
|
+
return
|
|
495
|
+
finally:
|
|
496
|
+
stderr_drained.set()
|
|
497
|
+
|
|
498
|
+
async with (
|
|
499
|
+
anyio.create_task_group() as tg,
|
|
500
|
+
process,
|
|
501
|
+
):
|
|
502
|
+
tg.start_soon(stdout_reader)
|
|
503
|
+
tg.start_soon(stdin_writer)
|
|
504
|
+
tg.start_soon(stderr_reader)
|
|
505
|
+
try:
|
|
506
|
+
yield read_stream, write_stream
|
|
507
|
+
finally:
|
|
508
|
+
if process.stdin:
|
|
509
|
+
with contextlib.suppress(Exception):
|
|
510
|
+
await process.stdin.aclose()
|
|
511
|
+
wait_result: object = None
|
|
512
|
+
try:
|
|
513
|
+
try:
|
|
514
|
+
with anyio.fail_after(PROCESS_TERMINATION_TIMEOUT):
|
|
515
|
+
wait_result = await process.wait()
|
|
516
|
+
except TimeoutError:
|
|
517
|
+
await _terminate_process_tree(process)
|
|
518
|
+
try:
|
|
519
|
+
with anyio.fail_after(PROCESS_TERMINATION_TIMEOUT):
|
|
520
|
+
wait_result = await process.wait()
|
|
521
|
+
except TimeoutError, ProcessLookupError:
|
|
522
|
+
pass
|
|
523
|
+
except ProcessLookupError:
|
|
524
|
+
pass
|
|
525
|
+
finally:
|
|
526
|
+
diagnostics.record_exit_code(wait_result, process)
|
|
527
|
+
# wait() only proves the child exited; unread bytes may still
|
|
528
|
+
# be buffered in its stderr pipe. Let the reader drain before
|
|
529
|
+
# process.__aexit__ closes that stream. A descendant can keep
|
|
530
|
+
# the pipe open after the direct child exits, so this wait must
|
|
531
|
+
# remain bounded.
|
|
532
|
+
with anyio.move_on_after(PROCESS_TERMINATION_TIMEOUT):
|
|
533
|
+
await stderr_drained.wait()
|
|
534
|
+
await read_stream.aclose()
|
|
535
|
+
await write_stream.aclose()
|
|
536
|
+
await read_stream_writer.aclose()
|
|
537
|
+
await write_stream_reader.aclose()
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
class _SafeStdioTool(_NoPrePagePingMixin, _StructuredContentFallbackMixin, MCPStdioTool):
|
|
541
|
+
"""MCPStdioTool that hardens the stdio transport for chrys.
|
|
542
|
+
|
|
543
|
+
Two behaviors layered on top of upstream ``MCPStdioTool``:
|
|
544
|
+
|
|
545
|
+
1. **Bounded stderr capture.** Upstream ``stdio_client`` defaults
|
|
546
|
+
``errlog=sys.stderr``, inheriting the parent's stderr fd into the
|
|
547
|
+
spawned child. Inside the Chrys TUI (especially on Python 3.14),
|
|
548
|
+
``sys.stderr.fileno()`` may raise or return a fd unusable for
|
|
549
|
+
subprocess inheritance, causing ``anyio.open_process`` to fail
|
|
550
|
+
outright. Even when the fd is valid, child stderr bytes corrupt
|
|
551
|
+
the Chrys TUI frame. The tolerant transport instead pipes and drains
|
|
552
|
+
stderr into a bounded tail, records the exit code, and uses devnull only
|
|
553
|
+
for the compatibility fallback to the stock SDK client.
|
|
554
|
+
|
|
555
|
+
2. **Tolerant stdout reader.** Many stdio MCP servers (vendor CLI
|
|
556
|
+
wrappers, some ``npx`` packages) emit human-readable banner text on stdout before
|
|
557
|
+
speaking JSON-RPC. Upstream's reader pushes a parse exception
|
|
558
|
+
onto the read stream — which the base session silently drops —
|
|
559
|
+
leaving the pending ``initialize()`` blocked forever. We swap in
|
|
560
|
+
:func:`tolerant_stdio_client` which ignores banner lines and
|
|
561
|
+
captures them on ``dropped_banner_lines`` so the adapter can
|
|
562
|
+
surface them in error messages.
|
|
563
|
+
"""
|
|
564
|
+
|
|
565
|
+
def __init__(self, *args: Any, env_is_complete: bool = False, **kwargs: Any) -> None:
|
|
566
|
+
self._errlog_file: io.TextIOWrapper | None = None
|
|
567
|
+
self.dropped_banner_lines: list[str] = []
|
|
568
|
+
self._process_diagnostics = _StdioProcessDiagnostics()
|
|
569
|
+
self._env_is_complete = env_is_complete
|
|
570
|
+
super().__init__(*args, **kwargs)
|
|
571
|
+
|
|
572
|
+
def get_mcp_client(self) -> Any:
|
|
573
|
+
"""Build a tolerant stdio transport with bounded process diagnostics."""
|
|
574
|
+
args: dict[str, Any] = {
|
|
575
|
+
"command": self.command,
|
|
576
|
+
"args": self.args,
|
|
577
|
+
"env": self.env,
|
|
578
|
+
}
|
|
579
|
+
if self.encoding:
|
|
580
|
+
args["encoding"] = self.encoding
|
|
581
|
+
if self._client_kwargs:
|
|
582
|
+
args.update(self._client_kwargs)
|
|
583
|
+
try:
|
|
584
|
+
from mcp.client.stdio import StdioServerParameters
|
|
585
|
+
except ModuleNotFoundError as ex:
|
|
586
|
+
raise ModuleNotFoundError("`mcp` is required to use `MCPStdioTool`. Please install `mcp`.") from ex
|
|
587
|
+
|
|
588
|
+
return tolerant_stdio_client(
|
|
589
|
+
server=StdioServerParameters(**args),
|
|
590
|
+
errlog=self._devnull_errlog(),
|
|
591
|
+
dropped_banner_lines=self.dropped_banner_lines,
|
|
592
|
+
process_diagnostics=self._process_diagnostics,
|
|
593
|
+
inherit_env=not self._env_is_complete,
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
def _devnull_errlog(self) -> io.TextIOWrapper:
|
|
597
|
+
"""Lazily open the stock-client fallback's safe stderr target."""
|
|
598
|
+
if self._errlog_file is None or self._errlog_file.closed:
|
|
599
|
+
self._errlog_file = open(os.devnull, "w") # noqa: SIM115
|
|
600
|
+
return self._errlog_file
|
|
601
|
+
|
|
602
|
+
async def __aexit__(
|
|
603
|
+
self,
|
|
604
|
+
exc_type: type[BaseException] | None,
|
|
605
|
+
exc_value: BaseException | None,
|
|
606
|
+
traceback: TracebackType | None,
|
|
607
|
+
) -> None:
|
|
608
|
+
"""Clean up the stock-client fallback's devnull handle on exit."""
|
|
609
|
+
try:
|
|
610
|
+
await super().__aexit__(exc_type, exc_value, traceback)
|
|
611
|
+
finally:
|
|
612
|
+
if self._errlog_file is not None and not self._errlog_file.closed:
|
|
613
|
+
self._errlog_file.close()
|
|
614
|
+
self._errlog_file = None
|