agent-recon 1.0.1
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/.claude/hooks/send-event-wsl.py +339 -0
- package/.claude/hooks/send-event.py +334 -0
- package/CHANGELOG.md +66 -0
- package/CONTRIBUTING.md +70 -0
- package/EULA.md +223 -0
- package/INSTALL.md +193 -0
- package/LICENSE +287 -0
- package/LICENSE-COMMERCIAL +241 -0
- package/PRIVACY.md +115 -0
- package/README.md +182 -0
- package/SECURITY.md +63 -0
- package/TERMS.md +233 -0
- package/install-service.ps1 +302 -0
- package/installer/cli.js +177 -0
- package/installer/detect.js +355 -0
- package/installer/install.js +195 -0
- package/installer/manifest.js +140 -0
- package/installer/package.json +12 -0
- package/installer/steps/api-keys.js +59 -0
- package/installer/steps/directory.js +41 -0
- package/installer/steps/env-report.js +48 -0
- package/installer/steps/hooks.js +149 -0
- package/installer/steps/service.js +159 -0
- package/installer/steps/tls.js +104 -0
- package/installer/steps/verify.js +117 -0
- package/installer/steps/welcome.js +46 -0
- package/installer/ui.js +133 -0
- package/installer/uninstall.js +233 -0
- package/installer/upgrade.js +289 -0
- package/package.json +58 -0
- package/public/index.html +13953 -0
- package/server/fixtures/allowlist-profiles.json +185 -0
- package/server/package.json +34 -0
- package/server/platform.js +270 -0
- package/server/rules/gitleaks.toml +3214 -0
- package/server/rules/security.yara +579 -0
- package/server/start.js +178 -0
- package/service/agent-recon.service +30 -0
- package/service/com.agent-recon.server.plist +56 -0
- package/setup-linux.sh +259 -0
- package/setup-macos.sh +264 -0
- package/setup-wsl.sh +248 -0
- package/setup.ps1 +171 -0
- package/start-agent-recon.bat +4 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#Requires -Version 5.1
|
|
2
|
+
<#
|
|
3
|
+
.SYNOPSIS
|
|
4
|
+
Install / uninstall / query the Agent Recon Windows Service.
|
|
5
|
+
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
Uses NSSM (Non-Sucking Service Manager) to wrap the Node.js process as a
|
|
8
|
+
proper Windows Service that responds to service-control messages. NSSM must
|
|
9
|
+
be installed first (e.g. `choco install nssm` or download from https://nssm.cc).
|
|
10
|
+
|
|
11
|
+
The service runs: node <repo>\server\start.js
|
|
12
|
+
Working directory: <repo>\server
|
|
13
|
+
Service name: AgentRecon
|
|
14
|
+
|
|
15
|
+
.PARAMETER Uninstall
|
|
16
|
+
Remove the AgentRecon service.
|
|
17
|
+
|
|
18
|
+
.PARAMETER Status
|
|
19
|
+
Show current service status and configuration.
|
|
20
|
+
|
|
21
|
+
.EXAMPLE
|
|
22
|
+
# Install (run as Administrator)
|
|
23
|
+
.\install-service.ps1
|
|
24
|
+
|
|
25
|
+
# Check status
|
|
26
|
+
.\install-service.ps1 -Status
|
|
27
|
+
|
|
28
|
+
# Remove
|
|
29
|
+
.\install-service.ps1 -Uninstall
|
|
30
|
+
#>
|
|
31
|
+
|
|
32
|
+
[CmdletBinding(DefaultParameterSetName = 'Install')]
|
|
33
|
+
param(
|
|
34
|
+
[Parameter(ParameterSetName = 'Uninstall')]
|
|
35
|
+
[switch]$Uninstall,
|
|
36
|
+
|
|
37
|
+
[Parameter(ParameterSetName = 'Status')]
|
|
38
|
+
[switch]$Status
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
$ErrorActionPreference = 'Stop'
|
|
42
|
+
|
|
43
|
+
# -- Constants ----------------------------------------------------------------
|
|
44
|
+
$ServiceName = 'AgentRecon'
|
|
45
|
+
$DisplayName = 'Agent Recon - Claude Code Observability'
|
|
46
|
+
$Description = 'Real-time observability dashboard for Claude Code sessions'
|
|
47
|
+
$RepoRoot = $PSScriptRoot
|
|
48
|
+
$ServerDir = Join-Path $RepoRoot 'server'
|
|
49
|
+
$StartScript = Join-Path $ServerDir 'start.js'
|
|
50
|
+
|
|
51
|
+
# -- Helpers ------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
function Write-Info { param([string]$Msg) Write-Host " [INFO] $Msg" -ForegroundColor Cyan }
|
|
54
|
+
function Write-Ok { param([string]$Msg) Write-Host " [OK] $Msg" -ForegroundColor Green }
|
|
55
|
+
function Write-Warn { param([string]$Msg) Write-Host " [WARN] $Msg" -ForegroundColor Yellow }
|
|
56
|
+
function Write-Err { param([string]$Msg) Write-Host " [FAIL] $Msg" -ForegroundColor Red }
|
|
57
|
+
|
|
58
|
+
function Assert-Admin {
|
|
59
|
+
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
60
|
+
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
|
|
61
|
+
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
62
|
+
Write-Warn 'Not running as Administrator. Relaunching elevated...'
|
|
63
|
+
$argList = '-ExecutionPolicy Bypass -File "' + $PSCommandPath + '"'
|
|
64
|
+
if ($Uninstall) { $argList += ' -Uninstall' }
|
|
65
|
+
if ($Status) { $argList += ' -Status' }
|
|
66
|
+
Start-Process powershell.exe -ArgumentList $argList -Verb RunAs
|
|
67
|
+
exit 0
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function Find-Nssm {
|
|
72
|
+
$nssm = Get-Command nssm -ErrorAction SilentlyContinue
|
|
73
|
+
if ($nssm) { return $nssm.Source }
|
|
74
|
+
|
|
75
|
+
# Common Chocolatey path
|
|
76
|
+
$chocoPath = Join-Path $env:ProgramData 'chocolatey\bin\nssm.exe'
|
|
77
|
+
if (Test-Path $chocoPath) { return $chocoPath }
|
|
78
|
+
|
|
79
|
+
return $null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function Find-Node {
|
|
83
|
+
$node = Get-Command node -ErrorAction SilentlyContinue
|
|
84
|
+
if (-not $node) {
|
|
85
|
+
Write-Err 'Node.js not found on PATH. Install Node.js 22+ and try again.'
|
|
86
|
+
exit 1
|
|
87
|
+
}
|
|
88
|
+
$ver = (& $node.Source --version 2>&1).ToString().Trim()
|
|
89
|
+
Write-Info "Node.js: $($node.Source) ($ver)"
|
|
90
|
+
return $node.Source
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# -- Status -------------------------------------------------------------------
|
|
94
|
+
|
|
95
|
+
if ($Status) {
|
|
96
|
+
Write-Host ''
|
|
97
|
+
Write-Host "Agent Recon Service Status" -ForegroundColor Cyan
|
|
98
|
+
Write-Host ('-' * 40) -ForegroundColor Cyan
|
|
99
|
+
|
|
100
|
+
$svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
|
101
|
+
if (-not $svc) {
|
|
102
|
+
Write-Warn "Service '$ServiceName' is not installed."
|
|
103
|
+
Write-Host ''
|
|
104
|
+
exit 0
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
Write-Info "Name: $($svc.Name)"
|
|
108
|
+
Write-Info "Display Name: $($svc.DisplayName)"
|
|
109
|
+
Write-Info "Status: $($svc.Status)"
|
|
110
|
+
Write-Info "Start Type: $($svc.StartType)"
|
|
111
|
+
|
|
112
|
+
$nssmExe = Find-Nssm
|
|
113
|
+
if ($nssmExe) {
|
|
114
|
+
try {
|
|
115
|
+
$appPath = (& $nssmExe get $ServiceName Application 2>&1).ToString().Trim()
|
|
116
|
+
$appDir = (& $nssmExe get $ServiceName AppDirectory 2>&1).ToString().Trim()
|
|
117
|
+
$appArgs = (& $nssmExe get $ServiceName AppParameters 2>&1).ToString().Trim()
|
|
118
|
+
Write-Info "Application: $appPath"
|
|
119
|
+
Write-Info "Arguments: $appArgs"
|
|
120
|
+
Write-Info "Working Dir: $appDir"
|
|
121
|
+
} catch { }
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
$stdoutLog = (& $nssmExe get $ServiceName AppStdout 2>&1).ToString().Trim()
|
|
125
|
+
$stderrLog = (& $nssmExe get $ServiceName AppStderr 2>&1).ToString().Trim()
|
|
126
|
+
if ($stdoutLog) { Write-Info "Stdout Log: $stdoutLog" }
|
|
127
|
+
if ($stderrLog) { Write-Info "Stderr Log: $stderrLog" }
|
|
128
|
+
} catch { }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Write-Host ''
|
|
132
|
+
Write-Host 'Quick commands:' -ForegroundColor Cyan
|
|
133
|
+
Write-Host " Start: Start-Service $ServiceName"
|
|
134
|
+
Write-Host " Stop: Stop-Service $ServiceName"
|
|
135
|
+
Write-Host " Restart: Restart-Service $ServiceName"
|
|
136
|
+
Write-Host ''
|
|
137
|
+
exit 0
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
# -- Require admin for install / uninstall ------------------------------------
|
|
141
|
+
Assert-Admin
|
|
142
|
+
|
|
143
|
+
# -- Uninstall ----------------------------------------------------------------
|
|
144
|
+
|
|
145
|
+
if ($Uninstall) {
|
|
146
|
+
Write-Host ''
|
|
147
|
+
Write-Host "Removing Agent Recon Service" -ForegroundColor Cyan
|
|
148
|
+
Write-Host ('-' * 40) -ForegroundColor Cyan
|
|
149
|
+
|
|
150
|
+
$svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
|
151
|
+
if (-not $svc) {
|
|
152
|
+
Write-Warn "Service '$ServiceName' is not installed. Nothing to remove."
|
|
153
|
+
Write-Host ''
|
|
154
|
+
exit 0
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Stop the service if running
|
|
158
|
+
if ($svc.Status -eq 'Running') {
|
|
159
|
+
Write-Info 'Stopping service...'
|
|
160
|
+
Stop-Service -Name $ServiceName -Force
|
|
161
|
+
Start-Sleep -Seconds 2
|
|
162
|
+
Write-Ok 'Service stopped.'
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
$nssmExe = Find-Nssm
|
|
166
|
+
if ($nssmExe) {
|
|
167
|
+
Write-Info 'Removing service via NSSM...'
|
|
168
|
+
& $nssmExe remove $ServiceName confirm
|
|
169
|
+
} else {
|
|
170
|
+
Write-Info 'Removing service via sc.exe...'
|
|
171
|
+
& sc.exe delete $ServiceName
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Verify removal
|
|
175
|
+
$svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
|
176
|
+
if ($svc) {
|
|
177
|
+
Write-Err "Service still exists. A reboot may be required to complete removal."
|
|
178
|
+
} else {
|
|
179
|
+
Write-Ok "Service '$ServiceName' removed successfully."
|
|
180
|
+
}
|
|
181
|
+
Write-Host ''
|
|
182
|
+
exit 0
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# -- Install ------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
Write-Host ''
|
|
188
|
+
Write-Host 'Installing Agent Recon as Windows Service' -ForegroundColor Cyan
|
|
189
|
+
Write-Host ('-' * 48) -ForegroundColor Cyan
|
|
190
|
+
|
|
191
|
+
# Check prerequisites
|
|
192
|
+
$NodeExe = Find-Node
|
|
193
|
+
|
|
194
|
+
if (-not (Test-Path $StartScript)) {
|
|
195
|
+
Write-Err "start.js not found at: $StartScript"
|
|
196
|
+
Write-Err 'Run this script from the agent-recon repo root.'
|
|
197
|
+
exit 1
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# Check for existing service
|
|
201
|
+
$existingSvc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
|
|
202
|
+
if ($existingSvc) {
|
|
203
|
+
Write-Warn "Service '$ServiceName' already exists (Status: $($existingSvc.Status))."
|
|
204
|
+
Write-Warn "Run .\install-service.ps1 -Uninstall first, then re-install."
|
|
205
|
+
exit 1
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
# Find NSSM
|
|
209
|
+
$NssmExe = Find-Nssm
|
|
210
|
+
|
|
211
|
+
if (-not $NssmExe) {
|
|
212
|
+
Write-Err 'NSSM (Non-Sucking Service Manager) not found.'
|
|
213
|
+
Write-Host ''
|
|
214
|
+
Write-Host ' Windows services must respond to Service Control Manager (SCM) messages.' -ForegroundColor Yellow
|
|
215
|
+
Write-Host ' Node.js does not do this natively, so a service wrapper is required.' -ForegroundColor Yellow
|
|
216
|
+
Write-Host ''
|
|
217
|
+
Write-Host ' Install NSSM using one of these methods:' -ForegroundColor Cyan
|
|
218
|
+
Write-Host ' choco install nssm # via Chocolatey' -ForegroundColor White
|
|
219
|
+
Write-Host ' scoop install nssm # via Scoop' -ForegroundColor White
|
|
220
|
+
Write-Host ' winget install nssm # via WinGet' -ForegroundColor White
|
|
221
|
+
Write-Host ' https://nssm.cc/download # manual download' -ForegroundColor White
|
|
222
|
+
Write-Host ''
|
|
223
|
+
Write-Host ' After installing NSSM, re-run this script.' -ForegroundColor Cyan
|
|
224
|
+
Write-Host ''
|
|
225
|
+
Write-Host ' Alternative: manual service setup without NSSM' -ForegroundColor Cyan
|
|
226
|
+
Write-Host ' ------------------------------------------------' -ForegroundColor Cyan
|
|
227
|
+
Write-Host ' If you prefer not to install NSSM, you can run Agent Recon at startup' -ForegroundColor Yellow
|
|
228
|
+
Write-Host ' using Task Scheduler instead:' -ForegroundColor Yellow
|
|
229
|
+
Write-Host ''
|
|
230
|
+
Write-Host " schtasks /create /tn `"AgentRecon`" /tr `"'$NodeExe' '$StartScript'`" /sc onlogon /rl highest" -ForegroundColor White
|
|
231
|
+
Write-Host ''
|
|
232
|
+
Write-Host ' Or add a shortcut to: shell:startup' -ForegroundColor White
|
|
233
|
+
Write-Host ''
|
|
234
|
+
exit 1
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Write-Info "NSSM: $NssmExe"
|
|
238
|
+
|
|
239
|
+
# Create log directory
|
|
240
|
+
$LogDir = Join-Path $RepoRoot 'data' 'logs'
|
|
241
|
+
if (-not (Test-Path $LogDir)) {
|
|
242
|
+
New-Item -ItemType Directory -Path $LogDir -Force | Out-Null
|
|
243
|
+
Write-Ok "Created log directory: $LogDir"
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
$StdoutLog = Join-Path $LogDir 'service-stdout.log'
|
|
247
|
+
$StderrLog = Join-Path $LogDir 'service-stderr.log'
|
|
248
|
+
|
|
249
|
+
# Install the service via NSSM
|
|
250
|
+
Write-Info 'Creating service via NSSM...'
|
|
251
|
+
& $NssmExe install $ServiceName $NodeExe $StartScript
|
|
252
|
+
if ($LASTEXITCODE -ne 0) {
|
|
253
|
+
Write-Err "NSSM install failed (exit code $LASTEXITCODE)."
|
|
254
|
+
exit 1
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
# Configure service properties
|
|
258
|
+
Write-Info 'Configuring service properties...'
|
|
259
|
+
|
|
260
|
+
& $NssmExe set $ServiceName DisplayName $DisplayName
|
|
261
|
+
& $NssmExe set $ServiceName Description $Description
|
|
262
|
+
& $NssmExe set $ServiceName AppDirectory $ServerDir
|
|
263
|
+
& $NssmExe set $ServiceName Start SERVICE_DELAYED_AUTO_START
|
|
264
|
+
& $NssmExe set $ServiceName AppStdout $StdoutLog
|
|
265
|
+
& $NssmExe set $ServiceName AppStderr $StderrLog
|
|
266
|
+
& $NssmExe set $ServiceName AppStdoutCreationDisposition 4 # append
|
|
267
|
+
& $NssmExe set $ServiceName AppStderrCreationDisposition 4 # append
|
|
268
|
+
& $NssmExe set $ServiceName AppRotateFiles 1
|
|
269
|
+
& $NssmExe set $ServiceName AppRotateBytes 5242880 # 5 MB
|
|
270
|
+
|
|
271
|
+
# Set environment: PORT=3131
|
|
272
|
+
& $NssmExe set $ServiceName AppEnvironmentExtra 'PORT=3131'
|
|
273
|
+
|
|
274
|
+
Write-Ok "Service '$ServiceName' installed successfully."
|
|
275
|
+
|
|
276
|
+
# -- Post-install instructions ------------------------------------------------
|
|
277
|
+
|
|
278
|
+
Write-Host ''
|
|
279
|
+
Write-Host '+----------------------------------------------------------+' -ForegroundColor Green
|
|
280
|
+
Write-Host '| Agent Recon Windows Service Installed |' -ForegroundColor Green
|
|
281
|
+
Write-Host '+----------------------------------------------------------+' -ForegroundColor Green
|
|
282
|
+
Write-Host ''
|
|
283
|
+
Write-Host ' Service Name: AgentRecon' -ForegroundColor Cyan
|
|
284
|
+
Write-Host " Node.js: $NodeExe"
|
|
285
|
+
Write-Host " Start Script: $StartScript"
|
|
286
|
+
Write-Host " Working Dir: $ServerDir"
|
|
287
|
+
Write-Host " Stdout Log: $StdoutLog"
|
|
288
|
+
Write-Host " Stderr Log: $StderrLog"
|
|
289
|
+
Write-Host ''
|
|
290
|
+
Write-Host ' Quick commands (run as Administrator):' -ForegroundColor Cyan
|
|
291
|
+
Write-Host ' Start-Service AgentRecon # Start the service'
|
|
292
|
+
Write-Host ' Stop-Service AgentRecon # Stop the service'
|
|
293
|
+
Write-Host ' Restart-Service AgentRecon # Restart'
|
|
294
|
+
Write-Host ' Get-Service AgentRecon # Check status'
|
|
295
|
+
Write-Host ' .\install-service.ps1 -Status # Detailed status'
|
|
296
|
+
Write-Host ' .\install-service.ps1 -Uninstall # Remove service'
|
|
297
|
+
Write-Host ''
|
|
298
|
+
Write-Host ' The service is set to start automatically (delayed) on boot.' -ForegroundColor Yellow
|
|
299
|
+
Write-Host ' To start it now: Start-Service AgentRecon' -ForegroundColor Yellow
|
|
300
|
+
Write-Host ''
|
|
301
|
+
Write-Host ' Dashboard: http://localhost:3131' -ForegroundColor Cyan
|
|
302
|
+
Write-Host ''
|
package/installer/cli.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Copyright 2026 PNW Great Loop LLC. All rights reserved.
|
|
3
|
+
// Licensed under the Agent Recon™ Commercial License — see LICENSE-COMMERCIAL.
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Agent Recon Installer — CLI Entry Point
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node cli.js # guided install (default)
|
|
11
|
+
* node cli.js install # guided install
|
|
12
|
+
* node cli.js install --tls # guided install with mkcert TLS pre-selected
|
|
13
|
+
* node cli.js upgrade # upgrade existing installation
|
|
14
|
+
* node cli.js upgrade --tls # add mkcert TLS to existing install
|
|
15
|
+
* node cli.js uninstall # remove Agent Recon
|
|
16
|
+
* node cli.js detect # print environment report and exit
|
|
17
|
+
* node cli.js tls setup # standalone mkcert TLS setup (server must be running)
|
|
18
|
+
* node cli.js tls status # print current TLS status (server must be running)
|
|
19
|
+
* node cli.js --help | -h # print usage
|
|
20
|
+
* node cli.js --version | -v # print version
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const ui = require('./ui');
|
|
25
|
+
|
|
26
|
+
// Read version from root package.json (the canonical version source)
|
|
27
|
+
function getVersion() {
|
|
28
|
+
try {
|
|
29
|
+
const pkg = require(path.join(__dirname, '..', 'package.json'));
|
|
30
|
+
return pkg.version || '1.0.0';
|
|
31
|
+
} catch {
|
|
32
|
+
return '1.0.0';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function printUsage() {
|
|
37
|
+
const version = getVersion();
|
|
38
|
+
console.log(`
|
|
39
|
+
${ui.bold('Agent Recon')}${ui.cyan('™')} Installer v${version}
|
|
40
|
+
|
|
41
|
+
${ui.bold('Usage:')}
|
|
42
|
+
node cli.js [command]
|
|
43
|
+
|
|
44
|
+
${ui.bold('Commands:')}
|
|
45
|
+
install Guided installation (default)
|
|
46
|
+
upgrade Upgrade an existing installation
|
|
47
|
+
uninstall Remove Agent Recon™
|
|
48
|
+
detect Print environment detection report
|
|
49
|
+
tls setup Configure mkcert TLS (server must be running)
|
|
50
|
+
tls status Show current TLS status (server must be running)
|
|
51
|
+
|
|
52
|
+
${ui.bold('Options:')}
|
|
53
|
+
--help, -h Show this help message
|
|
54
|
+
--version, -v Show version number
|
|
55
|
+
--force Force operation (skip version check on upgrade)
|
|
56
|
+
--tls Pre-select mkcert TLS during install/upgrade
|
|
57
|
+
`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function main() {
|
|
61
|
+
const args = process.argv.slice(2);
|
|
62
|
+
const command = args[0] || 'install';
|
|
63
|
+
const force = args.includes('--force');
|
|
64
|
+
const tlsFlag = args.includes('--tls');
|
|
65
|
+
|
|
66
|
+
if (command === '--help' || command === '-h') {
|
|
67
|
+
printUsage();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (command === '--version' || command === '-v') {
|
|
72
|
+
console.log(getVersion());
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Run environment detection (needed by all commands)
|
|
77
|
+
const { detectEnv } = require('./detect');
|
|
78
|
+
const envReport = await detectEnv();
|
|
79
|
+
|
|
80
|
+
switch (command) {
|
|
81
|
+
case 'detect': {
|
|
82
|
+
ui.banner(getVersion());
|
|
83
|
+
ui.printEnvReport(envReport);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
case 'install': {
|
|
88
|
+
// If existing install detected, suggest upgrade instead
|
|
89
|
+
if (envReport.existingInstall && envReport.existingInstall.manifestPath) {
|
|
90
|
+
ui.warn('An existing Agent Recon™ installation was detected.');
|
|
91
|
+
ui.info(`Version: ${envReport.existingInstall.version || 'unknown'}`);
|
|
92
|
+
ui.info(`Location: ${envReport.existingInstall.installDir || 'unknown'}`);
|
|
93
|
+
ui.info('Run "node cli.js upgrade" to upgrade, or "node cli.js install --force" to reinstall.');
|
|
94
|
+
if (!force) return;
|
|
95
|
+
}
|
|
96
|
+
const install = require('./install');
|
|
97
|
+
await install(envReport, { version: getVersion(), force, tls: tlsFlag });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
case 'upgrade': {
|
|
102
|
+
const upgrade = require('./upgrade');
|
|
103
|
+
await upgrade(envReport, { version: getVersion(), force, tls: tlsFlag });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
case 'tls': {
|
|
108
|
+
const sub = args[1];
|
|
109
|
+
if (sub === 'setup') {
|
|
110
|
+
await _tlsSetup();
|
|
111
|
+
} else if (sub === 'status') {
|
|
112
|
+
await _tlsStatus();
|
|
113
|
+
} else {
|
|
114
|
+
ui.error(`Unknown tls subcommand: ${sub || '(none)'}`);
|
|
115
|
+
ui.info('Usage: node cli.js tls setup | tls status');
|
|
116
|
+
process.exitCode = 1;
|
|
117
|
+
}
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
case 'uninstall': {
|
|
122
|
+
const uninstall = require('./uninstall');
|
|
123
|
+
await uninstall(envReport);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
default:
|
|
128
|
+
ui.error(`Unknown command: ${command}`);
|
|
129
|
+
printUsage();
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function _tlsSetup() {
|
|
135
|
+
ui.banner(getVersion());
|
|
136
|
+
ui.info('Configuring mkcert TLS via server API...');
|
|
137
|
+
try {
|
|
138
|
+
const r = await fetch('http://localhost:3131/api/settings', {
|
|
139
|
+
method: 'POST',
|
|
140
|
+
headers: { 'Content-Type': 'application/json' },
|
|
141
|
+
body: JSON.stringify({ key: 'tls_enabled', value: 'true' }),
|
|
142
|
+
});
|
|
143
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
144
|
+
const r2 = await fetch('http://localhost:3131/api/settings', {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
headers: { 'Content-Type': 'application/json' },
|
|
147
|
+
body: JSON.stringify({ key: 'tls_mode', value: 'mkcert' }),
|
|
148
|
+
});
|
|
149
|
+
if (!r2.ok) throw new Error(`HTTP ${r2.status}`);
|
|
150
|
+
ui.ok('TLS enabled with mkcert mode. Restart the server to activate HTTPS.');
|
|
151
|
+
ui.info('If mkcert is not installed, install it and run: mkcert -install');
|
|
152
|
+
} catch (err) {
|
|
153
|
+
ui.error(`Could not reach server at localhost:3131: ${err.message}`);
|
|
154
|
+
ui.info('Make sure the Agent Recon™ server is running first.');
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function _tlsStatus() {
|
|
159
|
+
try {
|
|
160
|
+
const r = await fetch('http://localhost:3131/api/tls-status');
|
|
161
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
162
|
+
const data = await r.json();
|
|
163
|
+
console.log(`TLS status: ${data.status}`);
|
|
164
|
+
if (data.hint) console.log(`Hint: ${data.hint}`);
|
|
165
|
+
if (data.valid_to) console.log(`Valid until: ${data.valid_to}`);
|
|
166
|
+
if (data.days_remaining != null) console.log(`Days remaining: ${data.days_remaining}`);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
ui.error(`Could not reach server at localhost:3131: ${err.message}`);
|
|
169
|
+
ui.info('Make sure the Agent Recon™ server is running first.');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
main().catch(err => {
|
|
174
|
+
ui.error(err.message || String(err));
|
|
175
|
+
if (process.env.AGENT_RECON_DEBUG) console.error(err);
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
});
|