Merge branch 'dongsheng123132:main' into main
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,6 +16,7 @@ social-assets/
|
|||||||
.download-cache/
|
.download-cache/
|
||||||
*.dmg
|
*.dmg
|
||||||
*.exe
|
*.exe
|
||||||
|
!website/downloads/agent.exe
|
||||||
*.blockmap
|
*.blockmap
|
||||||
builder-debug.yml
|
builder-debug.yml
|
||||||
|
|
||||||
|
|||||||
25
vercel.json
25
vercel.json
@@ -1,3 +1,26 @@
|
|||||||
{
|
{
|
||||||
"outputDirectory": "website"
|
"outputDirectory": "website",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"source": "/downloads/agent.exe",
|
||||||
|
"headers": [
|
||||||
|
{ "key": "Content-Type", "value": "application/octet-stream" },
|
||||||
|
{ "key": "Content-Disposition", "value": "attachment; filename=agent.exe" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "/downloads/agent",
|
||||||
|
"headers": [
|
||||||
|
{ "key": "Content-Type", "value": "application/octet-stream" },
|
||||||
|
{ "key": "Content-Disposition", "value": "attachment; filename=agent" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "/downloads/agent-linux",
|
||||||
|
"headers": [
|
||||||
|
{ "key": "Content-Type", "value": "application/octet-stream" },
|
||||||
|
{ "key": "Content-Disposition", "value": "attachment; filename=agent-linux" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
website/agent.exe
Executable file
BIN
website/agent.exe
Executable file
Binary file not shown.
201
website/agent.html
Normal file
201
website/agent.html
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>U-Claw 远程协助 - Agent 模式</title>
|
||||||
|
<style>
|
||||||
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
body { font-family: -apple-system, 'Microsoft YaHei', sans-serif; max-width: 640px; margin: 40px auto; padding: 0 20px; background: #1a1a2e; color: #eee; line-height: 1.6; }
|
||||||
|
h1 { text-align: center; font-size: 28px; margin-bottom: 8px; }
|
||||||
|
.subtitle { text-align: center; color: #aaa; margin-bottom: 30px; }
|
||||||
|
.step { background: #16213e; border-radius: 12px; padding: 20px; margin: 20px 0; }
|
||||||
|
.step h2 { color: #e94560; margin-bottom: 12px; font-size: 18px; }
|
||||||
|
.step p { color: #ccc; margin-bottom: 10px; }
|
||||||
|
.cmd { background: #0f3460; padding: 15px; border-radius: 8px; font-family: 'Consolas', 'Courier New', monospace; font-size: 15px; position: relative; word-break: break-all; cursor: pointer; transition: background 0.2s; }
|
||||||
|
.cmd:hover { background: #1a5276; }
|
||||||
|
.cmd:active { background: #1e6091; }
|
||||||
|
.copy-btn { position: absolute; right: 8px; top: 8px; background: #e94560; color: white; border: none; padding: 6px 14px; border-radius: 6px; cursor: pointer; font-size: 13px; }
|
||||||
|
.copy-btn:hover { background: #d63851; }
|
||||||
|
.note { color: #888; font-size: 13px; margin-top: 8px; }
|
||||||
|
.warn { color: #f0ad4e; font-size: 13px; margin-top: 8px; }
|
||||||
|
.tab-group { display: flex; gap: 0; margin-bottom: 0; }
|
||||||
|
.tab { padding: 8px 20px; border-radius: 8px 8px 0 0; cursor: pointer; font-size: 14px; background: #0d1b30; color: #888; border: 1px solid #1a3a5c; border-bottom: none; }
|
||||||
|
.tab.active { background: #16213e; color: #e94560; font-weight: bold; }
|
||||||
|
.tab-content { display: none; }
|
||||||
|
.tab-content.active { display: block; }
|
||||||
|
.screenshot { background: #0a0a1a; border-radius: 8px; padding: 15px; margin: 10px 0; border: 1px solid #333; }
|
||||||
|
.screenshot pre { color: #4ec9b0; font-family: 'Consolas', monospace; font-size: 13px; white-space: pre-wrap; }
|
||||||
|
.safe-badge { display: inline-block; background: #1b5e20; color: #a5d6a7; padding: 4px 12px; border-radius: 20px; font-size: 12px; margin-top: 10px; }
|
||||||
|
.faq { background: #16213e; border-radius: 12px; padding: 20px; margin: 20px 0; }
|
||||||
|
.faq h3 { color: #e94560; margin-bottom: 8px; font-size: 15px; }
|
||||||
|
.faq p { color: #aaa; font-size: 14px; margin-bottom: 15px; }
|
||||||
|
img.guide-img { width: 100%; border-radius: 8px; margin: 10px 0; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>U-Claw 远程协助</h1>
|
||||||
|
<p class="subtitle">Agent 模式 - 轻量快速,一行命令上线</p>
|
||||||
|
|
||||||
|
<!-- Step 1 -->
|
||||||
|
<div class="step">
|
||||||
|
<h2>第 1 步:打开终端</h2>
|
||||||
|
|
||||||
|
<div class="tab-group">
|
||||||
|
<div class="tab active" onclick="switchTab('os', 'win')">Windows</div>
|
||||||
|
<div class="tab" onclick="switchTab('os', 'mac')">macOS</div>
|
||||||
|
<div class="tab" onclick="switchTab('os', 'linux')">Linux</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="os-win" class="tab-content active">
|
||||||
|
<div style="background:#16213e; padding: 15px; border-radius: 0 8px 8px 8px; border: 1px solid #1a3a5c; border-top: none;">
|
||||||
|
<p><strong>方法 1(推荐):</strong></p>
|
||||||
|
<p>按键盘 <code style="background:#0f3460; padding:2px 8px; border-radius:4px;">Win + X</code>,选择 <strong>"终端(管理员)"</strong> 或 <strong>"PowerShell(管理员)"</strong></p>
|
||||||
|
<p style="margin-top:10px;"><strong>方法 2:</strong></p>
|
||||||
|
<p>按 <code style="background:#0f3460; padding:2px 8px; border-radius:4px;">Win</code> 键,搜索 <strong>"PowerShell"</strong>,右键选 <strong>"以管理员身份运行"</strong></p>
|
||||||
|
<div class="screenshot">
|
||||||
|
<pre>PS C:\Users\YourName> _</pre>
|
||||||
|
</div>
|
||||||
|
<p class="note">看到这样的界面就对了 ↑</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="os-mac" class="tab-content">
|
||||||
|
<div style="background:#16213e; padding: 15px; border-radius: 0 8px 8px 8px; border: 1px solid #1a3a5c; border-top: none;">
|
||||||
|
<p>按 <code style="background:#0f3460; padding:2px 8px; border-radius:4px;">Command + 空格</code>,搜索 <strong>"终端"</strong> 或 <strong>"Terminal"</strong>,回车打开</p>
|
||||||
|
<div class="screenshot">
|
||||||
|
<pre>yourname@MacBook ~ % _</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="os-linux" class="tab-content">
|
||||||
|
<div style="background:#16213e; padding: 15px; border-radius: 0 8px 8px 8px; border: 1px solid #1a3a5c; border-top: none;">
|
||||||
|
<p>按 <code style="background:#0f3460; padding:2px 8px; border-radius:4px;">Ctrl + Alt + T</code> 打开终端</p>
|
||||||
|
<div class="screenshot">
|
||||||
|
<pre>user@hostname:~$ _</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 2 -->
|
||||||
|
<div class="step">
|
||||||
|
<h2>第 2 步:粘贴运行</h2>
|
||||||
|
<p>复制下面的命令,粘贴到终端里,按回车:</p>
|
||||||
|
|
||||||
|
<div id="cmd-win-wrap" class="tab-content active">
|
||||||
|
<div class="cmd" id="cmd-win" onclick="copyCmd('cmd-win')">
|
||||||
|
irm https://u-claw.org/agent.ps1 | iex
|
||||||
|
<button class="copy-btn" onclick="event.stopPropagation(); copyCmd('cmd-win')">复制</button>
|
||||||
|
</div>
|
||||||
|
<p class="note">提示:在 PowerShell 里右键即可粘贴</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="cmd-mac-wrap" class="tab-content">
|
||||||
|
<div class="cmd" id="cmd-mac" onclick="copyCmd('cmd-mac')">
|
||||||
|
curl -fsSL https://u-claw.org/agent.sh | bash
|
||||||
|
<button class="copy-btn" onclick="event.stopPropagation(); copyCmd('cmd-mac')">复制</button>
|
||||||
|
</div>
|
||||||
|
<p class="note">提示:Command+V 粘贴,然后回车</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="cmd-linux-wrap" class="tab-content">
|
||||||
|
<div class="cmd" id="cmd-linux" onclick="copyCmd('cmd-linux')">
|
||||||
|
curl -fsSL https://u-claw.org/agent.sh | bash
|
||||||
|
<button class="copy-btn" onclick="event.stopPropagation(); copyCmd('cmd-linux')">复制</button>
|
||||||
|
</div>
|
||||||
|
<p class="note">提示:Ctrl+Shift+V 粘贴,然后回车</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Step 3 -->
|
||||||
|
<div class="step">
|
||||||
|
<h2>第 3 步:发送设备 ID</h2>
|
||||||
|
<p>运行成功后会看到:</p>
|
||||||
|
<div class="screenshot">
|
||||||
|
<pre>
|
||||||
|
==========================================
|
||||||
|
Connected! Send this ID to support:
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
+------------------------------------------+
|
||||||
|
| Device ID: desktop-a3f2 |
|
||||||
|
| Hostname: DESKTOP-ZHANGSAN |
|
||||||
|
+------------------------------------------+
|
||||||
|
|
||||||
|
* Close this window to disconnect
|
||||||
|
* Auto-disconnect after 2 hours</pre>
|
||||||
|
</div>
|
||||||
|
<p style="margin-top: 12px;">把 <strong>Device ID</strong>(如 <code style="background:#0f3460; padding:2px 8px; border-radius:4px;">desktop-a3f2</code>)发给技术支持即可。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Safety -->
|
||||||
|
<div class="step" style="border: 1px solid #1b5e20;">
|
||||||
|
<h2 style="color: #4caf50;">安全说明</h2>
|
||||||
|
<p>
|
||||||
|
<span class="safe-badge">单向连接</span>
|
||||||
|
Agent 只接收并执行技术支持发送的诊断命令
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="safe-badge">随时断开</span>
|
||||||
|
关闭终端窗口即可立即断开连接
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="safe-badge">自动过期</span>
|
||||||
|
连接 2 小时后自动断开,不会常驻
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="safe-badge">无残留</span>
|
||||||
|
断开后自动清理下载的文件
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- FAQ -->
|
||||||
|
<div class="faq">
|
||||||
|
<h3>Q: 运行报错"无法加载文件"怎么办?</h3>
|
||||||
|
<p>在 PowerShell 里先运行:<code style="background:#0f3460; padding:2px 6px; border-radius:4px;">Set-ExecutionPolicy Bypass -Scope Process</code>,然后再粘贴命令。</p>
|
||||||
|
|
||||||
|
<h3>Q: 下载失败?</h3>
|
||||||
|
<p>检查网络连接,或者联系技术支持获取离线安装包。</p>
|
||||||
|
|
||||||
|
<h3>Q: 连不上服务器?</h3>
|
||||||
|
<p>可能是公司防火墙限制,请联系技术支持。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p style="text-align:center; color:#555; margin: 30px 0; font-size: 13px;">
|
||||||
|
U-Claw Remote Support © 2026
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function switchTab(group, name) {
|
||||||
|
// Update tab buttons
|
||||||
|
document.querySelectorAll('.tab-group .tab').forEach(t => t.classList.remove('active'));
|
||||||
|
event.target.classList.add('active');
|
||||||
|
|
||||||
|
// Update step 1 content
|
||||||
|
document.querySelectorAll('[id^="os-"]').forEach(c => c.classList.remove('active'));
|
||||||
|
document.getElementById('os-' + name).classList.add('active');
|
||||||
|
|
||||||
|
// Update step 2 commands
|
||||||
|
document.querySelectorAll('[id^="cmd-"][id$="-wrap"]').forEach(c => c.classList.remove('active'));
|
||||||
|
const cmdName = name === 'win' ? 'win' : name === 'mac' ? 'mac' : 'linux';
|
||||||
|
document.getElementById('cmd-' + cmdName + '-wrap').classList.add('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyCmd(id) {
|
||||||
|
const el = document.getElementById(id);
|
||||||
|
const text = el.childNodes[0].textContent.trim();
|
||||||
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
|
const btn = el.querySelector('.copy-btn');
|
||||||
|
btn.textContent = '已复制 ✓';
|
||||||
|
btn.style.background = '#27ae60';
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.textContent = '复制';
|
||||||
|
btn.style.background = '#e94560';
|
||||||
|
}, 1500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
130
website/agent.ps1
Normal file
130
website/agent.ps1
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# ============================================================
|
||||||
|
# U-Claw Remote Agent (Windows)
|
||||||
|
# Usage: irm https://u-claw.org/agent.ps1 | iex
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
try { chcp 65001 | Out-Null } catch {}
|
||||||
|
Set-ExecutionPolicy Bypass -Scope Process -Force -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
$RELAY_SERVER = "wss://47.107.130.152:8900"
|
||||||
|
$DOWNLOAD_URL = "https://u-claw.org/downloads/agent.exe"
|
||||||
|
$AGENT_DIR = "$env:TEMP\uclaw"
|
||||||
|
$AGENT_PATH = "$AGENT_DIR\agent.exe"
|
||||||
|
$TOKEN = "uclaw-agent-pub"
|
||||||
|
$TIMEOUT_HOURS = 2
|
||||||
|
|
||||||
|
Clear-Host
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host " ==========================================" -ForegroundColor Cyan
|
||||||
|
Write-Host " U-Claw Remote Agent" -ForegroundColor Cyan
|
||||||
|
Write-Host " ==========================================" -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# ---- Safety notice ----
|
||||||
|
Write-Host " ! This script will:" -ForegroundColor Yellow
|
||||||
|
Write-Host " 1. Download a lightweight remote agent (~8MB)" -ForegroundColor DarkGray
|
||||||
|
Write-Host " 2. Connect to U-Claw relay server" -ForegroundColor DarkGray
|
||||||
|
Write-Host " 3. Allow remote command execution for support" -ForegroundColor DarkGray
|
||||||
|
Write-Host " 4. Close this window to disconnect anytime" -ForegroundColor DarkGray
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host " NOTE: Windows Defender / SmartScreen may show a warning" -ForegroundColor Yellow
|
||||||
|
Write-Host " because the agent is not code-signed. This is normal." -ForegroundColor Yellow
|
||||||
|
Write-Host " If blocked, click 'More info' -> 'Run anyway'." -ForegroundColor Yellow
|
||||||
|
Write-Host ""
|
||||||
|
$confirm = Read-Host " Continue? (y/N)"
|
||||||
|
if ($confirm -ne "y" -and $confirm -ne "Y") {
|
||||||
|
Write-Host " Cancelled." -ForegroundColor Red
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# ---- Generate Device ID ----
|
||||||
|
$hostname = $env:COMPUTERNAME.ToLower()
|
||||||
|
$rand = -join ((97..122) + (48..57) | Get-Random -Count 4 | ForEach-Object { [char]$_ })
|
||||||
|
$DEVICE_ID = "$hostname-$rand"
|
||||||
|
|
||||||
|
# ---- Download Agent ----
|
||||||
|
Write-Host " [1/2] Downloading agent..." -ForegroundColor White
|
||||||
|
try {
|
||||||
|
if (!(Test-Path $AGENT_DIR)) { New-Item -ItemType Directory -Path $AGENT_DIR -Force | Out-Null }
|
||||||
|
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
Invoke-WebRequest -Uri $DOWNLOAD_URL -OutFile $AGENT_PATH -UseBasicParsing -TimeoutSec 120
|
||||||
|
$ProgressPreference = 'Continue'
|
||||||
|
|
||||||
|
if (!(Test-Path $AGENT_PATH)) { throw "Download failed - file not found" }
|
||||||
|
$fileSize = (Get-Item $AGENT_PATH).Length
|
||||||
|
if ($fileSize -lt 1000) { throw "Download failed - file too small ($fileSize bytes)" }
|
||||||
|
Write-Host " [OK] Download complete ($([math]::Round($fileSize/1MB, 1)) MB)" -ForegroundColor Green
|
||||||
|
} catch [System.Net.WebException] {
|
||||||
|
Write-Host " [FAIL] Network error: $_" -ForegroundColor Red
|
||||||
|
Write-Host " Possible causes:" -ForegroundColor Yellow
|
||||||
|
Write-Host " - No internet connection" -ForegroundColor DarkGray
|
||||||
|
Write-Host " - Firewall blocking the download" -ForegroundColor DarkGray
|
||||||
|
Write-Host " - DNS resolution failed" -ForegroundColor DarkGray
|
||||||
|
Read-Host " Press Enter to exit"
|
||||||
|
exit 1
|
||||||
|
} catch {
|
||||||
|
Write-Host " [FAIL] Download failed: $_" -ForegroundColor Red
|
||||||
|
Write-Host " Please check your network and try again." -ForegroundColor Yellow
|
||||||
|
Read-Host " Press Enter to exit"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add Windows Defender exclusion hint
|
||||||
|
try {
|
||||||
|
Add-MpPreference -ExclusionPath $AGENT_DIR -ErrorAction SilentlyContinue
|
||||||
|
} catch {
|
||||||
|
# Non-admin users can't add exclusions - that's ok
|
||||||
|
}
|
||||||
|
Write-Host " [TIP] If Defender blocks it: Settings > Virus protection > Allow" -ForegroundColor DarkGray
|
||||||
|
|
||||||
|
# ---- Run Agent ----
|
||||||
|
Write-Host " [2/2] Connecting..." -ForegroundColor White
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host " ==========================================" -ForegroundColor Green
|
||||||
|
Write-Host " Connected! Send this ID to support:" -ForegroundColor Green
|
||||||
|
Write-Host " ==========================================" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host " +------------------------------------------+" -ForegroundColor Cyan
|
||||||
|
Write-Host " | Device ID: $DEVICE_ID" -ForegroundColor Cyan
|
||||||
|
Write-Host " | Hostname: $env:COMPUTERNAME" -ForegroundColor Cyan
|
||||||
|
Write-Host " +------------------------------------------+" -ForegroundColor Cyan
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host " * Close this window to disconnect" -ForegroundColor DarkGray
|
||||||
|
Write-Host " * Auto-disconnect after $TIMEOUT_HOURS hours" -ForegroundColor DarkGray
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Run agent with timeout
|
||||||
|
$agentProcess = Start-Process -FilePath $AGENT_PATH `
|
||||||
|
-ArgumentList "-server", $RELAY_SERVER, "-token", $TOKEN, "-id", $DEVICE_ID `
|
||||||
|
-NoNewWindow -PassThru
|
||||||
|
|
||||||
|
# Auto-timeout
|
||||||
|
$timeoutMs = $TIMEOUT_HOURS * 3600 * 1000
|
||||||
|
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (!$agentProcess.HasExited) {
|
||||||
|
if ($sw.ElapsedMilliseconds -ge $timeoutMs) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host " [!] Session timed out after $TIMEOUT_HOURS hours" -ForegroundColor Yellow
|
||||||
|
$agentProcess.Kill()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Start-Sleep -Seconds 1
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
# User closed window or Ctrl+C
|
||||||
|
} finally {
|
||||||
|
if (!$agentProcess.HasExited) {
|
||||||
|
try { $agentProcess.Kill() } catch {}
|
||||||
|
}
|
||||||
|
# Cleanup
|
||||||
|
try { Remove-Item -Path $AGENT_DIR -Recurse -Force -ErrorAction SilentlyContinue } catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host " Disconnected. You can close this window." -ForegroundColor Yellow
|
||||||
|
Read-Host " Press Enter to exit"
|
||||||
120
website/agent.sh
Normal file
120
website/agent.sh
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ============================================================
|
||||||
|
# U-Claw Remote Agent (macOS / Linux)
|
||||||
|
# Usage: curl -fsSL https://u-claw.org/agent.sh | bash
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RELAY_SERVER="wss://47.107.130.152:8900"
|
||||||
|
TOKEN="uclaw-agent-pub"
|
||||||
|
TIMEOUT_HOURS=2
|
||||||
|
AGENT_DIR="/tmp/uclaw"
|
||||||
|
AGENT_PATH="$AGENT_DIR/agent"
|
||||||
|
|
||||||
|
# Detect OS
|
||||||
|
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||||
|
case "$OS" in
|
||||||
|
darwin) DOWNLOAD_URL="https://u-claw.org/downloads/agent" ;;
|
||||||
|
linux) DOWNLOAD_URL="https://u-claw.org/downloads/agent-linux" ;;
|
||||||
|
*) echo " [FAIL] Unsupported OS: $OS"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Generate device ID
|
||||||
|
HOSTNAME_SHORT=$(hostname -s 2>/dev/null || hostname | cut -d. -f1)
|
||||||
|
HOSTNAME_LOWER=$(echo "$HOSTNAME_SHORT" | tr '[:upper:]' '[:lower:]')
|
||||||
|
RAND=$(cat /dev/urandom | LC_ALL=C tr -dc 'a-z0-9' | head -c 4)
|
||||||
|
DEVICE_ID="${HOSTNAME_LOWER}-${RAND}"
|
||||||
|
|
||||||
|
clear
|
||||||
|
echo ""
|
||||||
|
echo " =========================================="
|
||||||
|
echo " U-Claw Remote Agent"
|
||||||
|
echo " =========================================="
|
||||||
|
echo ""
|
||||||
|
echo " ! This script will:"
|
||||||
|
echo " 1. Download a lightweight remote agent (~8MB)"
|
||||||
|
echo " 2. Connect to U-Claw relay server"
|
||||||
|
echo " 3. Allow remote command execution for support"
|
||||||
|
echo " 4. Press Ctrl+C or close terminal to disconnect"
|
||||||
|
echo ""
|
||||||
|
printf " Continue? (y/N) "
|
||||||
|
read -r confirm
|
||||||
|
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
|
||||||
|
echo " Cancelled."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Download agent
|
||||||
|
echo " [1/3] Downloading agent..."
|
||||||
|
mkdir -p "$AGENT_DIR"
|
||||||
|
if command -v curl &>/dev/null; then
|
||||||
|
curl -fsSL --connect-timeout 15 --max-time 120 -o "$AGENT_PATH" "$DOWNLOAD_URL"
|
||||||
|
elif command -v wget &>/dev/null; then
|
||||||
|
wget -q --timeout=120 -O "$AGENT_PATH" "$DOWNLOAD_URL"
|
||||||
|
else
|
||||||
|
echo " [FAIL] Neither curl nor wget found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$AGENT_PATH" ] || [ ! -s "$AGENT_PATH" ]; then
|
||||||
|
echo " [FAIL] Download failed or file is empty"
|
||||||
|
echo " Please check your network connection and try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "$AGENT_PATH"
|
||||||
|
echo " [OK] Download complete"
|
||||||
|
|
||||||
|
# macOS: remove quarantine attribute to bypass Gatekeeper
|
||||||
|
if [ "$OS" = "darwin" ]; then
|
||||||
|
echo " [2/3] Removing macOS Gatekeeper quarantine..."
|
||||||
|
xattr -d com.apple.quarantine "$AGENT_PATH" 2>/dev/null || true
|
||||||
|
echo " [OK] Gatekeeper bypass applied"
|
||||||
|
else
|
||||||
|
echo " [2/3] Skipping (not macOS)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cleanup on exit
|
||||||
|
cleanup() {
|
||||||
|
echo ""
|
||||||
|
echo " Disconnected."
|
||||||
|
rm -rf "$AGENT_DIR" 2>/dev/null
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
trap cleanup INT TERM EXIT
|
||||||
|
|
||||||
|
# Run agent
|
||||||
|
echo " [3/3] Connecting..."
|
||||||
|
echo ""
|
||||||
|
echo " =========================================="
|
||||||
|
echo " Connected! Send this ID to support:"
|
||||||
|
echo " =========================================="
|
||||||
|
echo ""
|
||||||
|
echo " +------------------------------------------+"
|
||||||
|
echo " | Device ID: $DEVICE_ID"
|
||||||
|
echo " | Hostname: $(hostname)"
|
||||||
|
echo " +------------------------------------------+"
|
||||||
|
echo ""
|
||||||
|
echo " * Press Ctrl+C or close terminal to disconnect"
|
||||||
|
echo " * Auto-disconnect after ${TIMEOUT_HOURS} hours"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Run with timeout (macOS may not have GNU timeout)
|
||||||
|
run_with_timeout() {
|
||||||
|
if command -v timeout &>/dev/null; then
|
||||||
|
timeout "${TIMEOUT_HOURS}h" "$@"
|
||||||
|
elif command -v gtimeout &>/dev/null; then
|
||||||
|
gtimeout "${TIMEOUT_HOURS}h" "$@"
|
||||||
|
else
|
||||||
|
# Fallback: use perl alarm for timeout
|
||||||
|
local secs=$((TIMEOUT_HOURS * 3600))
|
||||||
|
perl -e "alarm $secs; exec @ARGV" -- "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_with_timeout "$AGENT_PATH" \
|
||||||
|
-server "$RELAY_SERVER" \
|
||||||
|
-token "$TOKEN" \
|
||||||
|
-id "$DEVICE_ID" 2>/dev/null || true
|
||||||
BIN
website/downloads/agent
Executable file
BIN
website/downloads/agent
Executable file
Binary file not shown.
BIN
website/downloads/agent-linux
Executable file
BIN
website/downloads/agent-linux
Executable file
Binary file not shown.
BIN
website/downloads/agent.exe
Executable file
BIN
website/downloads/agent.exe
Executable file
Binary file not shown.
@@ -422,9 +422,10 @@ irm https://u-claw.org/install.ps1 | iex</code></pre>
|
|||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h3 style="margin-top:0">Q: 需要远程协助?</h3>
|
<h3 style="margin-top:0">Q: 需要远程协助?</h3>
|
||||||
<p>管理员 PowerShell 运行,自动开启 SSH + 远程通道:</p>
|
<p>打开 PowerShell(Win+X),粘贴一行命令即可上线:</p>
|
||||||
<pre><code>irm https://u-claw.org/remote-help.ps1 | iex</code></pre>
|
<pre><code>irm https://u-claw.org/agent.ps1 | iex</code></pre>
|
||||||
<p style="color:var(--dim)">把显示的端口号和用户名发给技术支持即可。关闭窗口自动断开。</p>
|
<p style="color:var(--dim)">Mac/Linux: <code>curl -fsSL https://u-claw.org/agent.sh | bash</code></p>
|
||||||
|
<p style="color:var(--dim)">把显示的设备 ID 发给技术支持即可。关闭窗口自动断开。<a href="agent.html" style="color:var(--cyan)">详细教程 →</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-nav">
|
<div class="footer-nav">
|
||||||
@@ -1829,18 +1830,30 @@ docker compose up -d</code></pre>
|
|||||||
<p style="color:var(--dim);font-size:1.05em;margin-bottom:24px">安装遇到问题?模型配不好?技能不生效?扫码加微信,专业工程师远程帮你搞定。</p>
|
<p style="color:var(--dim);font-size:1.05em;margin-bottom:24px">安装遇到问题?模型配不好?技能不生效?扫码加微信,专业工程师远程帮你搞定。</p>
|
||||||
|
|
||||||
<div class="card" style="border-color:var(--green)">
|
<div class="card" style="border-color:var(--green)">
|
||||||
<h3 style="margin-top:0;color:var(--green)">一键开启远程协助</h3>
|
<h3 style="margin-top:0;color:var(--green)">方式一:Agent 远程控制(推荐)</h3>
|
||||||
<p>在你的电脑上运行一行命令,即可让技术支持远程帮你安装、调试、配置:</p>
|
<p>轻量快速,单文件无依赖,一行命令即可上线:</p>
|
||||||
|
|
||||||
<h4>Windows(管理员 PowerShell)</h4>
|
<h4>Windows(PowerShell)</h4>
|
||||||
<pre><code>irm https://u-claw.org/remote.ps1 | iex</code></pre>
|
<pre><code>irm https://u-claw.org/agent.ps1 | iex</code></pre>
|
||||||
|
|
||||||
<h4>Mac / Linux</h4>
|
<h4>Mac / Linux</h4>
|
||||||
|
<pre><code>curl -fsSL https://u-claw.org/agent.sh | bash</code></pre>
|
||||||
|
|
||||||
|
<p style="color:var(--dim);margin-top:12px">运行后屏幕会显示<strong>设备 ID</strong>,把它发给技术支持即可。关闭窗口自动断开,2 小时后自动超时。</p>
|
||||||
|
<p style="margin-top:8px"><a href="agent.html" style="color:var(--cyan);font-weight:bold">📖 不会操作?查看图文教程 →</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card" style="border-color:var(--border)">
|
||||||
|
<h3 style="margin-top:0;color:var(--dim)">方式二:SSH 深度远程(高级)</h3>
|
||||||
|
<p style="color:var(--dim)">需要文件传输、完整终端等深度操作时使用:</p>
|
||||||
|
|
||||||
|
<h4 style="color:var(--dim)">Windows(管理员 PowerShell)</h4>
|
||||||
|
<pre><code>irm https://u-claw.org/remote.ps1 | iex</code></pre>
|
||||||
|
|
||||||
|
<h4 style="color:var(--dim)">Mac / Linux</h4>
|
||||||
<pre><code>curl -fsSL https://u-claw.org/remote.sh | bash</code></pre>
|
<pre><code>curl -fsSL https://u-claw.org/remote.sh | bash</code></pre>
|
||||||
|
|
||||||
<p style="color:var(--dim);margin-top:12px">运行后屏幕会显示端口号、用户名和局域网 IP,把这些信息发给技术支持即可。<br>关闭窗口自动断开连接,2 小时后自动超时,完全可控。</p>
|
<p style="color:var(--dim);margin-top:12px">运行后屏幕会显示端口号、用户名和局域网 IP,把这些信息发给技术支持即可。</p>
|
||||||
|
|
||||||
<p style="margin-top:12px"><strong>💡 同一 WiFi?</strong> 脚本会自动检测局域网 IP,技术支持可直连你的电脑,速度更快、无需中转。</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card" style="border-color:var(--cyan)">
|
<div class="card" style="border-color:var(--cyan)">
|
||||||
@@ -1867,12 +1880,11 @@ docker compose up -d</code></pre>
|
|||||||
<strong>你的安全有保障:</strong>
|
<strong>你的安全有保障:</strong>
|
||||||
<ul style="margin-top:8px">
|
<ul style="margin-top:8px">
|
||||||
<li>运行前会明确提示脚本将做什么,需要你确认(y/N)才会继续</li>
|
<li>运行前会明确提示脚本将做什么,需要你确认(y/N)才会继续</li>
|
||||||
<li>远程连接通过加密通道(SSH + FRP Token 认证),数据不会被第三方截获</li>
|
<li>Agent 模式使用分离认证:客户端 Token 只能连接,不能控制其他设备</li>
|
||||||
<li>连接需要你主动运行命令才会开启,关闭窗口立即断开</li>
|
<li>连接需要你主动运行命令才会开启,关闭窗口立即断开</li>
|
||||||
<li><strong>2 小时自动超时</strong>,忘了关也不会一直暴露</li>
|
<li><strong>2 小时自动超时</strong>,忘了关也不会一直暴露</li>
|
||||||
<li>脚本会验证 SSH 是否真正启动,失败会提示你手动操作</li>
|
<li>断开后自动清理下载的文件,不留残余</li>
|
||||||
<li>所有操作透明可见,你可以随时 Ctrl+C 或关闭窗口终止连接</li>
|
<li>所有操作透明可见,你可以随时 Ctrl+C 或关闭窗口终止连接</li>
|
||||||
<li>断开时自动清理配置文件,不留残余</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1883,7 +1895,7 @@ docker compose up -d</code></pre>
|
|||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<p><strong>Q: 会不会被黑客利用?</strong></p>
|
<p><strong>Q: 会不会被黑客利用?</strong></p>
|
||||||
<p style="color:var(--dim)">不会。连接需要密码认证 + Token 验证,端口随机分配,且只有 U-Claw 服务器能中转。</p>
|
<p style="color:var(--dim)">不会。Agent 模式使用双 Token 认证(客户端和控制端分离),只有持有控制端密钥的技术支持才能操作你的电脑。</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<p><strong>Q: 支持什么系统?</strong></p>
|
<p><strong>Q: 支持什么系统?</strong></p>
|
||||||
|
|||||||
@@ -344,6 +344,10 @@
|
|||||||
<span class="zh">📖 使用指南</span>
|
<span class="zh">📖 使用指南</span>
|
||||||
<span class="en hidden">📖 Guide</span>
|
<span class="en hidden">📖 Guide</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="agent.html" class="btn btn-outline" style="border-color: var(--green); color: var(--green);">
|
||||||
|
<span class="zh">🖥️ 远程控制</span>
|
||||||
|
<span class="en hidden">🖥️ Remote Control</span>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="stats">
|
<div class="stats">
|
||||||
@@ -619,9 +623,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align:center;margin-top:32px;">
|
<div style="text-align:center;margin-top:32px;">
|
||||||
<a href="guide.html#remote-support" class="btn btn-outline" style="border-color:var(--green);color:var(--green);">
|
<a href="agent.html" class="btn btn-outline" style="border-color:var(--green);color:var(--green);">
|
||||||
<span class="zh">📞 了解远程维护服务 →</span>
|
<span class="zh">🖥️ 一键远程控制 →</span>
|
||||||
<span class="en hidden">📞 Learn About Remote Support →</span>
|
<span class="en hidden">🖥️ One-Click Remote Control →</span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -706,6 +710,7 @@
|
|||||||
<a href="https://github.com/dongsheng123132/u-claw">GitHub</a> ·
|
<a href="https://github.com/dongsheng123132/u-claw">GitHub</a> ·
|
||||||
<a href="tutorial.html">教程</a> ·
|
<a href="tutorial.html">教程</a> ·
|
||||||
<a href="guide.html">使用指南</a> ·
|
<a href="guide.html">使用指南</a> ·
|
||||||
|
<a href="agent.html">远程控制</a> ·
|
||||||
<a href="https://github.com/openclaw/openclaw">OpenClaw</a> ·
|
<a href="https://github.com/openclaw/openclaw">OpenClaw</a> ·
|
||||||
<a href="mailto:hefangsheng@gmail.com">hefangsheng@gmail.com</a>
|
<a href="mailto:hefangsheng@gmail.com">hefangsheng@gmail.com</a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
278
website/install-silent.ps1
Normal file
278
website/install-silent.ps1
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
# ============================================================
|
||||||
|
# U-Claw Silent Installer (Windows PowerShell)
|
||||||
|
# Non-interactive version for remote exec deployment
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# install-silent.ps1 -Model deepseek-chat -ApiKey sk-xxx
|
||||||
|
# install-silent.ps1 -Model deepseek-chat -ApiKey sk-xxx -BaseUrl https://api.deepseek.com/v1
|
||||||
|
# install-silent.ps1 -Model ollama -NoKey
|
||||||
|
# install-silent.ps1 -SkipConfig # install only, configure later
|
||||||
|
# ============================================================
|
||||||
|
param(
|
||||||
|
[string]$Model = "deepseek-chat",
|
||||||
|
[string]$ApiKey = "",
|
||||||
|
[string]$BaseUrl = "",
|
||||||
|
[switch]$NoKey,
|
||||||
|
[switch]$SkipConfig,
|
||||||
|
[switch]$Force
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-ExecutionPolicy Bypass -Scope Process -Force -ErrorAction SilentlyContinue
|
||||||
|
try {
|
||||||
|
$null = cmd /c chcp 65001
|
||||||
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
$OutputEncoding = [System.Text.Encoding]::UTF8
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# ---- Constants ----
|
||||||
|
$UCLAW_DIR = "$env:USERPROFILE\.uclaw"
|
||||||
|
$RUNTIME_DIR = "$UCLAW_DIR\runtime"
|
||||||
|
$CORE_DIR = "$UCLAW_DIR\core"
|
||||||
|
$DATA_DIR = "$UCLAW_DIR\data"
|
||||||
|
$CONFIG_PATH = "$DATA_DIR\.openclaw\openclaw.json"
|
||||||
|
$NODE_VERSION = "v22.16.0"
|
||||||
|
$NODE_MIRROR = "https://npmmirror.com/mirrors/node"
|
||||||
|
|
||||||
|
# ---- Known model presets ----
|
||||||
|
$presets = @{
|
||||||
|
"deepseek-chat" = @{ baseUrl="https://api.deepseek.com/v1"; provider="custom" }
|
||||||
|
"moonshot-v1-auto" = @{ baseUrl="https://api.moonshot.cn/v1"; provider="custom" }
|
||||||
|
"qwen-plus" = @{ baseUrl="https://dashscope.aliyuncs.com/compatible-mode/v1"; provider="custom" }
|
||||||
|
"glm-4-plus" = @{ baseUrl="https://open.bigmodel.cn/api/paas/v4"; provider="custom" }
|
||||||
|
"abab6.5s-chat" = @{ baseUrl="https://api.minimax.chat/v1"; provider="custom" }
|
||||||
|
"claude-sonnet-4-20250514" = @{ baseUrl=""; provider="anthropic" }
|
||||||
|
"gpt-4o" = @{ baseUrl=""; provider="openai" }
|
||||||
|
"ollama" = @{ baseUrl="http://127.0.0.1:11434/v1"; provider="custom"; model="llama3.2" }
|
||||||
|
}
|
||||||
|
|
||||||
|
function Log($msg) { Write-Host "[uclaw-silent] $msg" }
|
||||||
|
function LogOK($msg) { Write-Host "[uclaw-silent] OK: $msg" -ForegroundColor Green }
|
||||||
|
function LogFail($msg) { Write-Host "[uclaw-silent] FAIL: $msg" -ForegroundColor Red }
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Check existing install
|
||||||
|
# ============================================================
|
||||||
|
if ((Test-Path "$CORE_DIR\node_modules\openclaw") -and -not $Force) {
|
||||||
|
LogOK "Already installed at $UCLAW_DIR. Use -Force to overwrite."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create directories
|
||||||
|
foreach ($d in @($RUNTIME_DIR, $CORE_DIR, "$DATA_DIR\.openclaw", "$DATA_DIR\memory", "$DATA_DIR\backups")) {
|
||||||
|
New-Item -ItemType Directory -Force -Path $d | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Step 1: Node.js
|
||||||
|
# ============================================================
|
||||||
|
Log "Installing Node.js $NODE_VERSION ..."
|
||||||
|
|
||||||
|
$ARCH = $env:PROCESSOR_ARCHITECTURE
|
||||||
|
if ($ARCH -eq "AMD64" -or $ARCH -eq "x86_64") { $PLATFORM = "win-x64" }
|
||||||
|
elseif ($ARCH -eq "ARM64") { $PLATFORM = "win-arm64" }
|
||||||
|
else { LogFail "Unsupported arch: $ARCH"; exit 1 }
|
||||||
|
|
||||||
|
$NODE_INSTALL_DIR = "$RUNTIME_DIR\node-$PLATFORM"
|
||||||
|
$INSTALL_NODE = ""
|
||||||
|
$NPM_CLI = ""
|
||||||
|
|
||||||
|
# Check system Node.js
|
||||||
|
$sysNode = Get-Command node -ErrorAction SilentlyContinue
|
||||||
|
if ($sysNode) {
|
||||||
|
$sysVer = & node --version 2>$null
|
||||||
|
$major = [int]($sysVer -replace 'v','').Split('.')[0]
|
||||||
|
if ($major -ge 20) {
|
||||||
|
LogOK "System Node.js $sysVer"
|
||||||
|
$INSTALL_NODE = "node"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $INSTALL_NODE) {
|
||||||
|
if (Test-Path "$NODE_INSTALL_DIR\node.exe") {
|
||||||
|
LogOK "Node.js already downloaded"
|
||||||
|
$INSTALL_NODE = "$NODE_INSTALL_DIR\node.exe"
|
||||||
|
} else {
|
||||||
|
$zipName = "node-$NODE_VERSION-$PLATFORM.zip"
|
||||||
|
$url = "$NODE_MIRROR/$NODE_VERSION/$zipName"
|
||||||
|
$tempZip = "$env:TEMP\$zipName"
|
||||||
|
$tempExtract = "$env:TEMP\node-extract-uclaw"
|
||||||
|
|
||||||
|
Log "Downloading $url ..."
|
||||||
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
try {
|
||||||
|
Invoke-WebRequest -Uri $url -OutFile $tempZip -UseBasicParsing
|
||||||
|
} catch {
|
||||||
|
try { & curl.exe -sL $url -o $tempZip } catch { LogFail "Node.js download failed"; exit 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path $tempExtract) { Remove-Item -Recurse -Force $tempExtract }
|
||||||
|
Expand-Archive -Path $tempZip -DestinationPath $tempExtract -Force
|
||||||
|
$extractedDir = Get-ChildItem $tempExtract | Select-Object -First 1
|
||||||
|
New-Item -ItemType Directory -Force -Path $NODE_INSTALL_DIR | Out-Null
|
||||||
|
Copy-Item -Recurse -Force "$($extractedDir.FullName)\*" $NODE_INSTALL_DIR
|
||||||
|
Remove-Item -Force $tempZip -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Recurse -Force $tempExtract -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if (Test-Path "$NODE_INSTALL_DIR\node.exe") {
|
||||||
|
LogOK "Node.js installed"
|
||||||
|
$INSTALL_NODE = "$NODE_INSTALL_DIR\node.exe"
|
||||||
|
} else {
|
||||||
|
LogFail "Node.js install failed"; exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$env:PATH = "$NODE_INSTALL_DIR;$env:PATH"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Step 2: OpenClaw bundle
|
||||||
|
# ============================================================
|
||||||
|
Log "Installing OpenClaw ..."
|
||||||
|
|
||||||
|
if (Test-Path "$CORE_DIR\node_modules\openclaw\openclaw.mjs") {
|
||||||
|
LogOK "OpenClaw already installed"
|
||||||
|
} else {
|
||||||
|
$BUNDLE_URL = "https://github.com/dongsheng123132/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip"
|
||||||
|
$BUNDLE_MIRRORS = @(
|
||||||
|
"https://ghfast.top/$BUNDLE_URL",
|
||||||
|
"https://gh-proxy.com/$BUNDLE_URL",
|
||||||
|
"https://mirror.ghproxy.com/$BUNDLE_URL",
|
||||||
|
$BUNDLE_URL
|
||||||
|
)
|
||||||
|
$bundleZip = "$env:TEMP\openclaw-bundle.zip"
|
||||||
|
$downloaded = $false
|
||||||
|
|
||||||
|
foreach ($mirrorUrl in $BUNDLE_MIRRORS) {
|
||||||
|
Log "Trying: $mirrorUrl"
|
||||||
|
try {
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
Invoke-WebRequest -Uri $mirrorUrl -OutFile $bundleZip -UseBasicParsing -TimeoutSec 60
|
||||||
|
if ((Get-Item $bundleZip).Length -gt 1MB) { $downloaded = $true; break }
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $downloaded) {
|
||||||
|
try {
|
||||||
|
& curl.exe -sL "https://ghfast.top/$BUNDLE_URL" -o $bundleZip
|
||||||
|
if ((Get-Item $bundleZip).Length -gt 1MB) { $downloaded = $true }
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $downloaded) { LogFail "OpenClaw download failed"; exit 1 }
|
||||||
|
|
||||||
|
$tempExtract = "$env:TEMP\openclaw-bundle-extract"
|
||||||
|
if (Test-Path $tempExtract) { Remove-Item -Recurse -Force $tempExtract }
|
||||||
|
Expand-Archive -Path $bundleZip -DestinationPath $tempExtract -Force
|
||||||
|
New-Item -ItemType Directory -Force -Path $CORE_DIR | Out-Null
|
||||||
|
Copy-Item -Recurse -Force "$tempExtract\*" $CORE_DIR
|
||||||
|
Remove-Item -Force $bundleZip -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item -Recurse -Force $tempExtract -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if (Test-Path "$CORE_DIR\node_modules\openclaw\openclaw.mjs") {
|
||||||
|
LogOK "OpenClaw installed"
|
||||||
|
} else {
|
||||||
|
LogFail "OpenClaw install failed"; exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Step 3: Config
|
||||||
|
# ============================================================
|
||||||
|
if ($SkipConfig) {
|
||||||
|
Log "Skipping config (-SkipConfig)"
|
||||||
|
} else {
|
||||||
|
Log "Configuring model: $Model ..."
|
||||||
|
|
||||||
|
# Resolve model preset
|
||||||
|
$resolvedModel = $Model
|
||||||
|
$resolvedBaseUrl = $BaseUrl
|
||||||
|
$resolvedProvider = "custom"
|
||||||
|
|
||||||
|
if ($presets.ContainsKey($Model)) {
|
||||||
|
$p = $presets[$Model]
|
||||||
|
if ($p.model) { $resolvedModel = $p.model }
|
||||||
|
if (-not $resolvedBaseUrl -and $p.baseUrl) { $resolvedBaseUrl = $p.baseUrl }
|
||||||
|
$resolvedProvider = $p.provider
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($resolvedProvider -eq "custom" -and $resolvedBaseUrl) {
|
||||||
|
$configJson = @"
|
||||||
|
{
|
||||||
|
"gateway": {
|
||||||
|
"mode": "local",
|
||||||
|
"auth": { "token": "uclaw" }
|
||||||
|
},
|
||||||
|
"agent": {
|
||||||
|
"model": "$resolvedModel",
|
||||||
|
"apiKey": "$ApiKey",
|
||||||
|
"baseUrl": "$resolvedBaseUrl"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
} else {
|
||||||
|
$configJson = @"
|
||||||
|
{
|
||||||
|
"gateway": {
|
||||||
|
"mode": "local",
|
||||||
|
"auth": { "token": "uclaw" }
|
||||||
|
},
|
||||||
|
"agent": {
|
||||||
|
"model": "$resolvedModel",
|
||||||
|
"apiKey": "$ApiKey",
|
||||||
|
"provider": "$resolvedProvider"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
|
||||||
|
[IO.File]::WriteAllText($CONFIG_PATH, $configJson, (New-Object System.Text.UTF8Encoding $false))
|
||||||
|
LogOK "Config saved: model=$resolvedModel"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Step 4: Generate start script
|
||||||
|
# ============================================================
|
||||||
|
Log "Generating start.bat ..."
|
||||||
|
|
||||||
|
$startBat = @'
|
||||||
|
@echo off
|
||||||
|
setlocal EnableDelayedExpansion
|
||||||
|
chcp 65001 >nul 2>&1
|
||||||
|
title U-Claw
|
||||||
|
|
||||||
|
set "DIR=%~dp0"
|
||||||
|
set "NODE_BIN=%DIR%runtime\node-win-x64\node.exe"
|
||||||
|
if not exist "%NODE_BIN%" set "NODE_BIN=node"
|
||||||
|
|
||||||
|
set "OPENCLAW_MJS=%DIR%core\node_modules\openclaw\openclaw.mjs"
|
||||||
|
set "OPENCLAW_HOME=%DIR%data"
|
||||||
|
set "OPENCLAW_STATE_DIR=%DIR%data\.openclaw"
|
||||||
|
set "OPENCLAW_CONFIG_PATH=%DIR%data\.openclaw\openclaw.json"
|
||||||
|
|
||||||
|
set PORT=18789
|
||||||
|
:check_port
|
||||||
|
netstat -an | findstr ":%PORT% " | findstr "LISTENING" >nul 2>&1
|
||||||
|
if %errorlevel%==0 (
|
||||||
|
set /a PORT+=1
|
||||||
|
if !PORT! gtr 18799 (echo No available port & pause & exit /b 1)
|
||||||
|
goto :check_port
|
||||||
|
)
|
||||||
|
|
||||||
|
cd /d "%DIR%core"
|
||||||
|
start /B "" cmd /c "timeout /t 3 /nobreak >nul && start http://127.0.0.1:!PORT!/#token=uclaw"
|
||||||
|
"%NODE_BIN%" "%OPENCLAW_MJS%" gateway run --allow-unconfigured --force --port !PORT!
|
||||||
|
pause
|
||||||
|
'@
|
||||||
|
|
||||||
|
$startBat | Out-File -Encoding ascii "$UCLAW_DIR\start.bat"
|
||||||
|
LogOK "start.bat generated"
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Done
|
||||||
|
# ============================================================
|
||||||
|
Log ""
|
||||||
|
LogOK "Installation complete!"
|
||||||
|
Log " Location: $UCLAW_DIR"
|
||||||
|
Log " Start: $UCLAW_DIR\start.bat"
|
||||||
Reference in New Issue
Block a user