fix: make client installation observable
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s

This commit is contained in:
2026-08-18 14:16:17 +00:00
parent dd189c2acb
commit 40c5021c85
12 changed files with 233 additions and 21 deletions
+5
View File
@@ -49,8 +49,12 @@
不要在浏览器中复制脚本内容,不要对 URL 解码、重新编码或手工拼接。必须先校验安装引导 SHA-256,再执行它。
为执行平台安装引导的 Agent 工具调用设置至少 10 分钟超时。引导和安装器会把 `[dingtalk-approval]` 开头的阶段进度写入 stderr,把唯一的最终结果 JSON 写入 stdout;进度文本不是失败,也不能混入 JSON 解析。进程仍在运行时不得并发启动第二次安装。
### Windows(PowerShell)
无论当前 Agent 默认使用 PowerShell、CMD 还是 Git Bash,Windows 都必须调用普通 PowerShell 执行下面的完整流程。不得从 Git Bash 直接运行内部的 `node dingtalk-approval-installer.mjs ...` 命令;内部安装器不是用户安装入口。
在普通 PowerShell 中逐行运行:
```powershell
@@ -196,6 +200,7 @@ $dingLogin | ConvertTo-Json -Depth 20
6. **连接器一直未出现**:确认已信任本地连接器并完整重启 Agent。不要通过反复重装刷新连接器。
7. **授权链接过期**:MCP 已加载就再次调用 `approval_login`;否则执行保存的 `loginCommand`。不要重装。
8. **Linux/macOS 缺少下载或校验命令**:必须先具备 `curl` 或 `wget`,以及 `sha256sum` 或 `shasum`;不能绕过 SHA-256 校验。系统 `tar` 必须支持 gzip 归档。
9. **安装长时间无最终 JSON或被宿主终止**:先确认工具调用超时不少于 10 分钟,并查看 stderr 中最后一条 `[dingtalk-approval]` 阶段信息。不要改用内部安装器,也不要并发重试。原进程确认已经退出后,可重新执行同一平台引导;它会识别已经死亡的安装进程、清理残留 staging 并安全续装。若明确提示另一个安装仍在运行,应等待该进程结束。
## 更新
+12
View File
@@ -11,6 +11,10 @@ ding_manifest_url='{{MANIFEST_URL}}'
ding_temp_dir="$(mktemp -d "${TMPDIR:-/tmp}/dingmcp-install.XXXXXX")"
trap 'rm -rf "$ding_temp_dir"' EXIT HUP INT TERM
ding_progress() {
printf '[dingtalk-approval] %s\n' "$1" >&2
}
ding_hash_file() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
@@ -68,6 +72,7 @@ ding_download_verified() {
shift 2
ding_download_succeeded=0
for ding_download_url in "$@"; do
ding_progress "正在下载并校验:$ding_download_url"
rm -f "$ding_download_target"
if ding_fetch "$ding_download_url" "$ding_download_target"; then
ding_download_succeeded=1
@@ -111,9 +116,11 @@ case "$ding_os-$ding_arch" in
darwin-arm64) ding_node_file='{{NODE_DARWIN_ARM64_FILE}}'; ding_node_sha256='{{NODE_DARWIN_ARM64_SHA256}}' ;;
esac
ding_progress "1/4 检查 $ding_os-$ding_arch 的 Node/npm 运行环境"
ding_node_path=''
if command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1 && ding_test_node "$(command -v node)"; then
ding_node_path="$(command -v node)"
ding_progress "2/4 复用兼容的系统 Node"
else
if [ -n "${DINGTALK_APPROVAL_CLIENT_HOME:-}" ]; then
ding_client_root="$DINGTALK_APPROVAL_CLIENT_HOME"
@@ -128,6 +135,7 @@ else
ding_node_path="$ding_runtime_dir/bin/node"
ding_npm_cli="$ding_runtime_dir/lib/node_modules/npm/bin/npm-cli.js"
if ! ding_test_node "$ding_node_path" || [ ! -f "$ding_npm_cli" ]; then
ding_progress "2/4 系统 Node 不可用,准备插件私有 Node;下载可能需要一些时间"
mkdir -p "$ding_runtime_parent"
chmod 700 "$ding_client_root" "$ding_runtime_parent" 2>/dev/null || true
ding_runtime_archive="$ding_temp_dir/$ding_node_file"
@@ -148,12 +156,16 @@ else
fi
rm -rf "$ding_runtime_dir"
mv "$ding_extracted_dir" "$ding_runtime_dir"
else
ding_progress "2/4 复用已安装的插件私有 Node"
fi
fi
ding_progress '3/4 下载并校验签名安装器与发布公钥'
ding_installer="$ding_temp_dir/installer.mjs"
ding_public_key="$ding_temp_dir/release-signing-public.pem"
ding_download_verified "$ding_installer" "$ding_installer_sha256" "$ding_installer_url"
ding_download_verified "$ding_public_key" "$ding_public_key_sha256" "$ding_public_key_url"
ding_progress '4/4 执行安装器;最终 JSON 输出到 stdout,阶段进度输出到 stderr'
"$ding_node_path" "$ding_installer" install --manifest-url "$ding_manifest_url" --public-key "$ding_public_key" --json
@@ -1,5 +1,8 @@
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) {
$PSNativeCommandUseErrorActionPreference = $false
}
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
$dingSourceBases = @({{NODE_SOURCE_BASES_POWERSHELL}})
@@ -9,6 +12,10 @@ $dingPublicKeyUrl = "{{PUBLIC_KEY_URL}}"
$dingPublicKeySha256 = "{{PUBLIC_KEY_SHA256}}"
$dingManifestUrl = "{{MANIFEST_URL}}"
function Write-DingProgress([string] $dingMessage) {
[Console]::Error.WriteLine("[dingtalk-approval] $dingMessage")
}
function Get-DingSha256([string] $dingPath) {
return (Get-FileHash -Algorithm SHA256 -LiteralPath $dingPath).Hash.ToLowerInvariant()
}
@@ -16,6 +23,7 @@ function Get-DingSha256([string] $dingPath) {
function Save-DingDownload([string[]] $dingUrls, [string] $dingTarget, [string] $dingExpectedSha256) {
$dingLastError = $null
foreach ($dingUrl in $dingUrls) {
Write-DingProgress "正在下载并校验:$dingUrl"
try {
if (Test-Path -LiteralPath $dingTarget) { Remove-Item -LiteralPath $dingTarget -Force }
Invoke-WebRequest -UseBasicParsing -Uri $dingUrl -OutFile $dingTarget -TimeoutSec 300
@@ -57,6 +65,7 @@ switch ($dingArchitecture) {
default { throw "不支持的 Windows CPU 架构:$dingArchitecture" }
}
Write-DingProgress "1/4 检查 Windows-$dingArchitecture 的 Node/npm 运行环境"
$dingSystemNode = Get-Command node -ErrorAction SilentlyContinue
$dingNodePath = if ($dingSystemNode) { $dingSystemNode.Source } else { $null }
if (-not (Test-DingNode $dingNodePath $false)) {
@@ -73,6 +82,7 @@ if (-not (Test-DingNode $dingNodePath $false)) {
$dingRuntimeDir = Join-Path $dingRuntimeParent $dingRuntimeName
$dingNodePath = Join-Path $dingRuntimeDir "node.exe"
if (-not (Test-DingNode $dingNodePath $true)) {
Write-DingProgress "2/4 系统 Node 不可用,准备插件私有 Node;下载可能需要一些时间"
New-Item -ItemType Directory -Path $dingRuntimeParent -Force | Out-Null
$dingRuntimeTemp = Join-Path ([IO.Path]::GetTempPath()) ("dingmcp-node-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $dingRuntimeTemp -Force | Out-Null
@@ -90,9 +100,14 @@ if (-not (Test-DingNode $dingNodePath $false)) {
} finally {
if (Test-Path -LiteralPath $dingRuntimeTemp) { Remove-Item -LiteralPath $dingRuntimeTemp -Recurse -Force }
}
} else {
Write-DingProgress "2/4 复用已安装的插件私有 Node"
}
} else {
Write-DingProgress "2/4 复用兼容的系统 Node"
}
Write-DingProgress "3/4 下载并校验签名安装器与发布公钥"
$dingInstallTemp = Join-Path ([IO.Path]::GetTempPath()) ("dingmcp-install-" + [guid]::NewGuid().ToString("N"))
New-Item -ItemType Directory -Path $dingInstallTemp -Force | Out-Null
try {
@@ -100,6 +115,7 @@ try {
$dingPublicKey = Join-Path $dingInstallTemp "release-signing-public.pem"
Save-DingDownload @($dingInstallerUrl) $dingInstaller $dingInstallerSha256
Save-DingDownload @($dingPublicKeyUrl) $dingPublicKey $dingPublicKeySha256
Write-DingProgress "4/4 执行安装器;最终 JSON 输出到 stdout,阶段进度输出到 stderr"
$dingInstallOutput = & $dingNodePath $dingInstaller install --manifest-url $dingManifestUrl --public-key $dingPublicKey --json
$dingInstallExit = $LASTEXITCODE
if ($dingInstallExit -ne 0) { throw "钉钉审批安装器执行失败:$dingInstallOutput" }