关于 alibabacloud-ecs-code-deploy
此 Skill 指导 Agent 使用 `aliyun appmanager` 将本地目录或 Git URL 中的项目部署到 Alibaba Cloud ECS,并规定环境检查、项目准备和部署后的日志验证流程。
主要功能
- 01部署本地或 Git 项目
- 02检查 CLI、插件和凭据
- 03依据项目 README 运行说明
- 04通过日志验证部署
适用场景
- 01将当前目录项目部署到 ECS
- 02部署从 Git URL 获取的项目
- 03检查 ECS 部署后的日志
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ aliyun/ alibabacloud-aiops-skills --skill alibabacloud-ecs-code-deploy安装后在 Claude Code 中输入/alibabacloud-ecs-code-deploy确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/deploy-output-and-management.mdinit-and-credentials.mdlessons-learned.mdram-policies.mdscript-templates.mdskill-dir-resolution.mdtutorial-flask-app.mdscripts/deploy_toolkit.pyrequirements.txt详细介绍
通过 aliyun appmanager 部署到 Alibaba Cloud ECS
概述
aliyun appmanager 是一款对 Agent 友好的 CLI 工具,可一键将应用(App)和 AI Agent 部署到 Alibaba Cloud ECS。它支持非交互模式(--non-interactive)、结构化 JSON 输出(--output json)和流式 NDJSON 响应。
默认行为:用户调用 /alibabacloud-ecs-code-deploy,但未指定项目路径或 URL 时,将当前工作目录中的项目部署到 Alibaba Cloud ECS。如果用户提供 Git URL,则先将其克隆到当前目录,再 cd 进入克隆后的目录并继续部署。
执行顺序:Agent 必须按照本文档底部的“完整部署工作流”部分执行,以确保顺序正确。下方的任务部分按主题组织,供参考;其中的编号不代表执行顺序。
必须:开始前创建待办清单
执行任何步骤之前,Agent 必须创建一份包含以下所有事项的待办清单。不得遗漏任何事项。创建待办清单之前不得开始部署。
Todo list (Deploy to Alibaba Cloud ECS):
[ ] 0. Resolve $SKILL_DIR (cross-platform path — MUST run first; see "Step 0" below)
[ ] 1. Environment pre-check (MUST run deploy_toolkit.py check; manual commands FORBIDDEN as replacement)
[ ] 2. Obtain project (clone git URL here if needed; skip for local projects)
── Check whether .appmanager/config.yaml already exists (repeat-deploy shortcut) ──
│ Exists + new ECS (no instanceId) → skip 3-5, start from 5.5 (price check)
│ Exists + existing ECS (has instanceId) → skip 3-5.5, jump to 6 (deploy)
│ Does not exist → proceed normally from 3
───────────────────────────────────────────────────────────────────────────────
[ ] 3. Read project (README.md -> quick-deploy method) + identify type (agent / app)
[ ] 4. Ask user for deployment config (region + new ECS / existing ECS)
[ ] 5. Init + generate scripts (appmanager init -> write start/stop scripts to config.yaml)
[ ] 5.5. Pre-deploy price check + risk warning (MUST run deploy_toolkit.py price; confirm price / OSS billing / existing-ECS impact / group overwrite item by item)
[ ] 6. Deploy (MUST run deploy_toolkit.py deploy; manual deploy command FORBIDDEN as replacement)
[ ] 7. Verify (MUST run deploy_toolkit.py verify; manual status command FORBIDDEN as replacement)
[ ] 8. Output final result (console link + cost reminder + management commands)
⛔ 脚本优先规则:步骤 1、5、6、7 均有专用工具包脚本
$SKILL_DIR/scripts/deploy_toolkit.py(其中$SKILL_DIR在下方步骤 0中解析,适用于 Qoder、Claude Code 和任何其他平台)。Agent 必须直接运行对应的子命令,作为该步骤的第一个且唯一的操作——绝不可在运行脚本之前或以脚本替代手动运行 CLI 命令(例如aliyun version、版本检查、凭据检查)。脚本会在内部处理所有检查。仅当脚本文件本身不存在时,才允许将手动命令作为备用方案。❌ 错误(步骤 1):运行
aliyun version→ 检查版本 → 运行~/.aliyun/appmanager-venv/bin/python ...→ 检查版本 → 然后运行deploy_toolkit.py check✅ 正确(步骤 1):运行python3 "$SKILL_DIR/scripts/deploy_toolkit.py" check→ 如果退出码为 1,则修复其报告的问题 → 如果脚本文件缺失,此时才改用手动检查
第 6 项绝对不可妥协。如果 Agent 跳过日志验证,直接输出“部署成功”,则表示未正确完成此技能。如果
deploy_toolkit.py verify以 1(失败)退出,Agent 必须修复问题并重新部署,然后才能继续执行第 7 项。
步骤 0(必须):解析 $SKILL_DIR — 跨平台路径
工具包脚本位于
<skill-root>/scripts/deploy_toolkit.py。不同平台会将技能安装到不同位置(Qoder/Claude Code/Qwen/...)。Agent 必须在会话开始时解析出技能根目录的绝对路径,并在下文所有$SKILL_DIR出现的位置重复使用。严禁硬编码任何特定平台的路径。
有关完整的 10 个候选路径检测算法、export + test -f 验证代码片段,以及 Pattern A / Pattern B / ⛔ Anti-pattern 的使用规则,请参阅 references/skill-dir-resolution.md。
快速回顾(详情请阅读参考文档):
- ✅ Pattern A(持久 Shell):先运行
export SKILL_DIR="/abs/path",之后再运行python3 "$SKILL_DIR/scripts/deploy_toolkit.py" <sub> - ✅ Pattern B(每次调用都使用新的 Shell):直接填入绝对路径 —
python3 "/abs/path/scripts/deploy_toolkit.py" <sub> - ⛔ 反模式:
SKILL_DIR=/path python3 "$SKILL_DIR/..."— 外层 Shell 会在前缀赋值之前展开$SKILL_DIR,导致路径变为/scripts/deploy_toolkit.py并出现 ENOENT。如果看到python3: can't open file '/scripts/deploy_toolkit.py',请改用 Pattern A 或 B。
任务 1:安装 Alibaba Cloud CLI
主要操作:运行 python3 "$SKILL_DIR/scripts/deploy_toolkit.py" check——该命令会一次性检查 CLI 版本、appmanager-cli 版本和凭证。只有在脚本文件缺失时,才使用 references/init-and-credentials.md 中的备用方案。
必须 — 处理未满足的环境前置条件:当
check因 aliyun CLI 缺失或版本低于 3.3.19(或 appmanager-cli 缺失或版本过旧)而以状态码 1 退出时,Agent 不得默默停止工作流。必须按以下流程处理:
- 未安装 CLI → 直接自动安装,无需询问用户——执行安装命令(见下方代码片段,或查看 references/init-and-credentials.md 以确定适用的架构),然后重新运行
deploy_toolkit.py check进行确认。- 已安装 CLI → 先询问用户——显示检测到的版本、所需版本和升级命令,并征求用户明确同意(例如:“已安装 aliyun CLI 3.3.4,但低于 appmanager 所需的 >= 3.3.19;是否批准升级(覆盖安装到 /usr/local/bin,需要 sudo)?”)。绝不能默认用户同意;绝不能粘贴凭证。
- 用户同意后——执行安装/升级命令,然后重新运行
deploy_toolkit.py check进行确认。- 用户拒绝后——以用户拒绝为由停止。不要继续使用旧版本(部署无论如何都会失败)。
工具包的
check输出已针对每个可修复问题包含→ AGENT: DO NOT stop. ASK user ...行——请原样遵循(“未安装”情况除外,该情况会自动处理)。必须 — 升级方法优先级:由 brew 管理 → 使用
brew upgrade(不要再次覆盖/usr/local/bin/);有 sudo → 覆盖/usr/local/bin/;没有 sudo → 使用~/bin/并持久化设置 PATH(Unix)。Scoop/Choco → 使用%USERPROFILE%\bin并设置用户 PATH(Windows)。完整优先级规则 → references/init-and-credentials.md §“CLI Install/Upgrade Method Priority”。安装/升级后,始终重新运行deploy_toolkit.py check进行确认;如果which -a aliyun仍显示旧二进制文件排在首位,请修正 PATH 顺序——不要重复执行相同的覆盖操作。
可观测性(强制):注入 User-Agent
⛔ 每次
aliyunCLI 调用都必须携带此技能的 User-Agent,以便在云端日志中追踪所有 API 请求。Agent 必须在会话开始时(紧接着 Step 0 之后),在调用任何aliyun/deploy_toolkit.py之前,将 UA 环境变量导出一次。
完整 UA 模板:
AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/{session-id}
session-id 统一规则:
- 每个 Agent 会话只生成一次:
SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')——小写 UUID(任何长度不少于 16 个字符的小写十六进制随机令牌也可)。 - 在会话中的所有 CLI 调用中重复使用同一个 session-id——绝不要为每条命令重新生成,否则一次部署会散落成无法追踪的片段。
- 按照 Step 0 规则统一持久化:模式 A 使用
export SESSION_ID=...(持久 shell),或在每次调用使用全新 shell 时内联字面值。
注入方法(现代方式——环境变量):
export ALIBABA_CLOUD_USER_AGENT="AlibabaCloud-Agent-Skills/alibabacloud-ecs-code-deploy/${SESSION_ID}"
⛔ 旧版
aliyun configure ai-mode enable / set-user-agent机制已弃用——请勿使用。不要将ALIBABA_CLOUD_USER_AGENT与 ai-mode 或针对每条命令设置的环境变量前缀结合起来用于同一个技能令牌:CLI 会叠加这些来源并生成重复的 UA。每个会话只设置一次环境变量,然后保持不变。
任务 2:配置凭据
deploy_toolkit.py check 已会验证凭据。只有在凭据缺失或无效时,才参考 references/init-and-credentials.md,了解默认凭据链的补救流程。
⛔ 优先选择 OAuth,而非 AK:OAuth 更安全、更方便(无需长期存储密钥)。Agent 必须将 OAuth 作为首选方案。用户同意后,Agent 直接运行登录命令——但必须先提醒用户,该命令会打开浏览器授权页面,且会一直等待,直到用户在浏览器中完成授权——然后执行
aliyun configure --mode OAuth --profile oauth,并通过aliyun sts get-caller-identity --profile oauth验证。⛔ SA-2.12 — 不要在聊天中收集 AK/SK:如果用户更倾向于使用 AK 认证,请提供一条可直接运行的命令模板,其中包含占位符——
aliyun configure set --profile default --mode AK --access-key-id <your-access-key-id> --access-key-secret <your-access-key-secret> --region cn-hangzhou——并请用户填写自己的 AK/SK,然后在自己的终端中运行。Agent 绝不要求用户将 AccessKey/Secret/STS-Token 值粘贴到聊天中,绝不将原始 AK/SK 放入工具调用参数或脚本中,也绝不回显凭据值。也支持默认凭据链(ECS RAM Role / 环境变量 / 已有的~/.aliyun/config.json)。完整补救流程 → references/init-and-credentials.md。严格禁止:绝不运行独立的
appmanager或aliyun appmanager login。
任务 3:初始化项目
步骤 1(必须):首先阅读 README.md
严格的顺序规则:扫描任何项目文件之前,Agent 必须先阅读项目根目录中的
README.md(或README)。这始终是任务 3 的第一项操作。
从 README 中提取的信息:
- 快速入门 / 部署命令(例如
pip install -r requirements.txt && python main.py、npm install && npm start) - 官方构建 / 运行命令、Docker 部署方式、端口号、必需的环境变量
必须:向用户介绍 README 中的方法,并按决策流程执行
步骤 A:向用户列出 README 提供的信息。
步骤 B:按优先级选择方法:
| 优先级 | 方法类型 | 操作 |
|---|---|---|
| 1(最高) | 原生 CLI / 包管理器安装(npm install -g、pip install、go install) | 直接使用 |
| 2 | 原生构建并运行(pip install && python main.py、npm install && npm start) | 使用该方法,并安装运行时 |
| 3 | 基于脚本的部署(bash deploy.sh) | 必须确认其为非交互式 |
| 4(最低) | Docker / docker-compose | 仅在没有更高优先级的方法时使用;检查中国地区的可访问性 |
步骤 C:根据场景执行:
- README 中有原生方法(优先级 1/2) → 直接将其作为启动脚本的核心。绝不忽略 README 并从头构建。
- README 中只有 Docker 方法 → 检查镜像可访问性(参见 references/script-templates.md 中的“Docker 镜像可访问性检查”)。提醒用户中国镜像源可能带来的风险。
- README 中没有部署信息 / README 不存在 → Agent 独立扫描项目文件(仅允许在此情况下操作)。
为什么要先读 README? 大多数项目都会记录准确的构建 / 运行命令。仅根据文件自动检测容易出错。
步骤 2:确定项目类型
| 条件 | 类型 |
|---|---|
项目依赖 agentscope | agent |
| 其他所有情况(langchain、mcp、autogen、Web 服务、工具等) | app |
确定 --name
使用项目目录名称(转为小写,并使用连字符)。告知用户:Default app name uses the directory name <name>。
确定 --region 和 ECS 目标(必须询问用户)
Agent 必须在同一条消息中同时询问以下两个问题:
1. 你想部署到哪个区域?
- 上海 (cn-shanghai) / 杭州 (cn-hangzhou) / 北京 (cn-beijing) / 深圳 (cn-shenzhen) / 广州 (cn-guangzhou) / 成都 (cn-chengdu) / 南京 (cn-nanjing) / 香港 (cn-hongkong)
2. 使用新建 ECS 还是已有 ECS?
- 新建 ECS(自动创建实例,按量付费)
- 已有 ECS(从下方列表中选择,或手动提供实例 ID)
绝不能使用“华东 1”“华北 2”等基于可用区的标签。绝不能添加描述。仅使用城市名称。
已有 ECS — 列出所选区域中用户最近创建的 10 个实例(必须执行)
当用户选择已有 ECS时,Agent 必须先查询账号在所选区域中最近创建的 10 个实例(插件模式:aliyun ecs describe-instances),并将它们列成编号列表供用户选择——不得要求用户凭记忆提供实例 ID。始终也要允许用户手动输入实例 ID(例如 i-bp1xxxxxxxx)作为备用选项。查询时必须传入与部署相同的 --profile(同一账号),否则可能返回零个实例或错误的实例。完整命令(jq 管道、无 jq 时的回退方案、零实例处理)→ references/init-and-credentials.md §“列出现有 ECS 实例”。选定或输入的 ID 将传入 appmanager init --ecs existing --instance-id <ID>。
⚠️ 区域传递检查(必须执行):所选区域必须原样传入
appmanager init --region,写入config.yaml中的common.deployment.regionId,并作为--region <REGION_ID>附加到后续每一次deploy_toolkit.py {price,deploy,verify}调用中。区域不匹配或遗漏会导致 OOS API 返回InvalidParameter: DeployRegionId is invalid。
确定 --port(仅 App 类型,可选)
仅当项目实际监听 HTTP 时才指定。后台服务(机器人、工作进程、CLI 工具)无需指定。如确有需要但端口未知,默认使用 8080。Agent 类型不使用 --port。
非交互式初始化
所有初始化标志组合请参阅 references/init-and-credentials.md。
这会创建 .appmanager/config.yaml。不支持 --overwrite——如果 .appmanager/ 已存在,请先将其删除。
任务 4:生成部署脚本
对于所有项目类型,Agent 必须生成部署脚本并将其写入 .appmanager/config.yaml。
工作流
- 首先阅读 README.md——遵循任务 3 的决策树
- 如果 README 没有部署信息——扫描项目结构(见下方“语言检测”)
- 检查 Docker 可访问性——如果选择 Docker 路径(见 references/script-templates.md)
- 生成启动和停止脚本——遵循下方规则。启动脚本必须始终包含 zip 解压步骤。
- 写入 config.yaml——写入
common.scripts.start和common.scripts.stop下(绝不能写入顶层scripts)
语言检测、要读取的文件和入口点
语言检测规则(指示文件)、各语言必须读取的文件以及入口点检测顺序 → references/script-templates.md §“项目分析”。
通用脚本规则
| 规则 | 要求 |
|---|---|
| ⛔ 必须解压 zip | 启动脚本必须:查找 zip → mkdir -p → unzip -o → cd。否则,ECS 上的项目目录不存在 |
| 安装运行时 | 必须先安装语言运行时(ECS 是裸机环境) |
| 安装 unzip | command -v unzip &>/dev/null || $PKG_MGR install -y unzip |
| 幂等 | 可安全地多次运行 |
| ⛔ 日志文件路径固定 | 必须使用 /root/app.log 和 /root/app.pid。验证脚本是否将这些路径写死 |
| 追加日志 | 始终使用 >>(绝不使用 >) |
| PID 文件 | 在 nohup ... & 之后执行 echo $! > /root/app.pid |
| 后台运行 | nohup ... >> /root/app.log 2>&1 & |
| 停止旧进程 | [ -f /root/app.pid ] && kill "$(cat /root/app.pid)" 2>/dev/null || true |
| 应用目录 | /root/{app_name} |
| 禁止使用 heredoc | 脚本中绝不要使用 << 'EOF'——这会破坏 YAML。请使用 printf 或 python3 -c |
| 必须输出日志尾部 | 以 sleep 3 && cat /root/app.log 结束,以便捕获验证结果 |
| ⛔ 停止脚本:禁止使用 exit | 不得包含 exit。部署系统会将停止脚本与启动脚本拼接,exit 会终止整个进程 |
ECS 实例是裸 Linux 环境(通常为基于 RHEL 的 Alibaba Cloud Linux,使用
yum/dnf)。
脚本模板、语言安装命令和 config.yaml 写入方法,请参阅 references/script-templates.md。
任务 4.5:部署前价格检查 + 风险警告
必须执行:部署前运行
deploy_toolkit.py price。该脚本会输出价格估算(附带 OSS 额外计费提醒),并在适用时输出风险警告。Agent 必须向用户展示所有标记的事项,并在运行deploy前取得明确确认。
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" price --config .appmanager/config.yaml
- 退出码为 0 且出现
=== AGENT_CONFIRM_REQUIRED ===:向用户展示完整的价格和风险警告,并逐项确认。 - 退出码为 1:价格查询失败;不得继续部署。
Agent 必须确认最多 3 项(价格 + OSS 费用 / 现有 ECS 风险 / 组覆盖选项)——详细说明和示例措辞请参阅 references/deploy-output-and-management.md §“部署前价格检查:确认事项”。
在完成所有适用的确认之前,Agent 不得调用
deploy_toolkit.py deploy。
任务 5:部署
aliyun appmanager <agent|app> deploy --overwrite --output json
部署成功后停止——
status: success仅表示编排已完成。Agent 必须在输出结果前执行任务 6 验证。
处理部署失败
⛔ 必须执行的失败处理关卡:任何部署失败后(退出码为 1、超时或
ReleaseCancelled),Agent 必须立即运行deploy_toolkit.py verify——在尝试任何修复、回退到手动命令或输出部分结果之前。失败后跳过验证是禁止的,并视为技能失败。
ReleaseCancelled的含义:它表示 ECS 上的启动脚本失败或超时。它并不表示“有人取消了部署”。唯一正确的后续操作:运行deploy_toolkit.py verify→ 阅读日志 → 修复脚本 → 重新部署。
已知失败模式:临时排查问题前,请查看 references/lessons-learned.md,了解此前发现的部署失败模式及已验证的修复方法。
失败处理流程:
- 运行
deploy_toolkit.py verify获取/root/app.log(不得跳过)。 - 分析日志以定位根本原因。
- 修复脚本并重新部署(最多尝试 3 次)。
- 失败 3 次后停止——报告错误,但仍须输出控制台链接、费用提醒和删除命令。
任务 6:部署后验证(阻断性)
status: Deployed并不意味着应用正在运行。Agent 必须运行 verify 并对日志进行语义分析。
- 运行
deploy_toolkit.py verify(自动从 config.yaml 读取参数)。 - Agent 对日志进行语义分析,判断应用是否确实已成功启动。
- 未运行 -> 诊断 -> 修复 -> 重新部署并验证(最多 3 次尝试)。
- 只有在确认应用正在运行/需要用户手动操作/3 次尝试均失败后,Agent 才能输出最终结果。
任务 7 和 8:列出、删除、验证与最终输出
请参阅 references/deploy-output-and-management.md,了解以下内容:
- 列出/删除命令
- 配置验证
- 配置模板参考
- 关键注意事项和易错点
- 部署后必须遵循的输出格式(控制台链接、费用提醒、使用指南)
输出前关卡——自检(⛔ 阻断性)
输出结果前,Agent 必须准确打印 Deployment self-check report 模板(见工作流步骤 7.5)。跳过报告 = 技能失败(报告不是可选的摘要)。如果任何项目为 ❌,必须在输出步骤 8 之前修复。
📘 包含具体输入/输出及边缘情况的实操指南(Python Flask 示例):请参阅 references/tutorial-flask-app.md。
完整部署工作流
⛔ 强制执行规则:Agent 必须严格按照此顺序执行。对于指定脚本的步骤(步骤 1、5、6),Agent 必须运行脚本,绝不能用单独的命令手动复现脚本逻辑。上面的任务章节仅供参考(用于了解脚本的内部工作方式,或在脚本缺失时作为后备方案)。
# 0. Resolve $SKILL_DIR (MANDATORY — see "Step 0" section above for full algorithm)
# → Detect the absolute directory containing THIS SKILL.md (most accurate)
# → Or fall back to platform-specific candidates: ~/.qoder/skills/..., ~/.claude/skills/..., ~/.qwen/skills/..., $SKILLS_HOME/..., etc.
# → Pattern A (persistent shell): export SKILL_DIR=<abs_path> ; verify $SKILL_DIR/scripts/deploy_toolkit.py exists ; reuse $SKILL_DIR everywhere
# → Pattern B (fresh shell per command): inline the absolute path — `python3 "/abs/path/scripts/deploy_toolkit.py" ...`
# → ⛔ NEVER use `SKILL_DIR=/path python3 "$SKILL_DIR/..."` — outer shell expands $SKILL_DIR
# BEFORE the prefix assignment, producing `/scripts/deploy_toolkit.py` and ENOENT.
# 1. Environment check (MUST use deploy_toolkit.py check — DO NOT run manual commands)
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" check
# ⛔ FORBIDDEN: running `aliyun version`, `~/.aliyun/appmanager-venv/bin/python -c "..."`,
# credential checks, or ANY manual version-check commands before or instead of this script.
# The script checks ALL of: CLI version + appmanager-cli version + credentials in one run.
# Just run the script. Period.
# → If exit 0: all checks passed, proceed to step 2
# → If exit 1, address the issue printed by the script:
# ⚠️ DO NOT stop silently. For every fixable ❌ line the script prints,
# Agent MUST follow the flow below:
# - aliyun CLI NOT installed: AUTO-INSTALL directly (no need to ask user)
# - aliyun CLI already installed but outdated: ASK user to approve upgrade
# (covers to /usr/local/bin, needs sudo), then run the install command
# printed by the script (see Task 1).
# - appmanager-cli < 1.1.1 or BROKEN venv: ASK user to approve
# `rm -rf ~/.aliyun/appmanager-venv` (auto-recreates on next aliyun
# appmanager run).
# ⚠️ This path is fixed at ~/.aliyun/appmanager-venv (the venv is self-managed
# by the aliyun CLI). After deletion, the next `aliyun appmanager` run
# auto-recreates it. The Agent MUST use this exact literal path —
# NEVER replace it with a variable or build it via concatenation,
# to avoid accidentally wiping user data.
# - credentials missing/invalid: present OAuth-first remediation
# to the user (OAuth / RAM Role / env vars / `aliyun configure` interactive) — NEVER
# collect AK/SK in chat. See Task 2 + references/init-and-credentials.md.
# → If user refuses any fix: stop with that refusal as the reason — DO NOT
# continue with a broken environment (deployment will fail anyway).
# → If script file not found: ONLY THEN fall back to manual checks (Task 1 + Task 2)
# 2. Obtain project source (if needed)
# → If git URL provided: clone to CURRENT WORKING DIRECTORY, cd into cloned dir
# git clone <URL> && cd <cloned_dir>
# → If local path / current directory: skip this step, use directly
# 🔀 REPEAT DEPLOYMENT SHORTCUT — check BEFORE step 3
# → Check if .appmanager/config.yaml already exists in the project directory
# → If YES (config.yaml exists):
# Read the file and check for common.deployment.instanceId:
# - instanceId ABSENT (new ECS): skip steps 3-5, jump to step 5.5 (price check)
# - instanceId PRESENT (existing ECS): skip steps 3-5.5, jump to step 6 (deploy)
# In both cases, inform user: "Existing .appmanager/config.yaml detected; will reuse the existing config and deploy directly."
# → If NO (config.yaml does NOT exist): proceed normally from step 3
# 3. Read project + identify type (agent or app)
# → READ README.md FIRST — highest priority source for deployment method:
# - Agent MUST list README's methods to user and select by priority:
# Native CLI install > Native build+run > Script deploy > Docker
# - ❌ NEVER ignore README methods and scan project files instead
# - ❌ NEVER prefer Docker when native methods are available
# - Docker: ONLY when no native method exists, MUST warn user about China mirror risks
# - Only if README absent/empty/no deploy info → Agent scans project files independently
# → Only classify as "agent" if project depends on `agentscope`; everything else is "app"
# → Determine --name from directory name, --port from project config/README
# → For Docker: check image accessibility from China (see references/script-templates.md)
# 4. Ask user for deployment region + ECS target (MANDATORY — ask together in one question)
# → Question 1: "Which region do you want to deploy to? Shanghai(cn-shanghai)/Hangzhou(cn-hangzhou)/Beijing(cn-beijing)/Shenzhen(cn-shenzhen)/Guangzhou(cn-guangzhou)..."
# → Question 2: "New ECS or existing ECS?" — if existing, FIRST query the account's 10 most-recently-created
# ECS instances in the chosen region and present them as a numbered list for selection:
# aliyun ecs describe-instances --biz-region-id <REGION> --region <REGION> --page-size 100 | jq -r '.Instances.Instance | sort_by(.CreationTime) | reverse | .[:10] | .[] | "..."' (plugin mode; no `--output json`; JSON is the default)
# Also always support manual instance ID entry (e.g. i-bp1xxxxxxxx). See Task 3 "Existing ECS" section.
# → NEVER use zone-based labels like "East China 1" / "North China 2" — always use city names
# → NEVER skip the ECS choice and default to creating new
# → ⚠️ Region MUST be propagated verbatim to: appmanager init --region, config.yaml common.deployment.regionId, AND every deploy_toolkit.py --region. Mismatch → InvalidParameter: DeployRegionId from OOS API.
# 5. Init + generate scripts (appmanager init → write start/stop to config.yaml)
# → If .appmanager/ already exists in the CURRENT project directory, ask user before removing.
# ⚠️ DESTRUCTIVE: `rm -rf .appmanager` deletes the existing deployment config.
# Required guard before deletion:
# a. Confirm CWD matches the intended project directory (`pwd` shows expected path)
# b. Confirm target is the relative path `.appmanager` (NEVER absolute, NEVER with variables)
# c. Inform the user "About to delete the existing deployment config under ./.appmanager/. This is irreversible." and obtain consent
# Recommended safer alternative: back up first
# mv .appmanager .appmanager.bak.$(date +%Y%m%d%H%M%S)
# Only after explicit user consent: rm -rf ./.appmanager
# → Run: aliyun appmanager init --non-interactive --name <DIR_NAME> --type <app|agent> --region <REGION> [--port <PORT>] [--ecs existing --instance-id <ID>] [--model qwen3.6-plus --api-key "$API_KEY"]
# (See references/init-and-credentials.md for full flag combinations by type)
# → Then generate start/stop scripts and write to config.yaml:
# - MUST write to common.scripts.start and common.scripts.stop (NEVER top-level scripts key)
# - Use python3 yaml library: config['common']['scripts'] = {'start': ..., 'stop': ...}
# - PRIORITY: README deployment commands → use directly; only auto-generate when README has none
# - ⛔ MANDATORY: Start script MUST ALWAYS include zip extraction (mkdir + unzip + cd) BEFORE
# any build/run commands. appmanager uploads zip but does NOT extract it.
# 5.5. Pre-deploy price check + risk warning (MUST run deploy_toolkit.py price — Agent handles user confirmation)
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" price --config .appmanager/config.yaml
# → Script output structure:
# [Price table] estimate from `appmanager price` (order-billed resources: ECS/EIP/bandwidth) + the trailing 📦 OSS extra-billing reminder
# [Risk warning] only when detected: [Existing-ECS deployment risk] / [Group overwrite risk] / [Failure-leftover group]
# → Script does NOT ask user for confirmation — that's the Agent's job
# → If exit 0: Agent MUST read the output, present the COMPLETE breakdown to user — including:
# 1) Price estimate + OSS extra-billing reminder (OSS storage ~CNY 0.12/GB/month, public outbound ~CNY 0.50/GB only when cross-region, requests billed per 10k)
# 2) If output contains [Existing-ECS deployment risk] -> ask whether to deploy onto that existing ECS (may impact other apps on it)
# 3) If output contains [Group overwrite risk] -> ask user to choose A (overwrite) or B (new group)
# Example: "Estimated cost: compute resources CNY X.XXX/hour (~CNY XXX.XX/month); public traffic billed by usage at CNY 0.80/GB;
# the deployment also incurs minor OSS storage and request fees (intra-region pull is free of public outbound charges).
# Confirm to continue?"
# → After ALL items confirmed by user: run the matching deploy command per item 3's choice (default overwrite / --force-new-group for new group)
# → If ANY item refused: STOP deployment
# → If exit 1: price query failed, show error to user, do NOT proceed
# 6. Deploy (MUST use deploy_toolkit.py deploy — DO NOT run deploy manually)
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" deploy \
--type <agent|app> --name <APP_NAME> --group <GROUP_NAME> --region <REGION_ID>
# ⛔ FORBIDDEN: running `aliyun appmanager deploy` directly without this script
# → Handles: group status check → conflict auto-resolve → deploy
# → Exit 0: deploy submitted, proceed to step 7
# → Exit 1: ⛔ MUST run step 7 (verify) IMMEDIATELY to fetch /root/app.log;
# skipping to step 8, outputting partial results, or running manual
# commands instead is FORBIDDEN. Then fix script per log and redeploy
# (max 3 attempts).
# 7. Verify (MUST use deploy_toolkit.py verify — DO NOT check status manually)
python3 "$SKILL_DIR/scripts/deploy_toolkit.py" verify \
--type <agent|app> --name <APP_NAME> --group <GROUP_NAME> --region <REGION_ID>
# ⛔ FORBIDDEN: running `aliyun appmanager status` + manual log analysis instead of this script
# → Optional: --wait <seconds> for slow-starting apps (default 3s, Java/heavy use 15-30)
# → Dual-path: Cloud Assistant cat /root/app.log (preferred) → deployCommandOutput (fallback)
# → Exit 0: app running, proceed to step 8
# → Exit 1: app failed — fix start script, re-deploy (back to step 6)
# → Exit 2: inconclusive — retry with longer --wait or suggest SSH check
# 7.5. Self-check summary (⛔ BLOCKING — skill fails if omitted)
# MUST print the exact template below to the user — this is a completion criterion, NOT optional.
#
# ---
# ✅ Deployment self-check report:
# 0. Path resolution — SKILL_DIR=___ (script exists ✅)
# 1. Environment pre-check — CLI v___ / appmanager-cli v___ / credentials valid ✅
# 2. Project obtained — (local / cloned) ✅
# 3. Project identified — type: ___ / deploy method source: README.md ✅
# 4. Deployment region — user choice: ___ ✅
# 5. Init + scripts — config.yaml generated; start script: ___ (key command summary) ✅
# 5.5. Pre-deploy price check — user confirmed price (CNY ___/hour, ~CNY ___/month) ✅
# 6. Deploy executed — deploy_toolkit.py deploy exit 0 ✅
# 7. Run verification — deploy_toolkit.py verify exit 0 / log keywords: ___ ✅
# ---
#
# If any item is ❌, fix it BEFORE step 8 — this is for the USER to see, proving the work is properly done.
# 8. Output results (MANDATORY: console link + cost reminder + management commands)
# → See references/deploy-output-and-management.md for full output format