@geekbeer/minion 2.42.3 → 2.43.0
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.
- package/linux/minion-cli.sh +172 -0
- package/package.json +1 -1
- package/win/minion-cli.ps1 +215 -18
package/linux/minion-cli.sh
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
# Usage:
|
|
7
7
|
# sudo minion-cli setup [options] # Set up minion agent service (root)
|
|
8
8
|
# sudo minion-cli reconfigure [options] # Re-register with new HQ credentials (root)
|
|
9
|
+
# sudo minion-cli uninstall [--keep-data] # Remove agent and services (root)
|
|
9
10
|
# sudo minion-cli start # Start agent service (root)
|
|
10
11
|
# sudo minion-cli stop # Stop agent service (root)
|
|
11
12
|
# sudo minion-cli restart # Restart agent service (root)
|
|
@@ -807,6 +808,167 @@ CFEOF
|
|
|
807
808
|
fi
|
|
808
809
|
}
|
|
809
810
|
|
|
811
|
+
# ============================================================
|
|
812
|
+
# uninstall subcommand
|
|
813
|
+
# ============================================================
|
|
814
|
+
do_uninstall() {
|
|
815
|
+
local KEEP_DATA=false
|
|
816
|
+
|
|
817
|
+
# Parse arguments
|
|
818
|
+
while [[ $# -gt 0 ]]; do
|
|
819
|
+
case "$1" in
|
|
820
|
+
--keep-data)
|
|
821
|
+
KEEP_DATA=true
|
|
822
|
+
shift
|
|
823
|
+
;;
|
|
824
|
+
*)
|
|
825
|
+
echo "Unknown option: $1"
|
|
826
|
+
echo "Usage: sudo minion-cli uninstall [--keep-data]"
|
|
827
|
+
exit 1
|
|
828
|
+
;;
|
|
829
|
+
esac
|
|
830
|
+
done
|
|
831
|
+
|
|
832
|
+
echo "========================================="
|
|
833
|
+
echo " @geekbeer/minion Uninstall"
|
|
834
|
+
echo "========================================="
|
|
835
|
+
echo ""
|
|
836
|
+
echo "This will remove the minion agent and all related services."
|
|
837
|
+
if [ "$KEEP_DATA" = true ]; then
|
|
838
|
+
echo " --keep-data: /opt/minion-agent/.env will be preserved."
|
|
839
|
+
else
|
|
840
|
+
echo " Config directory /opt/minion-agent/ will be deleted."
|
|
841
|
+
fi
|
|
842
|
+
echo ""
|
|
843
|
+
echo -n "Type 'yes' to continue: "
|
|
844
|
+
read -r CONFIRM
|
|
845
|
+
if [ "$CONFIRM" != "yes" ]; then
|
|
846
|
+
echo "Uninstall cancelled."
|
|
847
|
+
exit 0
|
|
848
|
+
fi
|
|
849
|
+
echo ""
|
|
850
|
+
|
|
851
|
+
local TOTAL_STEPS=5
|
|
852
|
+
|
|
853
|
+
# Step 1: Stop and disable services
|
|
854
|
+
echo "[1/${TOTAL_STEPS}] Stopping and disabling services..."
|
|
855
|
+
case "$PROC_MGR" in
|
|
856
|
+
systemd)
|
|
857
|
+
for svc in minion-agent tmux-init novnc vnc autocutsel fluxbox xvfb; do
|
|
858
|
+
if [ -f "/etc/systemd/system/${svc}.service" ]; then
|
|
859
|
+
$SUDO systemctl stop "$svc" 2>/dev/null || true
|
|
860
|
+
$SUDO systemctl disable "$svc" 2>/dev/null || true
|
|
861
|
+
$SUDO rm -f "/etc/systemd/system/${svc}.service"
|
|
862
|
+
echo " -> Removed ${svc}.service"
|
|
863
|
+
fi
|
|
864
|
+
done
|
|
865
|
+
$SUDO systemctl daemon-reload
|
|
866
|
+
;;
|
|
867
|
+
supervisord)
|
|
868
|
+
for conf in minion-agent cloudflared; do
|
|
869
|
+
local CONF_FILE="/etc/supervisor/conf.d/${conf}.conf"
|
|
870
|
+
if [ -f "$CONF_FILE" ]; then
|
|
871
|
+
$SUDO supervisorctl stop "$conf" 2>/dev/null || true
|
|
872
|
+
$SUDO rm -f "$CONF_FILE"
|
|
873
|
+
echo " -> Removed ${conf}.conf"
|
|
874
|
+
fi
|
|
875
|
+
done
|
|
876
|
+
if $SUDO supervisorctl status &>/dev/null; then
|
|
877
|
+
$SUDO supervisorctl reread 2>/dev/null || true
|
|
878
|
+
$SUDO supervisorctl update 2>/dev/null || true
|
|
879
|
+
fi
|
|
880
|
+
;;
|
|
881
|
+
*)
|
|
882
|
+
echo " -> No supported process manager found, skipping"
|
|
883
|
+
;;
|
|
884
|
+
esac
|
|
885
|
+
|
|
886
|
+
# Step 2: Remove sudoers file
|
|
887
|
+
echo "[2/${TOTAL_STEPS}] Removing sudoers configuration..."
|
|
888
|
+
local SUDOERS_FILE="/etc/sudoers.d/minion-agent"
|
|
889
|
+
if [ -f "$SUDOERS_FILE" ]; then
|
|
890
|
+
$SUDO rm -f "$SUDOERS_FILE"
|
|
891
|
+
echo " -> Removed $SUDOERS_FILE"
|
|
892
|
+
else
|
|
893
|
+
echo " -> Not found, skipping"
|
|
894
|
+
fi
|
|
895
|
+
|
|
896
|
+
# Step 3: Remove config directory
|
|
897
|
+
echo "[3/${TOTAL_STEPS}] Removing config directory..."
|
|
898
|
+
if [ "$KEEP_DATA" = true ]; then
|
|
899
|
+
echo " -> Skipped (--keep-data)"
|
|
900
|
+
else
|
|
901
|
+
if [ -d /opt/minion-agent ]; then
|
|
902
|
+
$SUDO rm -rf /opt/minion-agent
|
|
903
|
+
echo " -> Removed /opt/minion-agent/"
|
|
904
|
+
else
|
|
905
|
+
echo " -> Not found, skipping"
|
|
906
|
+
fi
|
|
907
|
+
fi
|
|
908
|
+
|
|
909
|
+
# Step 4: Remove deployed skills and rules
|
|
910
|
+
echo "[4/${TOTAL_STEPS}] Removing deployed skills and rules..."
|
|
911
|
+
|
|
912
|
+
# Detect target user home (best-effort from existing service config)
|
|
913
|
+
local UNINSTALL_HOME="$TARGET_HOME"
|
|
914
|
+
|
|
915
|
+
local CLAUDE_SKILLS_DIR="${UNINSTALL_HOME}/.claude/skills"
|
|
916
|
+
local CLAUDE_RULES_DIR="${UNINSTALL_HOME}/.claude/rules"
|
|
917
|
+
|
|
918
|
+
# Remove bundled skills (only skills that ship with the package)
|
|
919
|
+
local NPM_ROOT
|
|
920
|
+
NPM_ROOT="$(npm root -g 2>/dev/null)" || true
|
|
921
|
+
local BUNDLED_SKILLS_DIR="${NPM_ROOT}/@geekbeer/minion/skills"
|
|
922
|
+
|
|
923
|
+
if [ -d "$BUNDLED_SKILLS_DIR" ] && [ -d "$CLAUDE_SKILLS_DIR" ]; then
|
|
924
|
+
for skill_dir in "$BUNDLED_SKILLS_DIR"/*/; do
|
|
925
|
+
if [ -d "$skill_dir" ]; then
|
|
926
|
+
local skill_name
|
|
927
|
+
skill_name=$(basename "$skill_dir")
|
|
928
|
+
if [ -d "${CLAUDE_SKILLS_DIR}/${skill_name}" ]; then
|
|
929
|
+
rm -rf "${CLAUDE_SKILLS_DIR}/${skill_name}"
|
|
930
|
+
echo " -> Removed skill: $skill_name"
|
|
931
|
+
fi
|
|
932
|
+
fi
|
|
933
|
+
done
|
|
934
|
+
else
|
|
935
|
+
echo " -> No bundled skills to remove"
|
|
936
|
+
fi
|
|
937
|
+
|
|
938
|
+
# Remove deployed rules
|
|
939
|
+
if [ -f "${CLAUDE_RULES_DIR}/core.md" ]; then
|
|
940
|
+
rm -f "${CLAUDE_RULES_DIR}/core.md"
|
|
941
|
+
echo " -> Removed rules: core.md"
|
|
942
|
+
fi
|
|
943
|
+
|
|
944
|
+
# Step 5: Remove Cloudflare Tunnel config
|
|
945
|
+
echo "[5/${TOTAL_STEPS}] Removing Cloudflare Tunnel configuration..."
|
|
946
|
+
if [ -d /etc/cloudflared ]; then
|
|
947
|
+
# Stop cloudflared service if running via systemd
|
|
948
|
+
if [ "$PROC_MGR" = "systemd" ]; then
|
|
949
|
+
$SUDO systemctl stop cloudflared 2>/dev/null || true
|
|
950
|
+
$SUDO systemctl disable cloudflared 2>/dev/null || true
|
|
951
|
+
fi
|
|
952
|
+
$SUDO rm -rf /etc/cloudflared
|
|
953
|
+
echo " -> Removed /etc/cloudflared/"
|
|
954
|
+
else
|
|
955
|
+
echo " -> Not found, skipping"
|
|
956
|
+
fi
|
|
957
|
+
|
|
958
|
+
echo ""
|
|
959
|
+
echo "========================================="
|
|
960
|
+
echo " Uninstall Complete!"
|
|
961
|
+
echo "========================================="
|
|
962
|
+
echo ""
|
|
963
|
+
echo "The minion agent services have been removed."
|
|
964
|
+
echo ""
|
|
965
|
+
echo "To also remove the npm package:"
|
|
966
|
+
echo " npm uninstall -g @geekbeer/minion"
|
|
967
|
+
echo ""
|
|
968
|
+
echo "Software installed by setup (Claude Code, Gemini CLI, VNC, etc.)"
|
|
969
|
+
echo "was NOT removed. Uninstall them manually if needed."
|
|
970
|
+
}
|
|
971
|
+
|
|
810
972
|
# ============================================================
|
|
811
973
|
# reconfigure subcommand
|
|
812
974
|
# ============================================================
|
|
@@ -1007,6 +1169,12 @@ case "${1:-}" in
|
|
|
1007
1169
|
do_setup "$@"
|
|
1008
1170
|
;;
|
|
1009
1171
|
|
|
1172
|
+
uninstall)
|
|
1173
|
+
require_root uninstall
|
|
1174
|
+
shift
|
|
1175
|
+
do_uninstall "$@"
|
|
1176
|
+
;;
|
|
1177
|
+
|
|
1010
1178
|
reconfigure)
|
|
1011
1179
|
require_root reconfigure
|
|
1012
1180
|
shift
|
|
@@ -1142,6 +1310,7 @@ case "${1:-}" in
|
|
|
1142
1310
|
echo "Usage:"
|
|
1143
1311
|
echo " sudo minion-cli setup [options] # Set up agent service (root)"
|
|
1144
1312
|
echo " sudo minion-cli reconfigure [options] # Re-register with new HQ credentials (root)"
|
|
1313
|
+
echo " sudo minion-cli uninstall [options] # Remove agent and services (root)"
|
|
1145
1314
|
echo " sudo minion-cli start # Start agent service (root)"
|
|
1146
1315
|
echo " sudo minion-cli stop # Stop agent service (root)"
|
|
1147
1316
|
echo " sudo minion-cli restart # Restart agent service (root)"
|
|
@@ -1164,6 +1333,9 @@ case "${1:-}" in
|
|
|
1164
1333
|
echo " --minion-id <UUID> Minion ID (required)"
|
|
1165
1334
|
echo " --api-token <TOKEN> API token (required)"
|
|
1166
1335
|
echo ""
|
|
1336
|
+
echo "Uninstall options:"
|
|
1337
|
+
echo " --keep-data Keep /opt/minion-agent/.env (preserve credentials)"
|
|
1338
|
+
echo ""
|
|
1167
1339
|
echo "Status values: online, offline, busy"
|
|
1168
1340
|
echo ""
|
|
1169
1341
|
echo "Environment:"
|
package/package.json
CHANGED
package/win/minion-cli.ps1
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# Usage:
|
|
4
4
|
# minion-cli-win setup --hq-url https://... --minion-id <UUID> --api-token <TOKEN>
|
|
5
5
|
# minion-cli-win setup --setup-tunnel
|
|
6
|
+
# minion-cli-win uninstall [--keep-data]
|
|
6
7
|
# minion-cli-win start | stop | restart | status | health | diagnose | version | help
|
|
7
8
|
|
|
8
9
|
# Parse arguments manually to avoid issues with npm wrapper passing $args as array
|
|
@@ -11,17 +12,19 @@ $HqUrl = ''
|
|
|
11
12
|
$MinionId = ''
|
|
12
13
|
$ApiToken = ''
|
|
13
14
|
$SetupTunnel = $false
|
|
15
|
+
$KeepData = $false
|
|
14
16
|
|
|
15
17
|
$i = 0
|
|
16
18
|
while ($i -lt $args.Count) {
|
|
17
19
|
$arg = [string]$args[$i]
|
|
18
20
|
switch -Regex ($arg) {
|
|
19
|
-
'^(setup|reconfigure|start|stop|restart|status|health|diagnose|version|help)$' { $Command = $arg }
|
|
21
|
+
'^(setup|reconfigure|uninstall|start|stop|restart|status|health|diagnose|version|help)$' { $Command = $arg }
|
|
20
22
|
'^(-v|--version)$' { $Command = 'version' }
|
|
21
23
|
'^--hq-url$' { $i++; if ($i -lt $args.Count) { $HqUrl = [string]$args[$i] } }
|
|
22
24
|
'^--minion-id$' { $i++; if ($i -lt $args.Count) { $MinionId = [string]$args[$i] } }
|
|
23
25
|
'^--api-token$' { $i++; if ($i -lt $args.Count) { $ApiToken = [string]$args[$i] } }
|
|
24
26
|
'^--setup-tunnel$' { $SetupTunnel = $true }
|
|
27
|
+
'^--keep-data$' { $KeepData = $true }
|
|
25
28
|
'^(-h|--help)$' { $Command = 'help' }
|
|
26
29
|
}
|
|
27
30
|
$i++
|
|
@@ -68,6 +71,28 @@ function Test-CommandExists {
|
|
|
68
71
|
$null -ne (Get-Command $Name -ErrorAction SilentlyContinue)
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
function Get-WebsockifyCommand {
|
|
75
|
+
# Returns @(executable, args-prefix) for launching websockify.
|
|
76
|
+
# 1) websockify.exe on PATH
|
|
77
|
+
if (Get-Command websockify -ErrorAction SilentlyContinue) {
|
|
78
|
+
return @((Get-Command websockify).Source)
|
|
79
|
+
}
|
|
80
|
+
# 2) Look in Python Scripts directories
|
|
81
|
+
if (Test-CommandExists 'python') {
|
|
82
|
+
$scriptsDir = & python -c "import sysconfig; print(sysconfig.get_path('scripts'))" 2>$null
|
|
83
|
+
if ($scriptsDir) {
|
|
84
|
+
$wsExe = Join-Path $scriptsDir 'websockify.exe'
|
|
85
|
+
if (Test-Path $wsExe) { return @($wsExe) }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
# 3) Fallback: python -m websockify
|
|
89
|
+
if (Test-CommandExists 'python') {
|
|
90
|
+
$check = & python -c "import websockify" 2>&1
|
|
91
|
+
if ($LASTEXITCODE -eq 0) { return @('python', '-m', 'websockify') }
|
|
92
|
+
}
|
|
93
|
+
return $null
|
|
94
|
+
}
|
|
95
|
+
|
|
71
96
|
function Get-LanIPAddress {
|
|
72
97
|
try {
|
|
73
98
|
$ip = (Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
|
@@ -329,17 +354,21 @@ function Invoke-Setup {
|
|
|
329
354
|
|
|
330
355
|
# Try prebuilt version first (no Build Tools required)
|
|
331
356
|
try {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
357
|
+
$npmResult = cmd /c "npm install node-pty-prebuilt-multiarch 2>&1"
|
|
358
|
+
if ($LASTEXITCODE -eq 0) {
|
|
359
|
+
Write-Detail "node-pty-prebuilt-multiarch installed (no Build Tools needed)"
|
|
360
|
+
$ptyInstalled = $true
|
|
361
|
+
}
|
|
335
362
|
} catch {}
|
|
336
363
|
|
|
337
364
|
# Fallback: source-compiled version (requires Visual Studio Build Tools)
|
|
338
365
|
if (-not $ptyInstalled) {
|
|
339
366
|
try {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
367
|
+
$npmResult = cmd /c "npm install node-pty 2>&1"
|
|
368
|
+
if ($LASTEXITCODE -eq 0) {
|
|
369
|
+
Write-Detail "node-pty installed (compiled from source)"
|
|
370
|
+
$ptyInstalled = $true
|
|
371
|
+
}
|
|
343
372
|
} catch {}
|
|
344
373
|
}
|
|
345
374
|
|
|
@@ -412,10 +441,17 @@ if (`$vncExe) {
|
|
|
412
441
|
}
|
|
413
442
|
# Reload registry config (ensures no-auth settings are applied)
|
|
414
443
|
& `$vncExe -controlapp -reload 2>`$null
|
|
415
|
-
|
|
444
|
+
`$wsCmd = Get-WebsockifyCommand
|
|
445
|
+
if (`$wsCmd) {
|
|
416
446
|
`$wsProc = Get-Process -Name websockify -ErrorAction SilentlyContinue
|
|
417
447
|
if (-not `$wsProc) {
|
|
418
|
-
|
|
448
|
+
if (`$wsCmd.Count -eq 1) {
|
|
449
|
+
Start-Process -FilePath `$wsCmd[0] -ArgumentList '6080', 'localhost:5900' -WindowStyle Hidden
|
|
450
|
+
} else {
|
|
451
|
+
# python -m websockify 6080 localhost:5900
|
|
452
|
+
`$wsArgs = (`$wsCmd[1..(`$wsCmd.Count-1)] + @('6080', 'localhost:5900')) -join ' '
|
|
453
|
+
Start-Process -FilePath `$wsCmd[0] -ArgumentList `$wsArgs -WindowStyle Hidden
|
|
454
|
+
}
|
|
419
455
|
}
|
|
420
456
|
}
|
|
421
457
|
}
|
|
@@ -547,7 +583,7 @@ Remove-Item `$PidFile -Force -ErrorAction SilentlyContinue
|
|
|
547
583
|
|
|
548
584
|
# Step 8: Setup websockify (WebSocket proxy for VNC)
|
|
549
585
|
Write-Step 8 $totalSteps "Setting up websockify..."
|
|
550
|
-
if (
|
|
586
|
+
if (Get-WebsockifyCommand) {
|
|
551
587
|
Write-Detail "websockify already installed"
|
|
552
588
|
}
|
|
553
589
|
else {
|
|
@@ -561,9 +597,10 @@ Remove-Item `$PidFile -Force -ErrorAction SilentlyContinue
|
|
|
561
597
|
if (-not $pythonUsable) {
|
|
562
598
|
Write-Host " Python not found. Installing via winget..."
|
|
563
599
|
try {
|
|
564
|
-
|
|
600
|
+
$wingetResult = cmd /c "winget install --id Python.Python.3.12 --accept-package-agreements --accept-source-agreements 2>&1"
|
|
565
601
|
$env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('PATH', 'User')
|
|
566
|
-
Write-Detail "Python installed"
|
|
602
|
+
if ($LASTEXITCODE -eq 0) { Write-Detail "Python installed" }
|
|
603
|
+
else { Write-Warn "winget install may have failed (exit code $LASTEXITCODE): $wingetResult" }
|
|
567
604
|
}
|
|
568
605
|
catch {
|
|
569
606
|
Write-Warn "Failed to install Python: $_"
|
|
@@ -573,21 +610,28 @@ Remove-Item `$PidFile -Force -ErrorAction SilentlyContinue
|
|
|
573
610
|
|
|
574
611
|
Write-Host " Installing websockify via pip..."
|
|
575
612
|
try {
|
|
613
|
+
# Use cmd /c to prevent pip's stderr (progress bars, warnings) from
|
|
614
|
+
# becoming RemoteException errors in PowerShell remoting sessions.
|
|
576
615
|
if (Test-CommandExists 'pip') {
|
|
577
|
-
|
|
578
|
-
Write-Detail "websockify installed"
|
|
616
|
+
$pipResult = cmd /c "pip install websockify 2>&1"
|
|
617
|
+
if ($LASTEXITCODE -eq 0) { Write-Detail "websockify installed" }
|
|
618
|
+
else { Write-Warn "pip install failed (exit code $LASTEXITCODE): $pipResult" }
|
|
579
619
|
}
|
|
580
620
|
elseif (Test-CommandExists 'pip3') {
|
|
581
|
-
|
|
582
|
-
Write-Detail "websockify installed"
|
|
621
|
+
$pipResult = cmd /c "pip3 install websockify 2>&1"
|
|
622
|
+
if ($LASTEXITCODE -eq 0) { Write-Detail "websockify installed" }
|
|
623
|
+
else { Write-Warn "pip3 install failed (exit code $LASTEXITCODE): $pipResult" }
|
|
583
624
|
}
|
|
584
625
|
elseif (Test-CommandExists 'python') {
|
|
585
|
-
|
|
586
|
-
Write-Detail "websockify installed (via python -m pip)"
|
|
626
|
+
$pipResult = cmd /c "python -m pip install websockify 2>&1"
|
|
627
|
+
if ($LASTEXITCODE -eq 0) { Write-Detail "websockify installed (via python -m pip)" }
|
|
628
|
+
else { Write-Warn "python -m pip install failed (exit code $LASTEXITCODE): $pipResult" }
|
|
587
629
|
}
|
|
588
630
|
else {
|
|
589
631
|
Write-Warn "pip not found. Install Python first, then: pip install websockify"
|
|
590
632
|
}
|
|
633
|
+
# Refresh PATH so websockify.exe in Python Scripts dir is discoverable
|
|
634
|
+
$env:PATH = [System.Environment]::GetEnvironmentVariable('PATH', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('PATH', 'User')
|
|
591
635
|
}
|
|
592
636
|
catch {
|
|
593
637
|
Write-Warn "Failed to install websockify: $_"
|
|
@@ -743,6 +787,152 @@ Remove-Item `$PidFile -Force -ErrorAction SilentlyContinue
|
|
|
743
787
|
Write-Host " Get-Content $(Join-Path $LogDir 'service-stdout.log') -Tail 50 # View logs"
|
|
744
788
|
}
|
|
745
789
|
|
|
790
|
+
# ============================================================
|
|
791
|
+
# Uninstall
|
|
792
|
+
# ============================================================
|
|
793
|
+
|
|
794
|
+
function Invoke-Uninstall {
|
|
795
|
+
Write-Host ""
|
|
796
|
+
Write-Host "=========================================" -ForegroundColor Red
|
|
797
|
+
Write-Host " @geekbeer/minion Uninstall" -ForegroundColor Red
|
|
798
|
+
Write-Host "=========================================" -ForegroundColor Red
|
|
799
|
+
Write-Host ""
|
|
800
|
+
Write-Host "This will remove the minion agent and all related configuration."
|
|
801
|
+
if ($KeepData) {
|
|
802
|
+
Write-Host " --keep-data: $EnvFile will be preserved."
|
|
803
|
+
}
|
|
804
|
+
else {
|
|
805
|
+
Write-Host " Data directory $DataDir will be deleted."
|
|
806
|
+
}
|
|
807
|
+
Write-Host ""
|
|
808
|
+
$confirm = Read-Host " Type 'yes' to continue"
|
|
809
|
+
if ($confirm -ne 'yes') {
|
|
810
|
+
Write-Host "Uninstall cancelled."
|
|
811
|
+
exit 0
|
|
812
|
+
}
|
|
813
|
+
Write-Host ""
|
|
814
|
+
|
|
815
|
+
$totalSteps = 5
|
|
816
|
+
|
|
817
|
+
# Step 1: Stop agent and child processes
|
|
818
|
+
Write-Step 1 $totalSteps "Stopping agent and related processes..."
|
|
819
|
+
Stop-MinionProcess
|
|
820
|
+
|
|
821
|
+
# Stop VNC server
|
|
822
|
+
$vncProc = Get-Process -Name tvnserver -ErrorAction SilentlyContinue
|
|
823
|
+
if ($vncProc) {
|
|
824
|
+
Stop-Process -Name tvnserver -Force -ErrorAction SilentlyContinue
|
|
825
|
+
Write-Detail "TightVNC server stopped"
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
# Stop websockify
|
|
829
|
+
$wsProc = Get-Process -Name websockify -ErrorAction SilentlyContinue
|
|
830
|
+
if ($wsProc) {
|
|
831
|
+
Stop-Process -Name websockify -Force -ErrorAction SilentlyContinue
|
|
832
|
+
Write-Detail "websockify stopped"
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
# Stop cloudflared
|
|
836
|
+
$cfProc = Get-Process -Name cloudflared -ErrorAction SilentlyContinue
|
|
837
|
+
if ($cfProc) {
|
|
838
|
+
Stop-Process -Name cloudflared -Force -ErrorAction SilentlyContinue
|
|
839
|
+
Write-Detail "cloudflared stopped"
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
Write-Detail "All processes stopped"
|
|
843
|
+
|
|
844
|
+
# Step 2: Remove startup shortcut
|
|
845
|
+
Write-Step 2 $totalSteps "Removing auto-start registration..."
|
|
846
|
+
$startupDir = [Environment]::GetFolderPath('Startup')
|
|
847
|
+
$shortcutPath = Join-Path $startupDir 'MinionAgent.lnk'
|
|
848
|
+
if (Test-Path $shortcutPath) {
|
|
849
|
+
Remove-Item $shortcutPath -Force
|
|
850
|
+
Write-Detail "Removed $shortcutPath"
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
Write-Detail "Startup shortcut not found, skipping"
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
# Step 3: Remove data directory (or keep .env)
|
|
857
|
+
Write-Step 3 $totalSteps "Removing data directory..."
|
|
858
|
+
if ($KeepData) {
|
|
859
|
+
# Remove everything except .env
|
|
860
|
+
if (Test-Path $DataDir) {
|
|
861
|
+
Get-ChildItem -Path $DataDir -Recurse -File | Where-Object { $_.FullName -ne $EnvFile } | Remove-Item -Force -ErrorAction SilentlyContinue
|
|
862
|
+
Get-ChildItem -Path $DataDir -Recurse -Directory | Sort-Object { $_.FullName.Length } -Descending | ForEach-Object {
|
|
863
|
+
if ((Get-ChildItem $_.FullName -Force | Measure-Object).Count -eq 0) {
|
|
864
|
+
Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
Write-Detail "Data directory cleaned (kept .env)"
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
Write-Detail "Data directory not found, skipping"
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
874
|
+
if (Test-Path $DataDir) {
|
|
875
|
+
Remove-Item $DataDir -Recurse -Force
|
|
876
|
+
Write-Detail "Removed $DataDir"
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
Write-Detail "Data directory not found, skipping"
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
# Step 4: Remove deployed skills and rules
|
|
884
|
+
Write-Step 4 $totalSteps "Removing deployed skills and rules..."
|
|
885
|
+
$claudeSkillsDir = Join-Path $env:USERPROFILE '.claude\skills'
|
|
886
|
+
$claudeRulesDir = Join-Path $env:USERPROFILE '.claude\rules'
|
|
887
|
+
|
|
888
|
+
# Remove bundled skills (only skills that ship with the package)
|
|
889
|
+
$npmRoot = & npm root -g 2>$null
|
|
890
|
+
$bundledSkillsDir = Join-Path $npmRoot '@geekbeer\minion\skills'
|
|
891
|
+
if ((Test-Path $bundledSkillsDir) -and (Test-Path $claudeSkillsDir)) {
|
|
892
|
+
Get-ChildItem -Path $bundledSkillsDir -Directory | ForEach-Object {
|
|
893
|
+
$targetSkill = Join-Path $claudeSkillsDir $_.Name
|
|
894
|
+
if (Test-Path $targetSkill) {
|
|
895
|
+
Remove-Item $targetSkill -Recurse -Force
|
|
896
|
+
Write-Detail "Removed skill: $($_.Name)"
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
Write-Detail "No bundled skills to remove"
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
# Remove deployed rules
|
|
905
|
+
$coreRule = Join-Path $claudeRulesDir 'core.md'
|
|
906
|
+
if (Test-Path $coreRule) {
|
|
907
|
+
Remove-Item $coreRule -Force
|
|
908
|
+
Write-Detail "Removed rules: core.md"
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
# Step 5: Remove Cloudflare Tunnel configuration
|
|
912
|
+
Write-Step 5 $totalSteps "Removing Cloudflare Tunnel configuration..."
|
|
913
|
+
$cfConfigDir = Join-Path $env:USERPROFILE '.cloudflared'
|
|
914
|
+
if (Test-Path $cfConfigDir) {
|
|
915
|
+
Remove-Item $cfConfigDir -Recurse -Force
|
|
916
|
+
Write-Detail "Removed $cfConfigDir"
|
|
917
|
+
}
|
|
918
|
+
else {
|
|
919
|
+
Write-Detail "Not found, skipping"
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
Write-Host ""
|
|
923
|
+
Write-Host "=========================================" -ForegroundColor Green
|
|
924
|
+
Write-Host " Uninstall Complete!" -ForegroundColor Green
|
|
925
|
+
Write-Host "=========================================" -ForegroundColor Green
|
|
926
|
+
Write-Host ""
|
|
927
|
+
Write-Host "The minion agent has been removed."
|
|
928
|
+
Write-Host ""
|
|
929
|
+
Write-Host "To also remove the npm package:"
|
|
930
|
+
Write-Host " npm uninstall -g @geekbeer/minion"
|
|
931
|
+
Write-Host ""
|
|
932
|
+
Write-Host "Software installed by setup (Node.js, Claude Code, TightVNC, etc.)"
|
|
933
|
+
Write-Host "was NOT removed. Uninstall them manually if needed."
|
|
934
|
+
}
|
|
935
|
+
|
|
746
936
|
# ============================================================
|
|
747
937
|
# Reconfigure
|
|
748
938
|
# ============================================================
|
|
@@ -828,6 +1018,9 @@ switch ($Command) {
|
|
|
828
1018
|
'setup' {
|
|
829
1019
|
Invoke-Setup
|
|
830
1020
|
}
|
|
1021
|
+
'uninstall' {
|
|
1022
|
+
Invoke-Uninstall
|
|
1023
|
+
}
|
|
831
1024
|
'reconfigure' {
|
|
832
1025
|
Invoke-Reconfigure
|
|
833
1026
|
}
|
|
@@ -904,6 +1097,7 @@ switch ($Command) {
|
|
|
904
1097
|
Write-Host "Usage (no admin required):"
|
|
905
1098
|
Write-Host " minion-cli-win setup [options] # Set up agent (auto-start on login)"
|
|
906
1099
|
Write-Host " minion-cli-win reconfigure [options] # Re-register with new HQ credentials"
|
|
1100
|
+
Write-Host " minion-cli-win uninstall [options] # Remove agent and configuration"
|
|
907
1101
|
Write-Host " minion-cli-win start # Start agent process"
|
|
908
1102
|
Write-Host " minion-cli-win stop # Stop agent process"
|
|
909
1103
|
Write-Host " minion-cli-win restart # Restart agent process"
|
|
@@ -923,6 +1117,9 @@ switch ($Command) {
|
|
|
923
1117
|
Write-Host " --minion-id <UUID> Minion ID (required)"
|
|
924
1118
|
Write-Host " --api-token <TOKEN> API token (required)"
|
|
925
1119
|
Write-Host ""
|
|
1120
|
+
Write-Host "Uninstall options:"
|
|
1121
|
+
Write-Host " --keep-data Keep .env file (preserve credentials)"
|
|
1122
|
+
Write-Host ""
|
|
926
1123
|
Write-Host "Data directory: $DataDir"
|
|
927
1124
|
Write-Host ""
|
|
928
1125
|
Write-Host "Environment:"
|