gabriel / muse public
feat patch task/supercharge-blame #1 / 1
gabriel · 164 days ago · Apr 16, 2026 · Diff

feat: supercharge muse blame + remove --porcelain everywhere

- Rewrote core_blame.py: removed --porcelain, added --json/-j (single JSON object with file/ref/line_count/lines), --range START-END (1-based inclusive filter), --author PATTERN (case-insensitive substring), branch name resolution for --ref, errors routed to stderr, indent=2 output.

- Removed --porcelain from status.py and _render_staged_status(); --json is now the sole machine-readable flag across all commands.

- TDD: 63 new tests in test_cmd_blame.py covering schema, attribution, flags, range, author, security, stress, performance, and data integrity.

- Updated test_cmd_status.py, test_code_stage.py, test_cli_workflow.py, test_cli_new_commands.py to replace --porcelain with --json equivalents.

sha256:2fa778aba8ab0ec15295b8624c6480a573482ffc9c206a6d9546f1c41d2c2b7b sha
+107 ~11 −11 symbols
704 changed · 704 in snapshot files
sha256:62164e95fc2f50b5646ffdfa8833ea161ca185bfbd78d4236de1487c7212f0bd snapshot
+107
symbols added
~11
symbols modified
−11
symbols removed
704
files changed
704
files in snapshot
0
dead code introduced
Semantic Changes 129 symbols
~ tests/test_cmd_blame.py .py 97 symbols added
+ TestBlameAuthor class class TestBlameAuthor L413–469
+ test_author_combined_with_range method method test_author_combined_with_range L455–461
+ test_author_filter_case_insensitive method method test_author_filter_case_insensitive L424–429
+ test_author_filter_matches method method test_author_filter_matches L416–422
+ test_author_filter_no_match_returns_empty method method test_author_filter_no_match_returns_empty L431–436
+ test_author_filter_substring_match method method test_author_filter_substring_match L438–443
+ test_author_filter_with_two_authors method method test_author_filter_with_two_authors L445–453
+ test_author_line_count_reflects_filter method method test_author_line_count_reflects_filter L463–469
+ TestBlameDataIntegrity class class TestBlameDataIntegrity L637–689
+ test_all_commit_ids_sha256_prefixed method method test_all_commit_ids_sha256_prefixed L646–650
+ test_author_never_empty_string method method test_author_never_empty_string L652–656
+ test_content_no_trailing_newline method method test_content_no_trailing_newline L658–662
+ test_json_is_valid_and_parseable method method test_json_is_valid_and_parseable L682–689
+ test_line_count_equals_lines_length_always method method test_line_count_equals_lines_length_always L674–680
+ test_linenos_are_contiguous_from_1 method method test_linenos_are_contiguous_from_1 L640–644
+ test_range_linenos_match_original_positions method method test_range_linenos_match_original_positions L664–672
+ TestBlameJsonAttribution class class TestBlameJsonAttribution L213–269
+ test_committed_at_is_iso8601 method method test_committed_at_is_iso8601 L255–260
+ test_content_has_no_trailing_newline method method test_content_has_no_trailing_newline L248–253
+ test_empty_file_returns_zero_lines method method test_empty_file_returns_zero_lines L262–269
+ test_message_is_first_line_of_commit_message method method test_message_is_first_line_of_commit_message L242–246
+ test_new_line_attributed_to_newer_commit method method test_new_line_attributed_to_newer_commit L234–240
+ test_older_lines_attributed_to_older_commit method method test_older_lines_attributed_to_older_commit L224–232
+ test_single_commit_all_lines_attributed method method test_single_commit_all_lines_attributed L216–222
+ TestBlameJsonFlag class class TestBlameJsonFlag L277–341
+ test_j_short_alias method method test_j_short_alias L285–290
+ test_json_flag_exits_0 method method test_json_flag_exits_0 L280–283
+ test_json_indent2 method method test_json_indent2 L337–341
+ test_porcelain_flag_rejected method method test_porcelain_flag_rejected L292–297
+ test_ref_branch_name method method test_ref_branch_name L330–335
+ test_short_n_changes_sha_width method method test_short_n_changes_sha_width L321–328
+ test_text_output_contains_content method method test_text_output_contains_content L307–311
+ test_text_output_contains_lineno method method test_text_output_contains_lineno L313–319
+ test_text_output_no_json method method test_text_output_no_json L299–305
+ TestBlameJsonSchema class class TestBlameJsonSchema L146–205
+ test_file_key_matches_input method method test_file_key_matches_input L157–162
+ test_line_count_is_int method method test_line_count_is_int L201–205
+ test_line_count_matches_lines_array method method test_line_count_matches_lines_array L171–176
+ test_line_entry_keys method method test_line_entry_keys L178–184
+ test_ref_key_is_full_commit_id method method test_ref_key_is_full_commit_id L164–169
+ test_short_id_default_length_is_12 method method test_short_id_default_length_is_12 L194–199
+ test_short_id_is_prefix_of_commit_id method method test_short_id_is_prefix_of_commit_id L186–192
+ test_top_level_keys method method test_top_level_keys L149–155
+ TestBlamePerformance class class TestBlamePerformance L607–629
+ test_100_line_file_under_2s method method test_100_line_file_under_2s L610–618
+ test_10_commit_chain_under_3s method method test_10_commit_chain_under_3s L620–629
+ TestBlameRange class class TestBlameRange L344–410
+ test_range_clamped_to_file_length method method test_range_clamped_to_file_length L387–394
+ test_range_full_file_explicit method method test_range_full_file_explicit L367–372
+ test_range_limits_lines_returned method method test_range_limits_lines_returned L347–355
+ test_range_line_count_reflects_filtered method method test_range_line_count_reflects_filtered L405–410
+ test_range_single_line method method test_range_single_line L357–365
+ test_range_start_gt_end_is_error method method test_range_start_gt_end_is_error L374–379
+ test_range_text_output_respected method method test_range_text_output_respected L396–403
+ test_range_zero_start_is_error method method test_range_zero_start_is_error L381–385
+ TestBlameSecurity class class TestBlameSecurity L477–540
+ test_ansi_in_author_sanitized_text method method test_ansi_in_author_sanitized_text L517–521
+ test_ansi_in_content_sanitized_text method method test_ansi_in_content_sanitized_text L511–515
+ test_json_output_no_ansi method method test_json_output_no_ansi L523–527
+ test_no_repo_exits_2 method method test_no_repo_exits_2 L529–534
+ test_null_byte_in_path_is_error method method test_null_byte_in_path_is_error L480–485
+ test_range_invalid_format_is_error method method test_range_invalid_format_is_error L536–540
+ test_unknown_file_error_on_stderr method method test_unknown_file_error_on_stderr L493–497
+ test_unknown_file_exits_1 method method test_unknown_file_exits_1 L487–491
+ test_unknown_ref_error_on_stderr method method test_unknown_ref_error_on_stderr L505–509
+ test_unknown_ref_exits_1 method method test_unknown_ref_exits_1 L499–503
+ TestBlameStress class class TestBlameStress L548–599
+ test_20_commit_chain method method test_20_commit_chain L561–570
+ test_500_line_file method method test_500_line_file L551–559
+ test_file_no_trailing_newline method method test_file_no_trailing_newline L580–588
+ test_range_on_large_file method method test_range_on_large_file L590–599
+ test_single_line_file method method test_single_line_file L572–578
+ _BASE_DT variable variable _BASE_DT L66–66
+ _commit function function _commit L95–130
+ _invoke function function _invoke L133–134
+ _make_repo function function _make_repo L69–80
+ _obj_id function function _obj_id L83–84
+ _parse_json function function _parse_json L137–138
+ _store_text function function _store_text L87–92
+ CliRunner import import CliRunner L58–58
+ CommitRecord import import CommitRecord L56–56
+ Manifest import import Manifest L57–57
+ SnapshotRecord import import SnapshotRecord L56–56
+ annotations import import annotations L43–43
+ compute_commit_id import import compute_commit_id L55–55
+ compute_snapshot_id import import compute_snapshot_id L55–55
+ datetime import import datetime L45–45
+ hashlib import import hashlib L46–46
+ json import import json L47–47
+ pathlib import import pathlib L48–48
+ pytest import import pytest L52–52
+ time import import time L49–49
+ uuid import import uuid L50–50
+ write_commit import import write_commit L56–56
+ write_object import import write_object L54–54
+ write_snapshot import import write_snapshot L56–56
+ runner variable variable runner L60–60
~ muse/cli/commands/core_blame.py .py 6 symbols added, 2 symbols modified
+ _BlameJson class class _BlameJson L60–64
+ _BlameLineJson class class _BlameLineJson L50–57
+ _RANGE_RE variable variable _RANGE_RE L47–47
+ _parse_range function function _parse_range L76–89
+ TypedDict import import TypedDict L33–33
+ re import import re L31–31
~ run
~ tests/test_cli_new_commands.py .py 1 symbol added, 1 symbol removed, 2 symbols modified
− test_blame_porcelain_json_output method method test_blame_porcelain_json_output L436–447
+ test_blame_json_output method method test_blame_json_output L436–448
~ tests/test_cli_workflow.py .py 1 symbol added, 1 symbol removed, 1 symbol modified
− test_porcelain_flag method method test_porcelain_flag L182–186
+ test_json_flag method method test_json_flag L182–188
~ tests/test_cmd_status.py .py 1 symbol added, 8 symbols removed, 2 symbols modified
− test_exit_code_with_porcelain method method test_exit_code_with_porcelain L483–487
− test_porcelain_shows_merging_suffix method method test_porcelain_shows_merging_suffix L664–667
− TestPorcelainOutput class class TestPorcelainOutput L413–441
− test_added_format method method test_added_format L431–435
− test_deleted_format method method test_deleted_format L437–441
− test_header_line_format method method test_header_line_format L414–417
− test_modified_format method method test_modified_format L425–429
− test_no_ansi_codes method method test_no_ansi_codes L419–423
+ test_text_shows_merging_message method method test_text_shows_merging_message L621–624
~ tests/test_code_stage.py .py 1 symbol added, 1 symbol removed, 1 symbol modified
− test_porcelain_format_with_stage method method test_porcelain_format_with_stage L517–523
+ test_json_format_with_stage method method test_json_format_with_stage L517–523
Files Changed
+704
704 in snapshot
+ .coverage .coverage
+ .museattributes .museattributes
+ .museignore .museignore
+ CLAUDE.md .md
+ README.md .md
+ out/docs.md .md
+ pyproject.toml .toml
← Older Oldest on task/supercharge-blame
All commits
Newer → Latest on task/supercharge-blame

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:2fa778aba8ab0ec15295b8624c6480a573482ffc9c206a6d9546f1c41d2c2b7b --body "your comment"