gabriel / muse public
feat BREAKING task/shell-lang-support #1 / 1
gabriel · 169 days ago · Apr 12, 2026 · Diff

feat: add bash/zsh tree-sitter grammar support and per-repo language config

- Add `name` field to LangSpec TypedDict (user-facing language identifier) and update all 13 existing specs - Add _BASH_SPEC covering .sh, .bash, .zsh, .plugin.zsh extensions via tree-sitter-bash (zsh is a strict backward-compatible superset of bash at the AST level); extracts function_definition and variable_assignment - Add `shell` optional extra to pyproject.toml (tree-sitter-bash>=0.23.3); include in `muse[all]` - Add CodeConfig dataclass + load_code_config() to read [code] languages list from .muse/code_config.toml; returns defaults on any error - Add _LANGUAGE_FILTER global + configure_language_filter() so callers (muse code commands) can restrict active grammars per-repo at startup - Add reset_adapter_cache() for test isolation (clears _ADAPTERS_CACHE, _SEM_EXT_CACHE, and promoted module attrs) - Add _BUILTIN_ADAPTER_NAMES frozenset to enable filtering built-in adapters (python, markdown, html, toml) by name alongside tree-sitter - Update _adapters() to respect _LANGUAGE_FILTER for both built-in and tree-sitter adapters - Update _framework.py module docstring to document [code] section - Add tests/test_code_language_config.py: 57 tests covering LangSpec.name, _BASH_SPEC, CodeConfig, load_code_config, configure_language_filter, reset_adapter_cache, and adapter_for_path shell routing - Add TestBashAdapter (18 tests) to tests/test_code_plugin.py covering function/variable extraction, content IDs, extension routing, and graceful skip when tree-sitter-bash is not installed - Regenerate docs/reference/type-contracts.md (LangSpec gains name field)

sha256:49941276913b80f63c92b9da2c610aacb9d828182caf8c317a6ed73eb25d861d sha
+115 ~31 −3 symbols
sha256:cc128bf0aeb7aa57327d6dc6aa01b298b457877c5d93761ec13c07d07fa10f15 snapshot
+115
symbols added
~31
symbols modified
−3
symbols removed
0
dead code introduced
Semantic Changes 149 symbols
~ tests/test_code_language_config.py .py 77 symbols added
+ TestBashSpec class class TestBashSpec L129–164
+ test_extensions_include_bash method method test_extensions_include_bash L133–134
+ test_extensions_include_plugin_zsh method method test_extensions_include_plugin_zsh L139–140
+ test_extensions_include_sh method method test_extensions_include_sh L130–131
+ test_extensions_include_zsh method method test_extensions_include_zsh L136–137
+ test_in_ts_lang_specs method method test_in_ts_lang_specs L154–155
+ test_module_name method method test_module_name L142–143
+ test_name_is_bash method method test_name_is_bash L151–152
+ test_no_async_child method method test_no_async_child L163–164
+ test_no_class_node_types class method test_no_class_node_types L157–158
+ test_no_receiver_capture method method test_no_receiver_capture L160–161
+ test_query_captures_function_definition method method test_query_captures_function_definition L145–146
+ test_query_captures_variable_assignment method method test_query_captures_variable_assignment L148–149
+ TestCodeConfig class class TestCodeConfig L172–186
+ test_active_languages_is_frozenset_when_set method method test_active_languages_is_frozenset_when_set L178–181
+ test_default_active_languages_is_none method method test_default_active_languages_is_none L173–176
+ test_empty_frozenset_is_valid method method test_empty_frozenset_is_valid L183–186
+ TestLangSpecName class class TestLangSpecName L95–121
+ test_all_specs_have_name method method test_all_specs_have_name L96–99
+ test_known_names_present method method test_known_names_present L115–121
+ test_names_are_lowercase_alphanumeric method method test_names_are_lowercase_alphanumeric L106–113
+ test_names_are_unique method method test_names_are_unique L101–104
+ TestLanguageFilter class class TestLanguageFilter L274–356
+ setup_method method method setup_method L277–279
+ teardown_method method method teardown_method L281–283
+ test_builtin_adapter_names_constant method method test_builtin_adapter_names_constant L352–356
+ test_default_filter_is_none method method test_default_filter_is_none L285–287
+ test_empty_filter_excludes_everything method method test_empty_filter_excludes_everything L345–350
+ test_filter_excludes_markdown_when_not_listed method method test_filter_excludes_markdown_when_not_listed L340–343
+ test_filter_html_by_name method method test_filter_html_by_name L330–333
+ test_filter_markdown_by_name method method test_filter_markdown_by_name L325–328
+ test_filter_none_includes_python method method test_filter_none_includes_python L320–323
+ test_filter_python_only_excludes_js method method test_filter_python_only_excludes_js L315–318
+ test_filter_python_only_includes_python_adapter method method test_filter_python_only_includes_python_adapter L309–313
+ test_filter_toml_by_name method method test_filter_toml_by_name L335–338
+ test_reset_cache_clears_adapters method method test_reset_cache_clears_adapters L300–307
+ test_reset_to_none method method test_reset_to_none L294–298
+ test_set_filter_stored method method test_set_filter_stored L289–292
+ TestLoadCodeConfig class class TestLoadCodeConfig L194–266
+ test_absent_code_section_returns_defaults method method test_absent_code_section_returns_defaults L214–217
+ test_both_sections_present method method test_both_sections_present L244–254
+ test_code_section_not_a_table method method test_code_section_not_a_table L262–266
+ test_code_section_without_languages_key method method test_code_section_without_languages_key L256–260
+ test_empty_languages_list method method test_empty_languages_list L238–242
+ test_languages_not_a_list_returns_defaults method method test_languages_not_a_list_returns_defaults L226–229
+ test_languages_with_non_string_entry_returns_defaults method method test_languages_with_non_string_entry_returns_defaults L231–236
+ test_malformed_toml_returns_defaults method method test_malformed_toml_returns_defaults L219–224
+ test_missing_file_returns_defaults method method test_missing_file_returns_defaults L195–197
+ test_names_are_lowercased method method test_names_are_lowercased L204–207
+ test_names_are_stripped method method test_names_are_stripped L209–212
+ test_valid_languages_list method method test_valid_languages_list L199–202
+ TestShellAdapterRouting class class TestShellAdapterRouting L364–417
+ setup_method method method setup_method L367–369
+ teardown_method method method teardown_method L371–373
+ test_filter_bash_routes_sh_to_bash_adapter_if_installed method method test_filter_bash_routes_sh_to_bash_adapter_if_installed L407–411
+ test_filter_without_bash_routes_sh_to_fallback method method test_filter_without_bash_routes_sh_to_fallback L413–417
+ test_shell_extension_routes_to_bash_or_fallback method method test_shell_extension_routes_to_bash_or_fallback L395–401
+ test_shell_path_does_not_route_to_python method method test_shell_path_does_not_route_to_python L382–387
+ test_unknown_extension_is_always_fallback method method test_unknown_extension_is_always_fallback L403–405
+ _write_toml function function _write_toml L82–87
+ CodeConfig import import CodeConfig L59–59
+ FallbackAdapter import import FallbackAdapter L59–59
+ HtmlAdapter import import HtmlAdapter L59–59
+ MarkdownAdapter import import MarkdownAdapter L59–59
+ PythonAdapter import import PythonAdapter L59–59
+ TomlAdapter import import TomlAdapter L59–59
+ TreeSitterAdapter import import TreeSitterAdapter L59–59
+ _BASH_SPEC import import _BASH_SPEC L59–59
+ _BUILTIN_ADAPTER_NAMES import import _BUILTIN_ADAPTER_NAMES L59–59
+ _TS_LANG_SPECS import import _TS_LANG_SPECS L59–59
+ adapter_for_path import import adapter_for_path L59–59
+ annotations import import annotations L53–53
+ configure_language_filter import import configure_language_filter L59–59
+ load_code_config import import load_code_config L59–59
+ pathlib import import pathlib L55–55
+ pytest import import pytest L57–57
+ reset_adapter_cache import import reset_adapter_cache L59–59
~ docs/reference/type-contracts.md .md 8 symbols added, 3 symbols removed, 12 symbols modified
− py` section ObjectPayload — `muse/core/pack.py` L3812–3823
− py` section _WhoamiJson — `muse/cli/commands/whoami.py` L2933–2946
− py` section _WhoamiOut — `tests/test_cmd_whoami_hardening.py` L6327–6340
+ py` section FrameworkPlugin — `muse/plugins/code/_framework.py` L6765–6773
+ py` section ConfirmObjectsResponse — `muse/core/transport.py` L4741–4752
+ py` section FilterObjectsResult — `muse/core/transport.py` L4753–4764
+ py` section HubTrustRecord — `muse/core/hub_trust.py` L3657–3670
+ py` section _EntryPointJson — `muse/cli/commands/impact.py` L1517–1529
+ py` section _LabelEntry — `muse/cli/commands/hub.py` L1421–1435
+ py` section _ObjectPayloadBase — `muse/core/pack.py` L3916–3927
+ py` section _PushPayload — `muse/core/transport.py` L4790–4803
~ py`
~ py`
~ py`
~ py`
~ py`
~ py`
~ py`
~ py`
~ muse/plugins/code/ast_parser.py .py 8 symbols added, 16 symbols modified
+ CodeConfig class class CodeConfig L2260–2283
+ _BASH_SPEC variable variable _BASH_SPEC L2212–2231
+ _BUILTIN_ADAPTER_NAMES variable variable _BUILTIN_ADAPTER_NAMES L2404–2404
+ _LANGUAGE_FILTER variable variable _LANGUAGE_FILTER L2348–2348
+ configure_language_filter function function configure_language_filter L2357–2377
+ _dataclass class import _dataclass L2256–2256
+ load_code_config function function load_code_config L2286–2329
+ reset_adapter_cache function function reset_adapter_cache L2380–2397
~ pyproject.toml .toml 1 symbol added, 3 symbols modified
+ shell variable variable shell L0–0
~ all
~ tests/test_code_plugin.py .py 21 symbols added
+ TestBashAdapter class class TestBashAdapter L1992–2134
+ _parse method method _parse L2001–2007
+ test_address_prefix_matches_file_path method method test_address_prefix_matches_file_path L2100–2105
+ test_body_hash_differs_for_different_bodies method method test_body_hash_differs_for_different_bodies L2058–2064
+ test_comment_only_file_returns_empty_tree method method test_comment_only_file_returns_empty_tree L2116–2118
+ test_content_id_stable_across_calls method method test_content_id_stable_across_calls L2051–2056
+ test_empty_file_returns_empty_tree method method test_empty_file_returns_empty_tree L2112–2114
+ test_file_content_id_differs_for_different_content method method test_file_content_id_differs_for_different_content L2129–2134
+ test_file_content_id_stable method method test_file_content_id_stable L2120–2127
+ test_function_and_variable_coexist method method test_function_and_variable_coexist L2038–2043
+ test_function_definition_extracted method method test_function_definition_extracted L2009–2012
+ test_function_kind_is_function method method test_function_kind_is_function L2014–2018
+ test_lineno_is_positive method method test_lineno_is_positive L2107–2110
+ test_multiple_functions_extracted method method test_multiple_functions_extracted L2031–2036
+ test_parse_zsh_function method method test_parse_zsh_function L2095–2098
+ test_plugin_zsh_extension_routed method method test_plugin_zsh_extension_routed L2087–2093
+ test_sh_extension_routes_to_same_adapter method method test_sh_extension_routes_to_same_adapter L2066–2077
+ test_symbol_record_has_content_id method method test_symbol_record_has_content_id L2045–2049
+ test_variable_assignment_extracted method method test_variable_assignment_extracted L2020–2023
+ test_variable_kind_is_variable method method test_variable_kind_is_variable L2025–2029
+ test_zsh_extension_routed method method test_zsh_extension_routed L2079–2085
← Older Oldest on task/shell-lang-support
All commits
Newer → Latest on task/shell-lang-support

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:49941276913b80f63c92b9da2c610aacb9d828182caf8c317a6ed73eb25d861d --body "your comment"