im_wower
·
2026-03-26
start-launchd.sh
1#!/usr/bin/env bash
2set -euo pipefail
3
4SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
5# shellcheck source=./common.sh
6source "${SCRIPT_DIR}/common.sh"
7
8usage() {
9 cat <<'EOF'
10Usage:
11 scripts/runtime/start-launchd.sh [options]
12
13Options:
14 --scope agent|daemon launchd domain type. Defaults to agent.
15 --service NAME Add one service to the start set. Repeatable.
16 --all-services Start conductor, codexd, worker-runner, and status-api.
17 --home-dir PATH Used only to derive the default LaunchAgents path.
18 --install-dir PATH Override launchd install directory.
19 --domain TARGET Override launchctl domain target. Defaults to gui/<uid> or system.
20 --dry-run Print launchctl commands instead of executing them.
21 --help Show this help text.
22
23Notes:
24 If no service is specified, conductor + codexd are started.
25 Use --service status-api to start the optional local read-only observer.
26EOF
27}
28
29require_command launchctl
30require_command plutil
31
32scope="agent"
33home_dir="$(default_home_dir)"
34install_dir=""
35domain_target=""
36dry_run="0"
37services=()
38
39while [[ $# -gt 0 ]]; do
40 case "$1" in
41 --scope)
42 scope="$2"
43 shift 2
44 ;;
45 --service)
46 validate_service "$2"
47 if ! contains_value "$2" "${services[@]-}"; then
48 services+=("$2")
49 fi
50 shift 2
51 ;;
52 --all-services)
53 while IFS= read -r service; do
54 if ! contains_value "$service" "${services[@]-}"; then
55 services+=("$service")
56 fi
57 done < <(all_services)
58 shift
59 ;;
60 --home-dir)
61 home_dir="$2"
62 shift 2
63 ;;
64 --install-dir)
65 install_dir="$2"
66 shift 2
67 ;;
68 --domain)
69 domain_target="$2"
70 shift 2
71 ;;
72 --dry-run)
73 dry_run="1"
74 shift
75 ;;
76 --help)
77 usage
78 exit 0
79 ;;
80 *)
81 die "Unknown option: $1"
82 ;;
83 esac
84done
85
86validate_scope "$scope"
87
88if [[ "${#services[@]}" -eq 0 ]]; then
89 while IFS= read -r service; do
90 services+=("$service")
91 done < <(default_node_verification_services)
92fi
93
94if [[ -z "$install_dir" ]]; then
95 install_dir="$(default_install_dir "$scope" "$home_dir")"
96fi
97
98if [[ -z "$domain_target" ]]; then
99 domain_target="$(default_domain_target "$scope")"
100fi
101
102service_is_loaded() {
103 launchctl print "${domain_target}/$(service_label "$1")" >/dev/null 2>&1
104}
105
106for service in "${services[@]}"; do
107 plist_path="$(service_install_path "$install_dir" "$service")"
108 assert_file "$plist_path"
109 plutil -lint "$plist_path" >/dev/null
110
111 if service_is_loaded "$service"; then
112 runtime_log "${service} already loaded"
113 continue
114 fi
115
116 run_or_print "$dry_run" launchctl bootstrap "$domain_target" "$plist_path"
117 run_or_print "$dry_run" launchctl kickstart -k "${domain_target}/$(service_label "$service")"
118done
119
120runtime_log "launchd start completed for ${domain_target}"