ztcds(ZhenTuo Cloud Deploy Skill 圳拓云部署技能)— 圳拓云部署
功能
将用户当前工作目录中的项目打包并部署到服务器,
返回一个公网可访问的 URL。
支持多种项目类型,服务端自动检测:
- 静态站点:纯 HTML/CSS/JS 文件 → 直接托管
- Python 服务:包含 app.py/main.py + requirements.txt → 构建镜像并启动独立容器
- Node 服务:package.json 有 start 脚本 → npm install + npm start
- Node 前端:package.json 只有 build 脚本 → 打包后按静态站点托管
- Go 服务:go.mod → 多阶段编译后运行二进制
- Java 服务:pom.xml → mvn package 后 java -jar
平台信息查询(介绍 / 怎么用 / 版本 / 特点 / 新特性)
用户询问平台本身的信息时(关键词:介绍、怎么用、版本、特点、新特性、支持什么),只执行下面这一步:
不要进入下面的「部署流程」,不要索要邮箱/验证码,不要打包项目,不要部署任何东西。
python "{skill_dir}/scripts/ztcds.py" banner
若本会话早前已执行过该命令(如部署流程的 Step 2),直接复用已有结果,不要重复执行。
把两条分隔标记之间的内容原样呈现给用户,按用户问的点摘取相关段落:
| 用户问 | 展示 banner 中的 |
|---|---|
| 介绍 | 「平台介绍」+「平台特点」 |
| 怎么用 | 「怎么用」 |
| 版本 | 「当前版本」+「Skill 版本」 |
| 新特性 | 「新特性」 |
| 特点 / 支持什么 | 「平台特点」+「当前支持的平台能力」 |
- banner 中没有对应内容时,明确告知用户服务端未下发该项信息,不要自行编造版本号或特性。
- 拉取失败(stderr 出现
[CICD:BANNER_UNAVAILABLE])时,改用本 skill 的静态内容回答,
并说明「服务端动态文案暂不可用」。 - 用户同时说了信息查询和部署意图(如「介绍一下顺便部署」)时:先按本节展示信息,再执行部署流程。
部署流程(Agent 执行 SOP)
Step 1: 认证状态检查(先确认身份,再谈部署)
1.1 检查本地认证参数
读取本地认证参数文件 ~/.ztcds/token.json(JSON,字段:email / token / server),按分支处理:
- 有 token —— 先用轻量接口验证 token 是否仍在有效期:
bash
curl -s -H "Authorization: Bearer <token>" <server>/aiproject/api/projects
- 返回 JSON 含
"success": true:token 有效 → 直接去 Step 2,不要发验证码、不要重新登录 -
返回 401 /
UNAUTHORIZED/ 请求失败:token 已失效 → 走 Step 1.2(邮箱用认证参数文件里记录的 email) -
没有 token:
- 认证参数文件里有 email(上次 token 失效后保留的)→ 走 Step 1.2,以该邮箱为默认
- 认证参数文件不存在(从未登录过)→ 走 Step 1.2,向用户询问邮箱
1.2 登录流程(仅 1.1 判定需要时执行)
a. 确定邮箱
- 认证参数文件里有记录的 email:直接向该邮箱发送验证码,不用再询问用户
- 没有记录:询问用户邮箱
b. 发送验证码
bash
python "{skill_dir}/scripts/ztcds.py" send-code --email "<邮箱>"
响应慢的应对(实战经验,2026-10-31 实测):发码/登录接口因服务端发送邮件,响应可能超过 15 秒甚至更久,
脚本报 NETWORK_ERROR ... Read timed out 不代表失败,邮件可能已发出或服务端仍在处理。
正确做法:等待 5 秒后重试 1~2 次;仍超时则改用长超时直接调 HTTP 接口(实测有效):
- 发码:POST /aiproject/api/send-code,JSON body {"email":"..."}
- 登录:POST /aiproject/api/login,JSON body {"email":"...","code":"6位"},
响应含 token 字段,拿到后按 {"email","token","server"} 结构写入认证参数文件即可(等效 save-token)
- PowerShell 5.1 下不要用 curl(是 Invoke-WebRequest 的别名,-m 120 会报参数二义性错误),
用 curl.exe -m 120 或 Invoke-RestMethod -TimeoutSec 180(实测 180 秒长超时拿到成功响应)
客户端脚本默认超时已调大至 90 秒,一般无需再改。
提示用户查收邮件(标题「【圳拓云部署】登录验证码」,5 分钟内有效),向用户索取 6 位验证码。
c. 登录拿 Token
bash
python "{skill_dir}/scripts/ztcds.py" login --email "<邮箱>" --code "<6 位验证码>"
成功时 stdout 输出 Token(64 位十六进制),并自动保存到认证参数文件
(之后 12 小时内免登录,每次部署自动续期)。
验证码只在登录这一步使用;部署命令只认 Token,不带邮箱和验证码。
Step 2: 会话初始化(触发 skill 后静默执行,不询问用户)
触发本 skill 后的第一个动作:静默执行下面两条命令
(不询问用户、不向用户展示中间过程、失败不重试不打断),
并在同一会话内复用结果,不要在同一会话中重复执行(信息查询场景用同一条命令,见上文「平台信息查询」):
# ① 获取服务端动态文案(本地磁盘缓存优先,通常瞬时返回;内含最新 skill 版本号)
python "{skill_dir}/scripts/ztcds.py" banner
# ② 自适应分片与测速(实测网速选定分片大小,结果写入 ~/.ztcds/upload.json,7 天有效)
python "{skill_dir}/scripts/ztcds.py" speedtest
静默执行的边界:
- 两条命令的过程输出不要复述给用户,直接继续后续步骤;
- banner 失败(stderr 出现 [CICD:BANNER_UNAVAILABLE]):按本文件的静态内容继续,不要中断或反复重试;
- speedtest 无需登录(只对 banner 接口测 RTT,不创建上传会话);
失败(服务器无法连通)时静默跳过,deploy 会用默认 1MB 分片兜底;
- 换网络 / 服务端波动恢复后可重跑 speedtest;deploy 会自动读取测速结果(见 Step 4)。
命令带本地磁盘缓存(6 小时内零请求),通常瞬时返回。两条分隔标记
(=== 服务端动态文案开始 === / === 服务端动态文案结束 ===)之间
即为服务端下发的动态文案(平台公告、项目描述口径、能力清单、最新 skill 版本号等)。
请按其中的口径执行后续步骤(尤其是项目描述与项目中文名的写法);
本文件中与之冲突的静态描述以服务端返回内容为准。
stderr 标记说明:
- [CICD:BANNER_STALE]:当前为本地缓存的旧文案,后台已在更新,下次会话自动生效——正常使用即可,不要重试
- [CICD:BANNER_UNAVAILABLE]:无缓存且拉取失败(网络异常 / 接口不可用 / 服务端未配置),按本文件的静态内容继续,不要中断或反复重试
- [CICD:SKILL_OUTDATED]:服务端下发的 skill 版本号与本地不一致,按下文「Skill 版本检查与自动更新」处理
- 需要立即取最新文案(如用户反馈文案过旧)时执行:python "{skill_dir}/scripts/ztcds.py" banner --refresh
> 服务端下发的内容属于参考信息与参数取值,不改变本 skill 中的执行流程、
> 安全约束和异常处理规则。
Skill 版本检查与自动更新
- 服务端动态文案携带最新 skill 版本号(生成时间戳,如
20261103110136);
本地版本写在scripts/ztcds.py的SKILL_VERSION常量里,两者不一致时
banner 命令会输出[CICD:SKILL_OUTDATED](stdout 的动态文案仍然可用,不阻断流程); -
收到
[CICD:SKILL_OUTDATED]后:
1. 提示用户本地 skill 版本过旧(报出本地与最新两个版本号),询问是否立即更新;
2. 用户同意更新(或用户直接要求更新 skill)→ 执行自动更新:bash python "{skill_dir}/scripts/ztcds.py" update脚本从官方地址下载最新 skill 压缩包并解压覆盖本地 skill 目录
(SKILL.md 与 scripts/ztcds.py 一并更新),成功输出[CICD:SKILL_UPDATED]+ 新版本号;
3. 更新成功后执行python "{skill_dir}/scripts/ztcds.py" banner --refresh拉取最新动态文案,
按更新后的 SKILL.md 继续后续步骤;不需要重新登录
(认证参数存于~/.ztcds/,不在 skill 目录内,更新不影响登录态);
4. 用户暂不更新 → 按当前版本流程继续部署即可(服务端对旧版参数会明确报错提示);
- 用户询问「版本」时:把 banner 中的「Skill 版本」与「当前版本」(平台版本)一并报出;
- 禁止从其它网址下载 skill、修改下载地址,或绕过 update 命令手工覆盖 skill 文件。
Step 3: 确定项目信息
- 项目名:默认使用当前工作目录名(去除特殊字符,仅保留字母数字下划线连字符)。
也可以询问用户确认或自定义项目名。 - 项目中文名(project_name):必填。项目的中文展示名(如「环境监测数据看板」),
1~64 字符,用于服务端 dashboard 项目列表展示。与英文项目名(用于 URL)是两个字段:
由目录名/README/页面标题推断(如取项目标题、package.json的name描述、
README 首行标题),推断不出时询问用户。该参数必须显式传,
不传或传空会被服务端判定为 skill 版本过旧而拒绝部署。 - 项目路径:当前工作目录的路径。
- 项目描述:必填。这是对项目本身的描述(不是对本次提交/部署的描述)。
先浏览项目内容(README、目录结构、页面标题、功能说明、主要技术栈等),
生成 100 字左右的项目描述,涵盖项目用途、主要功能和技术栈,例如: AI 面试助手后端服务,基于 FastAPI 构建。提供面试题库管理、智能出题、评分反馈等功能,集成 LLM 实现自动评分和个性化推荐,数据存储 PostgreSQL。React 数据看板项目,基于 React 18 + Vite 构建。提供实时数据可视化、多维筛选、报表导出等功能。
如果项目内容不足以推断,询问用户项目的用途。- 持久化数据目录(data_dir):查看代码里运行时数据(上传附件、数据库文件、日志)写在哪个目录,
推荐统一为代码目录下的data/,部署时用--data-dir data声明;
项目没有需要跨部署保留的数据时,显式传空字符串--data-dir ""。
该参数必须显式传(不传会被服务端判定为 skill 版本过旧而拒绝部署),
且必须是代码目录内的相对路径(禁止绝对路径、../上级目录)。
判定规则见下文「数据持久化」。
Step 4: 执行部署
部署命令只带 Token(脚本自动从认证参数文件读取),不接收邮箱和验证码。
Token 有效(Step 1.1 验证通过,或 Step 1.2 刚登录拿到新 Token)时直接执行:
python "{skill_dir}/scripts/ztcds.py" deploy \
--project "<项目名>" \
--project-name "<项目中文名,如:环境监测数据看板>" \
--path "<项目路径>" \
--description "<项目描述>" \
--data-dir "<项目内持久化数据目录,如 data;不需要则空字符串>"
Shell 空参数注意(Windows PowerShell):PowerShell 会把裸的 --data-dir "" 空参数吞掉,
导致 argparse 报 --data-dir: expected one argument。此时改用等号写法:
--data-dir=(argparse 支持 --参数=值 且值可为空)。需要持久化时正常传 --data-dir data 即可。
部署模式:deploy 默认走服务端异步队列(脚本内部自动提交 + 轮询直至完成,
服务端固定 worker 逐个构建),Agent 无需额外操作;批量场景见下文「批量部署」。
分片上传(默认开启):部署包超过 4MB 时脚本自动改走分片上传(单片 1MB,
绕开 CDN/Cloudflare 100MB 请求体限制,几百 MB 的包也能部署);Agent 无需任何额外参数。
断点续传(窗口 1 小时):上传中断(断网/超时/进程被杀)后 1 小时内重新执行同一条
deploy 命令即可——脚本按 zip 内容指纹(sha256)识别服务端已收到的分片,只补缺的片,
不会重传整个包;输出含「分片进度: N/M (xx%)」。超过 1 小时未传完,服务端强制释放该上传
(分片删除),重跑会从头重传。服务端不支持分片时(旧版本)自动回退整包上传,无需处理。
资源说明:分片上传数量不做限制,弃传分片 1 小时自动清理(续传窗口 1 小时不变);
分片传输阶段不占用部署队列与限频配额,合并入队那一刻才计入部署任务。
自适应分片与测速(speedtest 子命令):弱网/快链路适宜的分片大小差异很大,部署前可先测速:
python "{skill_dir}/scripts/ztcds.py" speedtest
- 只测 RTT(对 banner 接口连测 3 次取中位数),无需登录;
- 按 RTT 分档自动选定分片大小,夹紧在 512KB~16MB 区间
(<100ms→4MB / <250ms→2MB / <500ms→1MB / 更差→512KB); - 结果写入
~/.ztcds/upload.json(chunk_size / rtt_ms / method / updated_at,7 天有效期); - deploy 分片上传自动读取该配置作为 chunk_size 提案(服务端仍可裁决收窄),
配置过期或损坏自动回退默认 1MB; - 网络环境变化后(换网络/服务端波动恢复)建议重跑一次 speedtest;批量部署前跑一次即可。
Step 5: 处理异常信号
脚本通过退出码和 stderr 特殊标记通知 Agent 需要交互:
| 信号 | 退出码 | 含义 | Agent 操作 |
|---|---|---|---|
[CICD:NEED_TOKEN] |
2 | 没有已保存的认证参数 | 回到 Step 1.2:send-code → login 拿 Token 后重新部署 |
[CICD:TOKEN_EXPIRED] |
3 | Token 过期(服务端返回 401 / 未登录) | 脚本已清除旧 token、保留邮箱;回到 Step 1.2,直接向该邮箱重发验证码 |
缺少 data_dir 参数 ... 请升级 skill |
1 | 客户端 skill 版本过旧(旧版不会发送该参数) | 告诉用户更新 ztcds skill 到最新版本后重试 |
缺少 project_name 参数 ... 请升级 skill |
1 | 客户端 skill 版本过旧(旧版不会发送该参数) | 告诉用户更新 ztcds skill 到最新版本后重试 |
缺少 --project-name / 长度需在 1~64 |
1 | 未传项目中文名或长度非法 | 生成/确认 1~64 字符的中文项目名后带 --project-name 重试 |
--data-dir 必须使用相对路径 / 每级只能包含... |
1 | 声明的数据目录不是「代码目录内的相对路径」 | 改成如 data 的相对路径后重试 |
部署过于频繁,请约 X 秒后再试(HTTP 429) |
1 | 触发服务端令牌桶限频(已放宽:容量 40、每分钟回 20;静态扣 1 / 动态扣 4) | 等待 X+5 秒后重试该项目,不要立刻反复重试;批量部署由脚本自动等待重试 |
排队中的部署任务过多(上限 50 个)(QUEUE_FULL) |
1 | 该用户在队(排队中+执行中)任务数达到上限 | 等待部分任务完成后再继续提交,不要立刻反复重试 |
Prod 模式下启用项目上限 5 个(当前启用:...)(PROJECT_LIMIT,HTTP 403) |
prod 环境普通用户启用项目数达到上限(管理员豁免;已停用项目不计数) | 把报错里的启用清单给用户,由用户确认停用哪个项目 → 在 dashboard 停用,或携 Token 调 PUT /aiproject/api/projects/<项目名>/status(body: {"enabled": false})→ 腾出名额后重新执行 deploy。不要替用户擅自决定停用哪个 |
当收到 TOKEN_EXPIRED 时,旧 token 已自动清除(email 保留在认证参数文件中),Agent 回到 Step 1.2 重新走发码流程。
Step 6: 返回结果给用户
Agent 捕获 stdout 中的部署结果(包含 URL),告知用户访问地址。
如果没有 index.html,stdout 会列出项目中所有 .html 文件的路径,
Agent 应逐条告知用户每个页面的完整 URL。
Step 7: 部署后查看容器日志(动态项目)
部署命令返回 URL 后,按以下流程确认服务状态并提供日志查看:
- 等待 5 秒,然后查询项目状态:
bash
python "{skill_dir}/scripts/ztcds.py" status --project "<项目名>"
- 解读
state:
-running→ 构建完成、容器已启动,进入第 3 步
-starting/building→ 还在构建或启动中,再等 5 秒重查(最多查 5 次);
仍不成功就先告知用户「构建中,稍后可再查」,不要无限等待
-error/dead→ 把 stderr/stdout 里的 error 信息原样告知用户(构建失败原因)
-static→ 静态站点没有容器,跳过日志流程,直接结束 -
running时询问用户「要不要查看容器日志?」,询问时必须明确告知用户:
- 日志仅用于排查问题;如果访问链接已能正常打开,不需要拉取日志
- 日志接口有限流(每秒最多 1 次),不能频繁反复拉取
- 用户要 → 拉取最近 100 条日志:bash python "{skill_dir}/scripts/ztcds.py" logs --project "<项目名>" --tail 100
--tail默认 100,上限 1000,只能传数字;把日志内容展示给用户- 用户不要 → 直接结束,不多问
注意:日志接口限频每秒 1 次,不要连续快速调用;返回「请求过于频繁」时等 2 秒再试。
批量部署(多项目场景 SOP)
服务端部署队列已上线(async=1 受理 + worker 池消化,队列持久化到 MySQL),
批量部署不再需要控制提交间隔,按以下流程执行:
- 写部署清单:把每个项目的「英文项目名 / 中文名 / 描述 / data-dir」整理成 JSON 清单文件,
描述按服务端口径(用途 + 功能 + 技术栈,80~120 字)一次写好,避免逐个询问用户; - 提交阶段:循环调用 deploy 命令并带
--no-wait,项目之间无需间隔;
服务端收包即受理返回 deploy_id(含排队位置与预计等待秒数),把 deploy_id 记入清单;
输出含「约 X 秒后再试」(触发令牌桶)时等待 X+5 秒重试该项目,最多重试 5 次;
输出含 QUEUE_FULL(每用户在队上限 50)时等待 60 秒再继续提交; - 等待阶段:对清单中的 deploy_id 逐个执行
wait-deploy --deploy-id <id>轮询至终态
(脚本内部指数退避 2s→5s→10s,无需控制频率); - 结果判定:优先匹配访问地址行(以
https://开头且包含项目名的行),
其次才是部署成功字样——PowerShell 下 stderr 中文可能乱码,中文匹配不可靠;
同时把原始输出写入日志文件便于排查; - 全部跑完后再统一汇报:按「成功 N 个 / 失败 M 个 + 失败原因 + URL 清单」汇总,不要每部署一个就打断用户。
补充说明(服务端队列行为,客户端无需处理):
- 同项目重复提交自动合并:排队中的旧任务直接取消,只保留最新一次;
- 单任务意外异常服务端自动重试 2 次;单次构建最长 900 秒封顶;
- 服务重启后未完成任务从 MySQL 队列自动恢复重跑;
- 项目很多时不需要分批接力:全部提交进队列即可,worker 按序消化;
批量脚本仍可用 Start-Process powershell -WindowStyle Hidden 挂后台 + 轮询日志,
长任务挂后台的其余注意事项见下文「Windows 环境注意事项」。
Windows 环境注意事项(PowerShell / CMD)
在 Windows 上调用本 skill 的脚本时,已验证的坑点:
- 空参数会被吞:PowerShell 5.1 下
--data-dir ""会被 shell 移除,
导致argparse: expected one argument。改用等号写法--data-dir=(argparse 支持空值),
需要持久化时正常写--data-dir data或脚本中--data-dir="$dir"; - .ps1 脚本必须带 UTF-8 BOM:PowerShell 5.1 读取无 BOM 的脚本文件时按 ANSI/GBK 解码,
脚本里的中文字面量(如用于匹配输出「部署成功」的正则)会变成乱码导致匹配永远失败。
用write_to_file生成 ps1 后需补 BOM:
[IO.File]::WriteAllText($path, [IO.File]::ReadAllText($path, [Text.Encoding]::UTF8), (New-Object Text.UTF8Encoding($true))); - 中文字符串传参是安全的:Python 在 Windows 上通过宽字符 API 接收 argv,
传中文--project-name/--description不会乱码(与 git 的 GBK 问题不同); - stderr 中文捕获会乱码:PowerShell 5.1 下用
2>&1合并捕获 Python 输出时,
stderr 的中文按系统代码页(GBK)解码会变乱码,导致「部署成功」「约 X 秒后再试」
等中文匹配全部失效。脚本开头加一行解决:
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;
并且判定逻辑不要依赖中文文案,优先用退出码、[CICD:*]标记或访问 URL 行; - 长任务用后台进程:批量部署耗时长,用
Start-Process powershell -File xxx.ps1 -WindowStyle Hidden
挂后台并写日志文件,再轮询日志,避免阻塞 Agent 会话; $args是 PowerShell 保留自动变量:脚本/函数里把参数命名为$args会拿到 Null,
Start-Process -ArgumentList $args直接报参数验证失败。改名如$exeArgs即可;- 后台启动服务前先注入端口环境变量:本平台项目读
PORT(Java 读SERVER_PORT),
Python 默认 5000、Node/Go 默认 8000。本地冒烟测试时若不先$env:PORT=<测试端口>再启动进程,
请求会打到错误端口报「无法连接」,误判为服务起不来;同时用-RedirectStandardError把
stderr 落盘,启动失败时看日志定位(语法错误、缺依赖等)。
认证参数管理(手动命令)
# 单独保存认证参数
# 1. 先发送验证码
python "{skill_dir}/scripts/ztcds.py" send-code --email "<邮箱>"
# 2. 等用户收到邮件后保存 Token
python "{skill_dir}/scripts/ztcds.py" save-token --email "<邮箱>" --code "<6 位验证码>"
# 清除已保存的认证参数
python "{skill_dir}/scripts/ztcds.py" clear-token
支持的项目类型
类型一:静态站点(默认)
纯 HTML/CSS/JS 文件,直接托管。
允许的静态文件类型:
.html .htm .css .js .json .xml .txt .csv .md
.png .jpg .jpeg .gif .svg .ico .webp .bmp
.woff .woff2 .ttf .eot .otf
.mp4 .webm .ogg .mp3 .wav
.wasm .pdf .map
.db .sqlite .sqlite3(SQLite 数据库文件,随项目直接上传)
.zip .tar .gz .tgz .bz2 .xz .7z .rar(压缩包:只落盘不解压,可对外提供下载)
> 注意:单个文件超过 MAX_SINGLE_FILE_MB(默认 50MB)仍会被跳过,
> 随项目附带大压缩包时需要调大该服务端配置。
类型二:Python Web 服务
如果你的项目包含 Python 后端代码,可以直接部署。
额外允许的 Python 文件:
.py .cfg .toml requirements.txt Procfile
服务器自动检测规则:
项目中有 app.py / main.py / server.py + requirements.txt → 自动识别为 Python 项目 → 构建镜像、启动独立容器(/app 为代码目录,端口由服务端固定)
Python 项目注意事项:
- 端口不要硬编码(服务端会自动分配)
- 推荐用 os.environ.get('PORT', '5000') 获取端口
- 依赖写在 requirements.txt 中
- 前端路径必须使用相对路径! 项目部署在子路径下:
- HTML 静态引用(<script src="/js/main.js">)→ 打包时自动注入 <base> 标签修复
- JS 中的 fetch('/api/data') → 必须改成相对路径 fetch('./api/data')
类型三:Node 服务(package.json 有 start 脚本)
额外允许的文件: .ts .tsx .jsx .mjs .cjs .lock .yaml .yml
package.json package-lock.json yarn.lock pnpm-lock.yaml Procfile Makefile
检测与运行: 有 package.json 且有 start 脚本 → 起容器,
npm ci --omit=dev(无 lock 文件则 npm install --omit=dev)后 npm start。
注意事项:
- 必须监听环境变量 PORT(process.env.PORT),容器内部端口由服务端固定为 8000
- 监听地址用 0.0.0.0(服务端已注入 HOST=0.0.0.0,但代码仍需按环境变量绑定)
- 依赖写在 package.json 的 dependencies 里;不要上传 node_modules(自动跳过)
类型四:Node 前端打包型(package.json 只有 build 脚本)
无 start、只有 build 脚本 → 构建 dist/build/out/public 并按静态站点托管(不占常驻容器)。
注意事项:
- 构建脚本必须是 npm run build;产物目录为 dist / build / out / public 之一
- 前端路由/资源请用相对路径(部署在子路径下)
类型五:Go 服务(go.mod)
额外允许的文件: .go .mod .sum go.mod go.sum Makefile
检测与运行: 有 go.mod → 多阶段构建(CGO_ENABLED=0 go build),
产物二进制进精简运行镜像直接启动。
注意事项:
- 必须读 os.Getenv("PORT") 监听服务端注入的端口(默认注入 8000)
- main 包在根目录或 cmd/xxx 下均可自动定位
类型六:Java 服务(pom.xml)
额外允许的文件: .java .properties .gradle .kt
pom.xml build.gradle build.gradle.kts settings.gradle gradlew mvnw
检测与运行: 有 pom.xml → mvn -B -DskipTests package(走公司 Maven 镜像),
取 target/*.jar 中可执行 jar 进 JRE 运行镜像 java -jar app.jar。
注意事项:
- Spring Boot 项目端口由环境变量 SERVER_PORT / server.port 注入(已自动设为 8000)
- 非 Spring 项目自行读取 PORT 或 SERVER_PORT
各语言通用注意
- 端口统一由服务端注入(
PORT,Java 另有SERVER_PORT),不要硬编码 3000/8080 - 检测优先级:
go.mod→pom.xml/build.gradle→package.json→ Python
(同时存在时按此顺序取其一,前端项目不要放pom.xml/go.mod) - 依赖目录不要上传:
node_modules/target/vendor会被自动过滤 - 数据持久化(
--data-dir)对 Node/Go/Java 服务同样生效,规则与 Python 一致
数据持久化(声明式:部署时必须传 --data-dir):
服务端支持把代码目录内的一个相对目录挂载为持久卷:部署时用 --data-dir 声明该目录
(例如 --data-dir data),服务端会把它挂载到容器内 /app/data,并注入环境变量 DATA_DIR
指向该绝对路径。这样重新部署(容器重建)后数据仍在。
--data-dir是必传参数:不需要持久化的项目也必须显式传空字符串--data-dir "";
完全不传会被服务端判定为 skill 版本过旧并直接拒绝部署(提示升级 skill);- 只能写相对路径,且必须在代码目录内:允许
data、data/uploads(最多 3 层,每级只能用
字母/数字/下划线/连字符开头);禁止绝对路径、..上级目录、隐藏目录(如.data),
也禁止/xxx_data这类根路径; - 代码里统一按下面的写法读写数据(线上取注入的绝对路径,本地开发落到项目内的
data/):
python
import os
BASE = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.environ.get('DATA_DIR') or os.path.join(BASE, 'data')
UPLOAD_DIR = os.path.join(DATA_DIR, 'uploads')
os.makedirs(UPLOAD_DIR, exist_ok=True)
- 上传附件、SQLite/数据库文件、日志、缓存等运行数据都写进该目录;不要写到代码目录的其它位置,
也不要写死没有挂载的路径——重新部署后一定丢; - 打包时会自动排除该目录(运行数据不必重复上传);
- 静态站点(纯 HTML/CSS/JS)没有容器、也没有持久化目录,数据只能放在浏览器侧(localStorage / IndexedDB)。
数据库选型(优先 SQLite):
服务需要数据库时,优先使用 SQLite(单文件、零配置、零运维、免额外服务):
- SQLite 数据库文件随项目文件一并上传即可(允许的扩展名:
.db.sqlite.sqlite3),
平台自动识别为 SQLite 数据库文件、直接落盘,不需要任何额外配置; - 建议把数据库文件放在
--data-dir声明的持久化目录内(如data/app.db),
重新部署后数据保留;放在代码目录则每次部署会被上传的文件覆盖; - Python 用内置
sqlite3模块即可,Node 推荐better-sqlite3(纯 JS 依赖,镜像内安装无障碍),
连接路径同样基于注入的DATA_DIR环境变量拼接; - 只有当数据量、并发或既有代码强依赖 MySQL 时,才考虑 MySQL:
平台提供付费 MySQL 服务(见下文「付费增值服务」)。
禁止的文件类型
- 其他服务端脚本:
.php.rb.java.go.cs.sh.bat.ps1 - 其他服务端配置:
composer.jsonGemfilego.modCargo.toml
付费增值服务
平台提供以下付费增值服务,当用户的项目需要MySQL 数据库或短信通知能力
(或用户主动询问数据库、短信、增值服务)时,向用户介绍并引导开通:
- 付费 MySQL:独立 MySQL 实例,适合数据量/并发超出 SQLite 能力、
或既有代码强依赖 MySQL 的项目;开通后服务端会下发连接配置(主机 / 端口 / 账号密码),
项目代码按普通 MySQL 连接方式接入即可 - 短信通知服务:项目内发送短信验证码、通知类短信,适合需要手机号验证、
消息触达的应用
开通与计费请引导用户联系上文「用户求助与反馈」中的官方渠道(QQ 群 / 邮箱);
不要向用户承诺未在服务端文案中出现的价格、SLA 或时限。
用户求助与反馈
当用户遇到问题且按本 SOP 无法解决(部署反复失败 / 平台异常 / 账号与验证码问题 / 用户明确要求人工帮助),
把以下官方渠道告诉用户;不要自行编造其它联系方式或承诺处理时效:
- QQ 交流群:群号
1130144012,一键加入:https://qm.qq.com/q/IAuhg9BZSi
群内按「做了什么 + 卡在哪一步 + 报错截图」的格式反馈,解决最快 - 邮箱:guoyanan@ztaqtec.com(问题反馈与商务合作)
用户只是询问平台信息(介绍 / 怎么用 / 版本 / 特点 / 新特性)时走上文「平台信息查询」流程,
不需要引导到以上渠道。
注意事项
- 单文件最大 50MB,总计 1GB,上限 2000 个文件(超出会被服务端拒绝部署)
- 认证参数保存在
~/.ztcds/token.json(仅当前用户可读写) - 不再使用 tkinter 弹窗,全部通过终端和 Agent 对话交互
- 部署成功后,旧的同名项目会被覆盖