kash-shell 0.3.33__tar.gz → 0.3.34__tar.gz
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.
- {kash_shell-0.3.33 → kash_shell-0.3.34}/PKG-INFO +3 -3
- {kash_shell-0.3.33 → kash_shell-0.3.34}/pyproject.toml +3 -2
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/markdownify_html.py +1 -3
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/summarize_as_bullets.py +1 -1
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/actions_model.py +2 -2
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/items_model.py +11 -2
- kash_shell-0.3.34/src/kash/utils/api_utils/multitask_gather.py +134 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/rich_custom/multitask_status.py +84 -10
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/text_handling/markdown_footnotes.py +16 -43
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/text_handling/markdown_utils.py +108 -28
- {kash_shell-0.3.33 → kash_shell-0.3.34}/uv.lock +78 -78
- kash_shell-0.3.33/src/kash/utils/api_utils/multitask_gather.py +0 -74
- {kash_shell-0.3.33 → kash_shell-0.3.34}/.copier-answers.yml +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/.cursor/rules/general.mdc +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/.cursor/rules/python.mdc +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/.env.template +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/.github/workflows/ci.yml +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/.github/workflows/publish.yml +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/.gitignore +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/LICENSE +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/Makefile +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/README.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/development.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/devtools/generate_readme.xsh +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/devtools/lint.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/devtools/profile_main.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/installation.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/publishing.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/__main__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/assistant_chat.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/chat.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/combine_docs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/concat_docs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/format_markdown_template.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/minify_html.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/readability.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/render_as_html.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/save_sidematter_meta.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/show_webpage.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/strip_html.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/tabbed_webpage_config.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/tabbed_webpage_generate.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/core/zip_sidematter.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/meta/write_instructions.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/actions/meta/write_new_action.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/basic_file_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/browser_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/debug_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/diff_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/files_command.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/general_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/logs_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/model_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/reformat_command.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/search_command.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/base/show_command.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/extras/parse_uv_lock.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/extras/utils_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/help/assistant_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/help/doc_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/help/help_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/help/logo.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/help/welcome.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/workspace/selection_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/commands/workspace/workspace_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/capture_output.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/colors.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/env_settings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/init.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/lazy_imports.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/logger.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/logger_basic.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/logo.txt +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/server_config.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/settings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/setup.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/suppress_warnings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/text_styles.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/config/unified_live.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/all_docs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/load_actions_info.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/load_api_docs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/load_help_topics.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/load_source_code.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/api_docs_template.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/assistant_instructions_template.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/readme_template.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/a1_what_is_kash.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/a2_installation.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/a3_getting_started.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/a4_elements.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/a5_tips_for_use_with_other_tools.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/b0_philosophy_of_kash.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/b1_kash_overview.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/b2_workspace_and_file_formats.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/b3_modern_shell_tool_recommendations.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/topics/b4_faq.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/warning.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs/markdown/welcome.md +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs_base/docs_base.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs_base/load_custom_command_info.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs_base/load_faqs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs_base/load_recipe_snippets.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs_base/recipes/general_system_commands.sh +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs_base/recipes/python_dev_commands.sh +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/docs_base/recipes/tldr_standard_commands.sh +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/embeddings/cosine.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/embeddings/embeddings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/embeddings/text_similarity.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/action_decorators.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/action_exec.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/action_registry.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/combiners.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/command_exec.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/command_registry.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/fetch_url_items.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/history.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/importing.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/llm_transforms.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/precondition_checks.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/precondition_registry.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/preconditions.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/resolve_args.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/runtime_settings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec/shell_callable_action.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec_model/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec_model/args_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec_model/commands_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec_model/script_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/exec_model/shell_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/file_storage/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/file_storage/file_store.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/file_storage/item_file_format.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/file_storage/item_id_index.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/file_storage/metadata_dirs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/file_storage/persisted_yaml.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/file_storage/store_cache_warmer.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/file_storage/store_filenames.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/assistant.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/assistant_instructions.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/assistant_output.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/function_param_info.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/help_embeddings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/help_lookups.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/help_pages.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/help_printing.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/help_types.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/recommended_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/help/tldr_help.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/clean_headings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/custom_sliding_transforms.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/fuzzy_parsing.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/init_litellm.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/llm_api_keys.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/llm_completion.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/llm_messages.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/llm_names.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/llm_utils/llms.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/local_server/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/local_server/local_server.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/local_server/local_server_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/local_server/local_server_routes.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/local_server/local_url_formatters.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/local_server/port_tools.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/local_server/rich_html_template.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/mcp/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/mcp/mcp_cli.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/mcp/mcp_main.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/mcp/mcp_server_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/mcp/mcp_server_routes.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/mcp/mcp_server_sse.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/mcp/mcp_server_stdio.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/audio_processing.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/media_cache.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/media_services.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/media_tools.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/services/local_file_media.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/timestamp_citations.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/transcription_deepgram.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/transcription_format.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/media_base/transcription_whisper.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/assistant_response_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/compound_actions_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/concept_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/exec_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/graph_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/language_list.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/llm_actions_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/media_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/operations_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/params_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/paths_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/model/preconditions_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/completions/completion_scoring.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/completions/completion_types.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/completions/shell_completions.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/file_icons/color_for_format.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/file_icons/nerd_icons.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/input/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/input/input_prompts.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/input/inquirer_settings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/input/param_inputs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/input/shell_confirm.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/output/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/output/kerm_code_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/output/kerm_codes.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/output/kmarkdown.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/output/shell_formatting.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/output/shell_output.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/shell_main.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/ui/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/ui/shell_results.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/ui/shell_syntax.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/utils/exception_printing.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/utils/native_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/utils/shell_function_wrapper.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/shell/version.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/api_utils/api_retries.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/api_utils/cache_requests_limited.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/api_utils/gather_limited.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/api_utils/http_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/api_utils/progress_protocol.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/format_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/function_inspect.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/import_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/lazyobject.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/obj_replace.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/parse_docstring.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/parse_key_vals.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/parse_shell_args.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/s3_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/stack_traces.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/task_stack.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/testing.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/type_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/uniquifier.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/url.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/common/url_slice.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/errors.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_formats/chat_format.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/csv_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/dir_info.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/file_ext.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/file_formats.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/file_formats_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/file_sort_filter.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/file_walk.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/filename_parsing.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/ignore_files.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/mtime_cache.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/file_utils/path_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/lang_utils/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/lang_utils/capitalization.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/rich_custom/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/rich_custom/ansi_cell_len.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/rich_custom/rich_char_transform.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/rich_custom/rich_indent.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/rich_custom/rich_markdown_fork.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/text_handling/doc_normalization.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/text_handling/escape_html_tags.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/text_handling/markdown_render.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/text_handling/markdownify_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/utils/text_handling/unified_diffs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/canon_url.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/dir_store.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/file_cache_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/file_processing.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/local_file_cache.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/web_extract.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/web_extract_justext.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/web_extract_readabilipy.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/web_fetch.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_content/web_page_model.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/tabbed_webpage.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/template_render.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/base_styles.css.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/base_webpage.html.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/components/toc_scripts.js.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/components/toc_styles.css.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/components/tooltip_scripts.js.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/components/tooltip_styles.css.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/components/youtube_popover_scripts.js.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/components/youtube_popover_styles.css.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/content_styles.css.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/explain_view.html.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/item_view.html.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/simple_webpage.html.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/tabbed_webpage.html.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/templates/youtube_webpage.html.jinja +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/web_gen/webpage_render.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/workspaces/__init__.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/workspaces/param_state.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/workspaces/selections.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/workspaces/source_items.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/workspaces/workspace_dirs.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/workspaces/workspace_output.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/workspaces/workspace_registry.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/workspaces/workspaces.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/command_nl_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/custom_shell.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/customize_prompt.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/load_into_xonsh.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/shell_load_commands.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/shell_which.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/xonsh_completers.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/xonsh_env.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/xonsh_keybindings.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/xonsh_modern_tools.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xonsh_custom/xonsh_ranking_completer.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xontrib/fnm.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/src/kash/xontrib/kash_extension.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/file_storage/test_file_store.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/kash/utils/api_utils/test_gather_limited.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/kash/utils/file_utils/test_csv_utils.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/kash/utils/rich_custom/test_multitask_status.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/model/test_item_serialization.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/shell/input/interactive_input_test.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/test_shell.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/utils/text_handling/test_markdown_footnotes.py +0 -0
- {kash_shell-0.3.33 → kash_shell-0.3.34}/tests/web_gen/test_social_metadata.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kash-shell
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.34
|
|
4
4
|
Summary: The knowledge agent shell (core)
|
|
5
5
|
Project-URL: Repository, https://github.com/jlevy/kash-shell
|
|
6
6
|
Author-email: Joshua Levy <joshua@cal.berkeley.edu>
|
|
@@ -20,7 +20,7 @@ Requires-Dist: aiolimiter>=1.2.1
|
|
|
20
20
|
Requires-Dist: anyio>=4.8.0
|
|
21
21
|
Requires-Dist: audioop-lts>=0.2.1; python_version >= '3.13'
|
|
22
22
|
Requires-Dist: cachetools>=5.5.2
|
|
23
|
-
Requires-Dist: chopdiff>=0.2.
|
|
23
|
+
Requires-Dist: chopdiff>=0.2.6
|
|
24
24
|
Requires-Dist: clideps>=0.1.4
|
|
25
25
|
Requires-Dist: colour>=0.1.5
|
|
26
26
|
Requires-Dist: cssselect>=1.2.0
|
|
@@ -41,7 +41,7 @@ Requires-Dist: litellm>=1.74.15.post1
|
|
|
41
41
|
Requires-Dist: markdownify>=0.13.1
|
|
42
42
|
Requires-Dist: mcp-proxy>=0.5.0
|
|
43
43
|
Requires-Dist: mcp>=1.6.0
|
|
44
|
-
Requires-Dist: openai
|
|
44
|
+
Requires-Dist: openai==1.99.9
|
|
45
45
|
Requires-Dist: pandas>=2.2.3
|
|
46
46
|
Requires-Dist: patch-ng>=1.18.1
|
|
47
47
|
Requires-Dist: pathspec>=0.12.1
|
|
@@ -48,7 +48,7 @@ dependencies = [
|
|
|
48
48
|
"flowmark>=0.5.3",
|
|
49
49
|
"frontmatter-format>=0.2.3",
|
|
50
50
|
"sidematter-format>=0.0.5",
|
|
51
|
-
"chopdiff>=0.2.
|
|
51
|
+
"chopdiff>=0.2.6",
|
|
52
52
|
"clideps>=0.1.4",
|
|
53
53
|
"tminify>=0.1.6",
|
|
54
54
|
# Shell and file essentials:
|
|
@@ -84,7 +84,7 @@ dependencies = [
|
|
|
84
84
|
"curl-cffi>=0.11.4",
|
|
85
85
|
# LLM and API essentials:
|
|
86
86
|
"tiktoken>=0.9.0",
|
|
87
|
-
"openai
|
|
87
|
+
"openai==1.99.9", # FIXME: Pinning for now due to import errors (ImportError: cannot import name 'ResponseTextConfig' from 'openai.types.responses.response')
|
|
88
88
|
"litellm>=1.74.15.post1",
|
|
89
89
|
"pyrate-limiter>=3.7.0",
|
|
90
90
|
"aiolimiter>=1.2.1",
|
|
@@ -130,6 +130,7 @@ kash-mcp = "kash.mcp.mcp_cli:main"
|
|
|
130
130
|
|
|
131
131
|
[tool.uv.sources]
|
|
132
132
|
# For local development:
|
|
133
|
+
# flowmark = { path = "../flowmark", editable = true }
|
|
133
134
|
# clideps = { path = "../clideps", editable = true }
|
|
134
135
|
# tminify = { path = "../tminify", editable = true }
|
|
135
136
|
# chopdiff = { path = "../chopdiff", editable = true }
|
|
@@ -13,9 +13,7 @@ from kash.web_content.web_extract_readabilipy import extract_text_readabilipy
|
|
|
13
13
|
log = get_logger(__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
@kash_action(
|
|
17
|
-
precondition=is_url_resource | has_html_body, output_format=Format.markdown, mcp_tool=True
|
|
18
|
-
)
|
|
16
|
+
@kash_action(precondition=is_url_resource | has_html_body, output_format=Format.markdown)
|
|
19
17
|
def markdownify_html(item: Item) -> Item:
|
|
20
18
|
"""
|
|
21
19
|
Converts raw HTML or the URL of an HTML page to Markdown, fetching with the content
|
|
@@ -47,7 +47,7 @@ llm_options = LLMOptions(
|
|
|
47
47
|
)
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
@kash_action(llm_options=llm_options, params=common_params("model")
|
|
50
|
+
@kash_action(llm_options=llm_options, params=common_params("model"))
|
|
51
51
|
def summarize_as_bullets(item: Item, model: LLMName = LLM.default_standard) -> Item:
|
|
52
52
|
"""
|
|
53
53
|
Summarize text as bullet points.
|
|
@@ -585,9 +585,9 @@ class Action(ABC):
|
|
|
585
585
|
"type": "array",
|
|
586
586
|
"items": {
|
|
587
587
|
"type": "string",
|
|
588
|
-
"description": "A
|
|
588
|
+
"description": "A URL or S3 URL or a workspace file path, e.g. https://example.com/some/file/path or s3://somebucket/some/file/path or some/file/path",
|
|
589
589
|
},
|
|
590
|
-
"description": f"
|
|
590
|
+
"description": f"A list of paths or URLs of input items ({self.expected_args.as_str()}). Use an array of length one for a single input.",
|
|
591
591
|
}
|
|
592
592
|
|
|
593
593
|
# Set min/max items.
|
|
@@ -7,6 +7,7 @@ from datetime import UTC, datetime
|
|
|
7
7
|
from enum import Enum
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import TYPE_CHECKING, Any, NotRequired, TypedDict, TypeVar, Unpack
|
|
10
|
+
from urllib.parse import urlparse
|
|
10
11
|
|
|
11
12
|
from frontmatter_format import from_yaml_string, new_yaml
|
|
12
13
|
from prettyfmt import (
|
|
@@ -570,12 +571,19 @@ class Item:
|
|
|
570
571
|
from kash.file_storage.store_filenames import parse_item_filename
|
|
571
572
|
|
|
572
573
|
# Prefer original to external, e.g. if we know the original but the external might
|
|
573
|
-
# be a cache filename.
|
|
574
|
-
path =
|
|
574
|
+
# be a cache filename. Also check
|
|
575
|
+
path = (
|
|
576
|
+
self.store_path
|
|
577
|
+
or self.original_filename
|
|
578
|
+
or self.external_path
|
|
579
|
+
or (self.url and urlparse(self.url).path)
|
|
580
|
+
or ""
|
|
581
|
+
).strip()
|
|
575
582
|
if path:
|
|
576
583
|
path_name, _item_type, _format, _file_ext = parse_item_filename(Path(path).name)
|
|
577
584
|
else:
|
|
578
585
|
path_name = None
|
|
586
|
+
|
|
579
587
|
return path_name
|
|
580
588
|
|
|
581
589
|
def slug_name(
|
|
@@ -607,6 +615,7 @@ class Item:
|
|
|
607
615
|
|
|
608
616
|
slug = self.slug_name()
|
|
609
617
|
full_suffix = self.get_full_suffix()
|
|
618
|
+
|
|
610
619
|
return join_suffix(slug, full_suffix)
|
|
611
620
|
|
|
612
621
|
def body_heading(self, allowed_tags: tuple[str, ...] = ("h1", "h2")) -> str | None:
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, Generic, TypeVar, cast
|
|
6
|
+
|
|
7
|
+
from strif import abbrev_list
|
|
8
|
+
|
|
9
|
+
from kash.config.logger import get_logger
|
|
10
|
+
from kash.config.settings import global_settings
|
|
11
|
+
from kash.shell.output.shell_output import multitask_status
|
|
12
|
+
from kash.utils.api_utils.api_retries import RetrySettings
|
|
13
|
+
from kash.utils.api_utils.gather_limited import FuncTask, Limit, gather_limited_sync
|
|
14
|
+
|
|
15
|
+
T = TypeVar("T")
|
|
16
|
+
|
|
17
|
+
log = get_logger(name=__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class MultitaskResult(Generic[T]):
|
|
22
|
+
"""
|
|
23
|
+
Container for results from multitask_gather preserving original order.
|
|
24
|
+
Access `.successes` and `.errors` to get partitioned views.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
raw_results: list[T | BaseException]
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def successes_or_none(self) -> list[T | None]:
|
|
31
|
+
"""
|
|
32
|
+
Return a list of successes or None, aligned with the original order.
|
|
33
|
+
"""
|
|
34
|
+
return [
|
|
35
|
+
None if isinstance(item, BaseException) else cast(T, item) for item in self.raw_results
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def successes(self) -> list[T]:
|
|
40
|
+
"""
|
|
41
|
+
Return a list of successes only. May be shorter than the original list.
|
|
42
|
+
"""
|
|
43
|
+
return [cast(T, item) for item in self.raw_results if not isinstance(item, BaseException)]
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def errors(self) -> list[BaseException]:
|
|
47
|
+
"""
|
|
48
|
+
Return a list of errors only. May be shorter than the original list.
|
|
49
|
+
"""
|
|
50
|
+
return [item for item in self.raw_results if isinstance(item, BaseException)]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _default_labeler(total: int) -> Callable[[int, Any], str]:
|
|
54
|
+
def labeler(i: int, _spec: Any) -> str:
|
|
55
|
+
return f"Task {i + 1}/{total}"
|
|
56
|
+
|
|
57
|
+
return labeler
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
async def multitask_gather(
|
|
61
|
+
tasks: Iterable[FuncTask[T]] | Sequence[FuncTask[T]],
|
|
62
|
+
*,
|
|
63
|
+
labeler: Callable[[int, Any], str] | None = None,
|
|
64
|
+
limit: Limit | None = None,
|
|
65
|
+
bucket_limits: dict[str, Limit] | None = None,
|
|
66
|
+
retry_settings: RetrySettings | None = None,
|
|
67
|
+
show_progress: bool = True,
|
|
68
|
+
) -> MultitaskResult[T]:
|
|
69
|
+
"""
|
|
70
|
+
Run many `FuncTask`s concurrently with shared progress UI and rate limits.
|
|
71
|
+
|
|
72
|
+
This wraps the standard pattern of creating a status context, providing a labeler,
|
|
73
|
+
and calling `gather_limited_sync` with common options.
|
|
74
|
+
|
|
75
|
+
- `labeler` can be omitted; a simple "Task X/Y" label will be used.
|
|
76
|
+
- If `limit` is not provided, defaults are taken from `global_settings()`.
|
|
77
|
+
- If `show_progress` is False, tasks are run without the status context.
|
|
78
|
+
- Exceptions are collected (using return_exceptions=True). Use properties on the
|
|
79
|
+
returned `MultitaskResult` to access `.successes` and `.errors`.
|
|
80
|
+
"""
|
|
81
|
+
|
|
82
|
+
# Normalize tasks to a list for length and stable iteration
|
|
83
|
+
task_list: list[FuncTask[T]] = list(tasks)
|
|
84
|
+
|
|
85
|
+
# Provide a default labeler if none is supplied
|
|
86
|
+
effective_labeler: Callable[[int, Any], str] = (
|
|
87
|
+
labeler if labeler is not None else _default_labeler(len(task_list))
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Provide sensible default rate limits if none are supplied
|
|
91
|
+
effective_limit: Limit = (
|
|
92
|
+
limit
|
|
93
|
+
if limit is not None
|
|
94
|
+
else Limit(
|
|
95
|
+
rps=global_settings().limit_rps,
|
|
96
|
+
concurrency=global_settings().limit_concurrency,
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if not show_progress:
|
|
101
|
+
log.warning("Running %d tasks (progress disabled)…", len(task_list))
|
|
102
|
+
|
|
103
|
+
async with multitask_status(enabled=show_progress) as status:
|
|
104
|
+
raw_results = cast(
|
|
105
|
+
list[T | BaseException],
|
|
106
|
+
await gather_limited_sync(
|
|
107
|
+
*task_list,
|
|
108
|
+
limit=effective_limit,
|
|
109
|
+
bucket_limits=bucket_limits,
|
|
110
|
+
status=status,
|
|
111
|
+
labeler=effective_labeler,
|
|
112
|
+
retry_settings=retry_settings,
|
|
113
|
+
return_exceptions=True,
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
result = MultitaskResult[T](raw_results=raw_results)
|
|
118
|
+
|
|
119
|
+
if result.errors:
|
|
120
|
+
log.warning(
|
|
121
|
+
"multitask_gather: had %d errors (out of %d tasks): %s",
|
|
122
|
+
len(result.errors),
|
|
123
|
+
len(task_list),
|
|
124
|
+
abbrev_list(result.errors),
|
|
125
|
+
)
|
|
126
|
+
log.error(
|
|
127
|
+
"multitask_gather: first error (full traceback):",
|
|
128
|
+
exc_info=(
|
|
129
|
+
type(result.errors[0]),
|
|
130
|
+
result.errors[0],
|
|
131
|
+
result.errors[0].__traceback__,
|
|
132
|
+
),
|
|
133
|
+
)
|
|
134
|
+
return result
|
|
@@ -72,6 +72,8 @@ RUNNING_SYMBOL = ""
|
|
|
72
72
|
DEFAULT_LABEL_WIDTH = 40
|
|
73
73
|
DEFAULT_PROGRESS_WIDTH = 20
|
|
74
74
|
|
|
75
|
+
MAX_DISPLAY_TASKS = 20
|
|
76
|
+
|
|
75
77
|
|
|
76
78
|
# Calculate spinner width to maintain column alignment
|
|
77
79
|
def _get_spinner_width(spinner_name: str) -> int:
|
|
@@ -101,6 +103,9 @@ class StatusSettings:
|
|
|
101
103
|
transient: bool = True
|
|
102
104
|
refresh_per_second: float = 10
|
|
103
105
|
styles: StatusStyles = DEFAULT_STYLES
|
|
106
|
+
# Maximum number of tasks to keep visible in the live display.
|
|
107
|
+
# Older completed/skipped/failed tasks beyond this cap will be removed from the live view.
|
|
108
|
+
max_display_tasks: int = MAX_DISPLAY_TASKS
|
|
104
109
|
|
|
105
110
|
|
|
106
111
|
class SpinnerStatusColumn(ProgressColumn):
|
|
@@ -298,6 +303,10 @@ class MultiTaskStatus(AbstractAsyncContextManager):
|
|
|
298
303
|
self._task_info: dict[int, TaskInfo] = {}
|
|
299
304
|
self._next_id: int = 1
|
|
300
305
|
self._rich_task_ids: dict[int, TaskID] = {} # Map our IDs to Rich Progress IDs
|
|
306
|
+
# Track order of tasks added to the Progress so we can prune oldest completed ones
|
|
307
|
+
self._displayed_task_order: list[int] = []
|
|
308
|
+
# Track tasks pruned from the live display so we don't re-add them later
|
|
309
|
+
self._pruned_task_ids: set[int] = set()
|
|
301
310
|
|
|
302
311
|
# Unified live integration
|
|
303
312
|
self._unified_live: Any | None = None # Reference to the global unified live
|
|
@@ -442,6 +451,10 @@ class MultiTaskStatus(AbstractAsyncContextManager):
|
|
|
442
451
|
progress_display=None,
|
|
443
452
|
)
|
|
444
453
|
self._rich_task_ids[task_id] = rich_task_id
|
|
454
|
+
self._displayed_task_order.append(task_id)
|
|
455
|
+
|
|
456
|
+
# Prune if too many tasks are visible (prefer removing completed ones)
|
|
457
|
+
self._prune_completed_tasks_if_needed()
|
|
445
458
|
|
|
446
459
|
async def set_progress_display(self, task_id: int, display: RenderableType) -> None:
|
|
447
460
|
"""
|
|
@@ -536,18 +549,31 @@ class MultiTaskStatus(AbstractAsyncContextManager):
|
|
|
536
549
|
|
|
537
550
|
# Complete the progress bar and stop spinner
|
|
538
551
|
if rich_task_id is not None:
|
|
539
|
-
|
|
552
|
+
# Safely find the Task by id; Progress.tasks is a list, not a dict
|
|
553
|
+
task_obj = next((t for t in self._progress.tasks if t.id == rich_task_id), None)
|
|
554
|
+
if task_obj is not None and task_obj.total is not None:
|
|
555
|
+
total = task_obj.total
|
|
556
|
+
else:
|
|
557
|
+
total = task_info.steps_total or 1
|
|
540
558
|
self._progress.update(rich_task_id, completed=total, task_info=task_info)
|
|
541
559
|
else:
|
|
542
|
-
#
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
560
|
+
# If this task was pruned from the live display, skip re-adding it
|
|
561
|
+
if task_id in self._pruned_task_ids:
|
|
562
|
+
pass
|
|
563
|
+
else:
|
|
564
|
+
# Task was never started; add a completed row so it appears once
|
|
565
|
+
rich_task_id = self._progress.add_task(
|
|
566
|
+
"",
|
|
567
|
+
total=task_info.steps_total,
|
|
568
|
+
label=task_info.label,
|
|
569
|
+
completed=task_info.steps_total,
|
|
570
|
+
task_info=task_info,
|
|
571
|
+
)
|
|
572
|
+
self._rich_task_ids[task_id] = rich_task_id
|
|
573
|
+
self._displayed_task_order.append(task_id)
|
|
574
|
+
|
|
575
|
+
# After finishing, prune completed tasks to respect max visible cap
|
|
576
|
+
self._prune_completed_tasks_if_needed()
|
|
551
577
|
|
|
552
578
|
def get_task_info(self, task_id: int) -> TaskInfo | None:
|
|
553
579
|
"""Get additional task information."""
|
|
@@ -567,6 +593,54 @@ class MultiTaskStatus(AbstractAsyncContextManager):
|
|
|
567
593
|
"""Get console instance for additional output above progress."""
|
|
568
594
|
return self._progress.console
|
|
569
595
|
|
|
596
|
+
def _prune_completed_tasks_if_needed(self) -> None:
|
|
597
|
+
"""
|
|
598
|
+
Ensure at most `max_display_tasks` tasks are visible by removing the oldest
|
|
599
|
+
completed/skipped/failed tasks first. Running or waiting tasks are never
|
|
600
|
+
removed by this method.
|
|
601
|
+
Note: This method assumes it's called under self._lock.
|
|
602
|
+
"""
|
|
603
|
+
max_visible = self.settings.max_display_tasks
|
|
604
|
+
|
|
605
|
+
# Nothing to prune or unlimited
|
|
606
|
+
if max_visible <= 0:
|
|
607
|
+
return
|
|
608
|
+
|
|
609
|
+
# Count visible tasks (those with a Rich task id present)
|
|
610
|
+
visible_task_ids = [tid for tid in self._displayed_task_order if tid in self._rich_task_ids]
|
|
611
|
+
excess = len(visible_task_ids) - max_visible
|
|
612
|
+
if excess <= 0:
|
|
613
|
+
return
|
|
614
|
+
|
|
615
|
+
# Build list of terminal tasks that can be pruned (oldest first)
|
|
616
|
+
terminal_tasks = []
|
|
617
|
+
for tid in self._displayed_task_order:
|
|
618
|
+
if tid not in self._rich_task_ids:
|
|
619
|
+
continue
|
|
620
|
+
info = self._task_info.get(tid)
|
|
621
|
+
if info and info.state in (
|
|
622
|
+
TaskState.COMPLETED,
|
|
623
|
+
TaskState.FAILED,
|
|
624
|
+
TaskState.SKIPPED,
|
|
625
|
+
):
|
|
626
|
+
terminal_tasks.append(tid)
|
|
627
|
+
|
|
628
|
+
# Remove the oldest terminal tasks up to the excess count
|
|
629
|
+
tasks_to_remove = terminal_tasks[:excess]
|
|
630
|
+
|
|
631
|
+
for tid in tasks_to_remove:
|
|
632
|
+
rich_tid = self._rich_task_ids.pop(tid, None)
|
|
633
|
+
if rich_tid is not None:
|
|
634
|
+
# Remove from Rich progress display
|
|
635
|
+
self._progress.remove_task(rich_tid)
|
|
636
|
+
# Mark as pruned so we don't re-add on finish
|
|
637
|
+
self._pruned_task_ids.add(tid)
|
|
638
|
+
|
|
639
|
+
# Efficiently rebuild the displayed task order without the removed tasks
|
|
640
|
+
self._displayed_task_order = [
|
|
641
|
+
tid for tid in self._displayed_task_order if tid not in tasks_to_remove
|
|
642
|
+
]
|
|
643
|
+
|
|
570
644
|
|
|
571
645
|
## Tests
|
|
572
646
|
|
|
@@ -1,48 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import re
|
|
4
3
|
from dataclasses import dataclass, field
|
|
5
4
|
from typing import Any
|
|
6
5
|
|
|
7
|
-
from flowmark import flowmark_markdown, line_wrap_by_sentence
|
|
8
6
|
from marko import Markdown
|
|
7
|
+
from marko.block import Document
|
|
9
8
|
from marko.ext import footnote
|
|
10
9
|
|
|
11
|
-
from kash.utils.text_handling.markdown_utils import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Marko has a bug where consecutive footnotes without blank lines are parsed
|
|
19
|
-
as a single footnote. This adds blank lines where needed.
|
|
20
|
-
"""
|
|
21
|
-
lines = content.split("\n")
|
|
22
|
-
result = []
|
|
23
|
-
i = 0
|
|
24
|
-
|
|
25
|
-
while i < len(lines):
|
|
26
|
-
line = lines[i]
|
|
27
|
-
result.append(line)
|
|
28
|
-
|
|
29
|
-
# Check if this is a footnote definition
|
|
30
|
-
if re.match(r"^\[\^[^\]]+\]:", line):
|
|
31
|
-
# Look ahead to see if the next non-empty line is also a footnote
|
|
32
|
-
j = i + 1
|
|
33
|
-
while j < len(lines) and not lines[j].strip():
|
|
34
|
-
result.append(lines[j])
|
|
35
|
-
j += 1
|
|
36
|
-
|
|
37
|
-
if j < len(lines) and re.match(r"^\[\^[^\]]+\]:", lines[j]):
|
|
38
|
-
# Next non-empty line is also a footnote, add blank line
|
|
39
|
-
result.append("")
|
|
40
|
-
|
|
41
|
-
i = j
|
|
42
|
-
else:
|
|
43
|
-
i += 1
|
|
44
|
-
|
|
45
|
-
return "\n".join(result)
|
|
10
|
+
from kash.utils.text_handling.markdown_utils import (
|
|
11
|
+
MARKDOWN as DEFAULT_MARKDOWN,
|
|
12
|
+
)
|
|
13
|
+
from kash.utils.text_handling.markdown_utils import (
|
|
14
|
+
comprehensive_transform_tree,
|
|
15
|
+
normalize_footnotes_in_markdown,
|
|
16
|
+
)
|
|
46
17
|
|
|
47
18
|
|
|
48
19
|
@dataclass
|
|
@@ -81,15 +52,17 @@ class MarkdownFootnotes:
|
|
|
81
52
|
MarkdownFootnotes instance with all footnotes indexed by ID
|
|
82
53
|
"""
|
|
83
54
|
if markdown_parser is None:
|
|
84
|
-
markdown_parser =
|
|
55
|
+
markdown_parser = DEFAULT_MARKDOWN
|
|
85
56
|
|
|
86
57
|
# Normalize to work around marko bug with consecutive footnotes
|
|
87
|
-
normalized_content =
|
|
58
|
+
normalized_content = normalize_footnotes_in_markdown(content)
|
|
88
59
|
document = markdown_parser.parse(normalized_content)
|
|
89
60
|
return MarkdownFootnotes.from_document(document, markdown_parser)
|
|
90
61
|
|
|
91
62
|
@staticmethod
|
|
92
|
-
def from_document(
|
|
63
|
+
def from_document(
|
|
64
|
+
document: Document, markdown_parser: Markdown | None = None
|
|
65
|
+
) -> MarkdownFootnotes:
|
|
93
66
|
"""
|
|
94
67
|
Extract all footnotes from a parsed markdown document.
|
|
95
68
|
|
|
@@ -102,7 +75,7 @@ class MarkdownFootnotes:
|
|
|
102
75
|
MarkdownFootnotes instance with all footnotes indexed by ID
|
|
103
76
|
"""
|
|
104
77
|
if markdown_parser is None:
|
|
105
|
-
markdown_parser =
|
|
78
|
+
markdown_parser = DEFAULT_MARKDOWN
|
|
106
79
|
|
|
107
80
|
footnotes_dict: dict[str, FootnoteInfo] = {}
|
|
108
81
|
|
|
@@ -206,9 +179,9 @@ def extract_footnote_references(content: str, markdown_parser: Markdown | None =
|
|
|
206
179
|
List of unique footnote IDs that are referenced (with the ^)
|
|
207
180
|
"""
|
|
208
181
|
if markdown_parser is None:
|
|
209
|
-
markdown_parser =
|
|
182
|
+
markdown_parser = DEFAULT_MARKDOWN
|
|
210
183
|
|
|
211
|
-
normalized_content =
|
|
184
|
+
normalized_content = normalize_footnotes_in_markdown(content)
|
|
212
185
|
document = markdown_parser.parse(normalized_content)
|
|
213
186
|
references: list[str] = []
|
|
214
187
|
seen: set[str] = set()
|