kash-shell 0.3.10__tar.gz → 0.3.12__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.10 → kash_shell-0.3.12}/PKG-INFO +7 -7
- {kash_shell-0.3.10 → kash_shell-0.3.12}/pyproject.toml +7 -6
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/core/format_markdown_template.py +2 -5
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/core/markdownify.py +2 -4
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/core/readability.py +2 -4
- kash_shell-0.3.12/src/kash/actions/core/render_as_html.py +37 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/core/show_webpage.py +6 -11
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/core/strip_html.py +4 -8
- kash_shell-0.3.10/src/kash/actions/core/webpage_config.py → kash_shell-0.3.12/src/kash/actions/core/tabbed_webpage_config.py +5 -3
- kash_shell-0.3.10/src/kash/actions/core/webpage_generate.py → kash_shell-0.3.12/src/kash/actions/core/tabbed_webpage_generate.py +5 -4
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/basic_file_commands.py +21 -3
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/files_command.py +29 -10
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/extras/parse_uv_lock.py +12 -3
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/workspace/selection_commands.py +1 -1
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/workspace/workspace_commands.py +2 -3
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/colors.py +2 -2
- kash_shell-0.3.12/src/kash/config/env_settings.py +32 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/logger.py +30 -25
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/logger_basic.py +6 -6
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/settings.py +23 -7
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/setup.py +33 -5
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/text_styles.py +25 -22
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/embeddings/cosine.py +12 -4
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/embeddings/embeddings.py +16 -6
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/embeddings/text_similarity.py +10 -4
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/__init__.py +3 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/action_decorators.py +10 -25
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/action_exec.py +43 -23
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/llm_transforms.py +6 -3
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/preconditions.py +10 -12
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/resolve_args.py +4 -0
- kash_shell-0.3.12/src/kash/exec/runtime_settings.py +134 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/shell_callable_action.py +5 -3
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/file_storage/file_store.py +37 -38
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/file_storage/item_file_format.py +6 -3
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/file_storage/store_filenames.py +6 -3
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/function_param_info.py +1 -1
- kash_shell-0.3.12/src/kash/llm_utils/init_litellm.py +16 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/llm_api_keys.py +6 -2
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/llm_completion.py +11 -4
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/local_server/local_server_routes.py +1 -7
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/mcp/mcp_cli.py +3 -2
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/mcp/mcp_server_routes.py +11 -12
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/transcription_deepgram.py +15 -2
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/__init__.py +1 -1
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/actions_model.py +6 -54
- kash_shell-0.3.12/src/kash/model/exec_model.py +79 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/items_model.py +102 -35
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/operations_model.py +38 -15
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/paths_model.py +2 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/output/shell_output.py +10 -8
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/shell_main.py +2 -2
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/utils/exception_printing.py +2 -2
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/utils/shell_function_wrapper.py +15 -15
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/text_handling/doc_normalization.py +16 -8
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/text_handling/markdown_render.py +1 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/text_handling/markdown_utils.py +105 -2
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/format_utils.py +2 -8
- kash_shell-0.3.12/src/kash/utils/common/function_inspect.py +428 -0
- kash_shell-0.3.12/src/kash/utils/common/inflection.py +22 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/task_stack.py +4 -15
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/errors.py +14 -9
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/file_ext.py +4 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/file_formats_model.py +32 -1
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/file_sort_filter.py +10 -3
- kash_shell-0.3.12/src/kash/web_gen/__init__.py +0 -0
- kash_shell-0.3.12/src/kash/web_gen/simple_webpage.py +52 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_gen/tabbed_webpage.py +23 -16
- kash_shell-0.3.12/src/kash/web_gen/template_render.py +64 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_gen/templates/base_styles.css.jinja +84 -59
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_gen/templates/base_webpage.html.jinja +85 -67
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_gen/templates/item_view.html.jinja +47 -37
- kash_shell-0.3.12/src/kash/web_gen/templates/simple_webpage.html.jinja +24 -0
- kash_shell-0.3.12/src/kash/web_gen/templates/tabbed_webpage.html.jinja +58 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/workspaces/__init__.py +12 -3
- kash_shell-0.3.12/src/kash/workspaces/workspace_dirs.py +58 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/workspaces/workspace_importing.py +1 -1
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/workspaces/workspaces.py +26 -90
- {kash_shell-0.3.10 → kash_shell-0.3.12}/uv.lock +1371 -1370
- kash_shell-0.3.10/src/kash/actions/core/render_as_html.py +0 -18
- kash_shell-0.3.10/src/kash/config/env_settings.py +0 -72
- kash_shell-0.3.10/src/kash/shell/utils/argparse_utils.py +0 -20
- kash_shell-0.3.10/src/kash/utils/common/function_inspect.py +0 -178
- kash_shell-0.3.10/src/kash/utils/lang_utils/inflection.py +0 -18
- kash_shell-0.3.10/src/kash/web_gen/__init__.py +0 -4
- kash_shell-0.3.10/src/kash/web_gen/template_render.py +0 -29
- kash_shell-0.3.10/src/kash/web_gen/templates/tabbed_webpage.html.jinja +0 -48
- {kash_shell-0.3.10 → kash_shell-0.3.12}/.copier-answers.yml +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/.env.template +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/.github/workflows/ci.yml +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/.github/workflows/publish.yml +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/.gitignore +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/LICENSE +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/Makefile +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/README.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/development.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/devtools/generate_readme.xsh +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/devtools/lint.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/devtools/profile_main.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/installation.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/publishing.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/__main__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/core/assistant_chat.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/core/chat.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/core/summarize_as_bullets.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/meta/write_instructions.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/actions/meta/write_new_action.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/browser_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/debug_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/diff_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/general_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/logs_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/model_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/reformat_command.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/search_command.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/base/show_command.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/extras/utils_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/help/assistant_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/help/doc_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/help/help_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/help/logo.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/commands/help/welcome.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/capture_output.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/init.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/lazy_imports.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/logo.txt +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/server_config.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/config/suppress_warnings.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/all_docs.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/load_actions_info.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/load_api_docs.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/load_help_topics.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/load_source_code.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/api_docs_template.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/assistant_instructions_template.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/readme_template.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/a1_what_is_kash.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/a2_installation.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/a3_getting_started.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/a4_elements.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/a5_tips_for_use_with_other_tools.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/b0_philosophy_of_kash.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/b1_kash_overview.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/b2_workspace_and_file_formats.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/b3_modern_shell_tool_recommendations.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/topics/b4_faq.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/warning.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs/markdown/welcome.md +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs_base/docs_base.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs_base/load_custom_command_info.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs_base/load_faqs.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs_base/load_recipe_snippets.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs_base/recipes/general_system_commands.sh +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs_base/recipes/python_dev_commands.sh +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/docs_base/recipes/tldr_standard_commands.sh +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/action_registry.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/combiners.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/command_exec.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/command_registry.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/fetch_url_metadata.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/history.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/importing.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/precondition_checks.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec/precondition_registry.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec_model/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec_model/args_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec_model/commands_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec_model/script_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/exec_model/shell_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/file_storage/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/file_storage/metadata_dirs.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/file_storage/persisted_yaml.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/file_storage/store_cache_warmer.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/assistant.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/assistant_instructions.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/assistant_output.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/docstring_utils.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/help_embeddings.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/help_lookups.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/help_pages.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/help_printing.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/help_types.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/recommended_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/help/tldr_help.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/clean_headings.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/fuzzy_parsing.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/llm_features.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/llm_messages.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/llm_names.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/llm_utils/llms.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/local_server/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/local_server/local_server.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/local_server/local_server_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/local_server/local_url_formatters.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/local_server/port_tools.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/local_server/rich_html_template.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/mcp/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/mcp/mcp_main.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/mcp/mcp_server_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/mcp/mcp_server_sse.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/mcp/mcp_server_stdio.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/audio_processing.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/media_cache.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/media_services.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/media_tools.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/services/local_file_media.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/timestamp_citations.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/transcription_format.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/media_base/transcription_whisper.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/assistant_response_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/compound_actions_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/concept_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/graph_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/language_list.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/llm_actions_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/media_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/params_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/model/preconditions_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/completions/completion_scoring.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/completions/completion_types.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/completions/shell_completions.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/file_icons/color_for_format.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/file_icons/nerd_icons.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/input/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/input/input_prompts.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/input/inquirer_settings.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/input/param_inputs.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/input/shell_confirm.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/output/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/output/kerm_code_utils.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/output/kerm_codes.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/output/kmarkdown.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/output/shell_formatting.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/ui/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/ui/shell_results.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/ui/shell_syntax.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/utils/native_utils.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/shell/version.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/text_handling/custom_sliding_transforms.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/text_handling/unified_diffs.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/import_utils.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/lazyobject.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/obj_replace.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/parse_key_vals.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/parse_shell_args.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/stack_traces.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/type_utils.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/uniquifier.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/common/url.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_formats/chat_format.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/dir_info.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/file_formats.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/file_walk.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/filename_parsing.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/ignore_files.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/mtime_cache.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/file_utils/path_utils.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/lang_utils/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/lang_utils/capitalization.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/rich_custom/__init__.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/rich_custom/ansi_cell_len.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/rich_custom/rich_char_transform.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/rich_custom/rich_indent.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/utils/rich_custom/rich_markdown_fork.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/canon_url.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/dir_store.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/file_cache_utils.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/file_processing.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/local_file_cache.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/web_extract.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/web_extract_justext.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/web_extract_readabilipy.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/web_fetch.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_content/web_page_model.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_gen/templates/content_styles.css.jinja +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/web_gen/templates/explain_view.html.jinja +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/workspaces/param_state.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/workspaces/selections.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/workspaces/source_items.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/workspaces/workspace_output.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/workspaces/workspace_registry.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/command_nl_utils.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/custom_shell.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/customize_prompt.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/load_into_xonsh.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/shell_load_commands.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/shell_which.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/xonsh_completers.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/xonsh_env.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/xonsh_keybindings.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/xonsh_modern_tools.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xonsh_custom/xonsh_ranking_completer.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xontrib/fnm.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/src/kash/xontrib/kash_extension.py +0 -0
- {kash_shell-0.3.10 → kash_shell-0.3.12}/tests/test_shell.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.12
|
|
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,30 +20,30 @@ Requires-Dist: anyio>=4.8.0
|
|
|
20
20
|
Requires-Dist: audioop-lts>=0.2.1; python_version >= '3.13'
|
|
21
21
|
Requires-Dist: cachetools>=5.5.2
|
|
22
22
|
Requires-Dist: chopdiff>=0.2.1
|
|
23
|
-
Requires-Dist: clideps>=0.1.
|
|
23
|
+
Requires-Dist: clideps>=0.1.4
|
|
24
24
|
Requires-Dist: colour>=0.1.5
|
|
25
25
|
Requires-Dist: cssselect>=1.2.0
|
|
26
26
|
Requires-Dist: deepgram-sdk>=3.10.1
|
|
27
27
|
Requires-Dist: dunamai>=1.23.0
|
|
28
28
|
Requires-Dist: fastapi>=0.115.11
|
|
29
|
-
Requires-Dist: flowmark>=0.4.
|
|
29
|
+
Requires-Dist: flowmark>=0.4.6
|
|
30
30
|
Requires-Dist: frontmatter-format>=0.2.1
|
|
31
31
|
Requires-Dist: funlog>=0.2.0
|
|
32
32
|
Requires-Dist: humanfriendly>=10.0
|
|
33
|
-
Requires-Dist: inflect>=7.5.0
|
|
34
33
|
Requires-Dist: inquirerpy>=0.3.4
|
|
35
34
|
Requires-Dist: jinja2>=3.1.6
|
|
36
35
|
Requires-Dist: justext>=3.0.2
|
|
37
36
|
Requires-Dist: lazyasd>=0.1.4
|
|
38
37
|
Requires-Dist: litellm>=1.63.11
|
|
39
|
-
Requires-Dist: markdownify>=0.
|
|
38
|
+
Requires-Dist: markdownify>=0.13.1
|
|
40
39
|
Requires-Dist: mcp-proxy>=0.5.0
|
|
41
40
|
Requires-Dist: mcp>=1.6.0
|
|
42
41
|
Requires-Dist: openai>=1.66.3
|
|
43
42
|
Requires-Dist: pandas>=2.2.3
|
|
44
43
|
Requires-Dist: patch-ng>=1.18.1
|
|
45
44
|
Requires-Dist: pathspec>=0.12.1
|
|
46
|
-
Requires-Dist:
|
|
45
|
+
Requires-Dist: pluralizer>=1.2.0
|
|
46
|
+
Requires-Dist: prettyfmt>=0.3.1
|
|
47
47
|
Requires-Dist: prompt-toolkit>=3.0.50
|
|
48
48
|
Requires-Dist: pydantic>=2.10.6
|
|
49
49
|
Requires-Dist: pydub>=0.25.1
|
|
@@ -59,7 +59,7 @@ Requires-Dist: rich>=14.0.0
|
|
|
59
59
|
Requires-Dist: ripgrepy>=2.1.0
|
|
60
60
|
Requires-Dist: send2trash>=1.8.3
|
|
61
61
|
Requires-Dist: setproctitle>=1.3.5
|
|
62
|
-
Requires-Dist: strif>=3.0.
|
|
62
|
+
Requires-Dist: strif>=3.0.1
|
|
63
63
|
Requires-Dist: tenacity>=9.0.0
|
|
64
64
|
Requires-Dist: thefuzz>=0.22.1
|
|
65
65
|
Requires-Dist: tiktoken>=0.9.0
|
|
@@ -42,13 +42,13 @@ dependencies = [
|
|
|
42
42
|
"pydantic>=2.10.6",
|
|
43
43
|
"typing-extensions>=4.12.2",
|
|
44
44
|
# My tools:
|
|
45
|
-
"strif>=3.0.
|
|
45
|
+
"strif>=3.0.1",
|
|
46
46
|
"funlog>=0.2.0",
|
|
47
|
-
"prettyfmt>=0.3.
|
|
48
|
-
"flowmark>=0.4.
|
|
47
|
+
"prettyfmt>=0.3.1",
|
|
48
|
+
"flowmark>=0.4.6",
|
|
49
49
|
"frontmatter-format>=0.2.1",
|
|
50
50
|
"chopdiff>=0.2.1",
|
|
51
|
-
"clideps>=0.1.
|
|
51
|
+
"clideps>=0.1.4",
|
|
52
52
|
# Shell and file essentials:
|
|
53
53
|
# python-magic is most current and works with libmagic on macOS and Linux.
|
|
54
54
|
# on Windows, python-magic-bin seems like the best option.
|
|
@@ -71,7 +71,6 @@ dependencies = [
|
|
|
71
71
|
"tldr>=3.3.0",
|
|
72
72
|
"jinja2>=3.1.6",
|
|
73
73
|
"pygments>=2.19.1",
|
|
74
|
-
"inflect>=7.5.0",
|
|
75
74
|
"tenacity>=9.0.0",
|
|
76
75
|
"lazyasd>=0.1.4",
|
|
77
76
|
"pathspec>=0.12.1",
|
|
@@ -83,9 +82,10 @@ dependencies = [
|
|
|
83
82
|
"litellm>=1.63.11",
|
|
84
83
|
# Basic text handling and web scraping:
|
|
85
84
|
"readabilipy>=0.3.0",
|
|
86
|
-
"markdownify>=0.
|
|
85
|
+
"markdownify>=0.13.1",
|
|
87
86
|
"justext>=3.0.2",
|
|
88
87
|
"cssselect>=1.2.0",
|
|
88
|
+
"pluralizer>=1.2.0",
|
|
89
89
|
# Minimal media handling:
|
|
90
90
|
"pydub>=0.25.1",
|
|
91
91
|
# audioop-lts is a backport of audioop for Python 3.13 and later needed for pydub.
|
|
@@ -105,6 +105,7 @@ dependencies = [
|
|
|
105
105
|
[dependency-groups]
|
|
106
106
|
dev = [
|
|
107
107
|
"pytest>=8.3.5",
|
|
108
|
+
"pytest-sugar>=1.0.0",
|
|
108
109
|
"ruff>=0.11.0",
|
|
109
110
|
"codespell>=2.4.1",
|
|
110
111
|
"rich>=14.0.0",
|
|
@@ -4,7 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
from kash.config.logger import get_logger
|
|
5
5
|
from kash.exec import kash_action
|
|
6
6
|
from kash.exec.preconditions import is_markdown
|
|
7
|
-
from kash.model import ONE_OR_MORE_ARGS, ActionInput, ActionResult,
|
|
7
|
+
from kash.model import ONE_OR_MORE_ARGS, ActionInput, ActionResult, Param
|
|
8
8
|
from kash.utils.common.type_utils import not_none
|
|
9
9
|
from kash.utils.errors import InvalidInput
|
|
10
10
|
|
|
@@ -84,9 +84,6 @@ def format_markdown_template(
|
|
|
84
84
|
# Format the body using the mapped items.
|
|
85
85
|
body = template.format(**item_map)
|
|
86
86
|
|
|
87
|
-
result_item = items[0].derived_copy(
|
|
88
|
-
type=ItemType.doc,
|
|
89
|
-
body=body,
|
|
90
|
-
)
|
|
87
|
+
result_item = items[0].derived_copy(body=body)
|
|
91
88
|
|
|
92
89
|
return ActionResult([result_item])
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from kash.config.logger import get_logger
|
|
2
2
|
from kash.exec import kash_action
|
|
3
3
|
from kash.exec.preconditions import has_html_body, is_url_item
|
|
4
|
-
from kash.model import Format, Item
|
|
4
|
+
from kash.model import Format, Item
|
|
5
5
|
from kash.model.params_model import common_params
|
|
6
6
|
from kash.web_content.file_cache_utils import get_url_html
|
|
7
7
|
from kash.web_content.web_extract_readabilipy import extract_text_readabilipy
|
|
@@ -26,7 +26,5 @@ def markdownify(item: Item, refetch: bool = False) -> Item:
|
|
|
26
26
|
page_data = extract_text_readabilipy(url, html_content)
|
|
27
27
|
markdown_content = markdownify_convert(page_data.clean_html)
|
|
28
28
|
|
|
29
|
-
output_item = item.derived_copy(
|
|
30
|
-
type=ItemType.doc, format=Format.markdown, body=markdown_content
|
|
31
|
-
)
|
|
29
|
+
output_item = item.derived_copy(format=Format.markdown, body=markdown_content)
|
|
32
30
|
return output_item
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from kash.config.logger import get_logger
|
|
2
2
|
from kash.exec import kash_action
|
|
3
3
|
from kash.exec.preconditions import has_html_body, is_url_item
|
|
4
|
-
from kash.model import Format, Item
|
|
4
|
+
from kash.model import Format, Item
|
|
5
5
|
from kash.model.params_model import common_params
|
|
6
6
|
from kash.web_content.file_cache_utils import get_url_html
|
|
7
7
|
from kash.web_content.web_extract_readabilipy import extract_text_readabilipy
|
|
@@ -23,8 +23,6 @@ def readability(item: Item, refetch: bool = False) -> Item:
|
|
|
23
23
|
url, html_content = get_url_html(item, expiration_sec=expiration_sec)
|
|
24
24
|
page_data = extract_text_readabilipy(url, html_content)
|
|
25
25
|
|
|
26
|
-
output_item = item.derived_copy(
|
|
27
|
-
type=ItemType.doc, format=Format.html, body=page_data.clean_html
|
|
28
|
-
)
|
|
26
|
+
output_item = item.derived_copy(format=Format.html, body=page_data.clean_html)
|
|
29
27
|
|
|
30
28
|
return output_item
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from kash.actions.core.tabbed_webpage_config import tabbed_webpage_config
|
|
2
|
+
from kash.actions.core.tabbed_webpage_generate import tabbed_webpage_generate
|
|
3
|
+
from kash.exec import kash_action
|
|
4
|
+
from kash.exec.preconditions import has_full_html_page_body, has_html_body, has_simple_text_body
|
|
5
|
+
from kash.exec_model.args_model import ONE_OR_MORE_ARGS
|
|
6
|
+
from kash.model import ActionInput, ActionResult, Param
|
|
7
|
+
from kash.model.items_model import ItemType
|
|
8
|
+
from kash.utils.file_utils.file_formats_model import Format
|
|
9
|
+
from kash.web_gen.simple_webpage import simple_webpage_render
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@kash_action(
|
|
13
|
+
expected_args=ONE_OR_MORE_ARGS,
|
|
14
|
+
precondition=(has_html_body | has_simple_text_body) & ~has_full_html_page_body,
|
|
15
|
+
params=(Param("add_title", "Add a title to the page body.", type=bool),),
|
|
16
|
+
)
|
|
17
|
+
def render_as_html(input: ActionInput, add_title: bool = False) -> ActionResult:
|
|
18
|
+
"""
|
|
19
|
+
Convert text, Markdown, or HTML to pretty, formatted HTML using a clean
|
|
20
|
+
and simple page template. Supports GFM-flavored Markdown tables and footnotes.
|
|
21
|
+
|
|
22
|
+
If it's a single input, the output is a simple HTML page.
|
|
23
|
+
If it's multiple inputs, the output is a tabbed HTML page.
|
|
24
|
+
|
|
25
|
+
This adds a header, footer, etc. so should be used on a plain document or HTML basic
|
|
26
|
+
page, not a full HTML page with header and body already present.
|
|
27
|
+
"""
|
|
28
|
+
if len(input.items) == 1:
|
|
29
|
+
input_item = input.items[0]
|
|
30
|
+
html_body = simple_webpage_render(input_item, add_title_h1=add_title)
|
|
31
|
+
result_item = input_item.derived_copy(
|
|
32
|
+
type=ItemType.export, format=Format.html, body=html_body
|
|
33
|
+
)
|
|
34
|
+
return ActionResult([result_item])
|
|
35
|
+
else:
|
|
36
|
+
config_result = tabbed_webpage_config(input)
|
|
37
|
+
return tabbed_webpage_generate(ActionInput(items=config_result.items), add_title=add_title)
|
|
@@ -1,27 +1,22 @@
|
|
|
1
|
-
from kash.actions.core.
|
|
2
|
-
from kash.actions.core.webpage_generate import webpage_generate
|
|
1
|
+
from kash.actions.core.render_as_html import render_as_html
|
|
3
2
|
from kash.commands.base.show_command import show
|
|
4
|
-
from kash.config.logger import get_logger
|
|
5
3
|
from kash.exec import kash_action
|
|
6
|
-
from kash.exec.preconditions import
|
|
4
|
+
from kash.exec.preconditions import has_full_html_page_body, has_html_body, has_simple_text_body
|
|
5
|
+
from kash.exec_model.args_model import ONE_OR_MORE_ARGS
|
|
7
6
|
from kash.exec_model.commands_model import Command
|
|
8
7
|
from kash.exec_model.shell_model import ShellResult
|
|
9
8
|
from kash.model import ActionInput, ActionResult
|
|
10
9
|
|
|
11
|
-
log = get_logger(__name__)
|
|
12
|
-
|
|
13
10
|
|
|
14
11
|
@kash_action(
|
|
15
|
-
|
|
12
|
+
expected_args=ONE_OR_MORE_ARGS,
|
|
13
|
+
precondition=(has_html_body | has_simple_text_body) & ~has_full_html_page_body,
|
|
16
14
|
)
|
|
17
15
|
def show_webpage(input: ActionInput) -> ActionResult:
|
|
18
16
|
"""
|
|
19
17
|
Show text, Markdown, or HTML as a nicely formatted webpage.
|
|
20
18
|
"""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
log.message("Configured web page: %s", config_result)
|
|
24
|
-
result = webpage_generate(ActionInput(items=config_result.items))
|
|
19
|
+
result = render_as_html(input)
|
|
25
20
|
|
|
26
21
|
# Automatically show the result.
|
|
27
22
|
result.shell_result = ShellResult(display_command=Command.assemble(show))
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
from kash.config.logger import get_logger
|
|
2
2
|
from kash.exec import kash_action
|
|
3
|
-
from kash.exec.preconditions import has_html_body,
|
|
4
|
-
from kash.model import Format, Item
|
|
3
|
+
from kash.exec.preconditions import has_html_body, has_simple_text_body
|
|
4
|
+
from kash.model import Format, Item
|
|
5
5
|
from kash.utils.common.format_utils import html_to_plaintext
|
|
6
6
|
from kash.utils.errors import InvalidInput
|
|
7
7
|
|
|
8
8
|
log = get_logger(__name__)
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
@kash_action(precondition=has_html_body |
|
|
11
|
+
@kash_action(precondition=has_html_body | has_simple_text_body)
|
|
12
12
|
def strip_html(item: Item) -> Item:
|
|
13
13
|
"""
|
|
14
14
|
Strip HTML tags from HTML or Markdown. This is a simple filter, simply searching
|
|
@@ -19,10 +19,6 @@ def strip_html(item: Item) -> Item:
|
|
|
19
19
|
raise InvalidInput("Item must have a body")
|
|
20
20
|
|
|
21
21
|
clean_body = html_to_plaintext(item.body)
|
|
22
|
-
output_item = item.derived_copy(
|
|
23
|
-
type=ItemType.doc,
|
|
24
|
-
format=Format.markdown,
|
|
25
|
-
body=clean_body,
|
|
26
|
-
)
|
|
22
|
+
output_item = item.derived_copy(format=Format.markdown, body=clean_body)
|
|
27
23
|
|
|
28
24
|
return output_item
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from kash.config.logger import get_logger
|
|
2
2
|
from kash.exec import kash_action
|
|
3
|
+
from kash.exec_model.args_model import ONE_OR_MORE_ARGS
|
|
3
4
|
from kash.model import ActionInput, ActionResult, Param
|
|
4
5
|
from kash.utils.errors import InvalidInput
|
|
5
6
|
from kash.web_gen import tabbed_webpage
|
|
@@ -8,15 +9,16 @@ log = get_logger(__name__)
|
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@kash_action(
|
|
12
|
+
expected_args=ONE_OR_MORE_ARGS,
|
|
11
13
|
params=(
|
|
12
14
|
Param(
|
|
13
15
|
name="clean_headings",
|
|
14
16
|
type=bool,
|
|
15
17
|
description="Use an LLM to clean up headings.",
|
|
16
18
|
),
|
|
17
|
-
)
|
|
19
|
+
),
|
|
18
20
|
)
|
|
19
|
-
def
|
|
21
|
+
def tabbed_webpage_config(input: ActionInput, clean_headings: bool = False) -> ActionResult:
|
|
20
22
|
"""
|
|
21
23
|
Set up a web page config with optional tabs for each page of content. Uses first item as the page title.
|
|
22
24
|
"""
|
|
@@ -24,6 +26,6 @@ def webpage_config(input: ActionInput, clean_headings: bool = False) -> ActionRe
|
|
|
24
26
|
if not item.body:
|
|
25
27
|
raise InvalidInput(f"Item must have a body: {item}")
|
|
26
28
|
|
|
27
|
-
config_item = tabbed_webpage.
|
|
29
|
+
config_item = tabbed_webpage.tabbed_webpage_config(input.items, clean_headings)
|
|
28
30
|
|
|
29
31
|
return ActionResult([config_item])
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from kash.config.logger import get_logger
|
|
2
2
|
from kash.exec import kash_action
|
|
3
3
|
from kash.exec.preconditions import is_config
|
|
4
|
-
from kash.model import ONE_ARG, ActionInput, ActionResult, FileExt, Format, Item, ItemType
|
|
4
|
+
from kash.model import ONE_ARG, ActionInput, ActionResult, FileExt, Format, Item, ItemType, Param
|
|
5
5
|
from kash.web_gen import tabbed_webpage
|
|
6
6
|
|
|
7
7
|
log = get_logger(__name__)
|
|
@@ -10,13 +10,14 @@ log = get_logger(__name__)
|
|
|
10
10
|
@kash_action(
|
|
11
11
|
expected_args=ONE_ARG,
|
|
12
12
|
precondition=is_config,
|
|
13
|
+
params=(Param("add_title", "Add a title to the page body.", type=bool),),
|
|
13
14
|
)
|
|
14
|
-
def
|
|
15
|
+
def tabbed_webpage_generate(input: ActionInput, add_title: bool = False) -> ActionResult:
|
|
15
16
|
"""
|
|
16
|
-
Generate a web page from a
|
|
17
|
+
Generate a tabbed web page from a config item for the tabbed template.
|
|
17
18
|
"""
|
|
18
19
|
config_item = input.items[0]
|
|
19
|
-
html = tabbed_webpage.
|
|
20
|
+
html = tabbed_webpage.tabbed_webpage_generate(config_item, add_title_h1=add_title)
|
|
20
21
|
|
|
21
22
|
webpage_item = Item(
|
|
22
23
|
title=config_item.title,
|
|
@@ -2,7 +2,7 @@ import os
|
|
|
2
2
|
|
|
3
3
|
from frontmatter_format import fmf_read_raw, fmf_strip_frontmatter
|
|
4
4
|
from prettyfmt import fmt_lines
|
|
5
|
-
from strif import copyfile_atomic
|
|
5
|
+
from strif import atomic_output_file, copyfile_atomic
|
|
6
6
|
|
|
7
7
|
from kash.config.logger import get_logger
|
|
8
8
|
from kash.config.text_styles import STYLE_EMPH
|
|
@@ -28,10 +28,10 @@ log = get_logger(__name__)
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
@kash_command
|
|
31
|
-
def
|
|
31
|
+
def clipboard_copy(path: str | None = None, raw: bool = False) -> None:
|
|
32
32
|
"""
|
|
33
33
|
Copy the contents of a file (or the first file in the selection) to the OS-native
|
|
34
|
-
clipboard.
|
|
34
|
+
clipboard. Similar to `pbcopy` on macOS.
|
|
35
35
|
|
|
36
36
|
:param raw: Copy the full exact contents of the file. Otherwise frontmatter is omitted.
|
|
37
37
|
"""
|
|
@@ -39,6 +39,8 @@ def cbcopy(path: str | None = None, raw: bool = False) -> None:
|
|
|
39
39
|
import pyperclip
|
|
40
40
|
|
|
41
41
|
input_paths = assemble_path_args(path)
|
|
42
|
+
if not input_paths:
|
|
43
|
+
raise InvalidInput("No path provided")
|
|
42
44
|
input_path = input_paths[0]
|
|
43
45
|
|
|
44
46
|
format = detect_file_format(input_path)
|
|
@@ -69,6 +71,22 @@ def cbcopy(path: str | None = None, raw: bool = False) -> None:
|
|
|
69
71
|
)
|
|
70
72
|
|
|
71
73
|
|
|
74
|
+
@kash_command
|
|
75
|
+
def clipboard_paste(path: str = "untitled_paste.txt") -> None:
|
|
76
|
+
"""
|
|
77
|
+
Paste the contents of the OS-native clipboard into a new file.
|
|
78
|
+
"""
|
|
79
|
+
# TODO: Get this to work for images!
|
|
80
|
+
# And can we convert rich text to Markdown?
|
|
81
|
+
import pyperclip
|
|
82
|
+
|
|
83
|
+
contents = pyperclip.paste()
|
|
84
|
+
with atomic_output_file(path, backup_suffix=".{timestamp}.bak") as f:
|
|
85
|
+
f.write_text(contents)
|
|
86
|
+
|
|
87
|
+
print_status("Pasted clipboard contents to:\n%s", fmt_lines([fmt_loc(path)]))
|
|
88
|
+
|
|
89
|
+
|
|
72
90
|
@kash_command
|
|
73
91
|
def edit(path: str | None = None, all: bool = False) -> None:
|
|
74
92
|
"""
|
|
@@ -75,6 +75,10 @@ def _print_listing_tallies(
|
|
|
75
75
|
cprint("(use --no_max to remove cutoff)", style=STYLE_HINT)
|
|
76
76
|
|
|
77
77
|
|
|
78
|
+
DEFAULT_MAX_PER_GROUP = 50
|
|
79
|
+
"""Default maximum number of files to display per group."""
|
|
80
|
+
|
|
81
|
+
|
|
78
82
|
@kash_command
|
|
79
83
|
def files(
|
|
80
84
|
*paths: str,
|
|
@@ -108,9 +112,11 @@ def files(
|
|
|
108
112
|
and grouping.
|
|
109
113
|
|
|
110
114
|
:param overview: Recurse a couple levels and show files, but not too many.
|
|
111
|
-
Same as `--groupby=parent --depth=2 --max_per_group=
|
|
115
|
+
Same as `--groupby=parent --depth=2 --max_per_group=100 --omit_dirs`
|
|
116
|
+
except also scales down `max_per_group` to 25 or 50 if there are many files.
|
|
112
117
|
:param recent: Only shows the most recently modified files in each directory.
|
|
113
|
-
Same as `--sort=modified --reverse --groupby=parent --max_per_group=
|
|
118
|
+
Same as `--sort=modified --reverse --groupby=parent --max_per_group=100`
|
|
119
|
+
except also scales down `max_per_group` to 25 or 50 if there are many files.
|
|
114
120
|
:param recursive: List all files recursively. Same as `--depth=-1`.
|
|
115
121
|
:param flat: Show files in a flat list, rather than grouped by parent directory.
|
|
116
122
|
Same as `--groupby=flat`.
|
|
@@ -179,16 +185,17 @@ def files(
|
|
|
179
185
|
# Within workspaces, we show more files by default since they are always in
|
|
180
186
|
# subdirectories.
|
|
181
187
|
overview = True # Handled next.
|
|
188
|
+
cap_per_group = False
|
|
182
189
|
if overview:
|
|
183
|
-
max_per_group = 10 if max_per_group <= 0 else max_per_group
|
|
184
190
|
groupby = GroupByOption.parent if groupby is None else groupby
|
|
185
191
|
depth = 2 if depth is None else depth
|
|
192
|
+
cap_per_group = True
|
|
186
193
|
omit_dirs = True
|
|
187
194
|
if recent:
|
|
188
|
-
max_per_group = 10 if max_per_group <= 0 else max_per_group
|
|
189
195
|
groupby = GroupByOption.parent if groupby is None else groupby
|
|
190
196
|
depth = 2 if depth is None else depth
|
|
191
197
|
sort = SortOption.modified if sort is None else sort
|
|
198
|
+
cap_per_group = True
|
|
192
199
|
reverse = True
|
|
193
200
|
if flat:
|
|
194
201
|
groupby = GroupByOption.flat
|
|
@@ -291,6 +298,18 @@ def files(
|
|
|
291
298
|
|
|
292
299
|
return ShellResult(show_selection=True)
|
|
293
300
|
|
|
301
|
+
# Unless max_per_group is explicit, use heuristics to limit per group if
|
|
302
|
+
# there are lots of groups and lots of files per group.
|
|
303
|
+
# Default is max 100 per group but if we have 4 * 100 items, cut to 25.
|
|
304
|
+
# If we have 2 * 100 items, cut to 50.
|
|
305
|
+
final_max_pg = DEFAULT_MAX_PER_GROUP if cap_per_group else max_per_group
|
|
306
|
+
max_pg_explicit = max_per_group > 0
|
|
307
|
+
if not max_pg_explicit:
|
|
308
|
+
group_lens = [len(group_df) for group_df in grouped]
|
|
309
|
+
for ratio in [2, 4]:
|
|
310
|
+
if sum(group_lens) > ratio * DEFAULT_MAX_PER_GROUP:
|
|
311
|
+
final_max_pg = int(DEFAULT_MAX_PER_GROUP / ratio)
|
|
312
|
+
|
|
294
313
|
total_displayed = 0
|
|
295
314
|
total_displayed_size = 0
|
|
296
315
|
now = datetime.now(UTC)
|
|
@@ -312,8 +331,8 @@ def files(
|
|
|
312
331
|
text_wrap=Wrap.NONE,
|
|
313
332
|
)
|
|
314
333
|
|
|
315
|
-
if
|
|
316
|
-
display_df = group_df.head(
|
|
334
|
+
if final_max_pg > 0:
|
|
335
|
+
display_df = group_df.head(final_max_pg)
|
|
317
336
|
else:
|
|
318
337
|
display_df = group_df
|
|
319
338
|
|
|
@@ -378,9 +397,9 @@ def files(
|
|
|
378
397
|
total_displayed_size += row.size
|
|
379
398
|
|
|
380
399
|
# Indicate if items are omitted.
|
|
381
|
-
if groupby and
|
|
400
|
+
if groupby and final_max_pg > 0 and len(group_df) > final_max_pg:
|
|
382
401
|
cprint(
|
|
383
|
-
f"{indent}… and {len(group_df) -
|
|
402
|
+
f"{indent}… and {len(group_df) - final_max_pg} more files",
|
|
384
403
|
style=COLOR_EXTRA,
|
|
385
404
|
text_wrap=Wrap.NONE,
|
|
386
405
|
)
|
|
@@ -388,9 +407,9 @@ def files(
|
|
|
388
407
|
if group_name:
|
|
389
408
|
PrintHooks.spacer()
|
|
390
409
|
|
|
391
|
-
if not groupby and
|
|
410
|
+
if not groupby and final_max_pg > 0 and items_matching > final_max_pg:
|
|
392
411
|
cprint(
|
|
393
|
-
f"{indent}… and {items_matching -
|
|
412
|
+
f"{indent}… and {items_matching - final_max_pg} more files",
|
|
394
413
|
style=COLOR_EXTRA,
|
|
395
414
|
text_wrap=Wrap.NONE,
|
|
396
415
|
)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import subprocess
|
|
2
4
|
import tomllib
|
|
3
5
|
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
4
7
|
|
|
5
|
-
import pandas as pd
|
|
6
8
|
from packaging.tags import Tag, sys_tags
|
|
7
9
|
from packaging.utils import parse_wheel_filename
|
|
8
10
|
from prettyfmt import fmt_size_dual
|
|
@@ -13,6 +15,9 @@ from kash.config.text_styles import COLOR_STATUS
|
|
|
13
15
|
from kash.exec import kash_command
|
|
14
16
|
from kash.shell.output.shell_output import cprint
|
|
15
17
|
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from pandas import DataFrame
|
|
20
|
+
|
|
16
21
|
log = get_logger(__name__)
|
|
17
22
|
|
|
18
23
|
|
|
@@ -49,13 +54,15 @@ def get_platform() -> str:
|
|
|
49
54
|
return next(sys_tags()).platform
|
|
50
55
|
|
|
51
56
|
|
|
52
|
-
def parse_uv_lock(lock_path: Path) ->
|
|
57
|
+
def parse_uv_lock(lock_path: Path) -> DataFrame:
|
|
53
58
|
"""
|
|
54
59
|
Return one row per package from a uv.lock file, selecting the best
|
|
55
60
|
matching wheel for the current interpreter or falling back to the sdist.
|
|
56
61
|
|
|
57
62
|
Columns: name, version, registry, file_type, url, hash, size, filename.
|
|
58
63
|
"""
|
|
64
|
+
from pandas import DataFrame
|
|
65
|
+
|
|
59
66
|
with open(lock_path, "rb") as f:
|
|
60
67
|
data = tomllib.load(f)
|
|
61
68
|
|
|
@@ -88,7 +95,7 @@ def parse_uv_lock(lock_path: Path) -> pd.DataFrame:
|
|
|
88
95
|
}
|
|
89
96
|
)
|
|
90
97
|
|
|
91
|
-
return
|
|
98
|
+
return DataFrame(rows)
|
|
92
99
|
|
|
93
100
|
|
|
94
101
|
def uv_runtime_packages(
|
|
@@ -141,6 +148,8 @@ def uv_dep_info(
|
|
|
141
148
|
By default, filters to show only 'main' dependencies from pyproject.toml.
|
|
142
149
|
Helpful for looking at sizes of dependencies.
|
|
143
150
|
"""
|
|
151
|
+
import pandas as pd
|
|
152
|
+
|
|
144
153
|
uv_lock_path = Path(uv_lock)
|
|
145
154
|
pyproject_path = Path(pyproject)
|
|
146
155
|
|
|
@@ -10,8 +10,8 @@ from kash.exec_model.shell_model import ShellResult
|
|
|
10
10
|
from kash.model.paths_model import StorePath
|
|
11
11
|
from kash.shell.ui.shell_results import shell_print_selection_history
|
|
12
12
|
from kash.utils.common.format_utils import fmt_loc
|
|
13
|
+
from kash.utils.common.inflection import plural
|
|
13
14
|
from kash.utils.errors import InvalidInput
|
|
14
|
-
from kash.utils.lang_utils.inflection import plural
|
|
15
15
|
from kash.workspaces import Selection, current_ws
|
|
16
16
|
|
|
17
17
|
log = get_logger(__name__)
|
|
@@ -51,6 +51,7 @@ from kash.shell.output.shell_output import (
|
|
|
51
51
|
)
|
|
52
52
|
from kash.shell.utils.native_utils import tail_file
|
|
53
53
|
from kash.utils.common.format_utils import fmt_loc
|
|
54
|
+
from kash.utils.common.inflection import plural
|
|
54
55
|
from kash.utils.common.obj_replace import remove_values
|
|
55
56
|
from kash.utils.common.parse_key_vals import parse_key_value
|
|
56
57
|
from kash.utils.common.type_utils import not_none
|
|
@@ -58,7 +59,6 @@ from kash.utils.common.url import Url, is_url
|
|
|
58
59
|
from kash.utils.errors import InvalidInput
|
|
59
60
|
from kash.utils.file_formats.chat_format import tail_chat_history
|
|
60
61
|
from kash.utils.file_utils.dir_info import is_nonempty_dir
|
|
61
|
-
from kash.utils.lang_utils.inflection import plural
|
|
62
62
|
from kash.web_content.file_cache_utils import cache_file
|
|
63
63
|
from kash.workspaces import (
|
|
64
64
|
current_ws,
|
|
@@ -285,7 +285,7 @@ def init_workspace(path: str | None = None) -> None:
|
|
|
285
285
|
@kash_command
|
|
286
286
|
def workspace(workspace_name: str | None = None) -> None:
|
|
287
287
|
"""
|
|
288
|
-
If no args are given,
|
|
288
|
+
If no args are given, show current workspace info.
|
|
289
289
|
If a workspace name is given, change to that workspace, creating it if it doesn't exist.
|
|
290
290
|
"""
|
|
291
291
|
if workspace_name:
|
|
@@ -302,7 +302,6 @@ def workspace(workspace_name: str | None = None) -> None:
|
|
|
302
302
|
ws.log_workspace_info()
|
|
303
303
|
else:
|
|
304
304
|
ws = current_ws(silent=True)
|
|
305
|
-
os.chdir(ws.base_dir)
|
|
306
305
|
ws.log_workspace_info()
|
|
307
306
|
|
|
308
307
|
|
|
@@ -136,8 +136,8 @@ web_light_translucent = SimpleNamespace(
|
|
|
136
136
|
bg=hsl_to_hex("hsla(44, 6%, 100%, 0.75)"),
|
|
137
137
|
bg_solid=hsl_to_hex("hsla(44, 6%, 100%, 1)"),
|
|
138
138
|
bg_header=hsl_to_hex("hsla(188, 42%, 70%, 0.2)"),
|
|
139
|
-
bg_alt=hsl_to_hex("hsla(
|
|
140
|
-
bg_alt_solid=hsl_to_hex("hsla(
|
|
139
|
+
bg_alt=hsl_to_hex("hsla(39, 24%, 90%, 0.3)"),
|
|
140
|
+
bg_alt_solid=hsl_to_hex("hsla(39, 24%, 97%, 1)"),
|
|
141
141
|
text=hsl_to_hex("hsl(188, 39%, 11%)"),
|
|
142
142
|
border=hsl_to_hex("hsl(188, 8%, 50%)"),
|
|
143
143
|
border_hint=hsl_to_hex("hsla(188, 8%, 72%, 0.7)"),
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from clideps.env_vars.env_enum import EnvEnum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class KashEnv(EnvEnum):
|
|
5
|
+
"""
|
|
6
|
+
Environment variable settings for kash. None are required, but these may be
|
|
7
|
+
used to override default values.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
KASH_LOG_LEVEL = "KASH_LOG_LEVEL"
|
|
11
|
+
"""The log level for console-based logging."""
|
|
12
|
+
|
|
13
|
+
KASH_WS_ROOT = "KASH_WS_ROOT"
|
|
14
|
+
"""The root directory for kash workspaces."""
|
|
15
|
+
|
|
16
|
+
KASH_GLOBAL_WS = "KASH_GLOBAL_WS"
|
|
17
|
+
"""The global workspace directory."""
|
|
18
|
+
|
|
19
|
+
KASH_SYSTEM_LOGS_DIR = "KASH_SYSTEM_LOGS_DIR"
|
|
20
|
+
"""The directory for system logs."""
|
|
21
|
+
|
|
22
|
+
KASH_SYSTEM_CACHE_DIR = "KASH_SYSTEM_CACHE_DIR"
|
|
23
|
+
"""The directory for system cache (caches separate from workspace caches)."""
|
|
24
|
+
|
|
25
|
+
KASH_MCP_WS = "KASH_MCP_WS"
|
|
26
|
+
"""The directory for the workspace for MCP servers."""
|
|
27
|
+
|
|
28
|
+
KASH_SHOW_TRACEBACK = "KASH_SHOW_TRACEBACK"
|
|
29
|
+
"""Whether to show tracebacks on actions and commands in the shell."""
|
|
30
|
+
|
|
31
|
+
KASH_USER_AGENT = "KASH_USER_AGENT"
|
|
32
|
+
"""The user agent to use for HTTP requests."""
|