app.py
python
| 1 | """Muse CLI — Typer application root. |
| 2 | |
| 3 | Entry point for the ``muse`` console script. Registers all MVP |
| 4 | subcommands (amend, arrange, ask, bisect, blame, cat-object, checkout, cherry-pick, |
| 5 | chord-map, clone, commit, commit-tree, context, contour, describe, diff, divergence, |
| 6 | dynamics, emotion-diff, export, fetch, find, form, grep, groove-check, harmony, |
| 7 | hash-object, humanize, import, init, inspect, key, log, merge, meter, motif, open, |
| 8 | play, pull, push, read-tree, rebase, recall, release, remote, render-preview, rerere, |
| 9 | subcommands (amend, arrange, ask, attributes, bisect, blame, cat-object, checkout, |
| 10 | cherry-pick, chord-map, clone, commit, commit-tree, context, contour, describe, diff, |
| 11 | divergence, dynamics, emotion-diff, export, fetch, find, form, grep, groove-check, |
| 12 | harmony, hash-object, humanize, import, init, inspect, key, log, merge, meter, motif, |
| 13 | open, play, pull, push, read-tree, rebase, recall, release, remote, render-preview, |
| 14 | reset, resolve, restore, rev-parse, revert, session, show, similarity, stash, status, |
| 15 | swing, symbolic-ref, tag, tempo, tempo-scale, timeline, transpose, update-ref, |
| 16 | validate, worktree, write-tree) as Typer sub-applications. |
| 17 | """ |
| 18 | from __future__ import annotations |
| 19 | |
| 20 | import typer |
| 21 | |
| 22 | from maestro.muse_cli.commands import ( |
| 23 | amend, |
| 24 | attributes, |
| 25 | arrange, |
| 26 | ask, |
| 27 | bisect, |
| 28 | blame, |
| 29 | cat_object, |
| 30 | checkout, |
| 31 | cherry_pick, |
| 32 | chord_map, |
| 33 | clone, |
| 34 | commit, |
| 35 | commit_tree, |
| 36 | context, |
| 37 | contour, |
| 38 | describe, |
| 39 | diff, |
| 40 | divergence, |
| 41 | dynamics, |
| 42 | emotion_diff, |
| 43 | export, |
| 44 | fetch, |
| 45 | find, |
| 46 | form, |
| 47 | grep_cmd, |
| 48 | groove_check, |
| 49 | harmony, |
| 50 | hash_object, |
| 51 | humanize, |
| 52 | import_cmd, |
| 53 | init, |
| 54 | inspect, |
| 55 | key, |
| 56 | log, |
| 57 | merge, |
| 58 | meter, |
| 59 | motif, |
| 60 | open_cmd, |
| 61 | play, |
| 62 | pull, |
| 63 | push, |
| 64 | read_tree, |
| 65 | rebase, |
| 66 | recall, |
| 67 | release, |
| 68 | remote, |
| 69 | render_preview, |
| 70 | rerere, |
| 71 | reset, |
| 72 | resolve, |
| 73 | restore, |
| 74 | rev_parse, |
| 75 | revert, |
| 76 | session, |
| 77 | show, |
| 78 | similarity, |
| 79 | stash, |
| 80 | status, |
| 81 | swing, |
| 82 | symbolic_ref, |
| 83 | tag, |
| 84 | tempo, |
| 85 | tempo_scale, |
| 86 | timeline, |
| 87 | transpose, |
| 88 | update_ref, |
| 89 | validate, |
| 90 | worktree, |
| 91 | write_tree, |
| 92 | ) |
| 93 | from maestro.muse_cli.commands.checkout import run_checkout as _checkout_logic |
| 94 | |
| 95 | cli = typer.Typer( |
| 96 | name="muse", |
| 97 | help="Muse — Git-style version control for musical compositions.", |
| 98 | no_args_is_help=True, |
| 99 | ) |
| 100 | |
| 101 | cli.add_typer(amend.app, name="amend", help="Fold working-tree changes into the most recent commit.") |
| 102 | cli.add_typer(attributes.app, name="attributes", help="Read and validate the .museattributes merge-strategy configuration.") |
| 103 | cli.add_typer(bisect.app, name="bisect", help="Binary search for the commit that introduced a regression.") |
| 104 | cli.add_typer(blame.app, name="blame", help="Annotate files with the commit that last changed each one.") |
| 105 | cli.add_typer(cat_object.app, name="cat-object", help="Read and display a stored object by its SHA-256 hash.") |
| 106 | cli.add_typer(cherry_pick.app, name="cherry-pick", help="Apply a specific commit's diff on top of HEAD without merging the full branch.") |
| 107 | cli.add_typer(clone.app, name="clone", help="Clone a Muse Hub repository into a new local directory.") |
| 108 | cli.add_typer(hash_object.app, name="hash-object", help="Compute the SHA-256 object ID for a file (or stdin) and optionally store it.") |
| 109 | cli.add_typer(chord_map.app, name="chord-map", help="Visualize the chord progression embedded in a commit.") |
| 110 | cli.add_typer(contour.app, name="contour", help="Analyze the melodic contour and phrase shape of a commit.") |
| 111 | cli.add_typer(init.app, name="init", help="Initialise a new Muse repository.") |
| 112 | cli.add_typer(status.app, name="status", help="Show working-tree drift against HEAD.") |
| 113 | cli.add_typer(dynamics.app, name="dynamics", help="Analyse the dynamic (velocity) profile of a commit.") |
| 114 | cli.add_typer(commit.app, name="commit", help="Record a new variation in history.") |
| 115 | cli.add_typer( |
| 116 | commit_tree.app, |
| 117 | name="commit-tree", |
| 118 | help="Create a raw commit object from an existing snapshot (plumbing).", |
| 119 | ) |
| 120 | cli.add_typer(grep_cmd.app, name="grep", help="Search for a musical pattern across all commits.") |
| 121 | cli.add_typer(log.app, name="log", help="Display the variation history graph.") |
| 122 | cli.add_typer(find.app, name="find", help="Search commit history by musical properties.") |
| 123 | cli.add_typer(harmony.app, name="harmony", help="Analyze harmonic content (key, mode, chords, tension) of a commit.") |
| 124 | cli.add_typer(inspect.app, name="inspect", help="Print structured JSON of the Muse commit graph.") |
| 125 | cli.add_typer(checkout.app, name="checkout", help="Checkout a historical variation.") |
| 126 | # checkout is registered as a plain @cli.command() (not add_typer) so that Click |
| 127 | # treats it as a Command rather than a Group. Click Groups pass sub-contexts with |
| 128 | # allow_interspersed_args=False, which prevents --force from being recognised when |
| 129 | # it follows the positional BRANCH argument. A plain Command keeps the default |
| 130 | # allow_interspersed_args=True and parses options in any position. |
| 131 | @cli.command("checkout", help="Create or switch branches; update .muse/HEAD.") |
| 132 | def _checkout_cmd( |
| 133 | branch: str = typer.Argument(..., help="Branch name to checkout or create."), |
| 134 | create: bool = typer.Option( |
| 135 | False, "-b", "--create", help="Create a new branch at the current HEAD and switch to it." |
| 136 | ), |
| 137 | force: bool = typer.Option( |
| 138 | False, "--force", "-f", help="Ignore uncommitted changes in muse-work/." |
| 139 | ), |
| 140 | ) -> None: |
| 141 | _checkout_logic(branch=branch, create=create, force=force) |
| 142 | |
| 143 | |
| 144 | cli.add_typer(merge.app, name="merge", help="Three-way merge two variation branches.") |
| 145 | cli.add_typer(remote.app, name="remote", help="Manage remote server connections.") |
| 146 | cli.add_typer(fetch.app, name="fetch", help="Fetch refs from remote without merging.") |
| 147 | cli.add_typer(push.app, name="push", help="Upload local variations to a remote.") |
| 148 | cli.add_typer(pull.app, name="pull", help="Download remote variations locally.") |
| 149 | cli.add_typer(describe.app, name="describe", help="Describe what changed musically in a commit.") |
| 150 | cli.add_typer(diff.app, name="diff", help="Compare two commits across musical dimensions (harmonic, rhythmic, melodic, structural, dynamic).") |
| 151 | cli.add_typer(open_cmd.app, name="open", help="Open an artifact in the system default app (macOS).") |
| 152 | cli.add_typer(play.app, name="play", help="Play an audio artifact via afplay (macOS).") |
| 153 | cli.add_typer(arrange.app, name="arrange", help="Display arrangement map (instrument activity over sections).") |
| 154 | cli.add_typer(swing.app, name="swing", help="Analyze or annotate the swing factor of a composition.") |
| 155 | cli.add_typer(session.app, name="session", help="Record and query recording session metadata.") |
| 156 | cli.add_typer(export.app, name="export", help="Export a snapshot to MIDI, JSON, MusicXML, ABC, or WAV.") |
| 157 | cli.add_typer(ask.app, name="ask", help="Query musical history in natural language.") |
| 158 | cli.add_typer(meter.app, name="meter", help="Read or set the time signature of a commit.") |
| 159 | cli.add_typer(tag.app, name="tag", help="Attach and query music-semantic tags on commits.") |
| 160 | cli.add_typer(import_cmd.app, name="import", help="Import a MIDI or MusicXML file as a new Muse commit.") |
| 161 | cli.add_typer(tempo.app, name="tempo", help="Read or set the tempo (BPM) of a commit.") |
| 162 | cli.add_typer(read_tree.app, name="read-tree", help="Read a snapshot into muse-work/ without updating HEAD.") |
| 163 | cli.add_typer(rebase.app, name="rebase", help="Rebase commits onto a new base, producing a linear history.") |
| 164 | cli.add_typer(recall.app, name="recall", help="Search commit history by natural-language description.") |
| 165 | cli.add_typer(release.app, name="release", help="Export a tagged commit as distribution-ready release artifacts.") |
| 166 | cli.add_typer(revert.app, name="revert", help="Create a new commit that undoes a prior commit without rewriting history.") |
| 167 | cli.add_typer(key.app, name="key", help="Read or annotate the musical key of a commit.") |
| 168 | cli.add_typer(humanize.app, name="humanize", help="Apply micro-timing and velocity humanization to quantized MIDI.") |
| 169 | cli.add_typer(context.app, name="context", help="Output structured musical context for AI agent consumption.") |
| 170 | cli.add_typer(divergence.app, name="divergence", help="Show how two branches have diverged musically.") |
| 171 | cli.add_typer(transpose.app, name="transpose", help="Apply MIDI pitch transposition and record as a Muse commit.") |
| 172 | cli.add_typer(motif.app, name="motif", help="Identify, track, and compare recurring melodic motifs.") |
| 173 | cli.add_typer(emotion_diff.app, name="emotion-diff", help="Compare emotion vectors between two commits.") |
| 174 | cli.add_typer(rev_parse.app, name="rev-parse", help="Resolve a revision expression to a commit ID.") |
| 175 | cli.add_typer(symbolic_ref.app, name="symbolic-ref", help="Read or write a symbolic ref (e.g. HEAD).") |
| 176 | cli.add_typer(show.app, name="show", help="Inspect a commit: metadata, snapshot, diff, MIDI files, and audio preview.") |
| 177 | cli.add_typer(render_preview.app, name="render-preview", help="Generate an audio preview of a commit's snapshot.") |
| 178 | cli.add_typer(reset.app, name="reset", help="Reset the branch pointer to a prior commit.") |
| 179 | cli.add_typer(rerere.app, name="rerere", help="Reuse recorded resolutions for musical merge conflicts.") |
| 180 | cli.add_typer(resolve.app, name="resolve", help="Mark a conflicted file as resolved (--ours or --theirs).") |
| 181 | cli.add_typer(restore.app, name="restore", help="Restore specific files from a commit or index into muse-work/.") |
| 182 | cli.add_typer(groove_check.app, name="groove-check", help="Analyze rhythmic drift across commits to find groove regressions.") |
| 183 | cli.add_typer(form.app, name="form", help="Analyze or annotate the formal structure (sections) of a commit.") |
| 184 | cli.add_typer(similarity.app, name="similarity", help="Compare two commits by musical similarity score.") |
| 185 | cli.add_typer(stash.app, name="stash", help="Temporarily shelve uncommitted muse-work/ changes.") |
| 186 | cli.add_typer(tempo_scale.app, name="tempo-scale", help="Stretch or compress the timing of a commit.") |
| 187 | cli.add_typer(timeline.app, name="timeline", help="Visualize musical evolution chronologically.") |
| 188 | cli.add_typer(update_ref.app, name="update-ref", help="Write or delete a ref (branch or tag pointer).") |
| 189 | cli.add_typer(validate.app, name="validate", help="Check musical integrity of the working tree.") |
| 190 | cli.add_typer(worktree.app, name="worktree", help="Manage local Muse worktrees (add, remove, list, prune).") |
| 191 | cli.add_typer(write_tree.app, name="write-tree", help="Write the current muse-work/ state as a snapshot (tree) object.") |
| 192 | |
| 193 | |
| 194 | if __name__ == "__main__": |
| 195 | cli() |