feat(daemon): launchd plist + install/uninstall 脚本(tsk_nqvOyIZkd1Dn)

提供三个文件让 maestrod 作为 macOS User Agent 开机自启、崩溃自拉:

- scripts/com.maestro.maestrod.plist  — launchd plist 模板
    KeepAlive=true(崩溃自拉)、RunAtLoad=true(登录即启)
    stdout+stderr 统一写入 ~/.maestro/maestrod.log
    ThrottleInterval=10s 防崩溃风暴;ProcessType=Background
    占位符:__NODE__ / __PROJ_DIR__ / __HOME__ / __PATH__

- scripts/install-daemon.sh  — 安装脚本
    1. 检测 node(>= 20)
    2. npm run build 构建项目
    3. sed 替换占位符,生成真实 plist 并用 plutil 校验
    4. launchctl bootstrap gui/$UID(回退 load -w)加载服务

- scripts/uninstall-daemon.sh  — 卸载脚本
    launchctl bootout / unload -w 卸载,删除 plist

shellcheck 通过(两个脚本);现有 77 个单元测试全部通过。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-06-13 09:24:04 +08:00
parent fcca3f95e0
commit 2c4140a1a2
3 changed files with 230 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# uninstall-daemon.sh — 卸载 maestrod launchd 用户 Agent
#
# 功能:
# 1. 停止并卸载 launchd 服务
# 2. 删除 ~/Library/LaunchAgents/com.maestro.maestrod.plist
#
# 注意:数据目录 ~/.maestro(SQLite 数据库、日志)不会被删除,需手动清理。
#
# 用法:
# bash scripts/uninstall-daemon.sh
set -euo pipefail
LABEL="com.maestro.maestrod"
PLIST_DEST="${HOME}/Library/LaunchAgents/${LABEL}.plist"
echo "==> 卸载 maestrod (${LABEL})…"
# ── 1. 停止并卸载服务 ─────────────────────────────────────────
if launchctl list 2>/dev/null | grep -qF "${LABEL}"; then
echo " 服务运行中,正在停止…"
# 优先使用 bootoutmacOS 10.11+ 推荐),失败则回退 unload
if launchctl bootout "gui/${UID}" "${PLIST_DEST}" 2>/dev/null; then
echo " 已通过 bootout 卸载"
elif launchctl unload -w "${PLIST_DEST}" 2>/dev/null; then
echo " 已通过 unload 卸载"
else
echo "警告:无法正常卸载服务,将继续删除 plist 文件" >&2
fi
else
echo " 服务未加载,跳过停止步骤"
fi
# ── 2. 删除 plist ─────────────────────────────────────────────
if [[ -f "${PLIST_DEST}" ]]; then
rm -f "${PLIST_DEST}"
echo " 已删除: ${PLIST_DEST}"
else
echo " plist 不存在,跳过删除"
fi
echo ""
echo "✅ maestrod 已卸载"
echo ""
echo " 注意:数据目录 ${HOME}/.maestro 未被删除(保留数据库和日志)。"
echo " 如需彻底清除:rm -rf ${HOME}/.maestro"