diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 3469a70..ac8b616 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -7,6 +7,7 @@ irm https://agentkey.app/install.ps1 | iex & ([scriptblock]::Create((irm https://agentkey.app/install.ps1))) -Yes & ([scriptblock]::Create((irm https://agentkey.app/install.ps1))) -Only "claude-code,cursor" + & ([scriptblock]::Create((irm https://agentkey.app/install.ps1))) -NoTelemetry Behavior mirrors install.sh: checks Node >= 18 (installs via winget/scoop/choco), auto-detects which AI agents are installed and runs `npx skills add` for them, @@ -28,6 +29,7 @@ param( [switch]$ForceMcp, [switch]$SkipSkill, [switch]$SkipMcp, + [switch]$NoTelemetry, [switch]$Help ) @@ -159,6 +161,9 @@ Parameters: -ForceMcp Re-run MCP auth even if AgentKey is already configured -SkipSkill Skip the skill install step (only run MCP auth) -SkipMcp Skip the MCP auth step (only install the skill) + -NoTelemetry Disable anonymous usage telemetry (writes + %USERPROFILE%\.config\agentkey\telemetry-disabled so + the skill stays opted-out across runs) -Help Show this help Behavior: @@ -213,6 +218,19 @@ else { } Write-Ok "Mode: $Mode" +# Resolve telemetry intent: -NoTelemetry overrides everything; existing +# %USERPROFILE%\.config\agentkey\telemetry-disabled file means already-opted-out. +$TelemetryOptOutFile = Join-Path $env:USERPROFILE '.config\agentkey\telemetry-disabled' +if ($NoTelemetry) { + New-Item -ItemType Directory -Path (Split-Path $TelemetryOptOutFile) -Force | Out-Null + New-Item -ItemType File -Path $TelemetryOptOutFile -Force | Out-Null + Write-Ok 'Telemetry: disabled (-NoTelemetry)' +} elseif (Test-Path -LiteralPath $TelemetryOptOutFile) { + Write-Ok "Telemetry: disabled ($TelemetryOptOutFile exists)" +} else { + Write-Info 'Telemetry: anonymous usage stats enabled (re-run with -NoTelemetry to opt out)' +} + # Node check function Get-NodeMajor { try { @@ -357,6 +375,34 @@ if ($SkipMcp) { } Write-Host '' + # Telemetry context for install_completed. Opt-out is honored at the + # SOURCE: when AGENTKEY_TELEMETRY=0, no other context env vars are + # exported — hostname-derived fingerprint, agent lists, and installer + # flags are never computed nor passed to the child `npx @agentkey/mcp` + # process. The server treats AGENTKEY_TELEMETRY=0 as a hard skip. + if ($NoTelemetry -or (Test-Path -LiteralPath $TelemetryOptOutFile)) { + $env:AGENTKEY_TELEMETRY = '0' + } else { + $env:AGENTKEY_TELEMETRY = '1' + + $_hn = [System.Net.Dns]::GetHostName() + $_user = $env:USERNAME + $_input = "$_hn|windows|$_user" + $_bytes = [System.Text.Encoding]::UTF8.GetBytes($_input) + $_sha = [System.Security.Cryptography.SHA256]::Create() + $_hash = ($_sha.ComputeHash($_bytes) | ForEach-Object { $_.ToString('x2') }) -join '' + $DeviceFingerprint = $_hash.Substring(0, 16) + + $DetectedAgents = Get-DetectedAgents + if (-not (Get-Variable -Name targets -Scope Script -ErrorAction SilentlyContinue)) { $targets = @() } + + $env:AGENTKEY_INSTALL_SOURCE = 'one_liner' + $env:AGENTKEY_DETECTED_AGENTS = ($DetectedAgents -join ',') + $env:AGENTKEY_SELECTED_AGENTS = ($targets -join ',') + $env:AGENTKEY_INSTALLER_FLAGS = ($PSBoundParameters.Keys | ForEach-Object { "-$_" }) -join ',' + $env:AGENTKEY_DEVICE_FINGERPRINT = $DeviceFingerprint + } + & npx -y $McpPackage @authArgs if ($LASTEXITCODE -ne 0) { Write-Err 'MCP auth failed.' diff --git a/scripts/install.sh b/scripts/install.sh index 30009dc..4c1e8c3 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -111,6 +111,9 @@ Options: --force-mcp Re-run MCP auth even if AgentKey is already configured --skip-skill Skip the skill install step (only run MCP auth) --skip-mcp Skip the MCP auth step (only install the skill) + --no-telemetry Disable anonymous usage telemetry (writes + ~/.config/agentkey/telemetry-disabled so the skill + stays opted-out across runs) -h, --help Show this help Behavior: @@ -237,6 +240,26 @@ install_node() { ui_ok "Node.js installed" } +# Compute a stable per-device fingerprint for install_completed dedup. +# spec §6.3: sha256(hostname+platform+username)[:16]. Falls back to a random +# value if neither sha256sum nor shasum is available (extremely rare). +compute_device_fingerprint() { + local platform="$1" + local hn user input hash + hn="$(hostname 2>/dev/null || echo "")" + user="${USER:-$(id -un 2>/dev/null || echo "")}" + input="$hn|$platform|$user" + if command -v sha256sum >/dev/null 2>&1; then + hash="$(printf '%s' "$input" | sha256sum | cut -c1-16)" + elif command -v shasum >/dev/null 2>&1; then + hash="$(printf '%s' "$input" | shasum -a 256 | cut -c1-16)" + else + # Last resort: use $RANDOM. Won't dedup across runs but won't crash. + hash="rnd$(printf '%04x%04x%04x' "$RANDOM" "$RANDOM" "$RANDOM")" + fi + printf '%s' "$hash" +} + # ────────────────────────────────────────────────────────────────────────── # main — wraps the entire procedural body so that under `curl | bash` # bash finishes reading the script before any fd-rebinding happens. @@ -256,6 +279,11 @@ main() { # `set -u` happy. FORCE_REMOTE=false FORCE_LOCAL=false + local NO_TELEMETRY=false + + # Snapshot original args before the parse loop shifts them away — needed + # later for AGENTKEY_INSTALLER_FLAGS env passthrough. + local _orig_args=("$@") while [ $# -gt 0 ]; do case "$1" in @@ -270,6 +298,7 @@ main() { --force-mcp) FORCE_MCP=true; shift ;; --skip-skill) SKIP_SKILL=true; shift ;; --skip-mcp) SKIP_MCP=true; shift ;; + --no-telemetry) NO_TELEMETRY=true; shift ;; -h|--help) PRINT_HELP=true; shift ;; *) ui_warn "Unknown argument: $1"; shift ;; esac @@ -332,6 +361,19 @@ main() { fi ui_ok "Mode: $MODE" + # Resolve telemetry intent: --no-telemetry overrides everything; existing + # ~/.config/agentkey/telemetry-disabled file means already-opted-out. + local TELEMETRY_OPT_OUT_FILE="$HOME/.config/agentkey/telemetry-disabled" + if $NO_TELEMETRY; then + mkdir -p "$(dirname "$TELEMETRY_OPT_OUT_FILE")" 2>/dev/null || true + touch "$TELEMETRY_OPT_OUT_FILE" 2>/dev/null || true + ui_ok "Telemetry: disabled (--no-telemetry)" + elif [ -f "$TELEMETRY_OPT_OUT_FILE" ]; then + ui_ok "Telemetry: disabled (~/.config/agentkey/telemetry-disabled exists)" + else + ui_info "Telemetry: anonymous usage stats enabled (re-run with --no-telemetry to opt out)" + fi + # Node check local NODE_OK=false NODE_VERSION NODE_MAJOR if command -v node >/dev/null 2>&1; then @@ -471,6 +513,27 @@ main() { fi echo + # Telemetry context for `install_completed`. Opt-out is honored at + # the SOURCE: when AGENTKEY_TELEMETRY=0, no other context env vars + # are exported — hostname-derived fingerprint, agent lists, and + # installer flags are never computed nor passed to the child + # `npx @agentkey/mcp` process. The server treats AGENTKEY_TELEMETRY=0 + # as a hard skip. + if $NO_TELEMETRY || [ -f "$TELEMETRY_OPT_OUT_FILE" ]; then + export AGENTKEY_TELEMETRY=0 + else + export AGENTKEY_TELEMETRY=1 + local _flags="" + for _f in "${_orig_args[@]:-}"; do + _flags="${_flags:+$_flags,}$_f" + done + export AGENTKEY_INSTALL_SOURCE="one_liner" + export AGENTKEY_DETECTED_AGENTS="$(detect_agents)" + export AGENTKEY_SELECTED_AGENTS="${TARGETS:-}" + export AGENTKEY_INSTALLER_FLAGS="$_flags" + export AGENTKEY_DEVICE_FINGERPRINT="$(compute_device_fingerprint "$PLATFORM")" + fi + if ! npx -y "$MCP_PACKAGE" "${AUTH_ARGS[@]}"; then ui_error "MCP auth failed." ui_muted "Retry manually: npx -y $MCP_PACKAGE ${AUTH_ARGS[*]}"