@geekbeer/minion 2.70.2 → 3.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,8 +4,8 @@
4
4
  # CLI tool for interacting with and setting up the minion agent
5
5
  #
6
6
  # Usage:
7
- # sudo minion-cli setup [options] # Set up minion agent service (root)
8
- # sudo minion-cli reconfigure [options] # Re-register with new HQ credentials (root)
7
+ # sudo minion-cli setup --user <USERNAME> # Install software & register services (root)
8
+ # sudo minion-cli configure [options] # Connect to HQ, deploy skills, start services (root)
9
9
  # sudo minion-cli uninstall [--keep-data] # Remove agent and services (root)
10
10
  # sudo minion-cli start # Start agent service (root)
11
11
  # sudo minion-cli stop # Stop agent service (root)
@@ -19,10 +19,12 @@
19
19
  #
20
20
  # Setup options:
21
21
  # --user <USERNAME> Target user for the agent (required when running as root)
22
- # --hq-url <URL> HQ server URL (optional, omit for standalone mode)
23
- # --minion-id <UUID> Minion ID (optional)
24
- # --api-token <TOKEN> API token (optional)
25
- # --setup-tunnel Set up cloudflared tunnel (requires --hq-url and --api-token)
22
+ #
23
+ # Configure options:
24
+ # --hq-url <URL> HQ server URL (required)
25
+ # --minion-id <UUID> Minion ID (required)
26
+ # --api-token <TOKEN> API token (required)
27
+ # --setup-tunnel Set up cloudflared tunnel
26
28
 
27
29
  set -euo pipefail
28
30
 
@@ -129,12 +131,7 @@ fi
129
131
  # setup subcommand
130
132
  # ============================================================
131
133
  do_setup() {
132
- local HQ_URL=""
133
- local MINION_ID=""
134
- local API_TOKEN=""
135
134
  local CLI_USER=""
136
- local SETUP_TUNNEL=false
137
- local ARGS_PROVIDED=false
138
135
 
139
136
  # Parse arguments
140
137
  while [[ $# -gt 0 ]]; do
@@ -143,32 +140,13 @@ do_setup() {
143
140
  CLI_USER="$2"
144
141
  shift 2
145
142
  ;;
146
- --hq-url)
147
- HQ_URL="$2"
148
- ARGS_PROVIDED=true
149
- shift 2
150
- ;;
151
- --minion-id)
152
- MINION_ID="$2"
153
- ARGS_PROVIDED=true
154
- shift 2
155
- ;;
156
- --api-token)
157
- API_TOKEN="$2"
158
- ARGS_PROVIDED=true
159
- shift 2
160
- ;;
161
- --setup-tunnel)
162
- SETUP_TUNNEL=true
163
- shift
164
- ;;
165
143
  --non-interactive)
166
144
  # Accepted for cloud-init compatibility (setup is always non-interactive)
167
145
  shift
168
146
  ;;
169
147
  *)
170
148
  echo "Unknown option: $1"
171
- echo "Usage: minion-cli setup --user <USERNAME> [--hq-url <URL>] [--minion-id <UUID>] [--api-token <TOKEN>] [--setup-tunnel]"
149
+ echo "Usage: sudo minion-cli setup --user <USERNAME>"
172
150
  exit 1
173
151
  ;;
174
152
  esac
@@ -209,38 +187,13 @@ do_setup() {
209
187
  fi
210
188
  # Non-root case: TARGET_USER is already set to $(whoami)
211
189
 
212
- # Preserve existing .env values if no arguments were provided (redeploy scenario)
213
- if [ "$ARGS_PROVIDED" = false ] && [ -f /opt/minion-agent/.env ]; then
214
- echo "Reading existing .env values (redeploy mode)..."
215
- while IFS='=' read -r key value; do
216
- [[ -z "$key" || "$key" == \#* ]] && continue
217
- case "$key" in
218
- HQ_URL) [ -z "$HQ_URL" ] && HQ_URL="$value" ;;
219
- MINION_ID) [ -z "$MINION_ID" ] && MINION_ID="$value" ;;
220
- API_TOKEN) [ -z "$API_TOKEN" ] && API_TOKEN="$value" ;;
221
- esac
222
- done < /opt/minion-agent/.env
223
- fi
224
-
225
190
  echo "========================================="
226
191
  echo " @geekbeer/minion Setup"
227
192
  echo "========================================="
228
193
  echo "User: $TARGET_USER ($TARGET_HOME)"
229
-
230
- if [ -n "$HQ_URL" ]; then
231
- echo "Mode: Connected to HQ ($HQ_URL)"
232
- else
233
- echo "Mode: Standalone (no HQ connection)"
234
- fi
235
- if [ "$SETUP_TUNNEL" = true ]; then
236
- echo "Tunnel: Enabled"
237
- fi
238
194
  echo ""
239
195
 
240
196
  local TOTAL_STEPS=9
241
- if [ "$SETUP_TUNNEL" = true ]; then
242
- TOTAL_STEPS=10
243
- fi
244
197
 
245
198
  # Step 1: Install Claude Code
246
199
  echo "[1/${TOTAL_STEPS}] Installing Claude Code..."
@@ -289,30 +242,23 @@ do_setup() {
289
242
  $SUDO chown "${TARGET_USER}:${TARGET_USER}" /opt/minion-agent 2>/dev/null || true
290
243
  echo " -> /opt/minion-agent/ created"
291
244
 
292
- # Step 4: Generate .env file
245
+ # Step 4: Generate default .env file (HQ credentials set later via 'configure')
293
246
  echo "[4/${TOTAL_STEPS}] Generating .env file..."
294
- local ENV_CONTENT=""
295
- ENV_CONTENT+="# Minion Agent Configuration\n"
296
- ENV_CONTENT+="# Generated by minion-cli setup\n\n"
297
-
298
- if [ -n "$HQ_URL" ]; then
299
- ENV_CONTENT+="HQ_URL=${HQ_URL}\n"
300
- fi
301
- if [ -n "$API_TOKEN" ]; then
302
- ENV_CONTENT+="API_TOKEN=${API_TOKEN}\n"
303
- fi
304
- if [ -n "$MINION_ID" ]; then
305
- ENV_CONTENT+="MINION_ID=${MINION_ID}\n"
247
+ if [ ! -f /opt/minion-agent/.env ]; then
248
+ local ENV_CONTENT=""
249
+ ENV_CONTENT+="# Minion Agent Configuration\n"
250
+ ENV_CONTENT+="# Generated by minion-cli setup\n\n"
251
+ ENV_CONTENT+="AGENT_PORT=8080\n"
252
+ ENV_CONTENT+="MINION_USER=${TARGET_USER}\n"
253
+ ENV_CONTENT+="REFLECTION_TIME=03:00\n"
254
+
255
+ echo -e "$ENV_CONTENT" | $SUDO tee /opt/minion-agent/.env > /dev/null
256
+ $SUDO chown "${TARGET_USER}:${TARGET_USER}" /opt/minion-agent/.env
257
+ echo " -> /opt/minion-agent/.env created (run 'configure' to set HQ credentials)"
258
+ else
259
+ echo " -> /opt/minion-agent/.env already exists, preserving"
306
260
  fi
307
261
 
308
- ENV_CONTENT+="AGENT_PORT=8080\n"
309
- ENV_CONTENT+="MINION_USER=${TARGET_USER}\n"
310
- ENV_CONTENT+="REFLECTION_TIME=03:00\n"
311
-
312
- echo -e "$ENV_CONTENT" | $SUDO tee /opt/minion-agent/.env > /dev/null
313
- $SUDO chown "${TARGET_USER}:${TARGET_USER}" /opt/minion-agent/.env
314
- echo " -> /opt/minion-agent/.env generated"
315
-
316
262
  # Step 5: Configure sudoers for agent user
317
263
  echo "[5/${TOTAL_STEPS}] Configuring sudoers for agent user..."
318
264
  if [ "$TARGET_USER" != "root" ]; then
@@ -682,147 +628,20 @@ SUPEOF
682
628
  fi
683
629
  fi
684
630
 
685
- # Step 10 (optional): Cloudflare Tunnel setup
686
- if [ "$SETUP_TUNNEL" = true ]; then
687
- echo ""
688
- echo "[10/${TOTAL_STEPS}] Setting up Cloudflare Tunnel..."
689
-
690
- if [ -z "$HQ_URL" ] || [ -z "$API_TOKEN" ]; then
691
- echo " ERROR: --setup-tunnel requires --hq-url and --api-token"
692
- exit 1
693
- fi
694
-
695
- # Install cloudflared if not present (architecture-aware)
696
- if ! command -v cloudflared &>/dev/null; then
697
- echo " Installing cloudflared..."
698
- local CF_ARCH
699
- CF_ARCH=$(dpkg --print-architecture 2>/dev/null || echo "amd64")
700
- curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${CF_ARCH}.deb" \
701
- -o /tmp/cloudflared.deb
702
- $SUDO dpkg -i /tmp/cloudflared.deb
703
- rm -f /tmp/cloudflared.deb
704
- else
705
- echo " -> cloudflared already installed"
706
- fi
707
-
708
- # Fetch tunnel config from HQ API
709
- # Response contains credentials_json and config_yml (generated server-side)
710
- echo " Fetching tunnel configuration from HQ..."
711
- local TUNNEL_DATA
712
- TUNNEL_DATA=$(curl -sfL -H "Authorization: Bearer ${API_TOKEN}" \
713
- "${HQ_URL}/api/minion/tunnel-credentials" 2>&1) || true
714
-
715
- if [ -z "$TUNNEL_DATA" ] || ! echo "$TUNNEL_DATA" | jq -e '.tunnel_id' > /dev/null 2>&1; then
716
- echo " ERROR: Failed to fetch tunnel credentials from HQ"
717
- echo " Tunnel may not be configured for this minion yet"
718
- echo " Skipping tunnel setup (agent is running without tunnel)"
719
- else
720
- local TUNNEL_ID CREDS_JSON CONFIG_YML
721
- TUNNEL_ID=$(echo "$TUNNEL_DATA" | jq -r '.tunnel_id')
722
- CREDS_JSON=$(echo "$TUNNEL_DATA" | jq -r '.credentials_json')
723
- CONFIG_YML=$(echo "$TUNNEL_DATA" | jq -r '.config_yml')
724
-
725
- # Save credentials file (content from HQ, saved as-is)
726
- $SUDO mkdir -p /etc/cloudflared
727
- echo "$CREDS_JSON" | $SUDO tee "/etc/cloudflared/${TUNNEL_ID}.json" > /dev/null
728
- $SUDO chmod 600 "/etc/cloudflared/${TUNNEL_ID}.json"
729
- $SUDO chown root:root "/etc/cloudflared/${TUNNEL_ID}.json"
730
- echo " -> /etc/cloudflared/${TUNNEL_ID}.json saved"
731
-
732
- # Save config file (content from HQ, saved as-is)
733
- echo "$CONFIG_YML" | $SUDO tee /etc/cloudflared/config.yml > /dev/null
734
- echo " -> /etc/cloudflared/config.yml saved"
735
-
736
- # Install and start cloudflared service (process-manager aware)
737
- case "$PROC_MGR" in
738
- systemd)
739
- $SUDO cloudflared service install 2>/dev/null || true
740
- $SUDO systemctl enable cloudflared 2>/dev/null || true
741
- $SUDO systemctl start cloudflared 2>/dev/null || true
742
- ;;
743
- supervisord)
744
- # Create supervisord config for cloudflared
745
- $SUDO tee /etc/supervisor/conf.d/cloudflared.conf > /dev/null <<CFEOF
746
- [program:cloudflared]
747
- command=/usr/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run
748
- autorestart=true
749
- priority=150
750
- startsecs=5
751
- stdout_logfile=/var/log/supervisor/cloudflared.log
752
- stderr_logfile=/var/log/supervisor/cloudflared.log
753
- CFEOF
754
- # Reload supervisord if running
755
- if $SUDO supervisorctl status &>/dev/null; then
756
- $SUDO supervisorctl reread
757
- $SUDO supervisorctl update
758
- fi
759
- ;;
760
- *)
761
- echo " WARNING: No supported process manager for cloudflared"
762
- echo " You may need to start cloudflared manually:"
763
- echo " cloudflared tunnel --config /etc/cloudflared/config.yml run"
764
- ;;
765
- esac
766
- echo " -> cloudflared tunnel configured and started"
767
- fi
768
- fi
769
-
770
- # Notify HQ if configured (after all steps including tunnel setup)
771
- if [ -n "$HQ_URL" ] && [ -n "$API_TOKEN" ]; then
772
- echo ""
773
- echo "Notifying HQ of setup completion..."
774
- local NOTIFY_RESPONSE
775
- local HOSTNAME_VAL
776
- local LAN_IP
777
- HOSTNAME_VAL=$(hostname 2>/dev/null || echo "")
778
- LAN_IP=$(detect_lan_ip)
779
-
780
- # Build request body with LAN IP detection
781
- # Docker: use hostname (container name) for internal_ip_address (resolved via Docker DNS)
782
- # Self-hosted: use LAN IP for both fields (hostname is not resolvable on LAN)
783
- local BODY
784
- if [ -f /.dockerenv ]; then
785
- BODY="{\"internal_ip_address\":\"${HOSTNAME_VAL}\"}"
786
- elif [ -n "$LAN_IP" ]; then
787
- BODY="{\"internal_ip_address\":\"${LAN_IP}\",\"ip_address\":\"${LAN_IP}\"}"
788
- else
789
- BODY="{\"internal_ip_address\":\"${HOSTNAME_VAL}\"}"
790
- fi
791
-
792
- NOTIFY_RESPONSE=$(curl -sfL -X POST "${HQ_URL}/api/minion/setup-complete" \
793
- -H "Content-Type: application/json" \
794
- -H "Authorization: Bearer ${API_TOKEN}" \
795
- -d "$BODY" 2>&1) || true
796
-
797
- if echo "$NOTIFY_RESPONSE" | grep -q '"success":true' 2>/dev/null; then
798
- if [ -n "$LAN_IP" ] && [ ! -f /.dockerenv ]; then
799
- echo " -> HQ notified successfully (LAN IP: ${LAN_IP})"
800
- else
801
- echo " -> HQ notified successfully"
802
- fi
803
- else
804
- echo " -> HQ notification skipped (HQ may not be reachable)"
805
- fi
806
- fi
807
-
808
631
  echo ""
809
632
  echo "========================================="
810
633
  echo " Setup Complete!"
811
634
  echo "========================================="
812
635
  echo ""
813
636
  echo "Agent user: $TARGET_USER"
637
+ echo "Services registered (not yet started)."
638
+ echo ""
639
+ echo "Next step: Connect to HQ:"
640
+ echo " sudo minion-cli configure \\"
641
+ echo " --hq-url <HQ_URL> \\"
642
+ echo " --minion-id <MINION_ID> \\"
643
+ echo " --api-token <API_TOKEN>"
814
644
  echo ""
815
- echo "Useful commands:"
816
- echo " minion-cli status # Agent status"
817
- echo " minion-cli health # Health check"
818
- echo " minion-cli daemons # Daemon status"
819
- echo " sudo minion-cli restart # Restart agent"
820
- echo " sudo minion-cli stop # Stop agent"
821
- if [ "$PROC_MGR" = "systemd" ]; then
822
- echo " journalctl -u minion-agent -f # View logs"
823
- else
824
- echo " tail -f /var/log/supervisor/minion-agent.log # View logs"
825
- fi
826
645
  }
827
646
 
828
647
  # ============================================================
@@ -989,10 +808,11 @@ do_uninstall() {
989
808
  # ============================================================
990
809
  # reconfigure subcommand
991
810
  # ============================================================
992
- do_reconfigure() {
811
+ do_configure() {
993
812
  local HQ_URL=""
994
813
  local MINION_ID=""
995
814
  local API_TOKEN=""
815
+ local SETUP_TUNNEL=false
996
816
 
997
817
  # Parse arguments
998
818
  while [[ $# -gt 0 ]]; do
@@ -1009,9 +829,16 @@ do_reconfigure() {
1009
829
  API_TOKEN="$2"
1010
830
  shift 2
1011
831
  ;;
832
+ --setup-tunnel)
833
+ SETUP_TUNNEL=true
834
+ shift
835
+ ;;
836
+ --non-interactive)
837
+ shift
838
+ ;;
1012
839
  *)
1013
840
  echo "Unknown option: $1"
1014
- echo "Usage: sudo minion-cli reconfigure --hq-url <URL> --minion-id <UUID> --api-token <TOKEN>"
841
+ echo "Usage: sudo minion-cli configure --hq-url <URL> --minion-id <UUID> --api-token <TOKEN> [--setup-tunnel]"
1015
842
  exit 1
1016
843
  ;;
1017
844
  esac
@@ -1020,56 +847,172 @@ do_reconfigure() {
1020
847
  # Validate required arguments
1021
848
  if [ -z "$HQ_URL" ] || [ -z "$MINION_ID" ] || [ -z "$API_TOKEN" ]; then
1022
849
  echo "ERROR: All three options are required: --hq-url, --minion-id, --api-token"
1023
- echo "Usage: sudo minion-cli reconfigure --hq-url <URL> --minion-id <UUID> --api-token <TOKEN>"
850
+ echo "Usage: sudo minion-cli configure --hq-url <URL> --minion-id <UUID> --api-token <TOKEN> [--setup-tunnel]"
1024
851
  exit 1
1025
852
  fi
1026
853
 
1027
- # Check that .env exists (setup must have been run before)
1028
- if [ ! -f /opt/minion-agent/.env ]; then
1029
- echo "ERROR: /opt/minion-agent/.env not found."
1030
- echo "It looks like minion-cli setup has not been run on this server."
1031
- echo "Please run 'sudo minion-cli setup' first for initial installation."
854
+ # Check that setup has been run
855
+ if [ ! -d /opt/minion-agent ]; then
856
+ echo "ERROR: /opt/minion-agent not found."
857
+ echo "Please run 'sudo minion-cli setup --user <USERNAME>' first."
1032
858
  exit 1
1033
859
  fi
1034
860
 
861
+ local TOTAL_STEPS=5
862
+ if [ "$SETUP_TUNNEL" = true ]; then
863
+ TOTAL_STEPS=6
864
+ fi
865
+
1035
866
  echo "========================================="
1036
- echo " @geekbeer/minion Reconfigure"
867
+ echo " @geekbeer/minion Configure"
1037
868
  echo "========================================="
1038
869
  echo "HQ: $HQ_URL"
1039
870
  echo "Minion ID: $MINION_ID"
871
+ if [ "$SETUP_TUNNEL" = true ]; then
872
+ echo "Tunnel: Enabled"
873
+ fi
1040
874
  echo ""
1041
875
 
1042
- # Step 1: Read existing .env and preserve non-credential keys
1043
- echo "[1/4] Updating .env credentials..."
876
+ # Step 1: Write/update .env with HQ credentials
877
+ echo "[1/${TOTAL_STEPS}] Writing .env credentials..."
1044
878
  local ENV_CONTENT=""
1045
879
  ENV_CONTENT+="# Minion Agent Configuration\n"
1046
- ENV_CONTENT+="# Reconfigured by minion-cli reconfigure\n\n"
880
+ ENV_CONTENT+="# Configured by minion-cli configure\n\n"
1047
881
  ENV_CONTENT+="HQ_URL=${HQ_URL}\n"
1048
882
  ENV_CONTENT+="API_TOKEN=${API_TOKEN}\n"
1049
883
  ENV_CONTENT+="MINION_ID=${MINION_ID}\n"
1050
884
 
1051
885
  # Preserve non-credential keys from existing .env
1052
- while IFS='=' read -r key value; do
1053
- [[ -z "$key" || "$key" == \#* ]] && continue
1054
- case "$key" in
1055
- HQ_URL|API_TOKEN|MINION_ID) ;; # Skip — already set above
1056
- *) ENV_CONTENT+="${key}=${value}\n" ;;
1057
- esac
1058
- done < /opt/minion-agent/.env
886
+ if [ -f /opt/minion-agent/.env ]; then
887
+ while IFS='=' read -r key value; do
888
+ [[ -z "$key" || "$key" == \#* ]] && continue
889
+ case "$key" in
890
+ HQ_URL|API_TOKEN|MINION_ID) ;; # Skip — already set above
891
+ *) ENV_CONTENT+="${key}=${value}\n" ;;
892
+ esac
893
+ done < /opt/minion-agent/.env
894
+ fi
1059
895
 
1060
896
  echo -e "$ENV_CONTENT" | $SUDO tee /opt/minion-agent/.env > /dev/null
1061
897
  echo " -> /opt/minion-agent/.env updated"
1062
898
 
1063
- # Step 2: Update process manager config & restart service
1064
- echo "[2/4] Restarting minion-agent service..."
899
+ # Step 2: Deploy bundled skills and rules
900
+ echo "[2/${TOTAL_STEPS}] Deploying bundled assets..."
901
+ local NPM_ROOT
902
+ NPM_ROOT=$(npm root -g 2>/dev/null || echo "")
903
+ local BUNDLED_SKILLS_DIR="${NPM_ROOT}/@geekbeer/minion/skills"
904
+ # Detect target user from .env
905
+ local DEPLOY_USER
906
+ DEPLOY_USER=$(grep '^MINION_USER=' /opt/minion-agent/.env | cut -d= -f2 || echo "")
907
+ local DEPLOY_HOME
908
+ if [ -n "$DEPLOY_USER" ]; then
909
+ DEPLOY_HOME=$(getent passwd "$DEPLOY_USER" | cut -d: -f6 || echo "$HOME")
910
+ else
911
+ DEPLOY_HOME="$HOME"
912
+ fi
913
+ local DEPLOY_AS=""
914
+ if [ "$(id -u)" -eq 0 ] && [ -n "$DEPLOY_USER" ] && [ "$DEPLOY_USER" != "root" ]; then
915
+ DEPLOY_AS="sudo -u $DEPLOY_USER"
916
+ fi
917
+
918
+ local CLAUDE_SKILLS_DIR="${DEPLOY_HOME}/.claude/skills"
919
+ if [ -d "$BUNDLED_SKILLS_DIR" ]; then
920
+ $DEPLOY_AS mkdir -p "$CLAUDE_SKILLS_DIR"
921
+ for skill_dir in "$BUNDLED_SKILLS_DIR"/*/; do
922
+ if [ -d "$skill_dir" ]; then
923
+ local skill_name=$(basename "$skill_dir")
924
+ $DEPLOY_AS cp -r "$skill_dir" "${CLAUDE_SKILLS_DIR}/${skill_name}"
925
+ echo " -> Deployed skill: $skill_name"
926
+ fi
927
+ done
928
+ fi
929
+
930
+ local BUNDLED_RULES_DIR="${NPM_ROOT}/@geekbeer/minion/rules"
931
+ local CLAUDE_RULES_DIR="${DEPLOY_HOME}/.claude/rules"
932
+ if [ -d "$BUNDLED_RULES_DIR" ]; then
933
+ $DEPLOY_AS mkdir -p "$CLAUDE_RULES_DIR"
934
+ $DEPLOY_AS cp "$BUNDLED_RULES_DIR"/core.md "$CLAUDE_RULES_DIR"/core.md
935
+ echo " -> Deployed rules: core.md"
936
+ if [ -f "$CLAUDE_RULES_DIR/minion.md" ]; then
937
+ $DEPLOY_AS rm -f "$CLAUDE_RULES_DIR/minion.md"
938
+ echo " -> Removed legacy rules: minion.md"
939
+ fi
940
+ fi
941
+
942
+ # Step 3 (optional): Cloudflare Tunnel setup
943
+ local CURRENT_STEP=3
944
+ if [ "$SETUP_TUNNEL" = true ]; then
945
+ echo "[${CURRENT_STEP}/${TOTAL_STEPS}] Setting up Cloudflare Tunnel..."
946
+
947
+ # Install cloudflared if not present
948
+ if ! command -v cloudflared &>/dev/null; then
949
+ echo " Installing cloudflared..."
950
+ local CF_ARCH
951
+ CF_ARCH=$(dpkg --print-architecture 2>/dev/null || echo "amd64")
952
+ curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${CF_ARCH}.deb" \
953
+ -o /tmp/cloudflared.deb
954
+ $SUDO dpkg -i /tmp/cloudflared.deb
955
+ rm -f /tmp/cloudflared.deb
956
+ else
957
+ echo " -> cloudflared already installed"
958
+ fi
959
+
960
+ # Fetch tunnel config from HQ API
961
+ echo " Fetching tunnel configuration from HQ..."
962
+ local TUNNEL_DATA
963
+ TUNNEL_DATA=$(curl -sfL -H "Authorization: Bearer ${API_TOKEN}" \
964
+ "${HQ_URL}/api/minion/tunnel-credentials" 2>&1) || true
965
+
966
+ if [ -z "$TUNNEL_DATA" ] || ! echo "$TUNNEL_DATA" | jq -e '.tunnel_id' > /dev/null 2>&1; then
967
+ echo " ERROR: Failed to fetch tunnel credentials from HQ"
968
+ echo " Skipping tunnel setup"
969
+ else
970
+ local TUNNEL_ID CREDS_JSON CONFIG_YML
971
+ TUNNEL_ID=$(echo "$TUNNEL_DATA" | jq -r '.tunnel_id')
972
+ CREDS_JSON=$(echo "$TUNNEL_DATA" | jq -r '.credentials_json')
973
+ CONFIG_YML=$(echo "$TUNNEL_DATA" | jq -r '.config_yml')
974
+
975
+ $SUDO mkdir -p /etc/cloudflared
976
+ echo "$CREDS_JSON" | $SUDO tee "/etc/cloudflared/${TUNNEL_ID}.json" > /dev/null
977
+ $SUDO chmod 600 "/etc/cloudflared/${TUNNEL_ID}.json"
978
+ $SUDO chown root:root "/etc/cloudflared/${TUNNEL_ID}.json"
979
+ echo "$CONFIG_YML" | $SUDO tee /etc/cloudflared/config.yml > /dev/null
980
+
981
+ case "$PROC_MGR" in
982
+ systemd)
983
+ $SUDO cloudflared service install 2>/dev/null || true
984
+ $SUDO systemctl enable cloudflared 2>/dev/null || true
985
+ $SUDO systemctl start cloudflared 2>/dev/null || true
986
+ ;;
987
+ supervisord)
988
+ $SUDO tee /etc/supervisor/conf.d/cloudflared.conf > /dev/null <<CFEOF
989
+ [program:cloudflared]
990
+ command=/usr/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run
991
+ autorestart=true
992
+ priority=150
993
+ startsecs=5
994
+ stdout_logfile=/var/log/supervisor/cloudflared.log
995
+ stderr_logfile=/var/log/supervisor/cloudflared.log
996
+ CFEOF
997
+ if $SUDO supervisorctl status &>/dev/null; then
998
+ $SUDO supervisorctl reread
999
+ $SUDO supervisorctl update
1000
+ fi
1001
+ ;;
1002
+ esac
1003
+ echo " -> cloudflared tunnel configured and started"
1004
+ fi
1005
+ CURRENT_STEP=$((CURRENT_STEP + 1))
1006
+ fi
1007
+
1008
+ # Start/restart services
1009
+ echo "[$(( TOTAL_STEPS - 1 ))/${TOTAL_STEPS}] Starting services..."
1065
1010
  if [ -z "$PROC_MGR" ]; then
1066
1011
  echo " WARNING: No supported process manager found"
1067
- echo " Please restart the minion-agent service manually"
1068
1012
  elif [ "$PROC_MGR" = "supervisord" ]; then
1069
1013
  # supervisord bakes env vars into conf — must regenerate
1070
1014
  local CONF_FILE="/etc/supervisor/conf.d/minion-agent.conf"
1071
1015
  if [ -f "$CONF_FILE" ]; then
1072
- # Read current conf to preserve command, user, and other settings
1073
1016
  local CURRENT_COMMAND
1074
1017
  CURRENT_COMMAND=$(grep '^command=' "$CONF_FILE" | head -1)
1075
1018
  local CURRENT_DIRECTORY
@@ -1077,9 +1020,7 @@ do_reconfigure() {
1077
1020
  local CURRENT_USER_LINE
1078
1021
  CURRENT_USER_LINE=$(grep '^user=' "$CONF_FILE" || echo "")
1079
1022
 
1080
- # Rebuild environment line from updated .env
1081
1023
  local ENV_LINE="environment="
1082
- # Detect home dir for the service user
1083
1024
  local SVC_USER
1084
1025
  SVC_USER=$(echo "$CURRENT_USER_LINE" | sed 's/user=//')
1085
1026
  local SVC_HOME="$HOME"
@@ -1109,15 +1050,14 @@ SUPEOF
1109
1050
  fi
1110
1051
  $SUDO supervisorctl reread > /dev/null 2>&1
1111
1052
  $SUDO supervisorctl update > /dev/null 2>&1
1112
- echo " -> minion-agent restarted (supervisord)"
1053
+ echo " -> minion-agent started (supervisord)"
1113
1054
  else
1114
- # systemd reads .env via EnvironmentFile — just restart
1115
1055
  svc_control restart
1116
- echo " -> minion-agent restarted (systemd)"
1056
+ echo " -> minion-agent started (systemd)"
1117
1057
  fi
1118
1058
 
1119
- # Step 3: Health check
1120
- echo "[3/4] Verifying agent health..."
1059
+ # Health check
1060
+ echo "[${TOTAL_STEPS}/${TOTAL_STEPS}] Verifying agent health..."
1121
1061
  local HEALTH_OK=false
1122
1062
  for i in $(seq 1 5); do
1123
1063
  if curl -sf http://localhost:8080/api/health > /dev/null 2>&1; then
@@ -1133,8 +1073,9 @@ SUPEOF
1133
1073
  echo " Check logs for details"
1134
1074
  fi
1135
1075
 
1136
- # Step 4: Notify HQ (best-effort — heartbeat will also notify automatically)
1137
- echo "[4/4] Notifying HQ..."
1076
+ # Notify HQ
1077
+ echo ""
1078
+ echo "Notifying HQ..."
1138
1079
  local NOTIFY_RESPONSE
1139
1080
  local HOSTNAME_VAL
1140
1081
  local LAN_IP
@@ -1167,8 +1108,19 @@ SUPEOF
1167
1108
 
1168
1109
  echo ""
1169
1110
  echo "========================================="
1170
- echo " Reconfigure Complete!"
1111
+ echo " Configure Complete!"
1171
1112
  echo "========================================="
1113
+ echo ""
1114
+ echo "Useful commands:"
1115
+ echo " minion-cli status # Agent status"
1116
+ echo " minion-cli health # Health check"
1117
+ echo " sudo minion-cli restart # Restart agent"
1118
+ if [ "$PROC_MGR" = "systemd" ]; then
1119
+ echo " journalctl -u minion-agent -f # View logs"
1120
+ else
1121
+ echo " tail -f /var/log/supervisor/minion-agent.log # View logs"
1122
+ fi
1123
+ }
1172
1124
  echo ""
1173
1125
  echo "The minion should appear online in HQ shortly."
1174
1126
  }
@@ -1192,10 +1144,10 @@ case "${1:-}" in
1192
1144
  do_uninstall "$@"
1193
1145
  ;;
1194
1146
 
1195
- reconfigure)
1196
- require_root reconfigure
1147
+ configure|reconfigure)
1148
+ require_root "$1"
1197
1149
  shift
1198
- do_reconfigure "$@"
1150
+ do_configure "$@"
1199
1151
  ;;
1200
1152
 
1201
1153
  status)
@@ -1329,8 +1281,8 @@ case "${1:-}" in
1329
1281
  echo "Minion Agent CLI (@geekbeer/minion) v${CLI_VERSION}"
1330
1282
  echo ""
1331
1283
  echo "Usage:"
1332
- echo " sudo minion-cli setup [options] # Set up agent service (root)"
1333
- echo " sudo minion-cli reconfigure [options] # Re-register with new HQ credentials (root)"
1284
+ echo " sudo minion-cli setup --user <USERNAME> # Install software & register services (root)"
1285
+ echo " sudo minion-cli configure [options] # Connect to HQ, deploy skills, start services (root)"
1334
1286
  echo " sudo minion-cli uninstall [options] # Remove agent and services (root)"
1335
1287
  echo " sudo minion-cli start # Start agent service (root)"
1336
1288
  echo " sudo minion-cli stop # Stop agent service (root)"
@@ -1344,15 +1296,12 @@ case "${1:-}" in
1344
1296
  echo ""
1345
1297
  echo "Setup options:"
1346
1298
  echo " --user <USERNAME> Target user for the agent (required when running as root)"
1347
- echo " --hq-url <URL> HQ server URL (optional)"
1348
- echo " --minion-id <UUID> Minion ID (optional)"
1349
- echo " --api-token <TOKEN> API token (optional)"
1350
- echo " --setup-tunnel Set up cloudflared tunnel (requires --hq-url, --api-token)"
1351
1299
  echo ""
1352
- echo "Reconfigure options:"
1300
+ echo "Configure options:"
1353
1301
  echo " --hq-url <URL> HQ server URL (required)"
1354
1302
  echo " --minion-id <UUID> Minion ID (required)"
1355
1303
  echo " --api-token <TOKEN> API token (required)"
1304
+ echo " --setup-tunnel Set up cloudflared tunnel"
1356
1305
  echo ""
1357
1306
  echo "Uninstall options:"
1358
1307
  echo " --keep-data Keep /opt/minion-agent/.env (preserve credentials)"