gabriel / muse public
feat patch code task/directory-dimension #1 / 2
AI Agent gabriel · 127 days ago · May 8, 2026 · Diff

feat(code): directory-level insight dimension (issue #3)

- _query.py: add dir_of, flat_directory_ops, touched_directories helpers - diff: add 'directories' key to JSON output (added, deleted, renamed) - hotspots: add --granularity directory to count churn at dir level - entangle: add --granularity directory to find dir co-change pairs - impact: add --roll-up-to directory to aggregate blast radius by dir - handle empty-repo gracefully in hotspots and entangle (exit 0) - 37 TDD tests in test_directory_dimension.py, all passing

sha256:94c8baf97e035b357acca02c444ed2b73a380aa92afe74255a2ef4f9c12d8703 sha
+79 ~17 symbols
sha256:efb30506b57e61b2171d7d4122b9779ac293a2b8ef2c5c9a6621db7e84bd5c99 snapshot
+79
symbols added
~17
symbols modified
0
dead code introduced
Semantic Changes 96 symbols
~ tests/test_directory_dimension.py .py 65 symbols added
+ TestDiffDirectories class class TestDiffDirectories L257–289
+ test_clean_repo_has_empty_directories method method test_clean_repo_has_empty_directories L280–289
+ test_directories_key_has_expected_subkeys method method test_directories_key_has_expected_subkeys L269–278
+ test_json_has_directories_key method method test_json_has_directories_key L260–267
+ TestDirOf class class TestDirOf L205–226
+ test_deeply_nested method method test_deeply_nested L212–214
+ test_directory_address_trailing_slash method method test_directory_address_trailing_slash L220–222
+ test_nested_path method method test_nested_path L208–210
+ test_no_extension_file method method test_no_extension_file L224–226
+ test_root_level_file method method test_root_level_file L216–218
+ TestEntangleDirectoryGranularity class class TestEntangleDirectoryGranularity L397–462
+ test_directory_granularity_json_has_granularity_field method method test_directory_granularity_json_has_granularity_field L443–462
+ test_directory_granularity_json_pairs_have_no_colons method method test_directory_granularity_json_pairs_have_no_colons L419–441
+ test_granularity_default_is_symbol method method test_granularity_default_is_symbol L410–417
+ test_granularity_flag_accepted method method test_granularity_flag_accepted L401–408
+ TestFlatDirectoryOps class class TestFlatDirectoryOps L68–127
+ test_empty_ops method method test_empty_ops L117–119
+ test_mixed_ops_only_dir method method test_mixed_ops_only_dir L104–115
+ test_rename_carries_from_address method method test_rename_carries_from_address L121–127
+ test_skips_plain_file_insert method method test_skips_plain_file_insert L98–102
+ test_skips_symbol_level_patch_children method method test_skips_symbol_level_patch_children L90–96
+ test_yields_directory_delete method method test_yields_directory_delete L84–88
+ test_yields_directory_insert method method test_yields_directory_insert L78–82
+ test_yields_directory_rename method method test_yields_directory_rename L71–76
+ TestHotspotsDirectoryGranularity class class TestHotspotsDirectoryGranularity L297–389
+ test_directory_granularity_json_addresses_have_no_colons method method test_directory_granularity_json_addresses_have_no_colons L318–346
+ test_directory_granularity_json_has_granularity_field method method test_directory_granularity_json_has_granularity_field L348–367
+ test_granularity_default_is_symbol method method test_granularity_default_is_symbol L309–316
+ test_granularity_flag_accepted method method test_granularity_flag_accepted L300–307
+ test_symbol_granularity_json_addresses_contain_colons method method test_symbol_granularity_json_addresses_contain_colons L369–389
+ TestImpactDirectoryRollup class class TestImpactDirectoryRollup L470–536
+ test_directory_rollup_addresses_have_no_colons method method test_directory_rollup_addresses_have_no_colons L514–536
+ test_directory_rollup_json_has_directory_blast_radius method method test_directory_rollup_json_has_directory_blast_radius L491–512
+ test_roll_up_to_default_is_none method method test_roll_up_to_default_is_none L482–489
+ test_roll_up_to_flag_accepted method method test_roll_up_to_flag_accepted L473–480
+ TestTouchedDirectories class class TestTouchedDirectories L135–197
+ test_directory_rename_op_adds_both_dirs method method test_directory_rename_op_adds_both_dirs L180–185
+ test_empty_ops_returns_empty method method test_empty_ops_returns_empty L187–189
+ test_file_without_symbol_children_not_counted method method test_file_without_symbol_children_not_counted L191–197
+ test_multiple_files_same_dir_counted_once method method test_multiple_files_same_dir_counted_once L155–162
+ test_nested_path_returns_immediate_parent method method test_nested_path_returns_immediate_parent L172–178
+ test_returns_frozenset method method test_returns_frozenset L164–170
+ test_root_level_file_returns_dot_or_empty method method test_root_level_file_returns_dot_or_empty L146–153
+ test_single_file_returns_its_parent method method test_single_file_returns_its_parent L138–144
+ _delete function function _delete L41–42
+ _insert function function _insert L37–38
+ _make_diff_repo function function _make_diff_repo L240–254
+ _patch function function _patch L49–56
+ _rename function function _rename L45–46
+ _sym_insert function function _sym_insert L59–60
+ cli variable variable cli L236–236
+ CliRunner import import CliRunner L234–234
+ DeleteOp import import DeleteOp L30–30
+ DirectoryRenameOp import import DirectoryRenameOp L30–30
+ DomainOp import import DomainOp L30–30
+ InsertOp import import InsertOp L30–30
+ PatchOp import import PatchOp L30–30
+ ReplaceOp import import ReplaceOp L30–30
+ annotations import import annotations L21–21
+ cast import import cast L26–26
+ json import import json L23–23
+ pathlib import import pathlib L24–24
+ pytest import import pytest L28–28
+ textwrap import import textwrap L25–25
+ runner variable variable runner L237–237
~ muse/cli/commands/diff.py .py 2 symbols added, 2 symbols modified
+ _DiffDirectoriesJson class class _DiffDirectoriesJson L119–131
+ flat_directory_ops import import flat_directory_ops L75–75
~ run
~ muse/cli/commands/entangle.py .py 5 symbols added, 5 symbols modified
+ _DirectoryPair class class _DirectoryPair L184–190
+ _build_directory_pairs function function _build_directory_pairs L235–265
+ _collect_directory_pairs function function _collect_directory_pairs L193–232
+ dir_of import import dir_of L114–114
+ touched_directories import import touched_directories L114–114
~ run
~ muse/cli/commands/hotspots.py .py 3 symbols added, 6 symbols modified
+ _collect_directory_churn function function _collect_directory_churn L193–215
+ dir_of import import dir_of L51–51
+ touched_directories import import touched_directories L51–51
~ run
~ muse/cli/commands/impact.py .py 1 symbol added, 4 symbols modified
+ dir_of import import dir_of L115–115
~ run
~ muse/plugins/code/_query.py .py 3 symbols added
+ dir_of function function dir_of L321–332
+ flat_directory_ops function function flat_directory_ops L335–353
+ touched_directories function function touched_directories L356–376

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:94c8baf97e035b357acca02c444ed2b73a380aa92afe74255a2ef4f9c12d8703 --body "your comment"