From 00e0651ca226ed13a4b24920d83327856b8705f9 Mon Sep 17 00:00:00 2001 From: McAmner Date: Sun, 5 Jul 2026 21:30:11 +0300 Subject: [PATCH] refactor(mqlaunch): de-layer git & release menu launchers into a lib (P4 / Step 11a) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fifth Step 11a slice. Pull the git and release menu launchers (open_git_menu, open_release_menu) out of the mqlaunch.sh monolith into mqlaunch/lib/git-menus.sh, sourced back into the launcher's scope. Both launch an external menu script (gitlaunch.sh / mq-release-menu.sh) and invalidate the cached dashboard header on return. Verbatim move, no behavior change: still uses the ambient UI helpers, $BASE_DIR, and command -v-guarded mq_dashboard_cache_invalidate / release_menu_loop; every caller (main dispatch, command-mode, mq-main-menu) resolves because the lib sources before dispatch. Launcher: 1547 → 1479 lines (~600 out since 11a began). Two existing contract tests referenced these functions by their old home and correctly failed on the move — repointed to git-menus.sh (git-route→gitlaunch in test-mqlaunch.sh; cache-invalidation-on-Back in dashboard-header-cache-smoke). The contracts are unchanged, only the file that owns them. Smoke CONCERNS row added (31 functions across 4 libs); AUTHORITY_MAP and CHANGELOG updated. Scoping note: run_git_screen at the top of mqlaunch.sh is dead there (no live caller in the launcher graph; the live copy lives in tools/scripts/mqlaunch_desktop.sh), so it is deliberately NOT moved here — dead code is a separate cleanup, not something to launder into a lib as if live. run_github_repo_picker is live but a ~117-line picker; its own follow-up slice. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 11 ++-- docs/AUTHORITY_MAP.md | 1 + mqlaunch/lib/git-menus.sh | 91 +++++++++++++++++++++++++++ terminal/launchers/mqlaunch.sh | 87 +++---------------------- tests/dashboard-header-cache-smoke.sh | 8 ++- tests/monolith-delayer-smoke.sh | 1 + tools/scripts/test-mqlaunch.sh | 2 +- 7 files changed, 114 insertions(+), 87 deletions(-) create mode 100755 mqlaunch/lib/git-menus.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cc57c8..a713037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,15 +20,16 @@ All notable changes to this project will be documented in this file. ### Changed -* Monolith de-layering (Step 11a): three concerns moved verbatim out of +* Monolith de-layering (Step 11a): four concerns moved verbatim out of `terminal/launchers/mqlaunch.sh` into dedicated libraries sourced back into the launcher's scope — the network concern (status/diagnostics/connectivity, 17 functions → `mqlaunch/lib/network.sh`), the fzf interactive pickers (git log/branch, kill process/port, run snippet, recent files, 6 functions → - `mqlaunch/lib/fzf-pickers.sh`), and diagnostics (version reporting, - self-check, debug bundle, release notes, plus the system check, 6 functions → - `mqlaunch/lib/diagnostics.sh`). No behavior change; the launcher drops ~530 - lines and each concern now has a named owner. Guarded by + `mqlaunch/lib/fzf-pickers.sh`), diagnostics (version reporting, self-check, + debug bundle, release notes, plus the system check, 6 functions → + `mqlaunch/lib/diagnostics.sh`), and the git & release menu launchers + (2 functions → `mqlaunch/lib/git-menus.sh`). No behavior change; the launcher + drops ~600 lines and each concern now has a named owner. Guarded by `tests/monolith-delayer-smoke.sh`, a table-driven check that fails if any extracted function is redefined in the monolith or a lib source is dropped. * `semantic-memory-maintainer` renamed to `vector-store-maintainer` to avoid diff --git a/docs/AUTHORITY_MAP.md b/docs/AUTHORITY_MAP.md index 28343c9..8ec9b94 100644 --- a/docs/AUTHORITY_MAP.md +++ b/docs/AUTHORITY_MAP.md @@ -73,6 +73,7 @@ Reached through other live paths: | `mqlaunch/lib/network.sh` | `terminal/launchers/mqlaunch.sh` (sourced) — network concern de-layered out of the monolith (Step 11a) | | `mqlaunch/lib/fzf-pickers.sh` | `terminal/launchers/mqlaunch.sh` (sourced) — fzf interactive pickers de-layered out of the monolith (Step 11a) | | `mqlaunch/lib/diagnostics.sh` | `terminal/launchers/mqlaunch.sh` (sourced) — version/self-check/debug-bundle/release-notes/system-check de-layered out of the monolith (Step 11a) | +| `mqlaunch/lib/git-menus.sh` | `terminal/launchers/mqlaunch.sh` (sourced) — git & release menu launchers de-layered out of the monolith (Step 11a) | ## Bridges diff --git a/mqlaunch/lib/git-menus.sh b/mqlaunch/lib/git-menus.sh new file mode 100755 index 0000000..769ed19 --- /dev/null +++ b/mqlaunch/lib/git-menus.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# mqlaunch git & release menu launchers. +# +# Extracted from terminal/launchers/mqlaunch.sh as part of Step 11a (monolith +# de-layering, audit P4). Both functions launch an external menu script +# (gitlaunch.sh / mq-release-menu.sh) and invalidate the cached dashboard header +# on return, since a commit/stash/tag makes the cached Git status stale. Sourced +# into the launcher's scope, so it relies on the launcher's ambient UI helpers +# (print_header/row/empty_row/print_footer/pause_enter) and $BASE_DIR, and on +# mq_dashboard_cache_invalidate / release_menu_loop when present (both guarded +# with command -v). No behavior change — the functions are verbatim moves. Pure +# bash, so it carries a bash shebang and is covered by shellcheck. + +# Opens git menu. +open_git_menu() { + local repo_arg="${1:-}" + local git_script="$BASE_DIR/terminal/launchers/gitlaunch.sh" + local git_path="" back_marker restart_count + + if [[ -n "$repo_arg" ]]; then + git_path="$repo_arg" + else + git_path="$(pwd)" + fi + + if [[ ! -x "$git_script" && ! -f "$git_script" ]]; then + print_header + row "GIT MENU" + empty_row + row "Git menu not found:" + row " $git_script" + print_footer + pause_enter + return + fi + + back_marker="/tmp/mq-gitlaunch-back.$$" + restart_count=0 + + while true; do + rm -f "$back_marker" 2>/dev/null || true + + if [[ -x "$git_script" ]]; then + MQ_GIT_REPO="$git_path" MQ_GITLAUNCH_BACK_MARKER="$back_marker" "$git_script" + else + MQ_GIT_REPO="$git_path" MQ_GITLAUNCH_BACK_MARKER="$back_marker" zsh "$git_script" + fi + + [[ -f "$back_marker" ]] && break + + restart_count=$(( restart_count + 1 )) + if [[ "$restart_count" -ge 5 ]]; then + printf "Gitlaunch exited unexpectedly %d times; returning to mqlaunch.\n" "$restart_count" + sleep 1 + break + fi + done + + rm -f "$back_marker" 2>/dev/null || true + + # The git menu can commit/stash, so the cached dashboard header is now stale. + # Drop it so the main loop re-renders fresh Git status instead of waiting out + # the cache TTL. + command -v mq_dashboard_cache_invalidate >/dev/null 2>&1 && mq_dashboard_cache_invalidate +} + +# Opens release menu. +open_release_menu() { + local release_menu="$BASE_DIR/terminal/menus/mq-release-menu.sh" + + if command -v release_menu_loop >/dev/null 2>&1; then + MQ_USE_DASHBOARD_HEADER=1 release_menu_loop + elif [[ -x "$release_menu" ]]; then + MQ_USE_DASHBOARD_HEADER=1 "$release_menu" menu + elif [[ -f "$release_menu" ]]; then + chmod +x "$release_menu" 2>/dev/null || true + MQ_USE_DASHBOARD_HEADER=1 bash "$release_menu" menu + else + print_header + row "RELEASE MENU" + empty_row + row "Release menu not found:" + row " $release_menu" + print_footer + pause_enter + fi + + # The release flow can commit/tag, so invalidate the cached dashboard header + # before returning to the main loop. + command -v mq_dashboard_cache_invalidate >/dev/null 2>&1 && mq_dashboard_cache_invalidate +} diff --git a/terminal/launchers/mqlaunch.sh b/terminal/launchers/mqlaunch.sh index 487f211..f20d4c4 100755 --- a/terminal/launchers/mqlaunch.sh +++ b/terminal/launchers/mqlaunch.sh @@ -886,84 +886,15 @@ theme_source_state() { fi } -# Opens git menu. -open_git_menu() { - local repo_arg="${1:-}" - local git_script="$BASE_DIR/terminal/launchers/gitlaunch.sh" - local git_path="" back_marker restart_count - - if [[ -n "$repo_arg" ]]; then - git_path="$repo_arg" - else - git_path="$(pwd)" - fi - - if [[ ! -x "$git_script" && ! -f "$git_script" ]]; then - print_header - row "GIT MENU" - empty_row - row "Git menu not found:" - row " $git_script" - print_footer - pause_enter - return - fi - - back_marker="/tmp/mq-gitlaunch-back.$$" - restart_count=0 - - while true; do - rm -f "$back_marker" 2>/dev/null || true - - if [[ -x "$git_script" ]]; then - MQ_GIT_REPO="$git_path" MQ_GITLAUNCH_BACK_MARKER="$back_marker" "$git_script" - else - MQ_GIT_REPO="$git_path" MQ_GITLAUNCH_BACK_MARKER="$back_marker" zsh "$git_script" - fi - - [[ -f "$back_marker" ]] && break - - restart_count=$(( restart_count + 1 )) - if [[ "$restart_count" -ge 5 ]]; then - printf "Gitlaunch exited unexpectedly %d times; returning to mqlaunch.\n" "$restart_count" - sleep 1 - break - fi - done - - rm -f "$back_marker" 2>/dev/null || true - - # The git menu can commit/stash, so the cached dashboard header is now stale. - # Drop it so the main loop re-renders fresh Git status instead of waiting out - # the cache TTL. - command -v mq_dashboard_cache_invalidate >/dev/null 2>&1 && mq_dashboard_cache_invalidate -} - -# Opens release menu. -open_release_menu() { - local release_menu="$BASE_DIR/terminal/menus/mq-release-menu.sh" - - if command -v release_menu_loop >/dev/null 2>&1; then - MQ_USE_DASHBOARD_HEADER=1 release_menu_loop - elif [[ -x "$release_menu" ]]; then - MQ_USE_DASHBOARD_HEADER=1 "$release_menu" menu - elif [[ -f "$release_menu" ]]; then - chmod +x "$release_menu" 2>/dev/null || true - MQ_USE_DASHBOARD_HEADER=1 bash "$release_menu" menu - else - print_header - row "RELEASE MENU" - empty_row - row "Release menu not found:" - row " $release_menu" - print_footer - pause_enter - fi - - # The release flow can commit/tag, so invalidate the cached dashboard header - # before returning to the main loop. - command -v mq_dashboard_cache_invalidate >/dev/null 2>&1 && mq_dashboard_cache_invalidate -} +# Git & release menu launchers live in a dedicated library (Step 11a monolith +# de-layering, audit P4). Sourced into this scope so they keep using the ambient +# UI helpers and $BASE_DIR; no behavior change — the functions are verbatim +# moves. +if [[ -f "$BASE_DIR/mqlaunch/lib/git-menus.sh" ]]; then + source "$BASE_DIR/mqlaunch/lib/git-menus.sh" +else + mq_debug "mqlaunch: git menus lib missing: mqlaunch/lib/git-menus.sh" +fi # Runs mqworkflows. run_mqworkflows() { diff --git a/tests/dashboard-header-cache-smoke.sh b/tests/dashboard-header-cache-smoke.sh index 0777e54..105dc9e 100755 --- a/tests/dashboard-header-cache-smoke.sh +++ b/tests/dashboard-header-cache-smoke.sh @@ -64,10 +64,12 @@ pass "MQ_DASHBOARD_CACHE_TTL=0 disables caching" # 5. The mutating sub-menus invalidate the cache on the way back to the main # loop, so a commit/stash/tag is reflected immediately rather than after the TTL. -LAUNCHER="$ROOT/terminal/launchers/mqlaunch.sh" -awk '/^open_git_menu\(\)/{f=1} f&&/mq_dashboard_cache_invalidate/{print; exit}' "$LAUNCHER" \ +# open_git_menu / open_release_menu were de-layered into mqlaunch/lib/git-menus.sh +# (Step 11a); the contract is unchanged, only the file that owns it. +GIT_MENUS="$ROOT/mqlaunch/lib/git-menus.sh" +awk '/^open_git_menu\(\)/{f=1} f&&/mq_dashboard_cache_invalidate/{print; exit}' "$GIT_MENUS" \ | grep -q mq_dashboard_cache_invalidate || fail "open_git_menu does not invalidate the cache on Back" -awk '/^open_release_menu\(\)/{f=1} f&&/mq_dashboard_cache_invalidate/{print; exit}' "$LAUNCHER" \ +awk '/^open_release_menu\(\)/{f=1} f&&/mq_dashboard_cache_invalidate/{print; exit}' "$GIT_MENUS" \ | grep -q mq_dashboard_cache_invalidate || fail "open_release_menu does not invalidate the cache on Back" pass "git and release menus invalidate the cache on return" diff --git a/tests/monolith-delayer-smoke.sh b/tests/monolith-delayer-smoke.sh index 7caa5ff..de55615 100755 --- a/tests/monolith-delayer-smoke.sh +++ b/tests/monolith-delayer-smoke.sh @@ -17,6 +17,7 @@ CONCERNS=( "mqlaunch/lib/network.sh : network_default_interface network_service_name network_interface_ip network_dns_server network_gateway network_ssid network_ping_ms network_value network_report copy_network_info open_network_settings ping_test show_dns_gateway run_network_pulse run_network_ghost run_network_quality show_network_info" "mqlaunch/lib/fzf-pickers.sh : fzf_git_log fzf_git_branch fzf_kill_process fzf_kill_port fzf_run_snippet fzf_recent_files" "mqlaunch/lib/diagnostics.sh : get_repo_version show_version_info run_self_check run_debug_bundle show_release_notes system_check" + "mqlaunch/lib/git-menus.sh : open_git_menu open_release_menu" ) total=0 diff --git a/tools/scripts/test-mqlaunch.sh b/tools/scripts/test-mqlaunch.sh index fc94d2c..27167b7 100755 --- a/tools/scripts/test-mqlaunch.sh +++ b/tools/scripts/test-mqlaunch.sh @@ -61,7 +61,7 @@ assert_grep 'dev\).*open_dev_menu' "$LEGACY" "Dev route exists in launcher" assert_grep 'tools\) open_tools_menu' "$LEGACY" "Tools route exists in launcher" assert_grep 'restart\|reload\|relaunch\).*restart_mqlaunch' "$LEGACY" "mqlaunch restart route exists" assert_grep 'tools-menu\|toolsmenu\|menu-tools\|tools-v1\|menu-tools-v1\)' "$LEGACY" "Legacy Tools aliases still exist" -assert_grep 'terminal/launchers/gitlaunch\.sh' "$LEGACY" "Git route uses gitlaunch" +assert_grep 'terminal/launchers/gitlaunch\.sh' "$PROJECT_ROOT/mqlaunch/lib/git-menus.sh" "Git route uses gitlaunch" assert_grep 'RELEASE_SCRIPT="\$RELEASE_REPO/release\.sh"' "$RELEASE_MENU" "Release menu points at root release script" assert_grep 'render_main_menu_panel' "$PROJECT_ROOT/terminal/menus/mq-main-menu.sh" "Main menu panel exists"