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,575 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
3
|
+
# Contains code adapted from Microsoft Agent Framework (MIT License; see NOTICE).
|
|
4
|
+
|
|
5
|
+
"""Chrys-owned file-based skill discovery and frontmatter parsing.
|
|
6
|
+
|
|
7
|
+
Scans skill directories directly, following the
|
|
8
|
+
`Agent Skills specification <https://agentskills.io/specification>`_:
|
|
9
|
+
|
|
10
|
+
* a skill is a directory containing a ``SKILL.md`` with YAML frontmatter
|
|
11
|
+
whose ``name`` matches the directory name;
|
|
12
|
+
* discovery searches each configured root up to 2 directory levels deep;
|
|
13
|
+
* the first ``SKILL.md`` found on a branch establishes the skill boundary,
|
|
14
|
+
so nested directories and files belong to that parent skill;
|
|
15
|
+
* resource and script files are discovered recursively within each skill
|
|
16
|
+
directory by extension, up to :data:`DEFAULT_SEARCH_DEPTH`.
|
|
17
|
+
|
|
18
|
+
Parsing and failure reporting contracts:
|
|
19
|
+
|
|
20
|
+
* Frontmatter is parsed with PyYAML (full YAML fidelity) with a tolerant
|
|
21
|
+
line-based fallback for files whose frontmatter is not valid YAML but
|
|
22
|
+
contain scalar fields accepted by the legacy line-based parser.
|
|
23
|
+
* Load failures are returned as :class:`SkillLoadFailure` records carrying
|
|
24
|
+
the actual reason, instead of being silently skipped and reconstructed
|
|
25
|
+
by directory comparison in the adapter.
|
|
26
|
+
|
|
27
|
+
Path-traversal and symlink-escape guards are required: skill directories
|
|
28
|
+
may come from third-party repositories, so discovered resource/script paths
|
|
29
|
+
must stay inside the skill directory.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import logging
|
|
35
|
+
import os
|
|
36
|
+
import re
|
|
37
|
+
from datetime import date
|
|
38
|
+
from html import escape as xml_escape
|
|
39
|
+
from pathlib import Path, PurePosixPath
|
|
40
|
+
from typing import TYPE_CHECKING
|
|
41
|
+
|
|
42
|
+
import yaml
|
|
43
|
+
|
|
44
|
+
from chrys.service.skills.model import Skill, SkillLoadFailure, SkillResource, SkillScript
|
|
45
|
+
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from collections.abc import Callable, Sequence
|
|
48
|
+
|
|
49
|
+
logger = logging.getLogger(__name__)
|
|
50
|
+
|
|
51
|
+
SKILL_FILE_NAME = "SKILL.md"
|
|
52
|
+
# How deep to search for SKILL.md files within configured skill roots.
|
|
53
|
+
# This is separate from DEFAULT_SEARCH_DEPTH, which controls per-skill file scanning.
|
|
54
|
+
MAX_SEARCH_DEPTH = 2
|
|
55
|
+
MAX_NAME_LENGTH = 64
|
|
56
|
+
MAX_DESCRIPTION_LENGTH = 1024
|
|
57
|
+
MAX_COMPATIBILITY_LENGTH = 500
|
|
58
|
+
MAX_FRONTMATTER_LENGTH = 16 * 1024
|
|
59
|
+
MAX_FRONTMATTER_DEPTH = 64
|
|
60
|
+
|
|
61
|
+
# Text-based formats that are safe to advertise (and read) as skill resources.
|
|
62
|
+
# Binary assets (images, fonts, archives) are deliberately excluded.
|
|
63
|
+
DEFAULT_RESOURCE_EXTENSIONS: tuple[str, ...] = (
|
|
64
|
+
# Documentation / markup
|
|
65
|
+
".md",
|
|
66
|
+
".txt",
|
|
67
|
+
".rst",
|
|
68
|
+
".html",
|
|
69
|
+
".htm",
|
|
70
|
+
".xml",
|
|
71
|
+
".svg",
|
|
72
|
+
# Structured data
|
|
73
|
+
".json",
|
|
74
|
+
".jsonl",
|
|
75
|
+
".yaml",
|
|
76
|
+
".yml",
|
|
77
|
+
".toml",
|
|
78
|
+
".csv",
|
|
79
|
+
".tsv",
|
|
80
|
+
# Config / styling
|
|
81
|
+
".ini",
|
|
82
|
+
".cfg",
|
|
83
|
+
".css",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# How deep to scan resource/script files within an individual skill directory.
|
|
87
|
+
# Depth 1 means the skill root only; depth 2 means root plus one subdirectory level.
|
|
88
|
+
DEFAULT_SEARCH_DEPTH = 2
|
|
89
|
+
|
|
90
|
+
# Lowercase letters, numbers, hyphens; no leading/trailing/consecutive hyphens.
|
|
91
|
+
VALID_NAME_RE = re.compile(r"^[a-z0-9]([a-z0-9]*-[a-z0-9])*[a-z0-9]*$")
|
|
92
|
+
|
|
93
|
+
# YAML frontmatter delimited by "---" lines; the \uFEFF (regex-level escape)
|
|
94
|
+
# allows an optional UTF-8 BOM before the opening delimiter. Each delimiter is one
|
|
95
|
+
# line, so a file of blank lines with no closing one fails in linear time.
|
|
96
|
+
FRONTMATTER_RE = re.compile(r"\A\uFEFF?---[ \t]*\r?\n(.*?)^---[ \t]*\r?$", re.MULTILINE | re.DOTALL)
|
|
97
|
+
|
|
98
|
+
# What a YAML scalar loads as; a list or mapping is none of these.
|
|
99
|
+
_SCALAR_TYPES = (str, int, float, date)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class _FrontmatterRefused(Exception):
|
|
103
|
+
"""Frontmatter the loader will not compose; the message is the reason."""
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class _FrontmatterLoader(yaml.SafeLoader):
|
|
107
|
+
"""``SafeLoader`` that refuses anchors, aliases and deep nesting as it composes each node.
|
|
108
|
+
|
|
109
|
+
An alias expands before any length check: a few KiB of them can load as
|
|
110
|
+
gigabytes. Refusing node by node keeps the parse lazy, so nesting past
|
|
111
|
+
:data:`MAX_FRONTMATTER_DEPTH` stops after work that does not grow with the
|
|
112
|
+
document; scanning it whole first would cost time that grows with its nesting.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
def __init__(self, stream: str) -> None:
|
|
116
|
+
super().__init__(stream)
|
|
117
|
+
self._depth = 0
|
|
118
|
+
|
|
119
|
+
def compose_node(self, parent: yaml.Node | None, index: object) -> yaml.Node | None:
|
|
120
|
+
event = self.peek_event()
|
|
121
|
+
if isinstance(event, yaml.NodeEvent) and event.anchor is not None:
|
|
122
|
+
raise _FrontmatterRefused("YAML frontmatter must not use anchors or aliases")
|
|
123
|
+
if self._depth >= MAX_FRONTMATTER_DEPTH:
|
|
124
|
+
raise _FrontmatterRefused(f"YAML frontmatter must not nest more than {MAX_FRONTMATTER_DEPTH} levels deep")
|
|
125
|
+
self._depth += 1
|
|
126
|
+
try:
|
|
127
|
+
return super().compose_node(parent, index)
|
|
128
|
+
finally:
|
|
129
|
+
self._depth -= 1
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# Tolerant fallback for frontmatter that is not valid YAML: top-level
|
|
133
|
+
# "key: value" lines with optional single/double quoting. The value runs to its
|
|
134
|
+
# line's end with no backtracking, so a long line costs linear time.
|
|
135
|
+
_LINE_KV_RE = re.compile(r"^([\w-]+)\s*:\s*(\S.*)$", re.MULTILINE)
|
|
136
|
+
_QUOTES = "\"'"
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def validate_skill_metadata(name: str | None, description: str | None, compatibility: str | None = None) -> str | None:
|
|
140
|
+
"""Validate spec naming rules; return a diagnostic string or ``None`` when valid."""
|
|
141
|
+
if not name or not name.strip():
|
|
142
|
+
return "frontmatter is missing a `name`"
|
|
143
|
+
if len(name) > MAX_NAME_LENGTH or not VALID_NAME_RE.match(name):
|
|
144
|
+
return (
|
|
145
|
+
f"invalid skill name '{name}': must be {MAX_NAME_LENGTH} characters or fewer, "
|
|
146
|
+
"using only lowercase letters, numbers, and hyphens, with no leading, trailing, "
|
|
147
|
+
"or consecutive hyphens"
|
|
148
|
+
)
|
|
149
|
+
if not description or not description.strip():
|
|
150
|
+
return f"skill '{name}' is missing a `description`"
|
|
151
|
+
if len(description) > MAX_DESCRIPTION_LENGTH:
|
|
152
|
+
return f"skill '{name}' has an invalid description: must be {MAX_DESCRIPTION_LENGTH} characters or fewer"
|
|
153
|
+
if compatibility is not None and len(compatibility) > MAX_COMPATIBILITY_LENGTH:
|
|
154
|
+
return f"skill '{name}' has an invalid compatibility: must be {MAX_COMPATIBILITY_LENGTH} characters or fewer"
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _coerce_scalar(value: object) -> str | None:
|
|
159
|
+
"""Return a scalar field as text; None when it is absent, a list or a mapping."""
|
|
160
|
+
if not isinstance(value, _SCALAR_TYPES):
|
|
161
|
+
return None
|
|
162
|
+
return value if isinstance(value, str) else str(value)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def _fallback_line_parse(yaml_block: str) -> dict[str, object]:
|
|
166
|
+
"""Parse top-level ``key: value`` lines from frontmatter that is not valid YAML."""
|
|
167
|
+
fields: dict[str, object] = {}
|
|
168
|
+
for match in _LINE_KV_RE.finditer(yaml_block):
|
|
169
|
+
value = match.group(2).rstrip()
|
|
170
|
+
if len(value) > 2 and value[0] in _QUOTES and value[-1] in _QUOTES:
|
|
171
|
+
value = value[1:-1]
|
|
172
|
+
fields.setdefault(match.group(1).lower(), value)
|
|
173
|
+
return fields
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def parse_frontmatter(content: str) -> tuple[dict[str, object] | None, str | None]:
|
|
177
|
+
"""Extract frontmatter fields from SKILL.md text.
|
|
178
|
+
|
|
179
|
+
Returns ``(fields, None)`` on success — *fields* keyed by lowercased
|
|
180
|
+
top-level keys — or ``(None, reason)`` when the frontmatter block is
|
|
181
|
+
missing or unparseable.
|
|
182
|
+
"""
|
|
183
|
+
match = FRONTMATTER_RE.search(content)
|
|
184
|
+
if not match:
|
|
185
|
+
return None, "SKILL.md does not contain YAML frontmatter delimited by '---' lines"
|
|
186
|
+
|
|
187
|
+
yaml_block = match.group(1)
|
|
188
|
+
if len(yaml_block) > MAX_FRONTMATTER_LENGTH:
|
|
189
|
+
return None, f"YAML frontmatter must be {MAX_FRONTMATTER_LENGTH} characters or fewer"
|
|
190
|
+
loader: _FrontmatterLoader | None = None
|
|
191
|
+
try:
|
|
192
|
+
loader = _FrontmatterLoader(yaml_block) # Raises at once on a character YAML does not allow.
|
|
193
|
+
data = loader.get_single_data()
|
|
194
|
+
except _FrontmatterRefused as exc:
|
|
195
|
+
return None, str(exc)
|
|
196
|
+
except yaml.YAMLError as exc:
|
|
197
|
+
fields = _fallback_line_parse(yaml_block)
|
|
198
|
+
if fields:
|
|
199
|
+
logger.warning("SKILL.md frontmatter is not valid YAML (%s); using tolerant line parsing", exc)
|
|
200
|
+
return fields, None
|
|
201
|
+
return None, f"invalid YAML frontmatter: {exc}"
|
|
202
|
+
finally:
|
|
203
|
+
if loader is not None:
|
|
204
|
+
loader.dispose()
|
|
205
|
+
|
|
206
|
+
if data is None:
|
|
207
|
+
return {}, None
|
|
208
|
+
if not isinstance(data, dict):
|
|
209
|
+
return None, "YAML frontmatter must be a key-value mapping"
|
|
210
|
+
return {str(key).lower(): value for key, value in data.items()}, None
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _parse_metadata(value: object) -> dict[str, str] | None:
|
|
214
|
+
"""Return a flat mapping of scalars as text; anything else is dropped whole."""
|
|
215
|
+
if not isinstance(value, dict) or not all(
|
|
216
|
+
item is None or isinstance(item, _SCALAR_TYPES) for pair in value.items() for item in pair
|
|
217
|
+
):
|
|
218
|
+
return None
|
|
219
|
+
return {str(k): str(v) for k, v in value.items()}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def discover_skill_directories(skill_paths: Sequence[str]) -> list[str]:
|
|
223
|
+
"""Return absolute paths of all directories containing a ``SKILL.md`` file.
|
|
224
|
+
|
|
225
|
+
Searches each existing root up to :data:`MAX_SEARCH_DEPTH` levels deep.
|
|
226
|
+
Once a ``SKILL.md`` is found, that directory is the skill root and the
|
|
227
|
+
search does not descend further: everything below the boundary belongs to
|
|
228
|
+
that skill rather than defining another independent skill.
|
|
229
|
+
"""
|
|
230
|
+
discovered: list[str] = []
|
|
231
|
+
|
|
232
|
+
def search(directory: Path, depth: int) -> None:
|
|
233
|
+
if (directory / SKILL_FILE_NAME).is_file():
|
|
234
|
+
discovered.append(str(directory.absolute()))
|
|
235
|
+
return
|
|
236
|
+
if depth >= MAX_SEARCH_DEPTH:
|
|
237
|
+
return
|
|
238
|
+
try:
|
|
239
|
+
entries = list(directory.iterdir())
|
|
240
|
+
except OSError:
|
|
241
|
+
return
|
|
242
|
+
for entry in entries:
|
|
243
|
+
if entry.is_dir():
|
|
244
|
+
search(entry, depth + 1)
|
|
245
|
+
|
|
246
|
+
for root in skill_paths:
|
|
247
|
+
if not root or not root.strip() or not Path(root).is_dir():
|
|
248
|
+
continue
|
|
249
|
+
search(Path(root), 0)
|
|
250
|
+
|
|
251
|
+
return discovered
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _normalize_rel_path(path: str) -> str:
|
|
255
|
+
"""Normalize a relative path to canonical forward-slash form."""
|
|
256
|
+
return PurePosixPath(path.replace("\\", "/")).as_posix()
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _is_path_within_directory(path: str, directory: str) -> bool:
|
|
260
|
+
try:
|
|
261
|
+
return Path(path).is_relative_to(directory)
|
|
262
|
+
except ValueError, OSError:
|
|
263
|
+
return False
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def is_contained_skill_path(path: str, skill_dir: str) -> bool:
|
|
267
|
+
"""Whether *path* lies under *skill_dir* with no symlink or junction below it.
|
|
268
|
+
|
|
269
|
+
The scan admits only such files; a reader re-checks before opening one,
|
|
270
|
+
since the tree may have changed since the scan. The window between this
|
|
271
|
+
check and the open stays: a process that can swap files in the skill
|
|
272
|
+
directory while a read is in flight could as well copy any file it can
|
|
273
|
+
read into it.
|
|
274
|
+
"""
|
|
275
|
+
root = str(Path(skill_dir).absolute())
|
|
276
|
+
full_path = str(Path(os.path.normpath(path)).absolute())
|
|
277
|
+
try:
|
|
278
|
+
return _is_path_within_directory(full_path, root) and not _has_symlink_in_path(full_path, root)
|
|
279
|
+
except OSError:
|
|
280
|
+
return False
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _has_symlink_in_path(path: str, directory: str) -> bool:
|
|
284
|
+
"""Detect symlinks or NT junctions in the segments of *path* below *directory*.
|
|
285
|
+
|
|
286
|
+
Precondition: *path* is a descendant of *directory* (checked via
|
|
287
|
+
:func:`_is_path_within_directory` first).
|
|
288
|
+
"""
|
|
289
|
+
dir_path = Path(directory)
|
|
290
|
+
relative = Path(path).relative_to(dir_path)
|
|
291
|
+
current = dir_path
|
|
292
|
+
for part in relative.parts:
|
|
293
|
+
current = current / part
|
|
294
|
+
if current.is_symlink() or current.is_junction():
|
|
295
|
+
return True
|
|
296
|
+
return False
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _scan_skill_files(
|
|
300
|
+
skill_dir_path: str,
|
|
301
|
+
extensions: Sequence[str],
|
|
302
|
+
*,
|
|
303
|
+
search_depth: int,
|
|
304
|
+
exclude_skill_file: bool,
|
|
305
|
+
skill_name: str,
|
|
306
|
+
file_filter: Callable[[str, str], bool] | None = None,
|
|
307
|
+
) -> list[tuple[str, str]]:
|
|
308
|
+
"""Recursively scan a skill directory for files matching *extensions*.
|
|
309
|
+
|
|
310
|
+
``search_depth=1`` scans only the skill root; ``2`` scans the root plus
|
|
311
|
+
one subdirectory level. Candidates failing containment or symlink checks
|
|
312
|
+
are skipped with a warning. Nested ``SKILL.md`` files do not create a new
|
|
313
|
+
skill boundary during this per-skill scan: their sibling resources and
|
|
314
|
+
scripts belong to the parent, while every ``SKILL.md`` remains excluded.
|
|
315
|
+
Returns ``(name, full_path)`` pairs sorted by name: the skill-relative
|
|
316
|
+
forward-slash display name and the absolute path that passed the checks.
|
|
317
|
+
Readers use that path, never one rebuilt from the name: on POSIX a
|
|
318
|
+
backslash is an ordinary file-name character, so ``..\\x`` would
|
|
319
|
+
rebuild into a path outside the skill.
|
|
320
|
+
"""
|
|
321
|
+
if search_depth < 1:
|
|
322
|
+
raise ValueError(f"search_depth must be >= 1, got {search_depth}")
|
|
323
|
+
|
|
324
|
+
skill_dir = Path(skill_dir_path).absolute()
|
|
325
|
+
root_directory = str(skill_dir)
|
|
326
|
+
normalized_extensions = {e.lower() for e in extensions}
|
|
327
|
+
found: list[tuple[str, str]] = []
|
|
328
|
+
|
|
329
|
+
def scan_directory(target_dir: Path, current_depth: int) -> None:
|
|
330
|
+
if current_depth > search_depth:
|
|
331
|
+
return
|
|
332
|
+
|
|
333
|
+
is_root = target_dir == skill_dir
|
|
334
|
+
resolved_target = str(Path(os.path.normpath(target_dir)).absolute())
|
|
335
|
+
|
|
336
|
+
if not is_root:
|
|
337
|
+
if not _is_path_within_directory(resolved_target, root_directory):
|
|
338
|
+
logger.warning(
|
|
339
|
+
"Skipping directory '%s': resolves outside skill directory '%s'",
|
|
340
|
+
target_dir,
|
|
341
|
+
root_directory,
|
|
342
|
+
)
|
|
343
|
+
return
|
|
344
|
+
if _has_symlink_in_path(resolved_target, root_directory):
|
|
345
|
+
logger.warning(
|
|
346
|
+
"Skipping directory '%s': symlink detected under skill directory '%s'",
|
|
347
|
+
target_dir,
|
|
348
|
+
root_directory,
|
|
349
|
+
)
|
|
350
|
+
return
|
|
351
|
+
|
|
352
|
+
try:
|
|
353
|
+
entries = list(target_dir.iterdir())
|
|
354
|
+
except OSError:
|
|
355
|
+
logger.warning(
|
|
356
|
+
"Failed to list directory '%s' in skill directory '%s'; skipping", target_dir, root_directory
|
|
357
|
+
)
|
|
358
|
+
return
|
|
359
|
+
|
|
360
|
+
subdirectories: list[Path] = []
|
|
361
|
+
|
|
362
|
+
for entry in entries:
|
|
363
|
+
if entry.is_dir():
|
|
364
|
+
subdirectories.append(entry)
|
|
365
|
+
continue
|
|
366
|
+
if not entry.is_file():
|
|
367
|
+
continue
|
|
368
|
+
if exclude_skill_file and entry.name.upper() == SKILL_FILE_NAME.upper():
|
|
369
|
+
continue
|
|
370
|
+
if entry.suffix.lower() not in normalized_extensions:
|
|
371
|
+
continue
|
|
372
|
+
|
|
373
|
+
full_path = str(Path(os.path.normpath(entry)).absolute())
|
|
374
|
+
if not _is_path_within_directory(full_path, root_directory):
|
|
375
|
+
logger.warning("Skipping file '%s': resolves outside skill directory '%s'", entry, root_directory)
|
|
376
|
+
continue
|
|
377
|
+
if _has_symlink_in_path(full_path, root_directory):
|
|
378
|
+
logger.warning("Skipping file '%s': symlink detected under skill directory '%s'", entry, root_directory)
|
|
379
|
+
continue
|
|
380
|
+
|
|
381
|
+
rel_path = _normalize_rel_path(str(entry.relative_to(skill_dir)))
|
|
382
|
+
if file_filter is not None and not file_filter(skill_name, rel_path):
|
|
383
|
+
continue
|
|
384
|
+
|
|
385
|
+
found.append((rel_path, full_path))
|
|
386
|
+
|
|
387
|
+
if current_depth < search_depth:
|
|
388
|
+
for subdir in subdirectories:
|
|
389
|
+
scan_directory(subdir, current_depth + 1)
|
|
390
|
+
|
|
391
|
+
scan_directory(skill_dir, 1)
|
|
392
|
+
|
|
393
|
+
found.sort()
|
|
394
|
+
return found
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def load_file_skill(
|
|
398
|
+
skill_dir: str,
|
|
399
|
+
*,
|
|
400
|
+
resource_extensions: Sequence[str] = DEFAULT_RESOURCE_EXTENSIONS,
|
|
401
|
+
script_extensions: Sequence[str],
|
|
402
|
+
search_depth: int = DEFAULT_SEARCH_DEPTH,
|
|
403
|
+
script_filter: Callable[[str, str], bool] | None = None,
|
|
404
|
+
resource_filter: Callable[[str, str], bool] | None = None,
|
|
405
|
+
) -> Skill | SkillLoadFailure:
|
|
406
|
+
"""Load a single skill from a directory containing ``SKILL.md``."""
|
|
407
|
+
if search_depth < 1:
|
|
408
|
+
raise ValueError(f"search_depth must be >= 1, got {search_depth}")
|
|
409
|
+
|
|
410
|
+
skill_dir = str(Path(skill_dir).absolute())
|
|
411
|
+
skill_file = Path(skill_dir) / SKILL_FILE_NAME
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
content = skill_file.read_text(encoding="utf-8")
|
|
415
|
+
except (OSError, UnicodeDecodeError) as exc:
|
|
416
|
+
return SkillLoadFailure(skill_dir=skill_dir, reason=f"failed to read SKILL.md: {exc}")
|
|
417
|
+
|
|
418
|
+
fields, parse_error = parse_frontmatter(content)
|
|
419
|
+
if fields is None:
|
|
420
|
+
return SkillLoadFailure(skill_dir=skill_dir, reason=parse_error or "invalid frontmatter")
|
|
421
|
+
|
|
422
|
+
for key in ("name", "description"):
|
|
423
|
+
value = fields.get(key)
|
|
424
|
+
if value is not None and not isinstance(value, _SCALAR_TYPES):
|
|
425
|
+
return SkillLoadFailure(
|
|
426
|
+
skill_dir=skill_dir, reason=f"frontmatter `{key}` must be text, not a list or mapping"
|
|
427
|
+
)
|
|
428
|
+
name = _coerce_scalar(fields.get("name"))
|
|
429
|
+
description = _coerce_scalar(fields.get("description"))
|
|
430
|
+
compatibility = _coerce_scalar(fields.get("compatibility"))
|
|
431
|
+
|
|
432
|
+
error = validate_skill_metadata(name, description, compatibility)
|
|
433
|
+
if error or name is None or description is None:
|
|
434
|
+
return SkillLoadFailure(skill_dir=skill_dir, reason=error or "invalid frontmatter")
|
|
435
|
+
|
|
436
|
+
dir_name = Path(skill_dir).name
|
|
437
|
+
if name != dir_name:
|
|
438
|
+
return SkillLoadFailure(
|
|
439
|
+
skill_dir=skill_dir,
|
|
440
|
+
reason=(
|
|
441
|
+
f"frontmatter `name` '{name}' does not match the directory name '{dir_name}' "
|
|
442
|
+
"(required by the Agent Skills specification)"
|
|
443
|
+
),
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
resources = [
|
|
447
|
+
SkillResource(name=rel, full_path=full_path)
|
|
448
|
+
for rel, full_path in _scan_skill_files(
|
|
449
|
+
skill_dir,
|
|
450
|
+
resource_extensions,
|
|
451
|
+
search_depth=search_depth,
|
|
452
|
+
exclude_skill_file=True,
|
|
453
|
+
skill_name=name,
|
|
454
|
+
file_filter=resource_filter,
|
|
455
|
+
)
|
|
456
|
+
]
|
|
457
|
+
scripts = [
|
|
458
|
+
SkillScript(name=rel, full_path=full_path)
|
|
459
|
+
for rel, full_path in _scan_skill_files(
|
|
460
|
+
skill_dir,
|
|
461
|
+
script_extensions,
|
|
462
|
+
search_depth=search_depth,
|
|
463
|
+
exclude_skill_file=True,
|
|
464
|
+
skill_name=name,
|
|
465
|
+
file_filter=script_filter,
|
|
466
|
+
)
|
|
467
|
+
]
|
|
468
|
+
|
|
469
|
+
return Skill(
|
|
470
|
+
name=name,
|
|
471
|
+
description=description,
|
|
472
|
+
content=content,
|
|
473
|
+
path=skill_dir,
|
|
474
|
+
resources=resources,
|
|
475
|
+
scripts=scripts,
|
|
476
|
+
license=_coerce_scalar(fields.get("license")),
|
|
477
|
+
compatibility=compatibility,
|
|
478
|
+
allowed_tools=_coerce_scalar(fields.get("allowed-tools")),
|
|
479
|
+
metadata=_parse_metadata(fields.get("metadata")),
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def discover_file_skills(
|
|
484
|
+
skill_paths: Sequence[str],
|
|
485
|
+
*,
|
|
486
|
+
resource_extensions: Sequence[str] = DEFAULT_RESOURCE_EXTENSIONS,
|
|
487
|
+
script_extensions: Sequence[str],
|
|
488
|
+
search_depth: int = DEFAULT_SEARCH_DEPTH,
|
|
489
|
+
script_filter: Callable[[str, str], bool] | None = None,
|
|
490
|
+
resource_filter: Callable[[str, str], bool] | None = None,
|
|
491
|
+
) -> tuple[list[Skill], list[SkillLoadFailure]]:
|
|
492
|
+
"""Discover all file-based skills under *skill_paths*.
|
|
493
|
+
|
|
494
|
+
Returns ``(skills, failures)``. Duplicate skill names keep the first
|
|
495
|
+
discovered skill (with a log warning, matching prior behavior); duplicates
|
|
496
|
+
are not reported as failures.
|
|
497
|
+
"""
|
|
498
|
+
if search_depth < 1:
|
|
499
|
+
raise ValueError(f"search_depth must be >= 1, got {search_depth}")
|
|
500
|
+
|
|
501
|
+
skills: dict[str, Skill] = {}
|
|
502
|
+
failures: list[SkillLoadFailure] = []
|
|
503
|
+
|
|
504
|
+
discovered = discover_skill_directories(skill_paths)
|
|
505
|
+
logger.info("Discovered %d potential skill directories", len(discovered))
|
|
506
|
+
|
|
507
|
+
for skill_dir in discovered:
|
|
508
|
+
try:
|
|
509
|
+
loaded = load_file_skill(
|
|
510
|
+
skill_dir,
|
|
511
|
+
resource_extensions=resource_extensions,
|
|
512
|
+
script_extensions=script_extensions,
|
|
513
|
+
search_depth=search_depth,
|
|
514
|
+
script_filter=script_filter,
|
|
515
|
+
resource_filter=resource_filter,
|
|
516
|
+
)
|
|
517
|
+
except Exception as exc:
|
|
518
|
+
# One SKILL.md that breaks the loader (a YAML date with no such day, say) fails alone.
|
|
519
|
+
loaded = SkillLoadFailure(skill_dir=skill_dir, reason=f"failed to load SKILL.md: {exc}")
|
|
520
|
+
if isinstance(loaded, SkillLoadFailure):
|
|
521
|
+
logger.error("Failed to load skill from '%s': %s", loaded.skill_dir, loaded.reason)
|
|
522
|
+
failures.append(loaded)
|
|
523
|
+
continue
|
|
524
|
+
|
|
525
|
+
key = loaded.name.casefold()
|
|
526
|
+
if key in skills:
|
|
527
|
+
logger.warning(
|
|
528
|
+
"Duplicate skill name '%s': skill from '%s' skipped in favor of existing skill",
|
|
529
|
+
loaded.name,
|
|
530
|
+
skill_dir,
|
|
531
|
+
)
|
|
532
|
+
continue
|
|
533
|
+
|
|
534
|
+
skills[key] = loaded
|
|
535
|
+
logger.info("Loaded skill: %s", loaded.name)
|
|
536
|
+
|
|
537
|
+
return list(skills.values()), failures
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def build_inline_skill_content(
|
|
541
|
+
name: str,
|
|
542
|
+
description: str,
|
|
543
|
+
instructions: str,
|
|
544
|
+
resources: Sequence[SkillResource] | None = None,
|
|
545
|
+
) -> str:
|
|
546
|
+
"""Build the XML ``load_skill`` document for an inline (profile YAML) skill.
|
|
547
|
+
|
|
548
|
+
Empty resource and script categories are emitted as self-closing elements
|
|
549
|
+
(``<resources />`` / ``<scripts />``) so the model knows none are available
|
|
550
|
+
and does not hallucinate their names.
|
|
551
|
+
"""
|
|
552
|
+
result = (
|
|
553
|
+
f"<name>{xml_escape(name)}</name>\n"
|
|
554
|
+
f"<description>{xml_escape(description)}</description>\n"
|
|
555
|
+
"\n"
|
|
556
|
+
"<instructions>\n"
|
|
557
|
+
f"{instructions}\n"
|
|
558
|
+
"</instructions>"
|
|
559
|
+
)
|
|
560
|
+
lines = []
|
|
561
|
+
for resource in resources or ():
|
|
562
|
+
attrs = f'name="{xml_escape(resource.name, quote=True)}"'
|
|
563
|
+
if resource.description:
|
|
564
|
+
attrs += f' description="{xml_escape(resource.description, quote=True)}"'
|
|
565
|
+
lines.append(f" <resource {attrs}/>")
|
|
566
|
+
result += f"\n\n{_build_element_block('resources', lines)}"
|
|
567
|
+
result += "\n\n<scripts />"
|
|
568
|
+
return result
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
def _build_element_block(tag_name: str, lines: list[str]) -> str:
|
|
572
|
+
"""Return a named XML-ish block, self-closing when it has no child lines."""
|
|
573
|
+
if not lines:
|
|
574
|
+
return f"<{tag_name} />"
|
|
575
|
+
return f"<{tag_name}>\n" + "\n".join(lines) + f"\n</{tag_name}>"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Copyright (c) Microsoft. All rights reserved.
|
|
2
|
+
# Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved.
|
|
3
|
+
# Contains code adapted from Microsoft Agent Framework (MIT License; see NOTICE).
|
|
4
|
+
|
|
5
|
+
"""Chrys-owned skill data model.
|
|
6
|
+
|
|
7
|
+
Plain dataclasses populated by chrys's own loader
|
|
8
|
+
(:mod:`chrys.service.skills.loader`). Owning the model keeps skill internals
|
|
9
|
+
(scripts / resources / content) on stable public fields instead of fragile
|
|
10
|
+
private-attribute reads.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any, Protocol, runtime_checkable
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class SkillResource:
|
|
23
|
+
"""Supplementary content attached to a skill.
|
|
24
|
+
|
|
25
|
+
Exactly one of ``full_path`` (file-backed, read from disk on demand) or
|
|
26
|
+
``content`` (inline, served directly) is expected to be set.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
name: str
|
|
30
|
+
description: str | None = None
|
|
31
|
+
full_path: str | None = None
|
|
32
|
+
content: str | None = None
|
|
33
|
+
|
|
34
|
+
async def read(self) -> str:
|
|
35
|
+
"""Return the resource content, reading file-backed resources from disk."""
|
|
36
|
+
if self.content is not None:
|
|
37
|
+
return self.content
|
|
38
|
+
if not self.full_path:
|
|
39
|
+
raise ValueError(f"Resource '{self.name}' has neither inline content nor a file path.")
|
|
40
|
+
path = Path(self.full_path)
|
|
41
|
+
if not await asyncio.to_thread(path.is_file):
|
|
42
|
+
raise ValueError(f"Resource file '{self.name}' not found at '{self.full_path}'.")
|
|
43
|
+
return await asyncio.to_thread(path.read_text, encoding="utf-8")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class SkillScript:
|
|
48
|
+
"""An executable script file attached to a file-based skill."""
|
|
49
|
+
|
|
50
|
+
name: str
|
|
51
|
+
"""Relative forward-slash path within the skill directory (e.g. ``scripts/convert.py``)."""
|
|
52
|
+
|
|
53
|
+
full_path: str
|
|
54
|
+
"""Absolute path to the script file."""
|
|
55
|
+
|
|
56
|
+
description: str | None = None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class Skill:
|
|
61
|
+
"""A loaded skill — file-based (``path`` set) or inline from profile YAML.
|
|
62
|
+
|
|
63
|
+
``content`` holds the full ``load_skill`` body: the raw SKILL.md text
|
|
64
|
+
(including frontmatter) for file-based skills, or the synthesized XML
|
|
65
|
+
document for inline skills.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
name: str
|
|
69
|
+
description: str
|
|
70
|
+
content: str
|
|
71
|
+
path: str | None = None
|
|
72
|
+
"""Absolute skill directory for file-based skills; ``None`` for inline skills."""
|
|
73
|
+
|
|
74
|
+
resources: list[SkillResource] = field(default_factory=list)
|
|
75
|
+
scripts: list[SkillScript] = field(default_factory=list)
|
|
76
|
+
|
|
77
|
+
revision: str = ""
|
|
78
|
+
"""Cached catalog revision (12-hex content hash) for this staged Skill.
|
|
79
|
+
|
|
80
|
+
Computed and stamped by the skills provider at catalog staging; empty
|
|
81
|
+
until then. One stable value per staged Skill: the catalog block, the
|
|
82
|
+
``load_skill`` metadata suffix, and persisted call provenance all read
|
|
83
|
+
this cache so a ``run_skill_script`` that mutates its own skill files
|
|
84
|
+
cannot shift the model-visible or persisted revision mid-staging.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
# Optional Agent Skills specification frontmatter fields, parsed and kept
|
|
88
|
+
# for forward compatibility (not currently consumed beyond validation).
|
|
89
|
+
license: str | None = None
|
|
90
|
+
compatibility: str | None = None
|
|
91
|
+
allowed_tools: str | None = None
|
|
92
|
+
metadata: dict[str, str] | None = None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@dataclass(frozen=True)
|
|
96
|
+
class SkillLoadFailure:
|
|
97
|
+
"""A directory containing a ``SKILL.md`` that failed to produce a skill."""
|
|
98
|
+
|
|
99
|
+
skill_dir: str
|
|
100
|
+
reason: str
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass(frozen=True)
|
|
104
|
+
class SkillProviderWarning:
|
|
105
|
+
"""Non-fatal skills-stack warning ready to publish as a TUI warning event."""
|
|
106
|
+
|
|
107
|
+
code: str
|
|
108
|
+
message: str
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@runtime_checkable
|
|
112
|
+
class SkillScriptRunner(Protocol):
|
|
113
|
+
"""Protocol for chrys skill script runners.
|
|
114
|
+
|
|
115
|
+
Any callable (sync or async) matching this signature satisfies the
|
|
116
|
+
protocol; :class:`chrys.service.skills.runner.SubprocessScriptRunner` is the
|
|
117
|
+
default implementation.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def __call__(
|
|
121
|
+
self,
|
|
122
|
+
skill: Skill,
|
|
123
|
+
script: SkillScript,
|
|
124
|
+
args: dict[str, Any] | list[str] | None = None,
|
|
125
|
+
arguments: list[str] | None = None,
|
|
126
|
+
cwd: str | None = None,
|
|
127
|
+
max_tokens: int | None = None,
|
|
128
|
+
) -> Any:
|
|
129
|
+
"""Run *script* belonging to *skill* and return its output."""
|
|
130
|
+
...
|