# 发布脚本版本 (/docs/api/native/automation/publishScriptVersion)





从草稿或临时运行源码发布版本，校验定义并锁定依赖。草稿须匹配 expected_draft_revision；临时运行由 from_run 与 expected_source_sha256 指定。版本相同且内容相同返回已有版本，内容不同返回 VERSION_EXISTS；预发布版本必须显式带 tag（不能是 latest，tag 只能含 URL 安全字符且不能是版本号或范围，违规返回 TAG_REQUIRED 或 TAG_INVALID，hint 给出完整规则），校验不通过返回 DEFINITION_INVALID。稳定版本仅高于已有最高稳定版本时自动移动 latest；工作流成为 latest 时同步定义中的定时触发器。 发布会去掉版本号的 +build 元数据。

`POST /automation/v1/scripts/{ns}/{name}/versions`

## 鉴权 [#鉴权]

`Authorization: Bearer $PRAXIS_API_KEY`

## 请求字段 [#请求字段]

| 参数 | 类型 | 说明 |
| --- | --- | --- |
| path: ns | `string` | 必填；命名空间，存储前转为小写，格式 [a-z0-9][a-z0-9._-]&#123;0,63&#125;；praxis 只读。 |
| path: name | `string` | 必填；名称，存储前转为小写，格式 [a-z0-9][a-z0-9._-]&#123;0,63&#125;。 |
| header: Idempotency-Key | `string` | 可选；可选；1–256 字符。24 小时内同一 key 重放首个响应并带 Idempotent-Replayed: true；同 key 不同请求体返回 422；处理中返回 409。 minLength: 1；maxLength: 256 |

### application/json [#applicationjson]

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| （分支1).version | `string` | 必填 / 必有；规范的精确语义版本，例如 1.2.0 或 1.3.0-beta.1；不能是范围。 |
| （分支1).expected_draft_revision | `string` | 必填 / 必有；发布的草稿修订，必须匹配当前草稿；与 from_run 发布方式二选一。 |
| （分支1).tag | `string` | 可选；发布标签。预发布版本（如 1.3.0-beta.1）必须带 tag 且不能是 latest；tag 只能由 URL 安全字符组成（字母、数字及 - _ . ! ~ * ' ( )），不含空格和 / ? #，首尾无空白；不能是版本号或版本范围（如 1.2.3、^1、1.x、*）；beta、next、debug 等其余名称均可。违规返回 TAG_INVALID 或 TAG_REQUIRED，hint 给出完整规则。 |
| （分支2).version | `string` | 必填 / 必有；规范的精确语义版本，例如 1.2.0 或 1.3.0-beta.1；不能是范围。 |
| （分支2).from_run | `string` | 必填 / 必有；提供源码快照的临时运行 ID；已发布目标的运行当前没有可用于此入口的快照。须同时给出 expected_source_sha256，不能同时给 expected_draft_revision。 |
| （分支2).expected_source_sha256 | `string` | 必填 / 必有；运行源码的 SHA-256 摘要，必须与快照匹配。 |
| （分支2).tag | `string` | 可选；发布标签。预发布版本（如 1.3.0-beta.1）必须带 tag 且不能是 latest；tag 只能由 URL 安全字符组成（字母、数字及 - _ . ! ~ * ' ( )），不含空格和 / ? #，首尾无空白；不能是版本号或版本范围（如 1.2.3、^1、1.x、*）；beta、next、debug 等其余名称均可。违规返回 TAG_INVALID 或 TAG_REQUIRED，hint 给出完整规则。 |

## 示例 [#示例]

[SDK 安装与示例环境](/docs/api/native/automation)

先设置以下环境变量，使用你自己的资源：

| 变量 | 来源 |
| --- | --- |
| SCRIPT_NAME | [创建脚本返回的 name](/docs/api/native/automation/createScript) |
| DRAFT_REVISION | [当前 draft.revision](/docs/api/native/automation/getScript) |

```bash
: "${SCRIPT_NAME:?Set SCRIPT_NAME}"
: "${DRAFT_REVISION:?Set DRAFT_REVISION}"
BODY=$(jq -n --arg DRAFT_REVISION "$DRAFT_REVISION" '{
  "version": "1.0.0",
  "expected_draft_revision": $DRAFT_REVISION
}')
curl --fail-with-body -X POST "https://api.deepraxis.ai/automation/v1/scripts/docs-samples/${SCRIPT_NAME}/versions" \
  -H "Authorization: Bearer $PRAXIS_API_KEY" \
  -H "Content-Type: application/json" \
  --data "$BODY"
```

```typescript
import { createAutomationClient } from '@deepractice-ai/praxis-sdk/automation';

function env(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Set ${name}`);
  return value;
}
const automation = createAutomationClient({
  apiKey: env('PRAXIS_API_KEY'),
  baseUrl: 'https://api.deepraxis.ai',
  maxRetries: 0,
  timeoutMs: 90_000,
});
const result = await automation.scripts.versions.publish({
  "path": {
    "ns": "docs-samples",
    "name": env("SCRIPT_NAME")
  },
  "body": {
    "version": "1.0.0",
    "expected_draft_revision": env("DRAFT_REVISION")
  }
});
console.log(result);
```

## 响应 [#响应]

### HTTP 200 [#http-200]

Success

| 响应头 | 类型 | 说明 |
| --- | --- | --- |
| Idempotent-Replayed | `boolean` | Present and true when replaying the first response for this key. |

`application/json`

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| id | `string` | 必填 / 必有；版本 ID，脚本前缀 scv_，工作流前缀 wfv_。 |
| kind | `"script"` / `"workflow"` | 必填 / 必有；编排类型。script 为 TypeScript 脚本，一次执行；workflow 为 YAML 工作流，由步骤组成，可等待事件、定时器或子运行并可暂停。 |
| version | `string` | 必填 / 必有；版本号（semver，已去掉 +build 元数据）。 |
| digest | `string` | 必填 / 必有；源码与契约的内容摘要。 |
| source | `string` | 必填 / 必有；该版本的完整源码。版本列表默认不返回，需要时加 expand=source。 |
| input_schema | `object` | 必填 / 必有；任意 JSON 对象（键为字符串，值为任意 JSON 值）。 |
| input_schema.*（分支5) | `object` | 递归 JSON 值。 |
| input_schema.*（分支6)[] | `null` / `string` / `number` / `boolean` / `object` / `JSON[]` | 递归 JSON 值。 |
| output_schema | `object` | 必填 / 必有；脚本从返回类型推导，支持 Promise 解包、Record、交叉类型和 Date（date-time）；推不出时为空 schema，并在 /validate 的 warnings 给出 warning。 |
| output_schema.*（分支5) | `object` | 递归 JSON 值。 |
| output_schema.*（分支6)[] | `null` / `string` / `number` / `boolean` / `object` / `JSON[]` | 递归 JSON 值。 |
| references | `object[]` | 必填 / 必有；该版本依赖的动作、平台 API、脚本与工作流。脚本和工作流依赖在发布时锁定到精确版本。 |
| references[].kind | `"action"` / `"script"` / `"workflow"` / `"platform_api"` / `"run"` | 必填 / 必有；依赖类型。action 为动作；platform_api 为平台 API 操作；script 为脚本；workflow 为工作流；run 为脚本中 invoke("ns/name") 调用的子运行目标（脚本或工作流，发布时解析）。 |
| references[].name | `string` | 必填 / 必有；被依赖对象：动作为 ns/name，平台 API 为操作名，脚本与工作流为 ns/name。 |
| references[].range | `string` | 可选；引用时写的版本范围或标签（npm 规则）；未写时为空。 |
| references[].locked_version | `string` | 可选；发布时锁定的精确版本；仅脚本与工作流依赖有，动作与平台 API 不锁定。 |
| outline | `null` / `object[]` | 必填 / 必有；工作流的步骤大纲（OutlineNode 数组），由解析器静态生成；脚本为 null。 |
| outline（分支2)[].name | `string` | 必填 / 必有；步骤名，即工作流 YAML 中该步骤的键。 |
| outline（分支2)[].reference | `string` | 必填 / 必有；该步骤在工作流文档中的 JSON Pointer，例如 /do/0/start；与运行时 Task.reference 一致。 |
| outline（分支2)[].kind | `"run"` / `"call"` / `"wait"` / `"set"` / `"for"` / `"fork"` / `"try"` / `"switch"` / `"emit"` / `"raise"` / `"listen"` / `"do"` | 必填 / 必有；工作流步骤类型。call 调用动作；run 运行子脚本或子工作流；wait 等待时长；set 设置变量；for 循环；fork 并行分支；try 带捕获的块；switch 条件分支；emit 发出事件；raise 抛出错误；listen 等待事件；do 顺序执行的步骤块。 |
| outline（分支2)[].target | `string` | 可选；步骤调用的目标：call 步骤为动作 ns/name，run 步骤为 ns/name@范围；其它类型没有。 |
| outline（分支2)[].wait | `object` | 可选；等待步骤的摘要：时长（seconds 或 duration）或等待的事件类型（event）。 不接受额外字段。 |
| outline（分支2)[].wait.until | `string` | 可选；等待结束的绝对时刻，仅在可静态确定时给出；目前大纲不填充该字段。 |
| outline（分支2)[].wait.seconds | `number` | 可选；可静态换算的等待秒数；时长对象与可换算的 ISO 时长均投影到此字段。 |
| outline（分支2)[].wait.event | `string` | 可选；listen 步骤等待的事件类型。 |
| outline（分支2)[].wait.duration | `string` | 可选；无法静态换算成秒的原始时长或运行时表达式；不与 seconds 强行换算。 |
| outline（分支2)[].loop | `object` | 可选；for 步骤的循环信息 &#123;each, in&#125;。 不接受额外字段。 |
| outline（分支2)[].loop.each | `string` | 必填 / 必有；循环变量名；未指定时为 item。 |
| outline（分支2)[].loop.in | `string` | 必填 / 必有；被遍历的集合表达式原文。 |
| outline（分支2)[].children | `object[]` | 可选；嵌套的子步骤（do、fork 分支、try 与 catch 内的步骤）。 |
| outline（分支2)[].children[] | `object` | 递归 JSON 值。 |
| sdk_version | `null` / `string` | 必填 / 必有；发布脚本所用的 SDK 版本；工作流为 null。 |
| published_at | `string` | 必填 / 必有；发布时间（RFC 3339 UTC）。 |
| published_by | `object` | 必填 / 必有；网关注入的主体 &#123;type, id&#125;，表示谁发起或操作；本服务不解析名字，名字由控制台批量解析。 不接受额外字段。 |
| published_by.type | `"user"` / `"api_key"` / `"agent"` / `"run"` / `"trigger"` | 必填 / 必有；主体类型。user 为登录用户；api_key 为平台 API Key；agent 为智能体；run 为由运行本身（例如父运行）执行的操作；trigger 为触发器。 |
| published_by.id | `string` | 必填 / 必有；主体标识，含义随 type 而定：用户 ID、API Key ID、智能体 ID、运行 ID 或触发器 ID；按不透明字符串处理。 |
| deprecated | `null` / `string` | 必填 / 必有；弃用说明；未弃用为 null。弃用的版本仍可运行，但按范围或标签解析时优先选用未弃用的版本。 |
| deprecated_at | `null` / `string` | 必填 / 必有；弃用时间（RFC 3339 UTC）；未弃用为 null。 |
| deprecated_by | `null` / `object` | 必填 / 必有；执行弃用的主体；未弃用为 null。 |
| deprecated_by（分支2).type | `"user"` / `"api_key"` / `"agent"` / `"run"` / `"trigger"` | 必填 / 必有；主体类型。user 为登录用户；api_key 为平台 API Key；agent 为智能体；run 为由运行本身（例如父运行）执行的操作；trigger 为触发器。 |
| deprecated_by（分支2).id | `string` | 必填 / 必有；主体标识，含义随 type 而定：用户 ID、API Key ID、智能体 ID、运行 ID 或触发器 ID；按不透明字符串处理。 |

### 实测响应 [#实测响应]

HTTP 200

```json
{
  "id": "scv_00mv67lza679fc5498438040079f0c5684208c4915",
  "kind": "script",
  "version": "1.0.0",
  "digest": "7ae6678882a4ef2ea96e401c105d5c6ef512917cd72a9235289d2a3bf1f1b49d",
  "input_schema": {
    "type": "object",
    "properties": {
      "n": {
        "type": "number"
      }
    },
    "required": [
      "n"
    ]
  },
  "output_schema": {
    "type": "object",
    "properties": {
      "answer": {
        "type": "number"
      }
    },
    "required": [
      "answer"
    ]
  },
  "references": [],
  "outline": null,
  "sdk_version": "0.1.0",
  "published_at": "2026-10-13T04:57:22.398Z",
  "published_by": {
    "type": "api_key",
    "id": "key_3e00b8984967"
  },
  "deprecated": null,
  "deprecated_at": null,
  "deprecated_by": null,
  "source": "export default async (input: { n: number }) => ({ answer: input.n + 1 });"
}
```

## 错误码 [#错误码]

| HTTP | 错误码与说明 |
| --- | --- |
| 400 | INVALID_PARAMS：请求参数、路径、游标或请求体格式无效。 TAG_REQUIRED：预发布版本必须显式指定发布标签（例如 beta，不能是 latest）；响应 hint 列出完整规则。 TAG_INVALID：标签无效：预发布版本不能打 latest；tag 只能含 URL 安全字符（不含空格和 / ? #）；不能是版本号或范围；latest 不能删除。响应 hint 列出完整规则。 DEFINITION_INVALID：源码未通过定义校验。 |
| 403 | NAMESPACE_FORBIDDEN：命名空间只读或运行令牌不允许此调用。 |
| 404 | TARGET_NOT_FOUND：编排目标不存在或类型不匹配。 RUN_NOT_FOUND：运行不存在或当前租户不可见。 |
| 409 | IDEMPOTENCY_IN_FLIGHT：同一幂等键的请求仍在处理中。 TARGET_ARCHIVED：目标已归档，不能用于本操作；动作执行错误的 detail 包含 ns/name。 VERSION_EXISTS：版本号已存在且源码内容不同。 |
| 412 | PRECONDITION_FAILED：修订、源码摘要或并发写入条件不匹配。 |
| 422 | IDEMPOTENCY_KEY_MISMATCH：同一幂等键已用于不同请求内容。 DEFINITION_IDENTITY_MISMATCH：源码声明或运行语言与发布目标不一致。 NO_MATCHING_VERSION：没有满足标签、版本或范围的已发布版本。 CYCLE_DETECTED：发布后依赖会形成环（A 依赖 B、B 又依赖 A）；detail 给出环路径。 |
| default | RFC 9457 automation problem. 429 includes Retry-After. |

[鉴权错误与通用错误](/docs/api/errors) · 排查时保留响应头 `X-Request-Id`。
