#!/bin/sh set -eu ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)" DIST_DIR="${DWS_PACKAGE_DIST_DIR:-$ROOT/dist}" FORMULA_PATH="$DIST_DIR/homebrew/dingtalk-workspace-cli-local.rb" NPM_STAGE_DIR="$DIST_DIR/npm/dingtalk-workspace-cli" RUN_NPM=1 RUN_BREW=1 EXPECTED_VERSION="" VERIFY_SKILL_TARGETS=1 say() { printf '%s\n' "$*" } err() { printf 'error: %s\n' "$*" >&2 exit 1 } need_cmd() { command -v "$1" >/dev/null 2>&1 || err "missing required command: $1" } need_file() { [ -f "$1" ] || err "required file not found: $1" } usage() { printf '%s\n' "usage: $0 [--npm-only|--brew-only] [--expected-version ] [--skip-skill-targets]" >&2 } mode_seen=0 while [ "$#" -gt 0 ]; do case "$1" in --npm-only) [ "$mode_seen" -eq 0 ] || { usage; exit 2; } RUN_NPM=1; RUN_BREW=0; mode_seen=1; shift ;; --brew-only) [ "$mode_seen" -eq 0 ] || { usage; exit 2; } RUN_NPM=0; RUN_BREW=1; mode_seen=1; shift ;; --expected-version) [ "$#" -ge 2 ] || { usage; exit 2; } EXPECTED_VERSION="${2#v}" shift 2 ;; --skip-skill-targets) VERIFY_SKILL_TARGETS=0; shift ;; -h|--help) usage; exit 0 ;; *) usage; exit 2 ;; esac done TMP_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/dws-package-verify-XXXXXX")" HOME_AGENT_PARENTS=" .claude .cursor .qoder .qoderwork .gemini .codex .zcode .github .windsurf .augment .cline .amp .kiro .trae .openclaw .hermes " HOME_SKILL_BASES=" .agents/skills .claude/skills .cursor/skills .qoder/skills .qoderwork/skills .gemini/skills .codex/skills .zcode/skills .github/skills .windsurf/skills .augment/skills .cline/skills .amp/skills .kiro/skills .trae/skills .openclaw/skills .hermes/skills " cleanup() { if [ "$RUN_BREW" -eq 1 ] && command -v brew >/dev/null 2>&1 && [ -n "${BREW_TAP_NAME:-}" ]; then HOME="$TMP_ROOT/brew-home" HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \ brew uninstall --force dingtalk-workspace-cli-local >/dev/null 2>&1 || true HOME="$TMP_ROOT/brew-home" HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \ brew untap --force "$BREW_TAP_NAME" >/dev/null 2>&1 || true fi rm -rf "$TMP_ROOT" } trap cleanup EXIT INT TERM seed_agent_homes() { home_root="$1" for parent in $HOME_AGENT_PARENTS; do mkdir -p "$home_root/$parent" done } verify_skill_targets() { home_root="$1" for base in $HOME_SKILL_BASES; do need_file "$home_root/$base/dingtalk-shared/SKILL.md" need_file "$home_root/$base/dingtalk-misc/SKILL.md" [ ! -e "$home_root/$base/dws" ] || err "unexpected mono Skill layout found in $home_root/$base/dws" done } verify_npm() { need_cmd npm need_cmd node need_cmd tar need_cmd unzip need_file "$NPM_STAGE_DIR/package.json" npm_home="$TMP_ROOT/npm-home" npm_prefix="$TMP_ROOT/npm-prefix" npm_cache="$TMP_ROOT/npm-cache" mkdir -p "$npm_home" "$npm_prefix" "$npm_cache" seed_agent_homes "$npm_home" say "==> verifying npm package install" tarball_name="$( cd "$NPM_STAGE_DIR" HOME="$npm_home" npm_config_cache="$npm_cache" npm pack --silent )" tarball_path="$NPM_STAGE_DIR/$tarball_name" need_file "$tarball_path" HOME="$npm_home" npm_config_cache="$npm_cache" npm_config_prefix="$npm_prefix" \ npm install -g "$tarball_path" >/dev/null [ -x "$npm_prefix/bin/dws" ] || err "npm install did not expose dws in $npm_prefix/bin" HOME="$npm_home" "$npm_prefix/bin/dws" --help >/dev/null if [ -n "$EXPECTED_VERSION" ]; then vendor_bin="$npm_prefix/lib/node_modules/dingtalk-workspace-cli/vendor/dws" need_file "$vendor_bin" LC_ALL=C grep -aFq "v$EXPECTED_VERSION" "$vendor_bin" || \ err "npm-installed binary does not contain expected version marker v$EXPECTED_VERSION" EXPECTED_VERSION="$EXPECTED_VERSION" node -e ' const pkg = require(process.argv[1]); if (pkg.version !== process.env.EXPECTED_VERSION) process.exit(1); ' "$NPM_STAGE_DIR/package.json" || err "npm package.json version mismatch" fi [ "$VERIFY_SKILL_TARGETS" -eq 0 ] || verify_skill_targets "$npm_home" HOME="$npm_home" npm_config_cache="$npm_cache" npm_config_prefix="$npm_prefix" \ npm uninstall -g dingtalk-workspace-cli >/dev/null rm -f "$tarball_path" } verify_brew() { need_cmd brew need_file "$FORMULA_PATH" brew_home="$TMP_ROOT/brew-home" mkdir -p "$brew_home" BREW_TAP_NAME="local/dws-package-verify-$$" say "==> verifying Homebrew formula install" HOME="$brew_home" HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \ brew uninstall --force dingtalk-workspace-cli-local >/dev/null 2>&1 || true HOME="$brew_home" HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \ brew untap --force "$BREW_TAP_NAME" >/dev/null 2>&1 || true HOME="$brew_home" HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \ brew tap-new --no-git "$BREW_TAP_NAME" >/dev/null tap_repo="$( HOME="$brew_home" HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \ brew --repository "$BREW_TAP_NAME" )" mkdir -p "$tap_repo/Formula" cp "$FORMULA_PATH" "$tap_repo/Formula/dingtalk-workspace-cli-local.rb" HOME="$brew_home" HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \ brew install -y "$BREW_TAP_NAME/dingtalk-workspace-cli-local" >/dev/null prefix="$( HOME="$brew_home" HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 \ brew --prefix dingtalk-workspace-cli-local )" [ -x "$prefix/bin/dws" ] || err "brew install did not create $prefix/bin/dws" "$prefix/bin/dws" --help >/dev/null if [ -n "$EXPECTED_VERSION" ]; then LC_ALL=C grep -aFq "v$EXPECTED_VERSION" "$prefix/bin/dws" || \ err "Homebrew-installed binary does not contain expected version marker v$EXPECTED_VERSION" fi need_file "$prefix/share/dingtalk-workspace-cli-local/skills/dws/SKILL.md" } need_file "$DIST_DIR/dws-skills.zip" [ "$RUN_NPM" -eq 0 ] || verify_npm [ "$RUN_BREW" -eq 0 ] || verify_brew say "Package-manager verification complete."