Files
dingtalk-workspace-cli/scripts/install-devapp.sh
T
修雨 97678e6441 fix(devapp): drop the fork — repoint dev installer + docs to DingTalk-Real-AI (#505)
* fix(devapp): point dev installer at DingTalk-Real-AI, drop the fork

install-devapp.sh / .ps1 and the robot quickstart still pulled the dev
binary + dingtalk-dev skill from wxianfeng/dingtalk-workspace-cli's
feat/dws-devapp fork branch. The dev-app work has since landed on main and
shipped in stable v1.0.42 under DingTalk-Real-AI, so the fork dependency is
obsolete.

  - DEVAPP_REPO default: wxianfeng/... → DingTalk-Real-AI/...
  - Bootstrap URLs in headers + quickstart: fork feat/dws-devapp → main.
  - Drop "preview/prerelease" wording — releases are now stable; the
    newest-release resolution still works either way.
  - Quickstart China note now points at the standard install.sh Gitee
    mirror (which carries dws dev in v1.0.42); install-devapp.sh pulls its
    binary from github.com, so a gitee-raw script alone would not help China.

Verified: releases?per_page=1 on DingTalk-Real-AI resolves v1.0.42 and the
darwin/​skills assets are present.

Note: docs/devapp-agent-install-guide.md is separately stale (describes the
old source-build flow + the pre-rename `dws devapp` command) and needs its
own rewrite — left out of this change.

* docs(devapp): rewrite agent install guide for binary install + `dws dev`

The guide was stale on two axes:
  - It described the old source-build flow (clone the fork branch + go/make,
    env vars DEVAPP_REPO_URL / DEVAPP_BRANCH / DEVAPP_SOURCE_DIR), but
    install-devapp.sh now downloads a pre-built binary (curl + tar, no
    git/go/make) from DingTalk-Real-AI.
  - Every command used the pre-rename `dws devapp ...`; the command is now
    `dws dev app ...`.

Rewrite against the real `dws dev` tree (verified from the binary):
  - install: DingTalk-Real-AI binary installer + correct env (DEVAPP_REPO /
    DEVAPP_VERSION / DWS_INSTALL_DIR / DWS_NO_SKILLS) + a China Gitee note.
  - skill name corrected to `dingtalk-dev`.
  - commands: `dws dev app {list,get,create,update,enable,disable,delete,
    credentials,permission,member,robot,security,version,webapp,event}` with
    real flags (--confirm-name, --scope-values, --user-ids, --redirect-urls,
    --version-id/--confirmed-sensitive), async robot create via submit/result,
    version publish gated by check-approval.
2026-06-25 21:04:38 +08:00

158 lines
5.9 KiB
Bash
Executable File

#!/bin/sh
# Copyright 2026 Alibaba Group
# Licensed under the Apache License, Version 2.0
#
# One-command installer for dws dev — pre-built binary, no build tools.
# Downloads the dev binary + dingtalk-dev skill from the DingTalk-Real-AI GitHub Releases.
# Requires only curl + tar (no go / make / git).
#
# Usage:
# curl -fsSL https://raw.githubusercontent.com/DingTalk-Real-AI/dingtalk-workspace-cli/main/scripts/install-devapp.sh | sh
#
# Env (all optional):
# DEVAPP_REPO repo holding dev releases (default: DingTalk-Real-AI/dingtalk-workspace-cli)
# DEVAPP_VERSION pin a release tag (default: latest release)
# DWS_INSTALL_DIR binary dir (default: ~/.local/bin)
# DWS_NO_SKILLS set 1 to skip the dev skill
set -eu
DEVAPP_REPO="${DEVAPP_REPO:-DingTalk-Real-AI/dingtalk-workspace-cli}"
DEVAPP_VERSION="${DEVAPP_VERSION:-}"
INSTALL_DIR="${DWS_INSTALL_DIR:-$HOME/.local/bin}"
NO_SKILLS="${DWS_NO_SKILLS:-0}"
SKILL_NAME="dingtalk-dev"
say() { printf ' %s\n' "$@"; }
err() { printf ' ❌ %s\n' "$@" >&2; exit 1; }
need_cmd() { command -v "$1" >/dev/null 2>&1 || err "Missing required command: $1"; }
need_cmd curl
detect_os() {
case "$(uname -s)" in
Linux*) echo linux ;;
Darwin*) echo darwin ;;
MINGW*|MSYS*|CYGWIN*) echo windows ;; # Git Bash / MSYS2 / Cygwin on Windows
*) err "Unsupported OS: $(uname -s). On native Windows use install-devapp.ps1." ;;
esac
}
detect_arch() {
case "$(uname -m)" in
x86_64|amd64) echo amd64 ;;
arm64|aarch64) echo arm64 ;;
*) err "Unsupported architecture: $(uname -m)" ;;
esac
}
# Read the releases list (newest first) and take the top tag, so this also works
# if a release is ever published as a prerelease (which /releases/latest skips).
# Prefer `gh` CLI (authenticated, 5 000 req/h) over raw curl (60 req/h, easily rate-limited).
resolve_version() {
[ -n "$DEVAPP_VERSION" ] && return 0
# Try gh CLI first (authenticated, much higher rate limit)
if command -v gh >/dev/null 2>&1; then
DEVAPP_VERSION="$(gh api "repos/${DEVAPP_REPO}/releases?per_page=1" --jq '.[0].tag_name' 2>/dev/null || true)"
[ -n "$DEVAPP_VERSION" ] && return 0
fi
# Fallback: unauthenticated curl (may be rate-limited)
_tmpfile="$(mktemp)"
_http_code="$(curl -sSL -o "$_tmpfile" -w '%{http_code}' "https://api.github.com/repos/${DEVAPP_REPO}/releases?per_page=1" 2>/dev/null || echo "000")"
if [ "$_http_code" = "403" ] || [ "$_http_code" = "429" ]; then
rm -f "$_tmpfile"
err "GitHub API rate limit hit (HTTP ${_http_code}). Install the GitHub CLI (gh) or set DEVAPP_VERSION explicitly."
fi
DEVAPP_VERSION="$(grep -m1 '"tag_name"' "$_tmpfile" | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')"
rm -f "$_tmpfile"
[ -n "$DEVAPP_VERSION" ] || err "No release found on ${DEVAPP_REPO}. Set DEVAPP_VERSION to a published release tag."
}
install_skill() {
bundle="$1" # extracted skills bundle dir
src=""
for c in "$bundle/multi/$SKILL_NAME" "$bundle/skills/multi/$SKILL_NAME" "$bundle/$SKILL_NAME"; do
[ -f "$c/SKILL.md" ] && src="$c" && break
done
[ -n "$src" ] || { say " (dingtalk-dev not found in skills bundle; skipped)"; return 0; }
# cache so `dws skill setup --mode multi` can find a source later
cache="$HOME/.dws/skills/multi/$SKILL_NAME"
rm -rf "$cache"; mkdir -p "$cache"; cp -R "$src/." "$cache/"
installed=0; idx=0
for agent_dir in \
.agents/skills .claude/skills .cursor/skills .qoder/skills .qoderwork/skills \
.gemini/skills .codex/skills .github/skills .windsurf/skills .augment/skills \
.cline/skills .amp/skills .kiro/skills .trae/skills .openclaw/skills .hermes/skills \
.config/opencode/skills
do
base="$HOME/$agent_dir"
if [ "$idx" -gt 0 ] && [ ! -e "$(dirname "$base")" ]; then idx=$((idx + 1)); continue; fi
dest="$base/$SKILL_NAME"; rm -rf "$dest"; mkdir -p "$dest"; cp -R "$src/." "$dest/"
installed=$((installed + 1)); idx=$((idx + 1))
done
say "✅ Skill dingtalk-dev → ${installed} agent dir(s)"
}
main() {
resolve_version
os="$(detect_os)"; arch="$(detect_arch)"
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT INT TERM
printf '\n'
say "dws dev installer (pre-built binary)"
say "Repo: ${DEVAPP_REPO}"
say "Version: ${DEVAPP_VERSION}"
say "Target: ${os}/${arch}"
printf '\n'
# 1) binary (already ad-hoc signed by CI; copy does not break the signature)
if [ "$os" = "windows" ]; then
asset="dws-windows-${arch}.zip"; binname="dws.exe"
else
asset="dws-${os}-${arch}.tar.gz"; binname="dws"
fi
say "⬇ Downloading ${asset} ..."
curl -fsSL "https://github.com/${DEVAPP_REPO}/releases/download/${DEVAPP_VERSION}/${asset}" -o "$tmp/$asset" \
|| err "Binary download failed — does release ${DEVAPP_VERSION} have ${asset}?"
if [ "$os" = "windows" ]; then
need_cmd unzip; unzip -q "$tmp/$asset" -d "$tmp"
else
need_cmd tar; tar -xzf "$tmp/$asset" -C "$tmp"
fi
[ -f "$tmp/$binname" ] || err "${binname} not found inside ${asset}"
mkdir -p "$INSTALL_DIR"
cp "$tmp/$binname" "$INSTALL_DIR/$binname"; chmod +x "$INSTALL_DIR/$binname" 2>/dev/null || true
say "✅ Binary → ${INSTALL_DIR}/${binname}"
# 2) dev skill from the release's skills bundle
if [ "$NO_SKILLS" != "1" ]; then
if curl -fsSL "https://github.com/${DEVAPP_REPO}/releases/download/${DEVAPP_VERSION}/dws-skills.zip" -o "$tmp/skills.zip" 2>/dev/null; then
mkdir -p "$tmp/sk"
if command -v unzip >/dev/null 2>&1; then unzip -q "$tmp/skills.zip" -d "$tmp/sk"; else tar -xf "$tmp/skills.zip" -C "$tmp/sk"; fi
say ""
install_skill "$tmp/sk"
else
say " (no dws-skills.zip in release ${DEVAPP_VERSION}; skill skipped)"
fi
fi
printf '\n'
say "🎉 Done. Next steps:"
say " dws version"
say " dws auth login"
say " dws dev --help --format json"
say " dws dev app list --format json"
printf '\n'
case ":$PATH:" in
*":$INSTALL_DIR:"*) ;;
*) say "Note: ${INSTALL_DIR} is not on \$PATH — add it so 'dws' is found." ;;
esac
}
main