gabriel / muse public
feat patch task/ls-tree #1 / 1
gabriel · 166 days ago · Apr 14, 2026 · Diff

feat: implement muse ls-tree command with synthetic directory entries

- _build_tree_entries: synthesizes tree entries from flat manifest by detecting shared path prefixes; non-recursive collapses subdirs into synthetic 040000 tree nodes; recursive lists all blobs only - _synthetic_tree_id: deterministic SHA-256 of sorted (path, oid) pairs under a prefix — gives each synthetic tree a stable, content-addressed ID - _resolve_manifest: resolves HEAD, branch names (via .muse/refs/heads/), and commit IDs (prefix scan) to a manifest - Flags: -r/--recursive, -d/--dirs-only, -l/--long (with byte sizes), --name-only, --json, positional treeish (default HEAD) + path prefix - Text format: '<mode> <type> <object_id>TAB<path>' - JSON schema: treeish + commit_id + entries array - 31 tests: unit helpers, integration (all flag combos, refs, formats), security (path traversal + ANSI rejection), stress (500-file repo)

sha256:2844e173ab1a7d49e0a962310ee2b5d27036143ded9767102735f9848a21a719 sha
+81 ~26 symbols
sha256:4948278af4a6c0380695e0a088c3f94c4066abd9cfe16f0a433a9f31005cfa86 snapshot
+81
symbols added
~26
symbols modified
0
dead code introduced
Semantic Changes 107 symbols
~ muse/cli/commands/ls_tree.py .py 26 symbols added
+ _BLOB_MODE variable variable _BLOB_MODE L86–86
+ _TREE_MODE variable variable _TREE_MODE L87–87
+ _build_tree_entries function function _build_tree_entries L116–182
+ _resolve_manifest function function _resolve_manifest L185–245
+ _synthetic_tree_id function function _synthetic_tree_id L95–113
+ _validate_path_prefix function function _validate_path_prefix L248–292
+ ExitCode import import ExitCode L72–72
+ _json import import _json L67–67
+ annotations import import annotations L63–63
+ argparse import import argparse L65–65
+ get_head_commit_id import import get_head_commit_id L75–75
+ hashlib import import hashlib L66–66
+ logging import import logging L68–68
+ pathlib import import pathlib L69–69
+ read_commit import import read_commit L75–75
+ read_current_branch import import read_current_branch L75–75
+ read_object import import read_object L73–73
+ read_repo_id import import read_repo_id L74–74
+ read_snapshot import import read_snapshot L75–75
+ require_repo import import require_repo L74–74
+ resolve_commit_ref import import resolve_commit_ref L75–75
+ sanitize_display import import sanitize_display L82–82
+ sys import import sys L70–70
+ logger variable variable logger L84–84
+ register function function register L300–354
+ run function function run L362–443
~ tests/test_cmd_ls_tree.py .py 54 symbols added
+ _REPO_ID variable variable _REPO_ID L34–34
+ _commit_files function function _commit_files L64–97
+ _counter variable variable _counter L46–46
+ _env function function _env L60–61
+ _init_repo function function _init_repo L49–57
+ _invoke function function _invoke L100–102
+ _sha function function _sha L42–43
+ CliRunner import import CliRunner L25–25
+ CommitRecord import import CommitRecord L29–29
+ Manifest import import Manifest L30–30
+ SnapshotRecord import import SnapshotRecord L29–29
+ annotations import import annotations L16–16
+ compute_commit_id import import compute_commit_id L28–28
+ compute_snapshot_id import import compute_snapshot_id L28–28
+ datetime import import datetime L18–18
+ hashlib import import hashlib L19–19
+ json import import json L20–20
+ pathlib import import pathlib L21–21
+ pytest import import pytest L23–23
+ write_commit import import write_commit L29–29
+ write_object import import write_object L27–27
+ write_snapshot import import write_snapshot L29–29
+ runner variable variable runner L32–32
+ test_build_tree_entries_path_prefix_scoping function function test_build_tree_entries_path_prefix_scoping L143–154
+ test_build_tree_entries_recursive_only_blobs function function test_build_tree_entries_recursive_only_blobs L128–140
+ test_build_tree_entries_separates_blobs_and_dirs function function test_build_tree_entries_separates_blobs_and_dirs L110–125
+ test_build_tree_entries_sorted function function test_build_tree_entries_sorted L157–166
+ test_ls_tree_500_files_recursive function function test_ls_tree_500_files_recursive L490–497
+ test_ls_tree_500_files_root_listing function function test_ls_tree_500_files_root_listing L474–487
+ test_ls_tree_ansi_in_ref_rejected function function test_ls_tree_ansi_in_ref_rejected L462–466
+ test_ls_tree_branch_name_ref function function test_ls_tree_branch_name_ref L387–393
+ test_ls_tree_commit_id_ref function function test_ls_tree_commit_id_ref L396–402
+ test_ls_tree_dirs_only_shows_only_trees function function test_ls_tree_dirs_only_shows_only_trees L369–379
+ test_ls_tree_empty_repo_exits_nonzero function function test_ls_tree_empty_repo_exits_nonzero L412–415
+ test_ls_tree_entries_sorted_alphabetically function function test_ls_tree_entries_sorted_alphabetically L231–237
+ test_ls_tree_json_output_has_commit_id function function test_ls_tree_json_output_has_commit_id L440–447
+ test_ls_tree_long_includes_size_for_blobs function function test_ls_tree_long_includes_size_for_blobs L344–352
+ test_ls_tree_long_tree_size_is_none function function test_ls_tree_long_tree_size_is_none L355–361
+ test_ls_tree_name_only_json function function test_ls_tree_name_only_json L328–336
+ test_ls_tree_name_only_text_no_metadata function function test_ls_tree_name_only_text_no_metadata L317–325
+ test_ls_tree_nonexistent_ref_exits_nonzero function function test_ls_tree_nonexistent_ref_exits_nonzero L405–409
+ test_ls_tree_path_arg_nonexistent_shows_empty function function test_ls_tree_path_arg_nonexistent_shows_empty L261–267
+ test_ls_tree_path_arg_scopes_to_directory function function test_ls_tree_path_arg_scopes_to_directory L245–258
+ test_ls_tree_path_traversal_in_path_arg_rejected function function test_ls_tree_path_traversal_in_path_arg_rejected L455–459
+ test_ls_tree_recursive_lists_all_blobs function function test_ls_tree_recursive_lists_all_blobs L275–288
+ test_ls_tree_recursive_no_tree_entries function function test_ls_tree_recursive_no_tree_entries L291–296
+ test_ls_tree_recursive_with_path_prefix function function test_ls_tree_recursive_with_path_prefix L299–309
+ test_ls_tree_root_blob_mode_is_100644 function function test_ls_tree_root_blob_mode_is_100644 L213–219
+ test_ls_tree_root_shows_blob_for_root_file function function test_ls_tree_root_shows_blob_for_root_file L190–197
+ test_ls_tree_root_shows_synthetic_tree_for_subdir function function test_ls_tree_root_shows_synthetic_tree_for_subdir L200–210
+ test_ls_tree_root_tree_mode_is_040000 function function test_ls_tree_root_tree_mode_is_040000 L222–228
+ test_ls_tree_text_format_tab_separated function function test_ls_tree_text_format_tab_separated L423–437
+ test_synthetic_tree_id_differs_for_different_content function function test_synthetic_tree_id_differs_for_different_content L178–182
+ test_synthetic_tree_id_is_deterministic function function test_synthetic_tree_id_is_deterministic L169–175
← Older Oldest on task/ls-tree
All commits
Newer → Latest on task/ls-tree

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