gabriel / musehub public
feat BREAKING dev
AI Agent gabriel · 170 days ago · Apr 9, 2026 · Diff

feat: issue detail CLI/MCP/REST act panel with syntax highlighting and copy buttons

- Add REST tab to issue detail act panel (curl API examples) - Switch all snippets from br/nbsp HTML to clean <pre><code> blocks - Syntax highlighting via highlight.js (bash + javascript, design-system token overrides) - Per-snippet copy buttons injected by JS, top-right positioned, 2s confirmation - Idempotency guards on close_issue / reopen_issue service functions - Update SSR tests: replace stale 'Act via CLI' assertions with semantic content checks - All 18 issue detail SSR tests passing

sha256:b55224ca9c1d85450182407e56ffebdee04df6b309599af4e5a4a7ac5493e39c sha
+188 ~56 −1 symbols
sha256:e04bee24f25c44aefc2156ae2047c06a3b8e16cd4cdaee1a0a2a4e6ef597c1a5 snapshot
+188
symbols added
~56
symbols modified
−1
symbol removed
0
dead code introduced
Semantic Changes 245 symbols
+ branch_labels variable variable branch_labels L12–12
+ depends_on variable variable depends_on L13–13
+ down_revision variable variable down_revision L11–11
+ downgrade function function downgrade L27–28
+ op import import op L7–7
+ sa import import sa L8–8
+ revision variable variable revision L10–10
+ upgrade function function upgrade L16–24
+ branch_labels variable variable branch_labels L13–13
+ depends_on variable variable depends_on L14–14
+ down_revision variable variable down_revision L12–12
+ downgrade function function downgrade L29–30
+ op import import op L8–8
+ sa import import sa L9–9
+ revision variable variable revision L11–11
+ upgrade function function upgrade L17–26
+ _commit_id function function _commit_id L43–44
+ _make_branch function async_function _make_branch L80–84
+ _make_commit function async_function _make_commit L58–77
+ _make_proposal function async_function _make_proposal L87–109
+ _make_repo function async_function _make_repo L47–55
+ _uid function function _uid L39–40
+ AsyncSession import import AsyncSession L23–23
+ MusehubBranch import import MusehubBranch L25–25
+ MusehubCommit import import MusehubCommit L25–25
+ MusehubProposal import import MusehubProposal L25–25
+ MusehubRepo import import MusehubRepo L25–25
+ annotations import import annotations L17–17
+ datetime import import datetime L20–20
+ musehub_issues import import musehub_issues L31–31
+ pytest import import pytest L22–22
+ timezone import import timezone L20–20
+ uuid import import uuid L19–19
+ test_anchor_already_in_to_branch_not_matched function async_function test_anchor_already_in_to_branch_not_matched L155–178
+ test_anchor_at_depth_2_from_from_branch function async_function test_anchor_at_depth_2_from_from_branch L182–206
+ test_anchor_exclusively_on_from_branch_matches function async_function test_anchor_exclusively_on_from_branch_matches L127–151
+ test_cross_repo_isolation function async_function test_cross_repo_isolation L269–285
+ test_empty_anchors_returns_empty function async_function test_empty_anchors_returns_empty L118–123
+ test_merged_proposal_not_returned function async_function test_merged_proposal_not_returned L234–253
+ test_multiple_open_proposals_only_matching_returned function async_function test_multiple_open_proposals_only_matching_returned L289–318
+ test_short_anchor_prefix_resolved function async_function test_short_anchor_prefix_resolved L210–230
+ test_unresolved_anchor_returns_empty function async_function test_unresolved_anchor_returns_empty L257–265
+ _commit_id function function _commit_id L38–40
+ _make_commit function async_function _make_commit L57–78
+ _make_proposal function async_function _make_proposal L81–107
+ _make_repo function async_function _make_repo L43–54
+ _uid function function _uid L34–35
+ AsyncSession import import AsyncSession L18–18
+ MusehubCommit import import MusehubCommit L20–20
+ MusehubIssue import import MusehubIssue L20–20
+ MusehubProposal import import MusehubProposal L20–20
+ MusehubRepo import import MusehubRepo L20–20
+ annotations import import annotations L12–12
+ datetime import import datetime L15–15
+ musehub_issues import import musehub_issues L26–26
+ pytest import import pytest L17–17
+ timezone import import timezone L15–15
+ uuid import import uuid L14–14
+ test_anchor_unresolved_returns_empty function async_function test_anchor_unresolved_returns_empty L279–288
+ test_empty_anchors_returns_empty function async_function test_empty_anchors_returns_empty L116–122
+ test_merged_proposal_matched_depth_1 function async_function test_merged_proposal_matched_depth_1 L126–149
+ test_merged_proposal_matched_depth_2 function async_function test_merged_proposal_matched_depth_2 L153–178
+ test_no_match_when_anchor_not_in_graph function async_function test_no_match_when_anchor_not_in_graph L210–229
+ test_open_proposal_matched_via_branch function async_function test_open_proposal_matched_via_branch L182–206
+ test_proposals_from_other_repo_not_returned function async_function test_proposals_from_other_repo_not_returned L256–275
+ test_short_anchor_prefix_match function async_function test_short_anchor_prefix_match L233–252
+ _create_issue function async_function _create_issue L34–38
+ _create_repo function async_function _create_repo L28–31
+ AsyncClient import import AsyncClient L18–18
+ StrDict import import StrDict L20–20
+ annotations import import annotations L15–15
+ pytest import import pytest L17–17
+ test_comment_body_at_limit_accepted function async_function test_comment_body_at_limit_accepted L232–240
+ test_comment_body_empty_rejected function async_function test_comment_body_empty_rejected L256–264
+ test_comment_body_over_limit_rejected function async_function test_comment_body_over_limit_rejected L244–252
+ test_issue_body_at_limit_accepted function async_function test_issue_body_at_limit_accepted L47–54
+ test_issue_body_over_limit_rejected function async_function test_issue_body_over_limit_rejected L58–65
+ test_issue_commit_anchor_item_too_long_rejected function async_function test_issue_commit_anchor_item_too_long_rejected L216–223
+ test_issue_commit_anchors_at_limit_accepted function async_function test_issue_commit_anchors_at_limit_accepted L190–199
+ test_issue_commit_anchors_too_many_rejected function async_function test_issue_commit_anchors_too_many_rejected L203–212
+ test_issue_label_item_at_limit_accepted function async_function test_issue_label_item_at_limit_accepted L134–141
+ test_issue_label_item_too_long_rejected function async_function test_issue_label_item_too_long_rejected L123–130
+ test_issue_labels_at_limit_accepted function async_function test_issue_labels_at_limit_accepted L101–108
+ test_issue_labels_too_many_rejected function async_function test_issue_labels_too_many_rejected L112–119
+ test_issue_symbol_anchor_item_too_long_rejected function async_function test_issue_symbol_anchor_item_too_long_rejected L174–181
+ test_issue_symbol_anchors_at_limit_accepted function async_function test_issue_symbol_anchors_at_limit_accepted L150–158
+ test_issue_symbol_anchors_too_many_rejected function async_function test_issue_symbol_anchors_too_many_rejected L162–170
+ test_issue_title_at_limit_accepted function async_function test_issue_title_at_limit_accepted L74–81
+ test_issue_title_over_limit_rejected function async_function test_issue_title_over_limit_rejected L85–92
+ test_label_assign_item_too_long_rejected function async_function test_label_assign_item_too_long_rejected L285–293
+ test_label_assign_too_many_rejected function async_function test_label_assign_too_many_rejected L273–281
+ test_update_body_over_limit_rejected function async_function test_update_body_over_limit_rejected L302–310
+ test_update_labels_too_many_rejected function async_function test_update_labels_too_many_rejected L314–322
+ test_update_symbol_anchors_too_many_rejected function async_function test_update_symbol_anchors_too_many_rejected L326–334
+ _commit_id function function _commit_id L45–46
+ _delta function function _delta L49–61
+ _make_branch function async_function _make_branch L106–116
+ _make_commit function async_function _make_commit L78–103
+ _make_repo function async_function _make_repo L64–75
+ _uid function function _uid L41–42
+ Any import import Any L16–16
+ AsyncSession import import AsyncSession L19–19
+ MusehubBranch import import MusehubBranch L21–21
+ MusehubCommit import import MusehubCommit L21–21
+ MusehubProposal import import MusehubProposal L21–21
+ MusehubRepo import import MusehubRepo L21–21
+ _symbols_from_delta import import _symbols_from_delta L28–28
+ _touched_symbols_for_branch import import _touched_symbols_for_branch L28–28
+ annotations import import annotations L12–12
+ create_proposal import import create_proposal L28–28
+ datetime import import datetime L15–15
+ merge_proposal import import merge_proposal L28–28
+ musehub_issues import import musehub_issues L27–27
+ pytest import import pytest L18–18
+ timezone import import timezone L15–15
+ uuid import import uuid L14–14
+ test_create_proposal_populates_touched_symbols function async_function test_create_proposal_populates_touched_symbols L194–221
+ test_merge_proposal_refreshes_touched_symbols function async_function test_merge_proposal_refreshes_touched_symbols L225–274
+ test_symbol_overlap_cross_repo_isolation function async_function test_symbol_overlap_cross_repo_isolation L354–379
+ test_symbol_overlap_empty_anchors_returns_empty function async_function test_symbol_overlap_empty_anchors_returns_empty L341–350
+ test_symbol_overlap_no_match function async_function test_symbol_overlap_no_match L314–337
+ test_symbol_overlap_open_proposal_matched function async_function test_symbol_overlap_open_proposal_matched L383–409
+ test_symbol_overlap_returns_match function async_function test_symbol_overlap_returns_match L283–310
+ test_symbols_from_delta_deduplicates function function test_symbols_from_delta_deduplicates L155–161
+ test_symbols_from_delta_extracts_symbol_addresses function function test_symbols_from_delta_extracts_symbol_addresses L124–132
+ test_symbols_from_delta_handles_non_dict function function test_symbols_from_delta_handles_non_dict L149–152
+ test_symbols_from_delta_skips_file_level_ops function function test_symbols_from_delta_skips_file_level_ops L135–146
+ test_touched_symbols_for_branch_extracts_from_commits function async_function test_touched_symbols_for_branch_extracts_from_commits L170–190
+ _PY_SRC variable variable _PY_SRC L40–47
+ _make_issue function async_function _make_issue L64–85
+ _make_repo function async_function _make_repo L50–61
+ AsyncClient import import AsyncClient L28–28
+ AsyncSession import import AsyncSession L29–29
+ MusehubIssue import import MusehubIssue L32–32
+ MusehubRepo import import MusehubRepo L32–32
+ StrDict import import StrDict L33–33
+ _enrich_with_linenos import import _enrich_with_linenos L31–31
+ _symbol_line_map import import _symbol_line_map L31–31
+ annotations import import annotations L25–25
+ pytest import import pytest L27–27
+ test_blob_page_json_contains_symbol_lines_key function async_function test_blob_page_json_contains_symbol_lines_key L213–222
+ test_enrich_adds_lineno_for_class class function test_enrich_adds_lineno_for_class L99–102
+ test_enrich_adds_lineno_for_known_function function function test_enrich_adds_lineno_for_known_function L93–96
+ test_enrich_does_not_overwrite_existing_lineno function function test_enrich_does_not_overwrite_existing_lineno L111–114
+ test_enrich_ignores_symbol_not_in_ast function function test_enrich_ignores_symbol_not_in_ast L123–126
+ test_enrich_skips_non_python_files function function test_enrich_skips_non_python_files L105–108
+ test_enrich_tolerates_syntax_error function function test_enrich_tolerates_syntax_error L117–120
+ test_issue_detail_multiple_symbol_anchors_all_linked function async_function test_issue_detail_multiple_symbol_anchors_all_linked L189–204
+ test_issue_detail_symbol_anchor_link_contains_hash_fragment function async_function test_issue_detail_symbol_anchor_link_contains_hash_fragment L165–172
+ test_issue_detail_symbol_anchor_plain_file_no_fragment function async_function test_issue_detail_symbol_anchor_plain_file_no_fragment L176–185
+ test_symbol_line_map_excludes_falsy_lineno function function test_symbol_line_map_excludes_falsy_lineno L153–156
+ test_symbol_line_map_excludes_symbols_without_lineno function function test_symbol_line_map_excludes_symbols_without_lineno L143–150
+ test_symbol_line_map_returns_display_name_to_lineno function function test_symbol_line_map_returns_display_name_to_lineno L134–140
~ docs/reference/type-contracts.md .md 3 symbols added, 12 symbols modified
+ py`@L3755 section MyModel — `tests/test_api_contracts_section37.py` L3755–3763
+ py`@L3773 section MyModel — `tests/test_api_contracts_section37.py` L3773–3781
+ py`@L3782 section MyModel — `tests/test_api_contracts_section37.py` L3782–3790
~ py`
~ py`
~ py`
~ py`
~ musehub/api/routes/musehub/issues.py .py 6 symbols added, 10 symbols modified
+ ISSUE_COMMENT_LIMIT import import ISSUE_COMMENT_LIMIT L34–34
+ ISSUE_CREATE_LIMIT import import ISSUE_CREATE_LIMIT L34–34
+ MusehubCollaborator import import MusehubCollaborator L33–33
+ get_msign_handle import import get_msign_handle L34–34
+ limiter import import limiter L34–34
+ select import import select L27–27
~ musehub/api/routes/musehub/ui_blob.py .py 3 symbols added, 2 symbols modified
+ _enrich_with_linenos function function _enrich_with_linenos L111–131
+ _symbol_line_map function function _symbol_line_map L134–147
+ _symbol_line_map_from_content function function _symbol_line_map_from_content L150–156
~ musehub/models/musehub.py .py 4 symbols added, 7 symbols modified
+ _CommitAnchor variable variable _CommitAnchor L560–560
+ _Label variable variable _Label L558–558
+ _SymbolAnchor variable variable _SymbolAnchor L559–559
+ Annotated import import Annotated L10–10
~ musehub/rate_limits.py .py 4 symbols added
+ ISSUE_COMMENT_LIMIT variable variable ISSUE_COMMENT_LIMIT L64–64
+ ISSUE_CREATE_LIMIT variable variable ISSUE_CREATE_LIMIT L63–63
+ get_msign_handle function function get_msign_handle L67–81
+ Request import import Request L21–21
~ musehub/services/musehub_issues.py .py 4 symbols added, 8 symbols modified
+ find_proposals_by_branch_reachability function async_function find_proposals_by_branch_reachability L719–853
+ find_proposals_by_commit_graph function async_function find_proposals_by_commit_graph L557–713
+ find_proposals_by_symbol_overlap function async_function find_proposals_by_symbol_overlap L859–911
+ text import import text L17–17
~ func
~ select
~ musehub/services/musehub_proposals.py .py 2 symbols added, 2 symbols modified
+ _symbols_from_delta function function _symbols_from_delta L46–79
+ _touched_symbols_for_branch function async_function _touched_symbols_for_branch L82–106
~ musehub/templates/musehub/static/js/pages/blob.ts .ts 2 symbols added, 5 symbols modified
+ SymbolLineMap variable variable SymbolLineMap L60–60
+ resolveSymbolHash function function resolveSymbolHash L470–485
~ musehub/templates/musehub/static/js/pages/issue-detail.ts .ts 2 symbols added, 2 symbols modified
+ highlightSnippets function function highlightSnippets L65–69
+ injectCopyButtons function function injectCopyButtons L76–102
~ tests/test_musehub_issues.py .py 4 symbols added
+ test_close_already_closed_issue_is_idempotent function async_function test_close_already_closed_issue_is_idempotent L691–742
+ test_close_returns_current_state_without_db_write_when_already_closed function async_function test_close_returns_current_state_without_db_write_when_already_closed L800–850
+ test_reopen_already_open_issue_is_idempotent function async_function test_reopen_already_open_issue_is_idempotent L746–796
+ test_reopen_returns_current_state_without_db_write_when_already_open function async_function test_reopen_returns_current_state_without_db_write_when_already_open L854–903
~ tests/test_musehub_ui_issue_detail_ssr.py .py 1 symbol added, 1 symbol removed, 1 symbol modified
− test_act_via_cli_card_shown function async_function test_act_via_cli_card_shown L371–383
+ test_act_panel_shown function async_function test_act_panel_shown L370–383
← Older Oldest on dev
All commits
Newer → Latest on dev

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