From b8fd73cf5b079fecbd4c06f26222327ff5e18e3d Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 24 Mar 2026 16:01:14 +0000 Subject: [PATCH] Prefer managed runtime controls in launchd helper --- .../subsystems/deployment-installability.md | 6 +++ scripts/dev-launchd-setup.sh | 21 ++++++--- scripts/tests/test-hot-dev-bg.sh | 45 +++++++++++++++++++ 3 files changed, 66 insertions(+), 6 deletions(-) diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index 642722134..043586078 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -216,6 +216,12 @@ may not boot a separate legacy foreground runtime beside the managed dev stack: generated `com.pulse.hot-dev` LaunchAgent template must supervise the same managed `hot-dev-bg` control plane, so login-time auto-start, crash restart, and takeover diagnostics all operate on one runtime model. +That same launchd helper must also advertise the canonical managed runtime +controls as its primary operator surface. After installation it should point +developers back to the browser entrypoint on `http://127.0.0.1:5173` and the +repo-root `npm run dev`, `npm run dev:restart`, `npm run dev:status`, and +`npm run dev:logs` commands for daily use, while keeping raw `launchctl` +commands clearly secondary as LaunchAgent maintenance operations. That shared `scripts/install.sh` boundary must also keep one canonical service argument builder for the runtime flags it persists. Token-bearing install paths, token-file systemd paths, wrapper-script launches, and later service diff --git a/scripts/dev-launchd-setup.sh b/scripts/dev-launchd-setup.sh index e4d944210..8f4469a8b 100755 --- a/scripts/dev-launchd-setup.sh +++ b/scripts/dev-launchd-setup.sh @@ -93,12 +93,21 @@ install() { log_info "" log_info "The managed dev runtime will now auto-start on login and auto-restart on crash." log_info "" - log_info "Useful commands:" - log_info " Restart: launchctl kickstart -k ${GUI_DOMAIN}/${LABEL}" - log_info " Stop: launchctl kill SIGTERM ${GUI_DOMAIN}/${LABEL}" - log_info " Status: launchctl print ${GUI_DOMAIN}/${LABEL}" - log_info " Logs: tail -f ${LOG_DIR}/hot-dev.stderr.log" - log_info " Runtime: cd ${ROOT_DIR} && ./scripts/hot-dev-bg.sh status" + log_info "Browser entrypoint:" + log_info " http://127.0.0.1:5173" + log_info "" + log_info "Daily runtime commands:" + log_info " Start/repair: cd ${ROOT_DIR} && npm run dev" + log_info " Restart: cd ${ROOT_DIR} && npm run dev:restart" + log_info " Stop: cd ${ROOT_DIR} && npm run dev:stop" + log_info " Status: cd ${ROOT_DIR} && npm run dev:status" + log_info " Logs: cd ${ROOT_DIR} && npm run dev:logs" + log_info "" + log_info "LaunchAgent maintenance:" + log_info " Restart agent: launchctl kickstart -k ${GUI_DOMAIN}/${LABEL}" + log_info " Stop agent: launchctl kill SIGTERM ${GUI_DOMAIN}/${LABEL}" + log_info " Agent status: launchctl print ${GUI_DOMAIN}/${LABEL}" + log_info " Agent logs: tail -f ${LOG_DIR}/hot-dev.stderr.log" log_info " Disable: launchctl bootout ${GUI_DOMAIN}/${LABEL}" log_info " Remove: $0 uninstall" } diff --git a/scripts/tests/test-hot-dev-bg.sh b/scripts/tests/test-hot-dev-bg.sh index 7840f8e31..9c313d6a4 100755 --- a/scripts/tests/test-hot-dev-bg.sh +++ b/scripts/tests/test-hot-dev-bg.sh @@ -11,6 +11,7 @@ DEV_CHECK="${ROOT_DIR}/scripts/dev-check.sh" PACKAGE_JSON="${ROOT_DIR}/package.json" FRONTEND_PACKAGE_JSON="${ROOT_DIR}/frontend-modern/package.json" DEV_LAUNCHD_WRAPPER="${ROOT_DIR}/scripts/dev-launchd-wrapper.sh" +DEV_LAUNCHD_SETUP="${ROOT_DIR}/scripts/dev-launchd-setup.sh" if [[ ! -x "${HOT_DEV_BG}" ]]; then echo "hot-dev-bg.sh not found or not executable at ${HOT_DEV_BG}" >&2 @@ -181,6 +182,49 @@ test_launchd_wrapper_uses_managed_supervisor() { assert_contains "launchd wrapper uses managed launchd-session" "${output}" "scripts/hot-dev-bg.sh launchd-session --takeover" } +test_launchd_setup_advertises_managed_runtime_controls() { + local test_dir fake_bin output + test_dir="$(mktemp -d)" + temp_dirs+=("${test_dir}") + fake_bin="${test_dir}/bin" + mkdir -p "${fake_bin}" + + cat > "${fake_bin}/launchctl" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +case "${1:-}" in + bootout) + exit 0 + ;; + bootstrap) + exit 0 + ;; + print) + echo "pid = 4242" + exit 0 + ;; + *) + echo "unexpected launchctl command: $*" >&2 + exit 1 + ;; +esac +EOF + chmod +x "${fake_bin}/launchctl" + + output="$( + PATH="${fake_bin}:$PATH" \ + HOME="${test_dir}/home" \ + "${DEV_LAUNCHD_SETUP}" install + )" + + assert_contains "launchd setup shows browser entrypoint" "${output}" "http://127.0.0.1:5173" + assert_contains "launchd setup shows managed start command" "${output}" "npm run dev" + assert_contains "launchd setup shows managed restart command" "${output}" "npm run dev:restart" + assert_contains "launchd setup shows managed status command" "${output}" "npm run dev:status" + assert_contains "launchd setup shows managed logs command" "${output}" "npm run dev:logs" + assert_contains "launchd setup keeps launchctl maintenance commands" "${output}" "launchctl kickstart -k" +} + test_root_package_exposes_managed_runtime_entrypoints() { local output output="$( @@ -478,6 +522,7 @@ main() { test_verify_command_injects_managed_runtime_env test_launchd_session_supervises_managed_runtime test_launchd_wrapper_uses_managed_supervisor + test_launchd_setup_advertises_managed_runtime_controls test_root_package_exposes_managed_runtime_entrypoints test_frontend_package_exposes_managed_runtime_entrypoints test_clean_mock_alerts_prefers_managed_runtime