mirror of
https://github.com/chainbase-labs/Agentkey.git
synced 2026-09-20 14:20:23 +08:00
8e93c67a33
## Summary - install the AgentKey Skill through the Skills CLI universal target for DSH-only installs - avoid passing either dsh or the unsupported global PromptScript target while preserving explicit mixed-agent targets - update Bash, PowerShell, English/Chinese setup guidance, retry instructions, and release-asset source docs - add Bash mixed-target coverage and a Windows PowerShell invocation regression ## Root cause skills@1.5.23 -g -y adds PromptScript to its universal target set even though PromptScript has no global install directory. The canonical AgentKey Skill still installs, but the command prints Failed to install 1. Explicitly targeting universal writes the same ~/.agents/skills/agentkey copy without selecting PromptScript. ## Validation - bats tests/ — 42/42 - bash -n scripts/install.sh - bash -n scripts/uninstall.sh - bash -n scripts/build-release-assets.sh - scripts/build-release-assets.sh with an isolated output directory - workflow YAML parse - git diff --check - Windows behavior regression added to the windows-latest Scripts tests job ## Deployment follow-up Merging/releasing this PR does not automatically update agentkey.app/install.sh. After release, publish the current Bash/PowerShell install and uninstall scripts to the website origin and purge the CDN; the live endpoints were serving stale pre-DSH content during verification. Co-authored-by: Allen <0xfatdog@gmail.com>
442 lines
21 KiB
PowerShell
442 lines
21 KiB
PowerShell
#Requires -Version 5.1
|
||
<#
|
||
.SYNOPSIS
|
||
AgentKey installer for Windows
|
||
.DESCRIPTION
|
||
Usage:
|
||
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,
|
||
then `npx @agentkey/cli --auth-login` for device auth. The auth step always
|
||
tries to open a local browser AND prints the URL so headless / SSH users can
|
||
copy it elsewhere. MCP config is written automatically for Claude Code /
|
||
Claude Desktop / Cursor.
|
||
#>
|
||
|
||
[CmdletBinding()]
|
||
param(
|
||
[switch]$Yes,
|
||
[switch]$Interactive,
|
||
[string]$Only,
|
||
[switch]$AllAgents,
|
||
[switch]$ListAgents,
|
||
[switch]$SkipSkill,
|
||
[switch]$SkipMcp,
|
||
[switch]$NoTelemetry,
|
||
[switch]$Help
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
$SkillRepo = 'chainbase-labs/agentkey'
|
||
$CliPackage = '@agentkey/cli'
|
||
$NodeMinMajor = 18
|
||
|
||
# ── Agent markers (mirror of install.sh) ──────────────────────────────────
|
||
# Subset of vercel-labs/skills' 45 supported agent IDs that have reliable
|
||
# Windows-side markers. Sync source:
|
||
# https://github.com/vercel-labs/skills (Supported Agents table).
|
||
#
|
||
# IMPORTANT: ids here MUST match the `--only` ids accepted by both
|
||
# `npx skills add -a` and `npx -y @agentkey/cli --auth-login --only`.
|
||
# `claude-desktop` and `dsh` are exceptions. Neither is passed to
|
||
# `skills add -a`; DSH reads the global skill installed for `universal`.
|
||
$DshHome = if ([string]::IsNullOrWhiteSpace($env:DSH_HOME)) { Join-Path ([Environment]::GetFolderPath('UserProfile')) '.dsh' } else { $env:DSH_HOME }
|
||
if ($DshHome -eq '~') {
|
||
$DshHome = [Environment]::GetFolderPath('UserProfile')
|
||
} elseif ($DshHome -match '^~[\\/]') {
|
||
$DshHome = Join-Path ([Environment]::GetFolderPath('UserProfile')) $DshHome.Substring(2)
|
||
}
|
||
$DshHome = [System.IO.Path]::GetFullPath($DshHome)
|
||
$AgentMarkers = @(
|
||
@{ Id = 'claude-code'; Markers = @("path:$env:USERPROFILE\.claude.json", 'cmd:claude') }
|
||
@{ Id = 'claude-desktop'; Markers = @("path:$env:LOCALAPPDATA\AnthropicClaude", "path:$env:APPDATA\Claude\claude_desktop_config.json", "path:$env:APPDATA\Claude") }
|
||
@{ Id = 'cursor'; Markers = @("path:$env:USERPROFILE\.cursor", 'cmd:cursor', "path:$env:LOCALAPPDATA\Programs\cursor") }
|
||
@{ Id = 'codex'; Markers = @("path:$env:USERPROFILE\.codex", 'cmd:codex') }
|
||
@{ Id = 'dsh'; Markers = @("path:$DshHome", 'cmd:dsh') }
|
||
@{ Id = 'gemini-cli'; Markers = @("path:$env:USERPROFILE\.gemini", 'cmd:gemini') }
|
||
@{ Id = 'opencode'; Markers = @("path:$env:APPDATA\opencode", "path:$env:USERPROFILE\.opencode", 'cmd:opencode') }
|
||
@{ Id = 'openclaw'; Markers = @("path:$env:USERPROFILE\.openclaw", 'cmd:openclaw') }
|
||
@{ Id = 'qwen-code'; Markers = @("path:$env:USERPROFILE\.qwen", 'cmd:qwen') }
|
||
@{ Id = 'iflow-cli'; Markers = @("path:$env:USERPROFILE\.iflow", 'cmd:iflow') }
|
||
@{ Id = 'windsurf'; Markers = @("path:$env:USERPROFILE\.codeium\windsurf", "path:$env:USERPROFILE\.windsurf", 'cmd:windsurf') }
|
||
@{ Id = 'warp'; Markers = @("path:$env:USERPROFILE\.warp") }
|
||
@{ Id = 'amp'; Markers = @("path:$env:APPDATA\amp", 'cmd:amp') }
|
||
@{ Id = 'crush'; Markers = @("path:$env:APPDATA\crush", 'cmd:crush') }
|
||
@{ Id = 'goose'; Markers = @("path:$env:APPDATA\goose", 'cmd:goose') }
|
||
@{ Id = 'droid'; Markers = @('cmd:droid') }
|
||
@{ Id = 'kode'; Markers = @('cmd:kode') }
|
||
@{ Id = 'kilo'; Markers = @('cmd:kilo') }
|
||
@{ Id = 'kimi-cli'; Markers = @("path:$env:USERPROFILE\.kimi", 'cmd:kimi') }
|
||
@{ Id = 'kiro-cli'; Markers = @("path:$env:USERPROFILE\.kiro", 'cmd:kiro') }
|
||
)
|
||
|
||
# Agent ids excluded from per-agent `skills add -a`: Claude Desktop has no
|
||
# skill path, while DSH consumes the global `universal` copy.
|
||
$SkillsAgentExclusions = @('claude-desktop', 'dsh')
|
||
|
||
# Agent ids whose MCP registration the installer can drive automatically.
|
||
# Mirror of MCP_AUTO_AGENTS in install.sh and AGENT_REGISTRY in
|
||
# AgentKey-Server/cli/src/lib/mcp-clients.ts. Keep these three in sync.
|
||
$McpAutoAgents = @(
|
||
'claude-code', 'claude-desktop', 'cursor', 'codex', 'gemini-cli',
|
||
'opencode', 'qwen-code', 'iflow-cli', 'kimi-cli', 'kiro-cli',
|
||
'windsurf', 'warp', 'amp', 'crush', 'droid', 'openclaw', 'dsh'
|
||
)
|
||
|
||
# ── UI helpers ────────────────────────────────────────────────────────────
|
||
function Write-Banner {
|
||
Write-Host ''
|
||
Write-Host ' █████ ██████ ███████ ███ ██ ████████ ██ ██ ███████ ██ ██' -ForegroundColor Cyan
|
||
Write-Host ' ██ ██ ██ ██ ████ ██ ██ ██ ██ ██ ██ ██ ' -ForegroundColor Cyan
|
||
Write-Host ' ███████ ██ ███ █████ ██ ██ ██ ██ █████ █████ ████ ' -ForegroundColor Cyan
|
||
Write-Host ' ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ' -ForegroundColor Cyan
|
||
Write-Host ' ██ ██ ██████ ███████ ██ ████ ██ ██ ██ ███████ ██ ' -ForegroundColor Cyan
|
||
Write-Host ''
|
||
Write-Host ' One command. Full internet access for your AI agent.' -ForegroundColor White
|
||
Write-Host ' https://agentkey.app' -ForegroundColor DarkGray
|
||
Write-Host ''
|
||
}
|
||
|
||
function Write-Step ($text) { Write-Host ''; Write-Host " $text" -ForegroundColor White }
|
||
function Write-Info ($text) { Write-Host " › $text" -ForegroundColor Gray }
|
||
function Write-Ok ($text) { Write-Host " ✓ $text" -ForegroundColor Green }
|
||
function Write-Warn2($text) { Write-Host " ! $text" -ForegroundColor Yellow }
|
||
function Write-Err ($text) { Write-Host " ✗ $text" -ForegroundColor Red }
|
||
function Write-Muted($text) { Write-Host " $text" -ForegroundColor DarkGray }
|
||
|
||
function Die ($text) { Write-Err $text; exit 1 }
|
||
|
||
# ── Helpers: agent detection ──────────────────────────────────────────────
|
||
function Test-AgentMarker {
|
||
param([string]$Marker)
|
||
if ($Marker.StartsWith('cmd:')) {
|
||
return [bool](Get-Command $Marker.Substring(4) -ErrorAction SilentlyContinue)
|
||
}
|
||
if ($Marker.StartsWith('path:')) {
|
||
return Test-Path -LiteralPath $Marker.Substring(5)
|
||
}
|
||
return $false
|
||
}
|
||
|
||
function Get-DetectedAgents {
|
||
$hits = New-Object System.Collections.Generic.List[string]
|
||
foreach ($entry in $AgentMarkers) {
|
||
foreach ($m in $entry.Markers) {
|
||
if (Test-AgentMarker $m) { $hits.Add($entry.Id) | Out-Null; break }
|
||
}
|
||
}
|
||
return @($hits | Sort-Object -Unique)
|
||
}
|
||
|
||
# ── Help ──────────────────────────────────────────────────────────────────
|
||
if ($Help) {
|
||
@'
|
||
AgentKey installer for Windows
|
||
|
||
Usage:
|
||
irm https://agentkey.app/install.ps1 | iex
|
||
& ([scriptblock]::Create((irm https://agentkey.app/install.ps1))) -Yes
|
||
|
||
Parameters:
|
||
-Yes Non-interactive: install skill to every detected agent, no prompts
|
||
-Interactive Force interactive mode (fails if console input is redirected)
|
||
-Only <a,b,c> Only install skill for these agents (e.g. "claude-code,cursor")
|
||
-AllAgents Skip auto-detection; let 'skills' CLI install for every detected agent
|
||
-ListAgents Print the agents we'd auto-select on this machine and exit
|
||
-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:
|
||
The installer auto-detects which AI agents are on this machine and
|
||
pre-selects them for skill installation. The auth step always tries
|
||
to open a browser and also prints the URL — so SSH / WinRM / Docker
|
||
/ OpenClaw users can copy the URL to any device with a browser.
|
||
'@
|
||
exit 0
|
||
}
|
||
|
||
if ($ListAgents) {
|
||
$detected = Get-DetectedAgents
|
||
if ($detected.Count -gt 0) { $detected -join "`n" | Write-Output }
|
||
else { Write-Host 'no agents detected on this host' -ForegroundColor Yellow }
|
||
exit 0
|
||
}
|
||
|
||
Write-Banner
|
||
|
||
# ── 1. Preflight ──────────────────────────────────────────────────────────
|
||
Write-Step '1. Preflight'
|
||
|
||
# Platform guard
|
||
if (-not $IsWindows -and $PSVersionTable.PSVersion.Major -ge 6) {
|
||
Die 'This script targets Windows. On macOS/Linux use install.sh instead.'
|
||
}
|
||
Write-Ok 'Platform: windows'
|
||
|
||
# Resolve interactive mode. PowerShell's `iex` runs in the current session, so
|
||
# Read-Host works natively even under `irm | iex`. The only thing we need to
|
||
# guard is truly redirected input (scheduled tasks, CI with redirected stdin).
|
||
$InputRedirected = $false
|
||
try { $InputRedirected = [Console]::IsInputRedirected } catch { $InputRedirected = $false }
|
||
|
||
$Mode = $null
|
||
if ($Yes) { $Mode = 'noninteractive' }
|
||
elseif ($Interactive) {
|
||
if ($InputRedirected) { Die '-Interactive requested but console input is redirected.' }
|
||
$Mode = 'interactive'
|
||
}
|
||
elseif ($InputRedirected) {
|
||
$Mode = 'noninteractive'
|
||
Write-Warn2 'No interactive console detected — falling back to -Yes'
|
||
}
|
||
else {
|
||
$Mode = 'interactive'
|
||
}
|
||
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 {
|
||
$v = (& node --version) 2>$null
|
||
if ($v -match '^v(\d+)\.') { return [int]$Matches[1] }
|
||
} catch {}
|
||
return 0
|
||
}
|
||
|
||
function Install-Node {
|
||
Write-Info "Installing Node.js LTS ..."
|
||
if (Get-Command winget -ErrorAction SilentlyContinue) {
|
||
winget install -e --id OpenJS.NodeJS.LTS --silent --accept-source-agreements --accept-package-agreements | Out-Null
|
||
} elseif (Get-Command scoop -ErrorAction SilentlyContinue) {
|
||
scoop install nodejs-lts | Out-Null
|
||
} elseif (Get-Command choco -ErrorAction SilentlyContinue) {
|
||
choco install nodejs-lts -y | Out-Null
|
||
} else {
|
||
Die 'No package manager found (winget/scoop/choco). Install Node.js LTS manually: https://nodejs.org/'
|
||
}
|
||
# Refresh PATH so this session sees the newly installed node
|
||
$env:Path = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' +
|
||
[System.Environment]::GetEnvironmentVariable('Path', 'User')
|
||
Write-Ok 'Node.js installed'
|
||
}
|
||
|
||
$nodeMajor = Get-NodeMajor
|
||
if ($nodeMajor -ge $NodeMinMajor) {
|
||
Write-Ok "Node.js: v$nodeMajor.x"
|
||
} else {
|
||
if ($nodeMajor -gt 0) { Write-Warn2 "Node.js v$nodeMajor found but v$NodeMinMajor+ is required" }
|
||
if ($Mode -eq 'interactive') {
|
||
Write-Host ''
|
||
Write-Host " Node.js v$NodeMinMajor+ is required but not found." -ForegroundColor White
|
||
$reply = Read-Host ' Install it now? [Y/n]'
|
||
if ($reply -match '^(n|no)$') { Die 'Node.js required. Aborting.' }
|
||
}
|
||
Install-Node
|
||
}
|
||
|
||
if (-not (Get-Command npx -ErrorAction SilentlyContinue)) {
|
||
Die 'npx not found after Node install — please reopen your terminal or reinstall Node.js.'
|
||
}
|
||
|
||
# Resolve target agent list — shared between the skill step and the MCP step.
|
||
# $AllTargets — every detected agent, including local exceptions
|
||
# $SkillTargets — $AllTargets minus ids excluded from `skills add -a`
|
||
# $McpTargets — $AllTargets filtered to ids the MCP CLI knows how to write
|
||
$AllTargets = @()
|
||
if ($Only) {
|
||
$AllTargets = @($Only -split ',' | Where-Object { $_ -ne '' })
|
||
Write-Info "Targeting agents from -Only: $($AllTargets -join ', ')"
|
||
} elseif ($AllAgents) {
|
||
Write-Info "Installing for every agent the 'skills' CLI detects (-AllAgents)"
|
||
} else {
|
||
$AllTargets = @(Get-DetectedAgents)
|
||
if ($AllTargets.Count -gt 0) {
|
||
Write-Ok "Detected agents on this host: $($AllTargets -join ', ')"
|
||
Write-Muted '(override with -Only <ids>, or use -AllAgents)'
|
||
} else {
|
||
Write-Info "No agents auto-detected — letting 'skills' CLI scan."
|
||
}
|
||
}
|
||
|
||
$SkillTargets = @($AllTargets | Where-Object { $_ -notin $SkillsAgentExclusions })
|
||
$McpTargets = @($AllTargets | Where-Object { $_ -in $McpAutoAgents })
|
||
$DshSelected = $AllTargets -contains 'dsh'
|
||
$DshConfigured = $false
|
||
|
||
# ── 2. Install the AgentKey skill ─────────────────────────────────────────
|
||
if ($SkipSkill) {
|
||
Write-Step '2. Install the AgentKey skill'
|
||
Write-Muted 'Skipped (-SkipSkill)'
|
||
} elseif ($AllTargets.Count -gt 0 -and $SkillTargets.Count -eq 0 -and -not $DshSelected) {
|
||
# DSH never enters this branch: `-Only dsh` must still run the global
|
||
# `skills add -g -a universal` path, without passing dsh to `-a`.
|
||
Write-Step '2. Install the AgentKey skill'
|
||
Write-Muted "Skipped — selected targets ($($AllTargets -join ',')) are MCP-only (no skill install path)."
|
||
} else {
|
||
Write-Step '2. Install the AgentKey skill'
|
||
|
||
$skillsArgs = @('-y', 'skills', 'add', $SkillRepo, '-g')
|
||
if ($SkillTargets.Count -gt 0) {
|
||
$skillsArgs += '-a'
|
||
$skillsArgs += $SkillTargets
|
||
} elseif ($DshSelected) {
|
||
$skillsArgs += @('-a', 'universal', '-s', 'agentkey')
|
||
}
|
||
# Always pass -y in noninteractive mode AND when we already resolved
|
||
# an explicit target list — there's nothing left to ask the user.
|
||
if ($Mode -eq 'noninteractive' -or $AllTargets.Count -gt 0) {
|
||
$skillsArgs += '-y'
|
||
}
|
||
|
||
& npx @skillsArgs
|
||
if ($LASTEXITCODE -ne 0) { Die "Failed to install skill via 'skills' CLI" }
|
||
# The skills CLI sometimes prints "Installation failed" and still
|
||
# exits 0 (e.g. network error during git clone). Verify the skill
|
||
# actually landed on disk before declaring success. Paths must mirror
|
||
# the `path:` markers in $AgentMarkers: most agents live under
|
||
# %USERPROFILE%\.<agent>, but amp / crush / goose / opencode live
|
||
# under %APPDATA%\<agent>.
|
||
$userHome = [Environment]::GetFolderPath('UserProfile')
|
||
$candidatePaths = @(
|
||
(Join-Path $userHome '.agents\skills\agentkey'),
|
||
(Join-Path $userHome '.claude\skills\agentkey'),
|
||
(Join-Path $userHome '.cursor\skills\agentkey'),
|
||
(Join-Path $userHome '.codex\skills\agentkey'),
|
||
(Join-Path $userHome '.gemini\skills\agentkey'),
|
||
(Join-Path $userHome '.opencode\skills\agentkey'),
|
||
(Join-Path $userHome '.openclaw\skills\agentkey'),
|
||
(Join-Path $userHome '.qwen\skills\agentkey'),
|
||
(Join-Path $userHome '.iflow\skills\agentkey'),
|
||
(Join-Path $userHome '.windsurf\skills\agentkey'),
|
||
(Join-Path $userHome '.warp\skills\agentkey'),
|
||
(Join-Path $userHome '.kimi\skills\agentkey'),
|
||
(Join-Path $userHome '.kiro\skills\agentkey'),
|
||
# APPDATA-rooted agents (parity with install.sh's $HOME/.config/<agent>)
|
||
(Join-Path $env:APPDATA 'amp\skills\agentkey'),
|
||
(Join-Path $env:APPDATA 'crush\skills\agentkey'),
|
||
(Join-Path $env:APPDATA 'goose\skills\agentkey'),
|
||
(Join-Path $env:APPDATA 'opencode\skills\agentkey')
|
||
)
|
||
$agentkeyFound = $false
|
||
foreach ($abs in $candidatePaths) {
|
||
if (Test-Path (Join-Path $abs 'SKILL.md')) {
|
||
$agentkeyFound = $true
|
||
break
|
||
}
|
||
}
|
||
if (-not $agentkeyFound) {
|
||
Die "Skill install reported success but no agentkey SKILL.md was created — likely a network or git clone failure. Retry: npx -y skills add $SkillRepo -g -a universal -s agentkey -y"
|
||
}
|
||
Write-Ok 'Skill installed'
|
||
}
|
||
|
||
# ── 3. MCP authentication ────────────────────────────────────────────────
|
||
# Always run auth-login. The CLI itself decides whether the existing token
|
||
# can be reused or a fresh device-code flow is needed — the installer no
|
||
# longer second-guesses by sniffing config files (which produced false
|
||
# positives across the stdio → HTTP schema change).
|
||
if ($SkipMcp) {
|
||
Write-Step '3. Register the MCP server'
|
||
Write-Muted 'Skipped (-SkipMcp)'
|
||
} elseif ($AllTargets.Count -gt 0 -and $McpTargets.Count -eq 0) {
|
||
# User selected ONLY MCP-incompatible agents (goose / kode / kilo via
|
||
# -Only). Running auth-login without --only would silently register MCP
|
||
# in every detected agent, overriding the user's explicit scope. Skip
|
||
# rather than over-register. See PR #41 B1.
|
||
Write-Step '3. Register the MCP server'
|
||
Write-Muted "Skipped — selected agents ($($AllTargets -join ',')) need manual MCP setup (see SKILL.md Fallback section)."
|
||
} else {
|
||
# Pin MCP registration to the same agent list the skill step targeted.
|
||
# When McpTargets is empty (auto-detect found nothing), let
|
||
# `@agentkey/cli` do its own detection — same fallback we use for skill
|
||
# install. Older CLI versions silently ignore --only, so this is
|
||
# forward-compatible.
|
||
$authArgs = @('--auth-login')
|
||
if ($McpTargets.Count -gt 0) {
|
||
$authArgs += '--only'
|
||
$authArgs += ($McpTargets -join ',')
|
||
}
|
||
|
||
Write-Step '3. Register the MCP server'
|
||
Write-Info 'Opening your browser for AgentKey device authentication ...'
|
||
if ($McpTargets.Count -gt 0) {
|
||
Write-Muted "Will register MCP in: $($McpTargets -join ', ')"
|
||
} else {
|
||
Write-Muted "If a browser doesn't open (SSH / WinRM / Docker / headless), the auth URL is also printed below — open it on any device to finish."
|
||
}
|
||
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/cli`
|
||
# 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
|
||
|
||
$env:AGENTKEY_INSTALL_SOURCE = 'one_liner'
|
||
$env:AGENTKEY_DETECTED_AGENTS = ($DetectedAgents -join ',')
|
||
$env:AGENTKEY_SELECTED_AGENTS = ($AllTargets -join ',')
|
||
$env:AGENTKEY_INSTALLER_FLAGS = ($PSBoundParameters.Keys | ForEach-Object { "-$_" }) -join ','
|
||
$env:AGENTKEY_DEVICE_FINGERPRINT = $DeviceFingerprint
|
||
}
|
||
|
||
& npx -y $CliPackage @authArgs
|
||
if ($LASTEXITCODE -ne 0) {
|
||
Write-Err 'MCP auth failed.'
|
||
Write-Muted "Retry manually: npx -y $CliPackage $($authArgs -join ' ')"
|
||
exit 1
|
||
}
|
||
$DshConfigured = $McpTargets -contains 'dsh'
|
||
Write-Ok 'MCP server registered'
|
||
}
|
||
|
||
# ── 4. Summary ───────────────────────────────────────────────────────────
|
||
Write-Step '✨ Installation complete'
|
||
Write-Host ''
|
||
Write-Host ' Next steps' -ForegroundColor White
|
||
if ($DshConfigured) {
|
||
Write-Muted '1. Running DSH profiles hot-apply the home patch; start stopped DSH profiles and restart other clients.'
|
||
} else {
|
||
Write-Muted '1. Restart your agent (Claude Code / Cursor / etc.)'
|
||
}
|
||
Write-Muted '2. Ask it something that needs the internet:'
|
||
Write-Host ' "What has Musk been tweeting about lately?"' -ForegroundColor Cyan
|
||
Write-Host ''
|
||
Write-Host ' Docs https://agentkey.app/docs' -ForegroundColor White
|
||
Write-Host ' Uninstall irm https://agentkey.app/uninstall.ps1 | iex' -ForegroundColor White
|
||
Write-Host ''
|