> ## Documentation Index
> Fetch the complete documentation index at: https://docs.meoo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 项目导入、构建与发布

上传 Web 源码创建新项目，再单独发布。默认流程是：上传源码并等待 `import.completed`，再调用发布接口并等待 `release.completed`。Meoo 导出的 Web 项目保留原有运行方式；普通外部源码按 `mise.toml` 安装环境、执行工程任务和部署。如果需要补齐配置或修复运行问题，可启用本文末尾的 AI 适配与修复能力。

## 源码导入发布与静态直传怎么选

主要区别是**上传源码还是构建产物，以及由谁执行构建**。

| 对比项              | 源码导入后发布                                                                            | 静态产物直传                                          |
| :--------------- | :--------------------------------------------------------------------------------- | :---------------------------------------------- |
| 上传什么             | 工程源码、依赖清单、`mise.toml` 等                                                            | 已构建好的 HTML、CSS、JS、图片等静态文件                       |
| 由谁构建             | 平台在发布阶段沿用 Meoo 项目的原构建方式，或按 `mise.toml` 执行 install/build 任务                         | 接入方在本地或 CI 中提前构建；平台不执行安装和构建                     |
| 发布形式             | 静态站点，或持续运行的 HTTP 服务                                                                | 静态站点                                            |
| 是否需要 `mise.toml` | 旧 Meoo 项目无需补齐；使用 mise 的项目及普通外部源码发布前需要                                              | 不需要                                             |
| 调用流程             | `POST /projects/import` 上传源码 → 等待导入完成 → `POST /projects/{project&#95;id}/releases` | 创建或选择 Web 项目 → prepare → PUT 产物到 OSS → complete |
| 适合场景             | 希望在 Meoo 中保存、修改源码，使用可选 AI 修复，或托管后端服务                                               | 已有构建流水线，只需要托管静态文件并获得访问链接                        |

**导入本身不等于构建。** 默认流程先保存源码，单独调用发布接口后才按项目配置构建和部署。没有构建步骤的工程可以省略 `tasks.build`；静态项目直接发布 `output` 目录，HTTP 服务按 `tasks.start` 启动。

同一个静态工程可以走两条路径：上传源码和构建脚本，让 Meoo 构建；或者在自己的 CI 中完成构建，只将产物目录中的文件打成 ZIP 后[静态直传](https://app.mintlify.com/alibaba-b47c397f/alibaba-b47c397f/~/e0c02cae-8c7f-4fda-b17b-ca6303fe4903)。直传 ZIP 的根目录必须有 `index.html`，不要再包一层 `dist/`。静态直传不会运行 Python、Java、Go 等后端程序，也不会把产物还原成可编辑源码；两种发布方式都会按各自流程进行内容安全检查。

## Meoo 导出项目如何导入

直接上传 Meoo 导出的 Web 项目 ZIP，默认 `ai_adapt=false`，等待 `import.completed` 后调用发布接口。平台与首页使用相同的导出包识别规则，保留项目原有运行方式：旧 Meoo 项目无需补 `mise.toml`，原本使用 mise 的项目继续使用原配置。请保留导出包中的 manifest；无法验证导出标识的包会按普通外部源码处理。

导入只创建新项目，不覆盖原项目，也不自动恢复数据库、云函数等云资源。环境变量和外部服务仍需按新项目配置。

## 普通外部源码通过 mise 发布的要求

| 项目部分 | 要求                                                                                               |
| :--- | :----------------------------------------------------------------------------------------------- |
| 源码包  | 一个 Web 工程的 ZIP；源码在根目录或统一的单层外包装目录内，解包后的工程根目录包含 `mise.toml`                                        |
| 运行协议 | `mise.toml` 是有效 TOML，并声明 `&amp;#91;meoo.deploy]`；静态站点用 `mode="static"`，HTTP 服务用 `mode="server"`  |
| 工具版本 | 需要的语言运行时和包管理器在 `&amp;#91;tools]` 声明；不要依赖开发机上的全局工具                                                |
| 安装依赖 | 有依赖时提供依赖清单、锁文件及 `&amp;#91;tasks.install].run`；部署环境必须能访问所需依赖源。不要打包 `node&amp;#95;modules` 或本地虚拟环境 |
| 构建   | 需要构建时提供 `&amp;#91;tasks.build].run`；命令必须能无人值守运行并成功退出，不需要构建可省略                                    |
| 外部服务 | 数据库、第三方 API、环境变量等应已按项目需求配置；源码导入不会替你配置这些依赖                                                        |

导入成功只表示源码已提交和持久化，**不会提前验证构建或生产服务启动一定成功**。普通外部源码缺少 `mise.toml` 时也可导入，但发布前需要补齐；可识别的旧 Meoo 导出包沿用原有配置。不要把 API 返回 HTTP 200 当作导入或发布成功；必须读取对应的 SSE 终态。

首期自测基线是无依赖静态 HTML 和 Node.js HTTP 服务。其他框架可通过相同任务协议接入，但能否部署取决于其工具、系统依赖与运行环境兼容性；本接口不提供任意工程的兼容性保证，也不提供 App 安装包、小程序渠道发布或多服务编排。

## 静态站点的最小例子

工程包含 `index.html` 和以下 `mise.toml`：

```text theme={null}
[tasks.build]
run = "mkdir -p dist && cp index.html dist/index.html"

[meoo.deploy]
mode = "static"
output = "dist"
```

`output` 是工程内的相对目录，不能使用绝对路径或越过工程根目录。构建结束后该目录必须包含可访问的站点文件（本例为 `dist/index.html`）。如果产物已经随源码放在该目录，可以省略构建任务。涉及 npm 等依赖的项目还需自行声明工具版本和安装任务。

## HTTP 服务的最小例子

工程包含以下 `server.cjs`：

```text theme={null}
const http = require('node:http');
http.createServer((req, res) => {
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify({ path: req.url }));
}).listen(3000, '0.0.0.0');
```

以及 `mise.toml`：

```text theme={null}
[tools]
node = "20"

[tasks.start]
run = "node server.cjs"

[meoo.deploy]
mode = "server"
port = 3000
```

服务端必须有非空 `tasks.start.run`，启动命令保持前台运行，并在 `0.0.0.0` 上监听与 `meoo.deploy.port` 一致的端口（整数 1–65535）。服务端模式不要声明静态 `output`；若声明了 `install` 或 `build` 任务，也必须提供非空 `run`。需要编译的服务应在构建任务里生成产物，再由启动任务运行生产入口。

仅做正式发布不要求 `tasks.dev`。如果还需要 Meoo 沙箱预览，另行提供 `tasks.dev.run`，让预览服务监听 `0.0.0.0:3015`；生产端口仍以 `meoo.deploy.port` 为准。预览页面需要允许 Meoo 跨域 iframe 嵌入，不能返回阻止嵌入的响应头。

## 非 JavaScript 项目示例：Python

项目不要求使用 JavaScript。部署方式由最终需要静态文件还是 HTTP 服务决定，工具和执行命令在 `mise.toml` 中声明。下面两个示例都使用前文同一套导入、发布 API。

### 示例一：用 Python 构建静态页面

工程包含 `build.py` 和 `mise.toml`。`build.py` 读取数据并生成站点文件：

```text theme={null}
from pathlib import Path

output = Path("dist")
output.mkdir(exist_ok=True)
(output / "index.html").write_text(
    '<!doctype html><html lang="zh-CN"><meta charset="utf-8">'
    '<title>Python site</title><h1>Hello from Python</h1></html>',
    encoding="utf-8",
)
```

`mise.toml`：

```text theme={null}
[tools]
python = "3.12"

[tasks.build]
run = "python build.py"

[meoo.deploy]
mode = "static"
output = "dist"
```

将这两个文件放在源码 ZIP 根目录，导入后调用发布接口。平台执行 `python build.py`，再托管生成的 `dist/index.html`；网站访问时不运行 Python。本例只用标准库，不需要安装依赖，也不需要 `tasks.start`。

若改走静态直传，先在自己的环境运行 `python build.py`，再将 `dist` 里的文件打包，使 ZIP 根目录直接包含 `index.html`。这时无需上传 `build.py` 和 `mise.toml`，平台也不会再次构建。

### 示例二：Python HTTP 服务（Flask + Gunicorn）

工程根目录包含 `app.py`、`requirements.txt` 和 `mise.toml`。`app.py`：

```text theme={null}
from flask import Flask, jsonify

app = Flask(__name__)


@app.get("/")
def index():
    return "<h1>Hello from Python</h1>"


@app.get("/api/hello")
def hello():
    return jsonify(message="Hello from Python")
```

`requirements.txt`（示例固定依赖版本）：

```text theme={null}
Flask==3.1.2
gunicorn==23.0.0
```

`mise.toml`：

```text theme={null}
[tools]
python = "3.12"

[tasks.install]
run = "python -m venv .venv && .venv/bin/python -m pip install -r requirements.txt"

[tasks.start]
run = ".venv/bin/gunicorn --bind 0.0.0.0:3000 --workers 1 --access-logfile - app:app"

[meoo.deploy]
mode = "server"
port = 3000
```

只打包这三个源码文件，不要打包本地 `.venv`。发布时平台安装 Python 和依赖，再使用 Gunicorn 启动 HTTP 服务；访问 `/` 返回页面，访问 `/api/hello` 返回 JSON。本例不需要编译，所以省略 `tasks.build`；如果项目需要生成代码或编译资源，再声明对应的 build 命令。Gunicorn 的 `app:app` 表示加载 `app.py` 中的 `app` 对象，写法见 [Flask 部署说明](https://flask.palletsprojects.com/en/stable/deploying/gunicorn/)。

如需沙箱预览，可另外配置 `tasks.dev.run` 为 `.venv/bin/gunicorn --bind 0.0.0.0:3015 --workers 1 app:app`。预览和生产启动分别使用 3015、3000 端口。

这个示例需要持续运行 Python 服务，因此应使用源码导入后发布，不能把 `.py` 文件通过静态直传当作后端运行。示例说明的是协议和工程组织方式；实际部署仍取决于目标环境的工具安装、依赖源和服务运行结果。

## 调用顺序

先导入；Token 需要 `project.write source.write`：

```text theme={null}
curl -N 'https://meoo.com/open/v1/projects/import' \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H 'Idempotency-Key: source-import-001' \
  -F 'file=@./project.zip;type=application/zip' \
  -F 'ai_adapt=false'
```

收到 `import.completed` 且 `ai.status=skipped` 后，保存其 `project_id`。再发布；Token 需要 `release.write`：

```text theme={null}
curl -N "https://meoo.com/open/v1/projects/${PROJECT_ID}/releases" \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H 'Idempotency-Key: source-publish-001' \
  -H 'Content-Type: application/json' \
  --data '{}'
```

收到 `release.completed` 后访问 `access_url` 验证站点或服务。发布使用项目当前源码，无需传 Git 提交 ID。导入期间请勿从其他入口编辑、启动 Agent、发布或删除项目，必须等到 `import.completed` 再继续；服务端不额外加锁。发布失败时保留当前项目，按 `release.failed.message` 修复配置或源码，再用新的发布 Key 发起新的发布尝试，无需重复导入。

网络断开时先使用同一有效凭证、同一请求和原 Key 重连确认结果，不要把断线当成失败而立即换 Key。完整字段、ZIP 限制、凭证续期限制及错误处理见[源码导入 API](https://app.mintlify.com/alibaba-b47c397f/alibaba-b47c397f/~/91f543e7-3294-43b9-9690-d60c1e5c1aa5)和[发布 API](https://app.mintlify.com/alibaba-b47c397f/alibaba-b47c397f/~/b31b1b0b-7d62-41df-a2f9-3643354ac937)。

## 可选：AI 适配与修复

在导入表单中设置 `ai_adapt=true`，其余字段和 ZIP 要求不变。除 `project.write source.write` 外，还需 `agent.run`；查看 AI 状态和输出需 `agent.read`，最后发布需 `release.write`。

```text theme={null}
curl -N 'https://meoo.com/open/v1/projects/import' \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H 'Idempotency-Key: source-import-ai-001' \
  -F 'file=@./project.zip;type=application/zip' \
  -F 'ai_adapt=true'
```

### AI 能做什么

导入完成后，平台通过已有 Agent 能力处理项目。旧 Meoo 项目沿用原框架和构建发布方式，按需修复依赖、源码和运行配置；使用 mise 的项目通过 `mise-import` 补齐配置并验证预览。按工程情况尝试：

* 识别项目结构、技术栈、依赖和启动方式。
* 使用 mise 的项目补齐或调整 `mise.toml`；旧 Meoo 项目修复原有构建和运行配置。
* 在验证过程中定位配置或源码问题，并尝试修改相关文件，使工程能够运行。
* 验证沙箱预览，并通过 Agent 事件输出处理过程和结果。

这些是 AI 尝试完成的任务，不是确定性的格式转换或修复保证。开启选项即允许 AI 修改配置及源码，请检查最终改动和运行结果。该导入适配任务不会开通平台云资源，也不执行正式发布；数据库、第三方服务、授权和环境变量仍需接入方准备。内容安全检查不通过时不会通过 AI 绕过审核；超出导入支持范围的 ZIP 也不会先交给 AI 修复。

### 如何知道 AI 完成了

导入接口的完成事件只返回 AI 的启动结果，不在导入 SSE 中转发 AI 输出：

```text theme={null}
event: import.completed
data: {"import_id":"imp_example","project_id":"demo","conversation_id":"123","ai":{"status":"started","run_id":"run_example"}}
```

保存 `project_id`、`conversation_id` 和 `ai.run_id`，继续使用[已有 Agent API](https://app.mintlify.com/alibaba-b47c397f/alibaba-b47c397f/~/0cacadf2-712b-4a08-9c29-550e056ef249)：

```text theme={null}
GET /open/v1/projects/{project_id}/agent/runs/{run_id}/events
GET /open/v1/projects/{project_id}/agent/runs/current
```

通过 Agent 事件展示 AI 输出，按原有协议处理用户交互，并等待 Run 的终态。`ai.status=started` 不代表修复完成，Run 完成也不代表已经正式发布；检查结果后再调用本文的发布接口，等待 `release.completed`。

### AI 或发布失败后怎么办

* `ai.status=failed` 表示源码已导入，但未确认 AI 启动成功。先查询当前 Run，避免重复启动；确认没有任务运行后，再通过原有 Agent 接口继续处理这个项目。
* AI Run 失败或修复不完整时，保留该项目，使用 `POST /open/v1/projects/{project_id}/agent/runs`，传入导入返回的 `conversation_id` 和明确的修复要求继续会话。请求格式、幂等和事件处理沿用 Agent API。
* 发布构建失败时，可以把 `release.failed.message` 中的错误交给后续 Agent Run 修复。修复完成并确认没有任务运行后，用新的发布 Key 重试发布；这一步需要接入方发起，不会由导入接口自动循环修复和发布。
* 后续自行发起的 Agent Run 不等于导入自带的适配任务，请按 Agent 协议明确任务范围；不要在提示词中提交 Secret 或 Token。
