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,176 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Workflow hook lifetimes: session attachments outlive individual run resources.
|
|
4
|
+
|
|
5
|
+
Browsing history is passive. First admitted execution attaches a session (start
|
|
6
|
+
for a new session, restored for an existing one); later runs may reload hook
|
|
7
|
+
configuration without synthesizing another session lifetime. Host shutdown or
|
|
8
|
+
explicit session release ends the attachment. Run hooks are observers, once per
|
|
9
|
+
admitted run, including cancellation and failure.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import logging
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from typing import TYPE_CHECKING, Any
|
|
18
|
+
|
|
19
|
+
from chrys.foundation.trajectory.context import trajectory_scope
|
|
20
|
+
from chrys.foundation.trajectory.event_types import RuntimeFinishReason
|
|
21
|
+
from chrys.foundation.util.once_close import finish_close
|
|
22
|
+
from chrys.service.hooks.events import HookEvent
|
|
23
|
+
from chrys.service.trajectory.session import SessionStartInfo, SessionTrajectory
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
from chrys.orchestration.workflows.session import WorkflowSessionOwner
|
|
31
|
+
from chrys.service.hooks.manager import HookManager
|
|
32
|
+
from chrys.service.state.locks import ActiveSessionGuard
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class _Attachment:
|
|
37
|
+
manager: HookManager | None
|
|
38
|
+
payload: dict[str, Any]
|
|
39
|
+
recorder: SessionTrajectory
|
|
40
|
+
guard: ActiveSessionGuard
|
|
41
|
+
write_lock_path: Path | None
|
|
42
|
+
recovery: asyncio.Task[int] | None = None
|
|
43
|
+
|
|
44
|
+
def new_recorder(self) -> SessionTrajectory:
|
|
45
|
+
return SessionTrajectory(
|
|
46
|
+
session_id=self.recorder.session_id,
|
|
47
|
+
session_dir=self.recorder.session_dir,
|
|
48
|
+
write_lock_path=self.write_lock_path,
|
|
49
|
+
session_start_info=lambda: SessionStartInfo(self.payload["cwd"], "", ""),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
async def settle_recovery(self, *, cancel: bool = False) -> None:
|
|
53
|
+
task = self.recovery
|
|
54
|
+
if task is None:
|
|
55
|
+
return
|
|
56
|
+
if cancel and not task.done():
|
|
57
|
+
task.cancel()
|
|
58
|
+
try:
|
|
59
|
+
await task
|
|
60
|
+
except asyncio.CancelledError:
|
|
61
|
+
if not cancel:
|
|
62
|
+
raise
|
|
63
|
+
except Exception:
|
|
64
|
+
logger.exception("Workflow hook outbox recovery failed")
|
|
65
|
+
finally:
|
|
66
|
+
self.recovery = None
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class WorkflowSessionHooks:
|
|
70
|
+
def __init__(self) -> None:
|
|
71
|
+
self._sessions: dict[str, _Attachment] = {}
|
|
72
|
+
|
|
73
|
+
async def attach(self, resources: WorkflowSessionOwner) -> None:
|
|
74
|
+
session = resources.session
|
|
75
|
+
if not session.session_id or not session.workspace or (not resources.identity):
|
|
76
|
+
raise RuntimeError("Attaching workflow hooks requires a session id, workspace and workflow identity.")
|
|
77
|
+
manager = session.hook_manager
|
|
78
|
+
recorder = resources.trajectory
|
|
79
|
+
if recorder is None:
|
|
80
|
+
raise RuntimeError("Attaching workflow hooks requires a trajectory recorder.")
|
|
81
|
+
context = recorder.context()
|
|
82
|
+
if manager is not None:
|
|
83
|
+
manager.trajectory_context_provider = lambda: context
|
|
84
|
+
payload = {
|
|
85
|
+
"session_id": session.session_id,
|
|
86
|
+
"cwd": session.workspace.primary_cwd,
|
|
87
|
+
"profile": "",
|
|
88
|
+
"session_kind": "workflow",
|
|
89
|
+
"workflow_id": resources.identity.workflow_id,
|
|
90
|
+
}
|
|
91
|
+
previous = self._sessions.get(session.session_id)
|
|
92
|
+
# Transfer ownership before the first suspension, so cancellation during
|
|
93
|
+
# attachment still leaves a valid owner for run-end and session-end.
|
|
94
|
+
attachment = _Attachment(
|
|
95
|
+
manager, payload, recorder, session.guard, session.session_write_lock_path(session.session_id)
|
|
96
|
+
)
|
|
97
|
+
self._sessions[session.session_id] = attachment
|
|
98
|
+
resources.hooks_transferred = True
|
|
99
|
+
if previous is not None:
|
|
100
|
+
# Recovery belongs to the attachment, not the per-run manager.
|
|
101
|
+
# Finish dispatch before retiring the manager that owns it.
|
|
102
|
+
try:
|
|
103
|
+
await previous.settle_recovery()
|
|
104
|
+
finally:
|
|
105
|
+
if previous.manager is not None:
|
|
106
|
+
await finish_close(asyncio.create_task(previous.manager.drain_session()))
|
|
107
|
+
if manager is not None and (previous is None or previous.manager is None):
|
|
108
|
+
with trajectory_scope(context):
|
|
109
|
+
attachment.recovery = asyncio.create_task(manager.recover_outbox())
|
|
110
|
+
if previous is not None:
|
|
111
|
+
return
|
|
112
|
+
if manager is not None:
|
|
113
|
+
event = HookEvent.SESSION_RESTORED if resources.restoring else HookEvent.SESSION_START
|
|
114
|
+
if resources.restoring:
|
|
115
|
+
payload = {**payload, "restored_session_id": session.session_id}
|
|
116
|
+
with trajectory_scope(context):
|
|
117
|
+
await manager.fire(event, payload, scope="session")
|
|
118
|
+
|
|
119
|
+
async def run_event(self, session_id: str, event: HookEvent, *, run_id: str, **fields: Any) -> None:
|
|
120
|
+
attachment = self._sessions[session_id]
|
|
121
|
+
if attachment.manager is not None:
|
|
122
|
+
with trajectory_scope(attachment.recorder.context(run_operation_id=run_id)):
|
|
123
|
+
await attachment.manager.fire(
|
|
124
|
+
event, {**attachment.payload, "run_id": run_id, **fields}, scope="session"
|
|
125
|
+
)
|
|
126
|
+
await attachment.manager.drain_session(close=False)
|
|
127
|
+
|
|
128
|
+
async def release(self, session_id: str) -> None:
|
|
129
|
+
attachment = self._sessions.pop(session_id, None)
|
|
130
|
+
if attachment is None or attachment.manager is None:
|
|
131
|
+
return
|
|
132
|
+
await finish_close(asyncio.create_task(self._end_session(attachment)))
|
|
133
|
+
|
|
134
|
+
async def _end_session(self, attachment: _Attachment) -> None:
|
|
135
|
+
"""Idle end hooks borrow the same session guard before opening a fresh writer."""
|
|
136
|
+
manager = attachment.manager
|
|
137
|
+
if manager is None:
|
|
138
|
+
raise RuntimeError("Ending an attached hook session requires its hook manager.")
|
|
139
|
+
session_id = attachment.recorder.session_id
|
|
140
|
+
recorder = None
|
|
141
|
+
acquired = False
|
|
142
|
+
manager.trajectory_context_provider = None
|
|
143
|
+
try:
|
|
144
|
+
await attachment.settle_recovery(cancel=True)
|
|
145
|
+
if attachment.recorder.is_closed:
|
|
146
|
+
try:
|
|
147
|
+
lock = await asyncio.to_thread(attachment.guard.acquire_for_restore, session_id, timeout=0)
|
|
148
|
+
except TimeoutError:
|
|
149
|
+
logger.warning("Session-end hook trajectory unavailable: workflow session %s is in use", session_id)
|
|
150
|
+
else:
|
|
151
|
+
attachment.guard.install(session_id, lock)
|
|
152
|
+
acquired = True
|
|
153
|
+
directory = attachment.recorder.session_dir
|
|
154
|
+
# SessionDeleted also releases attachments. Never recreate
|
|
155
|
+
# the deleted directory just to record its end hooks.
|
|
156
|
+
if directory is not None and directory.is_dir():
|
|
157
|
+
recorder = attachment.new_recorder()
|
|
158
|
+
else:
|
|
159
|
+
recorder = attachment.recorder
|
|
160
|
+
context = recorder.context() if recorder is not None else None
|
|
161
|
+
with trajectory_scope(context):
|
|
162
|
+
await manager.fire(HookEvent.SESSION_END, attachment.payload, scope="session")
|
|
163
|
+
finally:
|
|
164
|
+
try:
|
|
165
|
+
await manager.drain_session()
|
|
166
|
+
finally:
|
|
167
|
+
try:
|
|
168
|
+
if acquired and recorder is not None:
|
|
169
|
+
await recorder.close(reason=RuntimeFinishReason.GRACEFUL_SHUTDOWN)
|
|
170
|
+
finally:
|
|
171
|
+
if acquired:
|
|
172
|
+
attachment.guard.release()
|
|
173
|
+
|
|
174
|
+
async def close(self) -> None:
|
|
175
|
+
for session_id in tuple(self._sessions):
|
|
176
|
+
await self.release(session_id)
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""Loading a workflow file in a worker before a run: environment, manifest and digests.
|
|
4
|
+
|
|
5
|
+
A preview is the same two steps the run itself starts with, environment
|
|
6
|
+
preparation and a worker load, done on a throwaway worker. What comes back
|
|
7
|
+
is the data-only manifest plus the digests the confirmation ledger pins, so
|
|
8
|
+
the CLI can show and confirm exactly what a run would execute.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
import os
|
|
15
|
+
from collections.abc import Awaitable, Callable
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any, Final
|
|
19
|
+
|
|
20
|
+
from chrys.foundation.events.types import WorkflowRunRequest
|
|
21
|
+
from chrys.foundation.models.workflow_session import WorkflowPins, WorkflowTarget
|
|
22
|
+
from chrys.foundation.platform.files import surrogate_safe_text
|
|
23
|
+
from chrys.foundation.util.once_close import finish_close
|
|
24
|
+
from chrys.orchestration.workflows.worker_client import (
|
|
25
|
+
LOAD_TIMED_OUT,
|
|
26
|
+
AskHandler,
|
|
27
|
+
CapturedOutput,
|
|
28
|
+
EmitHandler,
|
|
29
|
+
LoadDiagnostic,
|
|
30
|
+
LoadResult,
|
|
31
|
+
WorkerLostError,
|
|
32
|
+
WorkerRpcError,
|
|
33
|
+
WorkerStartError,
|
|
34
|
+
WorkflowWorkerClient,
|
|
35
|
+
load_diagnostics,
|
|
36
|
+
)
|
|
37
|
+
from chrys.service.workflows.admission import spec_digest
|
|
38
|
+
from chrys.service.workflows.discovery import WORKFLOWS_DIR_NAME, WorkflowSource
|
|
39
|
+
from chrys.service.workflows.environment import (
|
|
40
|
+
EnvironmentPlan,
|
|
41
|
+
PreparedEnvironment,
|
|
42
|
+
WorkflowEnvironmentError,
|
|
43
|
+
WorkflowEnvironmentManager,
|
|
44
|
+
parse_environment_request,
|
|
45
|
+
plan_environment,
|
|
46
|
+
)
|
|
47
|
+
from chrys.service.workflows.graph import ManifestWarning, manifest_warnings
|
|
48
|
+
from chrys.service.workflows.ledger import LedgerEntry
|
|
49
|
+
from chrys.service.workflows.sdk_artifact import SdkArtifact, materialize_sdk_artifact
|
|
50
|
+
|
|
51
|
+
PREVIEW_ENVIRONMENT_ERROR: Final = "environment_error"
|
|
52
|
+
PREVIEW_WORKER_START_FAILED: Final = "worker_start_failed"
|
|
53
|
+
PREVIEW_LOAD_FAILED: Final = "load_failed"
|
|
54
|
+
PREVIEW_WORKER_LOST: Final = "worker_lost"
|
|
55
|
+
PREVIEW_WORKING_DIR_MISSING: Final = "working_dir_missing"
|
|
56
|
+
REJECT_SPEC_CHANGED: Final = "spec_changed"
|
|
57
|
+
REJECT_NOT_CONFIRMED: Final = "not_confirmed"
|
|
58
|
+
|
|
59
|
+
SDK_ARTIFACT_DIR_NAME: Final = "sdk"
|
|
60
|
+
BYTECODE_CACHE_DIR_NAME: Final = ".pycache"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class WorkflowPreviewError(Exception):
|
|
64
|
+
"""The workflow cannot be loaded; ``code`` is the deterministic rejection reason.
|
|
65
|
+
|
|
66
|
+
A ``diagnose`` load also says where it failed (``diagnostics``, whether
|
|
67
|
+
any were left out) and whether it ran out of time (``timed_out``).
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
code: str,
|
|
73
|
+
message: str,
|
|
74
|
+
*,
|
|
75
|
+
traceback: str = "",
|
|
76
|
+
stdout: CapturedOutput | None = None,
|
|
77
|
+
diagnostics: tuple[LoadDiagnostic, ...] = (),
|
|
78
|
+
diagnostics_truncated: bool = False,
|
|
79
|
+
timed_out: bool = False,
|
|
80
|
+
) -> None:
|
|
81
|
+
super().__init__(message)
|
|
82
|
+
self.code = code
|
|
83
|
+
self.message = message
|
|
84
|
+
self.traceback = traceback
|
|
85
|
+
self.stdout = stdout or CapturedOutput("", False)
|
|
86
|
+
self.diagnostics = diagnostics
|
|
87
|
+
self.diagnostics_truncated = diagnostics_truncated
|
|
88
|
+
self.timed_out = timed_out
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@dataclass(frozen=True, slots=True)
|
|
92
|
+
class WorkflowInspection:
|
|
93
|
+
"""Source bytes and a lexical environment plan; creating this never runs user code."""
|
|
94
|
+
|
|
95
|
+
source: WorkflowSource
|
|
96
|
+
environment: EnvironmentPlan
|
|
97
|
+
prepared_environment: PreparedEnvironment | None = None
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def read(cls, source: WorkflowSource) -> WorkflowInspection:
|
|
101
|
+
try:
|
|
102
|
+
request = parse_environment_request(source.source)
|
|
103
|
+
return cls(source, plan_environment(request, entry_path=Path(source.canonical_path)))
|
|
104
|
+
except WorkflowEnvironmentError as exc:
|
|
105
|
+
raise WorkflowPreviewError(PREVIEW_ENVIRONMENT_ERROR, _located(exc)) from exc
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class WorkflowTrustDeclined(Exception):
|
|
109
|
+
"""The user declined execution of the inspected source; no worker was launched."""
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass(frozen=True, slots=True)
|
|
113
|
+
class LoadedWorkflow:
|
|
114
|
+
"""A worker that has executed the workflow file; the caller owns ``client``."""
|
|
115
|
+
|
|
116
|
+
client: WorkflowWorkerClient
|
|
117
|
+
load: LoadResult
|
|
118
|
+
manifest: dict[str, Any]
|
|
119
|
+
spec_digest: str
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass(frozen=True, slots=True)
|
|
123
|
+
class WorkflowPreview:
|
|
124
|
+
"""What a run of ``source`` would execute, as reported by a throwaway worker."""
|
|
125
|
+
|
|
126
|
+
source: WorkflowSource
|
|
127
|
+
environment: PreparedEnvironment
|
|
128
|
+
load: LoadResult
|
|
129
|
+
manifest: dict[str, Any]
|
|
130
|
+
spec_digest: str
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def title(self) -> str:
|
|
134
|
+
title = self.manifest.get("title")
|
|
135
|
+
return title if isinstance(title, str) else ""
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def warnings(self) -> tuple[ManifestWarning, ...]:
|
|
139
|
+
return manifest_warnings(self.manifest)
|
|
140
|
+
|
|
141
|
+
def ledger_entry(self) -> LedgerEntry:
|
|
142
|
+
return ledger_entry_for(self.source, self.load, self.spec_digest, self.environment, title=self.title)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@dataclass(frozen=True, slots=True)
|
|
146
|
+
class PreparedWorkflow:
|
|
147
|
+
"""A transient execution target and the preview whose pins it submits."""
|
|
148
|
+
|
|
149
|
+
target: WorkflowTarget
|
|
150
|
+
preview: WorkflowPreview
|
|
151
|
+
|
|
152
|
+
def run_request(self, *, input_text: str, request_id: str, timeout: float = 0.0) -> WorkflowRunRequest:
|
|
153
|
+
preview = self.preview
|
|
154
|
+
return WorkflowRunRequest(
|
|
155
|
+
target=self.target,
|
|
156
|
+
pins=WorkflowPins(
|
|
157
|
+
preview.source.identity, preview.spec_digest, preview.environment.environment_fingerprint
|
|
158
|
+
),
|
|
159
|
+
input_text=input_text,
|
|
160
|
+
request_id=request_id,
|
|
161
|
+
timeout=timeout,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def ledger_entry_for(
|
|
166
|
+
source: WorkflowSource, load: LoadResult, digest: str, environment: PreparedEnvironment, *, title: str
|
|
167
|
+
) -> LedgerEntry:
|
|
168
|
+
return LedgerEntry(
|
|
169
|
+
title=title,
|
|
170
|
+
canonical_path=source.canonical_path,
|
|
171
|
+
source_kind=source.source_kind,
|
|
172
|
+
workflow_id=source.workflow_id,
|
|
173
|
+
entry_digest=source.source_digest,
|
|
174
|
+
manifest_digest=load.manifest_digest,
|
|
175
|
+
schema_version=load.manifest["schema_version"],
|
|
176
|
+
spec_digest=digest,
|
|
177
|
+
environment_fingerprint=environment.environment_fingerprint,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def sdk_artifact_dir(config_dir: Path) -> Path:
|
|
182
|
+
"""Where the injected SDK lives; discovery reserves the name ``sdk`` in the global directory, so it never collides."""
|
|
183
|
+
return config_dir / WORKFLOWS_DIR_NAME / SDK_ARTIFACT_DIR_NAME
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def worker_bytecode_cache_dir(config_dir: Path) -> Path:
|
|
187
|
+
"""The private bytecode cache of every workflow worker; discovery ignores hidden names, so it never collides."""
|
|
188
|
+
return config_dir / WORKFLOWS_DIR_NAME / BYTECODE_CACHE_DIR_NAME
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
async def materialize_runtime_sdk(config_dir: Path) -> SdkArtifact:
|
|
192
|
+
return await asyncio.to_thread(materialize_sdk_artifact, sdk_artifact_dir(config_dir))
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
async def prepare_workflow_environment(source: WorkflowSource, *, sdk: SdkArtifact) -> PreparedEnvironment:
|
|
196
|
+
"""Parse the file's environment request, choose the interpreter, and probe it."""
|
|
197
|
+
try:
|
|
198
|
+
request = parse_environment_request(source.source)
|
|
199
|
+
plan = plan_environment(request, entry_path=Path(source.canonical_path))
|
|
200
|
+
return await WorkflowEnvironmentManager(sdk_digest=sdk.digest).prepare(plan)
|
|
201
|
+
except WorkflowEnvironmentError as exc:
|
|
202
|
+
raise WorkflowPreviewError(PREVIEW_ENVIRONMENT_ERROR, _located(exc)) from exc
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
async def load_workflow(
|
|
206
|
+
source: WorkflowSource,
|
|
207
|
+
*,
|
|
208
|
+
environment: PreparedEnvironment,
|
|
209
|
+
sdk: SdkArtifact,
|
|
210
|
+
workspace: Path,
|
|
211
|
+
bytecode_cache: Path,
|
|
212
|
+
ask_handler: AskHandler | None = None,
|
|
213
|
+
emit_handler: EmitHandler | None = None,
|
|
214
|
+
diagnose: bool = False,
|
|
215
|
+
) -> LoadedWorkflow:
|
|
216
|
+
"""Start a fresh worker and execute the file in it; on any failure the worker is closed before raising.
|
|
217
|
+
|
|
218
|
+
*diagnose* (validation) also compiles a folder's other Python files first
|
|
219
|
+
and places a failure in the error's ``diagnostics``.
|
|
220
|
+
"""
|
|
221
|
+
_require_workspace(workspace)
|
|
222
|
+
try:
|
|
223
|
+
client = await WorkflowWorkerClient.launch(
|
|
224
|
+
environment=environment,
|
|
225
|
+
sdk=sdk,
|
|
226
|
+
workspace=workspace,
|
|
227
|
+
bytecode_cache=bytecode_cache,
|
|
228
|
+
ask_handler=ask_handler,
|
|
229
|
+
emit_handler=emit_handler,
|
|
230
|
+
)
|
|
231
|
+
except WorkerStartError as exc:
|
|
232
|
+
raise WorkflowPreviewError(PREVIEW_WORKER_START_FAILED, str(exc)) from exc
|
|
233
|
+
package_dir = source.package.directory if source.package is not None else None
|
|
234
|
+
precompile = source.package.python_files(Path(source.canonical_path).name) if source.package is not None else ()
|
|
235
|
+
try:
|
|
236
|
+
load = await client.load(
|
|
237
|
+
source.source,
|
|
238
|
+
filename=source.canonical_path,
|
|
239
|
+
workspace=workspace,
|
|
240
|
+
package_dir=package_dir,
|
|
241
|
+
diagnose=diagnose,
|
|
242
|
+
precompile=precompile if diagnose else (),
|
|
243
|
+
)
|
|
244
|
+
manifest = load.manifest
|
|
245
|
+
digest = spec_digest(source.source_digest, load.manifest_digest, manifest["schema_version"])
|
|
246
|
+
except WorkerRpcError as exc:
|
|
247
|
+
await _close_worker(client)
|
|
248
|
+
diagnostics, truncated = load_diagnostics(exc.data)
|
|
249
|
+
raise WorkflowPreviewError(
|
|
250
|
+
PREVIEW_LOAD_FAILED,
|
|
251
|
+
f"{exc.code}: {exc.message}",
|
|
252
|
+
traceback=exc.traceback,
|
|
253
|
+
stdout=exc.stdout,
|
|
254
|
+
diagnostics=diagnostics,
|
|
255
|
+
diagnostics_truncated=truncated,
|
|
256
|
+
timed_out=exc.data.get("reason") == LOAD_TIMED_OUT,
|
|
257
|
+
) from exc
|
|
258
|
+
except WorkerLostError as exc:
|
|
259
|
+
await _close_worker(client)
|
|
260
|
+
raise WorkflowPreviewError(PREVIEW_WORKER_LOST, str(exc)) from exc
|
|
261
|
+
except BaseException:
|
|
262
|
+
await _close_worker(client)
|
|
263
|
+
raise
|
|
264
|
+
return LoadedWorkflow(client=client, load=load, manifest=manifest, spec_digest=digest)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
async def preview_workflow(
|
|
268
|
+
source: WorkflowSource,
|
|
269
|
+
*,
|
|
270
|
+
sdk: SdkArtifact,
|
|
271
|
+
workspace: Path,
|
|
272
|
+
bytecode_cache: Path,
|
|
273
|
+
on_environment_ready: Callable[[PreparedEnvironment], Awaitable[None]] | None = None,
|
|
274
|
+
diagnose: bool = False,
|
|
275
|
+
) -> WorkflowPreview:
|
|
276
|
+
"""Prepare the environment and load the file on a worker that is closed before returning."""
|
|
277
|
+
_require_workspace(workspace)
|
|
278
|
+
environment = await prepare_workflow_environment(source, sdk=sdk)
|
|
279
|
+
if on_environment_ready is not None:
|
|
280
|
+
await on_environment_ready(environment)
|
|
281
|
+
loaded = await load_workflow(
|
|
282
|
+
source,
|
|
283
|
+
environment=environment,
|
|
284
|
+
sdk=sdk,
|
|
285
|
+
workspace=workspace,
|
|
286
|
+
bytecode_cache=bytecode_cache,
|
|
287
|
+
diagnose=diagnose,
|
|
288
|
+
)
|
|
289
|
+
await _close_worker(loaded.client)
|
|
290
|
+
return WorkflowPreview(
|
|
291
|
+
source=source,
|
|
292
|
+
environment=environment,
|
|
293
|
+
load=loaded.load,
|
|
294
|
+
manifest=loaded.manifest,
|
|
295
|
+
spec_digest=loaded.spec_digest,
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _require_workspace(workspace: Path) -> None:
|
|
300
|
+
"""Refuse before probing or spawning anything when the worker's cwd is gone."""
|
|
301
|
+
if not workspace.is_dir():
|
|
302
|
+
raise WorkflowPreviewError(
|
|
303
|
+
PREVIEW_WORKING_DIR_MISSING,
|
|
304
|
+
f"The working directory no longer exists: {surrogate_safe_text(os.fspath(workspace))}",
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def _located(exc: WorkflowEnvironmentError) -> str:
|
|
309
|
+
"""The message with its place in the file, for surfaces that show only the message."""
|
|
310
|
+
if exc.line is None:
|
|
311
|
+
return str(exc)
|
|
312
|
+
place = f"line {exc.line}" if exc.column is None else f"line {exc.line}, column {exc.column}"
|
|
313
|
+
return f"{exc} ({place})"
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
async def _close_worker(client: WorkflowWorkerClient) -> None:
|
|
317
|
+
try:
|
|
318
|
+
await client.close()
|
|
319
|
+
except asyncio.CancelledError:
|
|
320
|
+
# close owns a shielded task; drain it even if the caller is cancelled repeatedly.
|
|
321
|
+
await finish_close(asyncio.create_task(client.close()))
|
|
322
|
+
raise
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
2
|
+
|
|
3
|
+
"""File-only Workflow rollback under the caller's execution and session fences."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import hashlib
|
|
9
|
+
import json
|
|
10
|
+
from dataclasses import asdict
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from time import time
|
|
13
|
+
from typing import TYPE_CHECKING, Any
|
|
14
|
+
|
|
15
|
+
from chrys.foundation.events.types import WorkflowRollbackRequest, WorkflowRollbackResult
|
|
16
|
+
from chrys.foundation.models.mutation_scope import WorkflowRunScope
|
|
17
|
+
from chrys.foundation.util.once_close import finish_close
|
|
18
|
+
from chrys.service.mutations.coordination import ATTRIBUTION_DIR_NAME, MutationCoordinator
|
|
19
|
+
from chrys.service.mutations.store import SnapshotPolicy, SnapshotStore
|
|
20
|
+
from chrys.service.mutations.tracker import MutationTracker
|
|
21
|
+
from chrys.service.mutations.types import FileMutation, MutationOp, MutationProvenance, MutationSource
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from chrys.foundation.config.settings import Settings
|
|
25
|
+
from chrys.orchestration.workflows.session import WorkflowSessionOwner
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _file_revision(path: str) -> tuple[int, ...] | None:
|
|
29
|
+
"""Fence editor writes and endpoint replacements without reading large files."""
|
|
30
|
+
try:
|
|
31
|
+
entry = Path(path).lstat()
|
|
32
|
+
except FileNotFoundError, NotADirectoryError:
|
|
33
|
+
return None
|
|
34
|
+
return (entry.st_dev, entry.st_ino, entry.st_mode, entry.st_size, entry.st_mtime_ns, entry.st_ctime_ns)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def rollback_files(
|
|
38
|
+
owner: WorkflowSessionOwner, request: WorkflowRollbackRequest, *, settings: Settings
|
|
39
|
+
) -> WorkflowRollbackResult:
|
|
40
|
+
"""Reload and recheck the plan on both preview and commit; keep Run history intact."""
|
|
41
|
+
state = owner.require_state()
|
|
42
|
+
directory, workspace = owner.require_session_dir(), owner.require_workspace()
|
|
43
|
+
if state.mutations is None:
|
|
44
|
+
raise ValueError("This session has no recorded file changes.")
|
|
45
|
+
mutations = state.mutations
|
|
46
|
+
coordinator = MutationCoordinator(
|
|
47
|
+
registry_root=directory.parent / ATTRIBUTION_DIR_NAME, session_id=request.session_id
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def apply() -> tuple[WorkflowRollbackResult, dict[str, Any] | None]:
|
|
51
|
+
snapshots = SnapshotStore(directory, policy=SnapshotPolicy.from_settings(settings))
|
|
52
|
+
tracker = MutationTracker.deserialize(mutations, snapshots)
|
|
53
|
+
cwd = workspace.primary_cwd
|
|
54
|
+
scope_paths = [cwd, *(directory.path for directory in workspace.working_dirs)]
|
|
55
|
+
reclassified = coordinator.reclassify(tracker, force=True, fallback_root=cwd)
|
|
56
|
+
periods = tracker.get_all_periods()
|
|
57
|
+
target = tracker.get_period(WorkflowRunScope(request.run_id))
|
|
58
|
+
scopes = {period.scope for period in periods if period.period_index >= target.period_index}
|
|
59
|
+
plan = coordinator.augment_rollback_plan(
|
|
60
|
+
tracker, tracker.get_rollback_plan_for_periods(scopes), scope_paths=scope_paths, fallback_root=cwd
|
|
61
|
+
)
|
|
62
|
+
revisions = {path: _file_revision(path) for path, _ in plan.entries}
|
|
63
|
+
token = hashlib.sha256(
|
|
64
|
+
json.dumps(
|
|
65
|
+
{
|
|
66
|
+
"ledger": tracker.serialize(),
|
|
67
|
+
"plan": asdict(plan),
|
|
68
|
+
"run": request.run_id,
|
|
69
|
+
"files": revisions,
|
|
70
|
+
},
|
|
71
|
+
sort_keys=True,
|
|
72
|
+
default=str,
|
|
73
|
+
).encode()
|
|
74
|
+
).hexdigest()
|
|
75
|
+
result = WorkflowRollbackResult(
|
|
76
|
+
session_id=request.session_id,
|
|
77
|
+
request_id=request.request_id,
|
|
78
|
+
run_id=request.run_id,
|
|
79
|
+
token=token,
|
|
80
|
+
paths=tuple(path for path, _ in plan.entries),
|
|
81
|
+
exclusions=tuple((path, reason.value) for path, reason in plan.exclusions),
|
|
82
|
+
warnings=tuple(warning.message for warning in plan.warnings),
|
|
83
|
+
)
|
|
84
|
+
if request.token:
|
|
85
|
+
if request.token != token:
|
|
86
|
+
raise ValueError("The rollback plan changed. Review the updated plan before confirming.")
|
|
87
|
+
# An open window makes concurrent peers aware of the explicit user operation.
|
|
88
|
+
window = coordinator.open_window(scope_paths, fallback_root=cwd)
|
|
89
|
+
try:
|
|
90
|
+
started = time()
|
|
91
|
+
before = {path: snapshots.probe(path) for path, _ in plan.entries}
|
|
92
|
+
if any(_file_revision(path) != revision for path, revision in revisions.items()):
|
|
93
|
+
raise ValueError(
|
|
94
|
+
"Files changed while preparing rollback. Review the updated plan before confirming."
|
|
95
|
+
)
|
|
96
|
+
restored = tracker.restore_files(plan)
|
|
97
|
+
finished = time()
|
|
98
|
+
restored_paths = {item.path for item in restored if item.changed}
|
|
99
|
+
coordinator.publish_claims(
|
|
100
|
+
[
|
|
101
|
+
FileMutation(
|
|
102
|
+
path=path,
|
|
103
|
+
operation=(
|
|
104
|
+
MutationOp.DELETE
|
|
105
|
+
if not snapshot.existed
|
|
106
|
+
else MutationOp.MODIFY
|
|
107
|
+
if before[path].existed
|
|
108
|
+
else MutationOp.CREATE
|
|
109
|
+
),
|
|
110
|
+
source=MutationSource.IMPLICIT,
|
|
111
|
+
provenance=MutationProvenance.PROVEN,
|
|
112
|
+
tool_call_id=request.request_id,
|
|
113
|
+
timestamp=finished,
|
|
114
|
+
t_start=started,
|
|
115
|
+
t_end=finished,
|
|
116
|
+
before_hash=before[path].content_hash,
|
|
117
|
+
before_skip=before[path].skip_reason,
|
|
118
|
+
after_hash=snapshot.content_hash,
|
|
119
|
+
after_skip=snapshot.skip_reason,
|
|
120
|
+
)
|
|
121
|
+
for path, snapshot in plan.entries
|
|
122
|
+
if path in restored_paths
|
|
123
|
+
],
|
|
124
|
+
fallback_root=cwd,
|
|
125
|
+
)
|
|
126
|
+
finally:
|
|
127
|
+
coordinator.close_window(window)
|
|
128
|
+
result.applied = True
|
|
129
|
+
result.changed = sum(item.changed for item in restored)
|
|
130
|
+
result.error = "\n".join(f"{item.path}: {item.reason}" for item in restored if not item.ok)
|
|
131
|
+
return result, tracker.serialize() if reclassified or result.applied else None
|
|
132
|
+
|
|
133
|
+
result: WorkflowRollbackResult | None = None
|
|
134
|
+
|
|
135
|
+
async def complete() -> None:
|
|
136
|
+
nonlocal result
|
|
137
|
+
result, updated = await asyncio.to_thread(apply)
|
|
138
|
+
if updated is not None:
|
|
139
|
+
try:
|
|
140
|
+
await owner.save_mutations(updated)
|
|
141
|
+
except OSError as exc:
|
|
142
|
+
result.error = "\n".join(part for part in (result.error, f"Session checkpoint failed: {exc}") if part)
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
# Drain both the file writes and checkpoint before releasing the lock.
|
|
146
|
+
await finish_close(asyncio.create_task(complete()))
|
|
147
|
+
if result is None:
|
|
148
|
+
raise RuntimeError("Workflow rollback completed without a result.")
|
|
149
|
+
return result
|
|
150
|
+
finally:
|
|
151
|
+
await asyncio.to_thread(coordinator.close)
|